Compare commits

...

23 Commits

Author SHA1 Message Date
David Kuder
8012d85d23 CHS Settings 2023-05-29 19:51:19 -04:00
David Kuder
a09d5dbf13 Update scsibus.ino 2023-05-13 03:01:20 -04:00
David Kuder
d420244da9 RAW disk support and LittleFS support 2023-05-13 02:49:13 -04:00
David Kuder
c5c4c51667
preAllocate fail
preAllocate has angered the TrackZero and must be punished, out with preAllocate, in with writing zeros 512 bytes at a time.
2022-10-14 22:40:33 -04:00
David Kuder
bc114096ac
Update README.md 2022-09-16 12:43:09 -04:00
David Kuder
41455971d4 Update GreenSCSI Manual.pdf 2022-06-12 01:44:36 -04:00
David Kuder
1205f4ad6e Schematic for MVP 2022-06-11 23:29:39 -04:00
David Kuder
382052a5a0 MVP Edition Hardware
Minimum Viable Product schematic, PCB layout & Gerbers.
2022-06-11 23:09:38 -04:00
David Kuder
1714acb3a2 Merge branch 'main' of https://github.com/dkgrizzly/GreenSCSI 2022-06-11 23:06:51 -04:00
David Kuder
8d84bc8ece 3D Printed Case 2022-06-11 23:06:47 -04:00
David Kuder
0abf96bd82
Update README.md 2022-06-11 15:32:06 -04:00
David Kuder
4ab58d0fff
Reference Manual First Draft 2022-06-11 15:31:30 -04:00
David Kuder
3429bab34b Send Diagnostic, Prefetch and Sync Cache stubs 2022-06-11 11:13:45 -04:00
David Kuder
7d1227a193 Rigid Geometry & Format Parameters
Updates from upstream
2022-06-11 11:12:43 -04:00
David Kuder
b8bdb3fe37 Verify10 command 2022-06-11 11:10:50 -04:00
David Kuder
7c51723a2b Import checkBlockCommand from upstream 2022-06-11 11:10:16 -04:00
David Kuder
4f4a9b1a33 Flexible Disk support 2022-06-11 11:09:01 -04:00
David Kuder
b8580bd4e6 Verify Data Phase
Verify stub
2022-06-11 11:07:37 -04:00
David Kuder
cb123509d2 Tape Fixes
Fixing various tape commands
2022-06-11 11:06:20 -04:00
David Kuder
2f14c0fed2 Constant consistency
Cleaning up "Magic Values" and replacing them with defined constants.
misc fixes.
2022-06-11 11:05:47 -04:00
David Kuder
968f3336af Control channel framework
Building the framework for communicating with the GreenSCSI command line over the SCSI bus.
2022-06-11 10:59:23 -04:00
David Kuder
5aeb32e928 File allocation fix
mkimg would create files 1/1048576 in size compared to the request.
2022-06-11 10:56:21 -04:00
David Kuder
cf468bcbde Debug Logging Toggle
Debug Logging disabled by default, On/Off toggle with setvar debug 1/0
2022-06-11 10:54:54 -04:00
22 changed files with 11510 additions and 250 deletions

BIN
GreenSCSI Manual.pdf Normal file

Binary file not shown.

View File

@ -2,15 +2,15 @@
![DeadBug assembly of a Teensy 3.5 directly on a 50 pin SCSI header!](/GreenSCSI-DeadBug.jpg "GreenSCSI Teensy 3.5 Dead Bug")
GreenSCSI, BlueSCSI & ArdSCSino are hardware that reproduces SCSI devices (hard disks) with Arduino like devices.
GreenSCSI, BlueSCSI & ArdSCSino are hardware that reproduce SCSI devices (hard disks) with Arduino like devices.
`GreenSCSI` created by https://github.com/dkgrizzly[dkgrizzly] is a fork of `BlueSCSI` which adds:
`GreenSCSI` created by https://github.com/dkgrizzly [dkgrizzly] is a fork of `BlueSCSI` which adds:
* Teensy 3.5 (Kinetis K64...) support
* Better LUN handling
`BlueSCSI` created by https://github.com/erichelgeson[erichelgeson] is a fork of `ArdSCSino-stm32`
`BlueSCSI` created by https://github.com/erichelgeson [erichelgeson] is a fork of `ArdSCSino-stm32`
`ArdSCSino-stm32` created by https://github.com/ztto/ArdSCSino-stm32[ztto] is the STM32 version of `ArdSCSino`
`ArdSCSino-stm32` created by https://github.com/ztto/ArdSCSino-stm32 [ztto] is the STM32 version of `ArdSCSino`
`ArdSCSino` created by https://twitter.com/h_koma2[Tambo (TNB Seisakusho)]
`ArdSCSino` created by https://twitter.com/h_koma2 [Tambo (TNB Seisakusho)]

4202
case/GreenSCSI-bottom.stl Normal file

File diff suppressed because it is too large Load Diff

1402
case/GreenSCSI-top.stl Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,220 @@
EESchema-LIBRARY Version 2.4
#encoding utf-8
#
# Connector_Generic_Conn_01x02
#
DEF Connector_Generic_Conn_01x02 J 0 40 Y N 1 F N
F0 "J" 0 100 50 H V C CNN
F1 "Connector_Generic_Conn_01x02" 0 -200 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 50 50 -150 1 1 10 f
X Pin_1 1 -200 0 150 R 50 50 1 1 P
X Pin_2 2 -200 -100 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Generic_Conn_01x04
#
DEF Connector_Generic_Conn_01x04 J 0 40 Y N 1 F N
F0 "J" 0 200 50 H V C CNN
F1 "Connector_Generic_Conn_01x04" 0 -300 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 150 50 -250 1 1 10 f
X Pin_1 1 -200 100 150 R 50 50 1 1 P
X Pin_2 2 -200 0 150 R 50 50 1 1 P
X Pin_3 3 -200 -100 150 R 50 50 1 1 P
X Pin_4 4 -200 -200 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Generic_Conn_01x22
#
DEF Connector_Generic_Conn_01x22 J 0 40 Y N 1 F N
F0 "J" 0 1100 50 H V C CNN
F1 "Connector_Generic_Conn_01x22" 0 -1200 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
S -50 -1095 0 -1105 1 1 6 N
S -50 -995 0 -1005 1 1 6 N
S -50 -895 0 -905 1 1 6 N
S -50 -795 0 -805 1 1 6 N
S -50 -695 0 -705 1 1 6 N
S -50 -595 0 -605 1 1 6 N
S -50 -495 0 -505 1 1 6 N
S -50 -395 0 -405 1 1 6 N
S -50 -295 0 -305 1 1 6 N
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 205 0 195 1 1 6 N
S -50 305 0 295 1 1 6 N
S -50 405 0 395 1 1 6 N
S -50 505 0 495 1 1 6 N
S -50 605 0 595 1 1 6 N
S -50 705 0 695 1 1 6 N
S -50 805 0 795 1 1 6 N
S -50 905 0 895 1 1 6 N
S -50 1005 0 995 1 1 6 N
S -50 1050 50 -1150 1 1 10 f
X Pin_1 1 -200 1000 150 R 50 50 1 1 P
X Pin_10 10 -200 100 150 R 50 50 1 1 P
X Pin_11 11 -200 0 150 R 50 50 1 1 P
X Pin_12 12 -200 -100 150 R 50 50 1 1 P
X Pin_13 13 -200 -200 150 R 50 50 1 1 P
X Pin_14 14 -200 -300 150 R 50 50 1 1 P
X Pin_15 15 -200 -400 150 R 50 50 1 1 P
X Pin_16 16 -200 -500 150 R 50 50 1 1 P
X Pin_17 17 -200 -600 150 R 50 50 1 1 P
X Pin_18 18 -200 -700 150 R 50 50 1 1 P
X Pin_19 19 -200 -800 150 R 50 50 1 1 P
X Pin_2 2 -200 900 150 R 50 50 1 1 P
X Pin_20 20 -200 -900 150 R 50 50 1 1 P
X Pin_21 21 -200 -1000 150 R 50 50 1 1 P
X Pin_22 22 -200 -1100 150 R 50 50 1 1 P
X Pin_3 3 -200 800 150 R 50 50 1 1 P
X Pin_4 4 -200 700 150 R 50 50 1 1 P
X Pin_5 5 -200 600 150 R 50 50 1 1 P
X Pin_6 6 -200 500 150 R 50 50 1 1 P
X Pin_7 7 -200 400 150 R 50 50 1 1 P
X Pin_8 8 -200 300 150 R 50 50 1 1 P
X Pin_9 9 -200 200 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Generic_Conn_02x25_Odd_Even
#
DEF Connector_Generic_Conn_02x25_Odd_Even J 0 40 Y N 1 F N
F0 "J" 50 1300 50 H V C CNN
F1 "Connector_Generic_Conn_02x25_Odd_Even" 50 -1300 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_2x??_*
$ENDFPLIST
DRAW
S -50 -1195 0 -1205 1 1 6 N
S -50 -1095 0 -1105 1 1 6 N
S -50 -995 0 -1005 1 1 6 N
S -50 -895 0 -905 1 1 6 N
S -50 -795 0 -805 1 1 6 N
S -50 -695 0 -705 1 1 6 N
S -50 -595 0 -605 1 1 6 N
S -50 -495 0 -505 1 1 6 N
S -50 -395 0 -405 1 1 6 N
S -50 -295 0 -305 1 1 6 N
S -50 -195 0 -205 1 1 6 N
S -50 -95 0 -105 1 1 6 N
S -50 5 0 -5 1 1 6 N
S -50 105 0 95 1 1 6 N
S -50 205 0 195 1 1 6 N
S -50 305 0 295 1 1 6 N
S -50 405 0 395 1 1 6 N
S -50 505 0 495 1 1 6 N
S -50 605 0 595 1 1 6 N
S -50 705 0 695 1 1 6 N
S -50 805 0 795 1 1 6 N
S -50 905 0 895 1 1 6 N
S -50 1005 0 995 1 1 6 N
S -50 1105 0 1095 1 1 6 N
S -50 1205 0 1195 1 1 6 N
S -50 1250 150 -1250 1 1 10 f
S 150 -1195 100 -1205 1 1 6 N
S 150 -1095 100 -1105 1 1 6 N
S 150 -995 100 -1005 1 1 6 N
S 150 -895 100 -905 1 1 6 N
S 150 -795 100 -805 1 1 6 N
S 150 -695 100 -705 1 1 6 N
S 150 -595 100 -605 1 1 6 N
S 150 -495 100 -505 1 1 6 N
S 150 -395 100 -405 1 1 6 N
S 150 -295 100 -305 1 1 6 N
S 150 -195 100 -205 1 1 6 N
S 150 -95 100 -105 1 1 6 N
S 150 5 100 -5 1 1 6 N
S 150 105 100 95 1 1 6 N
S 150 205 100 195 1 1 6 N
S 150 305 100 295 1 1 6 N
S 150 405 100 395 1 1 6 N
S 150 505 100 495 1 1 6 N
S 150 605 100 595 1 1 6 N
S 150 705 100 695 1 1 6 N
S 150 805 100 795 1 1 6 N
S 150 905 100 895 1 1 6 N
S 150 1005 100 995 1 1 6 N
S 150 1105 100 1095 1 1 6 N
S 150 1205 100 1195 1 1 6 N
X Pin_1 1 -200 1200 150 R 50 50 1 1 P
X Pin_10 10 300 800 150 L 50 50 1 1 P
X Pin_11 11 -200 700 150 R 50 50 1 1 P
X Pin_12 12 300 700 150 L 50 50 1 1 P
X Pin_13 13 -200 600 150 R 50 50 1 1 P
X Pin_14 14 300 600 150 L 50 50 1 1 P
X Pin_15 15 -200 500 150 R 50 50 1 1 P
X Pin_16 16 300 500 150 L 50 50 1 1 P
X Pin_17 17 -200 400 150 R 50 50 1 1 P
X Pin_18 18 300 400 150 L 50 50 1 1 P
X Pin_19 19 -200 300 150 R 50 50 1 1 P
X Pin_2 2 300 1200 150 L 50 50 1 1 P
X Pin_20 20 300 300 150 L 50 50 1 1 P
X Pin_21 21 -200 200 150 R 50 50 1 1 P
X Pin_22 22 300 200 150 L 50 50 1 1 P
X Pin_23 23 -200 100 150 R 50 50 1 1 P
X Pin_24 24 300 100 150 L 50 50 1 1 P
X Pin_25 25 -200 0 150 R 50 50 1 1 P
X Pin_26 26 300 0 150 L 50 50 1 1 P
X Pin_27 27 -200 -100 150 R 50 50 1 1 P
X Pin_28 28 300 -100 150 L 50 50 1 1 P
X Pin_29 29 -200 -200 150 R 50 50 1 1 P
X Pin_3 3 -200 1100 150 R 50 50 1 1 P
X Pin_30 30 300 -200 150 L 50 50 1 1 P
X Pin_31 31 -200 -300 150 R 50 50 1 1 P
X Pin_32 32 300 -300 150 L 50 50 1 1 P
X Pin_33 33 -200 -400 150 R 50 50 1 1 P
X Pin_34 34 300 -400 150 L 50 50 1 1 P
X Pin_35 35 -200 -500 150 R 50 50 1 1 P
X Pin_36 36 300 -500 150 L 50 50 1 1 P
X Pin_37 37 -200 -600 150 R 50 50 1 1 P
X Pin_38 38 300 -600 150 L 50 50 1 1 P
X Pin_39 39 -200 -700 150 R 50 50 1 1 P
X Pin_4 4 300 1100 150 L 50 50 1 1 P
X Pin_40 40 300 -700 150 L 50 50 1 1 P
X Pin_41 41 -200 -800 150 R 50 50 1 1 P
X Pin_42 42 300 -800 150 L 50 50 1 1 P
X Pin_43 43 -200 -900 150 R 50 50 1 1 P
X Pin_44 44 300 -900 150 L 50 50 1 1 P
X Pin_45 45 -200 -1000 150 R 50 50 1 1 P
X Pin_46 46 300 -1000 150 L 50 50 1 1 P
X Pin_47 47 -200 -1100 150 R 50 50 1 1 P
X Pin_48 48 300 -1100 150 L 50 50 1 1 P
X Pin_49 49 -200 -1200 150 R 50 50 1 1 P
X Pin_5 5 -200 1000 150 R 50 50 1 1 P
X Pin_50 50 300 -1200 150 L 50 50 1 1 P
X Pin_6 6 300 1000 150 L 50 50 1 1 P
X Pin_7 7 -200 900 150 R 50 50 1 1 P
X Pin_8 8 300 900 150 L 50 50 1 1 P
X Pin_9 9 -200 800 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
#End Library

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
update=22/05/2015 07:44:53
version=1
last_client=kicad
[general]
version=1
RootSch=
BoardNm=
[pcbnew]
version=1
LastNetListRead=
UseCmpFile=1
PadDrill=0.600000000000
PadDrillOvalY=0.600000000000
PadSizeH=1.500000000000
PadSizeV=1.500000000000
PcbTextSizeV=1.500000000000
PcbTextSizeH=1.500000000000
PcbTextThickness=0.300000000000
ModuleTextSizeV=1.000000000000
ModuleTextSizeH=1.000000000000
ModuleTextSizeThickness=0.150000000000
SolderMaskClearance=0.000000000000
SolderMaskMinWidth=0.000000000000
DrawSegmentWidth=0.200000000000
BoardOutlineThickness=0.100000000000
ModuleOutlineThickness=0.150000000000
[cvpcb]
version=1
NetIExt=net
[eeschema]
version=1
LibDir=
[eeschema/libraries]

374
hardware/mvp/GreenSCSI.sch Normal file
View File

@ -0,0 +1,374 @@
EESchema Schematic File Version 4
EELAYER 30 0
EELAYER END
$Descr A4 11693 8268
encoding utf-8
Sheet 1 1
Title ""
Date ""
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndDescr
$Comp
L Connector_Generic:Conn_02x25_Odd_Even P4
U 1 1 61981AC2
P 2900 4150
F 0 "P4" H 2950 5567 50 0000 C CNN
F 1 "SCSI" H 2950 5476 50 0000 C CNN
F 2 "Connector_PinHeader_2.54mm:PinHeader_2x25_P2.54mm_Horizontal" H 2900 4150 50 0001 C CNN
F 3 "~" H 2900 4150 50 0001 C CNN
1 2900 4150
1 0 0 -1
$EndComp
$Comp
L Connector_Generic:Conn_01x04 P3
U 1 1 6198359E
P 7950 4800
F 0 "P3" H 7950 5050 50 0000 C CNN
F 1 "Teensy" H 7950 4450 50 0000 C CNN
F 2 "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical" H 7950 4800 50 0001 C CNN
F 3 "~" H 7950 4800 50 0001 C CNN
1 7950 4800
1 0 0 -1
$EndComp
$Comp
L Connector_Generic:Conn_01x22 P1
U 1 1 61983D48
P 6700 4100
F 0 "P1" H 6700 5250 50 0000 C CNN
F 1 "Teensy" H 6700 2850 50 0000 C CNN
F 2 "Connector_PinHeader_2.54mm:PinHeader_1x22_P2.54mm_Vertical" H 6700 4100 50 0001 C CNN
F 3 "~" H 6700 4100 50 0001 C CNN
1 6700 4100
1 0 0 -1
$EndComp
$Comp
L Connector_Generic:Conn_01x22 P2
U 1 1 61984761
P 8250 4100
F 0 "P2" H 8250 5250 50 0000 C CNN
F 1 "Teensy" H 8250 2850 50 0000 C CNN
F 2 "Connector_PinHeader_2.54mm:PinHeader_1x22_P2.54mm_Vertical" H 8250 4100 50 0001 C CNN
F 3 "~" H 8250 4100 50 0001 C CNN
1 8250 4100
-1 0 0 -1
$EndComp
Wire Wire Line
2700 2950 2450 2950
Wire Wire Line
2450 2950 2450 3050
Wire Wire Line
2450 4050 2700 4050
Wire Wire Line
2700 4250 2450 4250
Wire Wire Line
2450 4250 2450 4350
Wire Wire Line
2450 5350 2700 5350
Wire Wire Line
2700 5250 2450 5250
Connection ~ 2450 5250
Wire Wire Line
2450 5250 2450 5350
Wire Wire Line
2700 5150 2450 5150
Connection ~ 2450 5150
Wire Wire Line
2450 5150 2450 5250
Wire Wire Line
2700 5050 2450 5050
Connection ~ 2450 5050
Wire Wire Line
2450 5050 2450 5150
Wire Wire Line
2700 4950 2450 4950
Connection ~ 2450 4950
Wire Wire Line
2450 4950 2450 5050
Wire Wire Line
2700 4850 2450 4850
Connection ~ 2450 4850
Wire Wire Line
2450 4850 2450 4950
Wire Wire Line
2700 4750 2450 4750
Connection ~ 2450 4750
Wire Wire Line
2450 4750 2450 4850
Wire Wire Line
2700 4650 2450 4650
Connection ~ 2450 4650
Wire Wire Line
2450 4650 2450 4750
Wire Wire Line
2700 4550 2450 4550
Connection ~ 2450 4550
Wire Wire Line
2450 4550 2450 4650
Wire Wire Line
2700 4450 2450 4450
Connection ~ 2450 4450
Wire Wire Line
2450 4450 2450 4550
Wire Wire Line
2700 4350 2450 4350
Connection ~ 2450 4350
Wire Wire Line
2450 4350 2450 4450
Wire Wire Line
2700 3050 2450 3050
Connection ~ 2450 3050
Wire Wire Line
2450 3050 2450 3150
Wire Wire Line
2700 3150 2450 3150
Connection ~ 2450 3150
Wire Wire Line
2450 3150 2450 3250
Wire Wire Line
2700 3250 2450 3250
Connection ~ 2450 3250
Wire Wire Line
2450 3250 2450 3350
Wire Wire Line
2700 3350 2450 3350
Connection ~ 2450 3350
Wire Wire Line
2450 3350 2450 3450
Wire Wire Line
2700 3450 2450 3450
Connection ~ 2450 3450
Wire Wire Line
2450 3450 2450 3550
Wire Wire Line
2700 3550 2450 3550
Connection ~ 2450 3550
Wire Wire Line
2450 3550 2450 3650
Wire Wire Line
2700 3650 2450 3650
Connection ~ 2450 3650
Wire Wire Line
2450 3650 2450 3750
Wire Wire Line
2700 3750 2450 3750
Connection ~ 2450 3750
Wire Wire Line
2450 3750 2450 3850
Wire Wire Line
2700 3850 2450 3850
Connection ~ 2450 3850
Wire Wire Line
2450 3850 2450 3950
Wire Wire Line
2700 3950 2450 3950
Connection ~ 2450 3950
Wire Wire Line
2450 3950 2450 4050
Wire Wire Line
2150 4150 2700 4150
Wire Wire Line
3200 2950 3750 2950
Wire Wire Line
3200 3050 3750 3050
Wire Wire Line
3200 3150 3750 3150
Wire Wire Line
3200 3250 3750 3250
Wire Wire Line
3200 3350 3750 3350
Wire Wire Line
3200 3450 3750 3450
Wire Wire Line
3200 3550 3750 3550
Wire Wire Line
3200 3650 3750 3650
Wire Wire Line
3200 3750 3750 3750
Wire Wire Line
3200 5350 3750 5350
Wire Wire Line
3200 5250 3750 5250
Wire Wire Line
3200 5150 3750 5150
Wire Wire Line
3200 5050 3750 5050
Wire Wire Line
3200 4950 3750 4950
Wire Wire Line
3200 4850 3750 4850
Wire Wire Line
3200 4750 3750 4750
Wire Wire Line
3200 4650 3750 4650
Wire Wire Line
3200 4450 3750 4450
Wire Wire Line
3450 4350 3200 4350
Wire Wire Line
3450 3850 3200 3850
Wire Wire Line
3450 3950 3200 3950
Wire Wire Line
3450 4050 3200 4050
Wire Wire Line
3450 4250 3200 4250
Wire Wire Line
3450 4350 3450 4250
Wire Wire Line
3450 4250 3450 4050
Connection ~ 3450 4250
Wire Wire Line
3450 4050 3450 3950
Connection ~ 3450 4050
Wire Wire Line
3450 3950 3450 3850
Connection ~ 3450 3950
Text Label 2500 4050 0 50 ~ 0
GND
Text Label 2500 5350 0 50 ~ 0
GND
Text Label 3250 4050 0 50 ~ 0
GND
Text Label 2150 4150 0 50 ~ 0
TERMPWR
Text Label 3750 2950 2 50 ~ 0
~DB0
Text Label 3750 3050 2 50 ~ 0
~DB1
Text Label 3750 3150 2 50 ~ 0
~DB2
Text Label 3750 3250 2 50 ~ 0
~DB3
Text Label 3750 3350 2 50 ~ 0
~DB4
Text Label 3750 3450 2 50 ~ 0
~DB5
Text Label 3750 3550 2 50 ~ 0
~DB6
Text Label 3750 3650 2 50 ~ 0
~DB7
Text Label 3750 3750 2 50 ~ 0
~DBP
Text Label 3750 4450 2 50 ~ 0
~ATN
Text Label 3750 4650 2 50 ~ 0
~BSY
Text Label 3750 4750 2 50 ~ 0
~ACK
Text Label 3750 4850 2 50 ~ 0
~RST
Text Label 3750 4950 2 50 ~ 0
~MSG
Text Label 3750 5050 2 50 ~ 0
~SEL
Text Label 3750 5150 2 50 ~ 0
~C~\D
Text Label 3750 5250 2 50 ~ 0
~REQ
Text Label 3750 5350 2 50 ~ 0
~I~\O
Wire Wire Line
6500 3500 5950 3500
Wire Wire Line
6500 3600 5950 3600
Wire Wire Line
6500 3700 5950 3700
Wire Wire Line
6500 3800 5950 3800
Wire Wire Line
6500 3900 5950 3900
Wire Wire Line
6500 4000 5950 4000
Wire Wire Line
6500 4100 5950 4100
Wire Wire Line
6500 4200 5950 4200
Wire Wire Line
6500 4400 5950 4400
Text Label 5950 4400 0 50 ~ 0
~ATN
Text Label 5950 4200 0 50 ~ 0
~BSY
Text Label 5950 4100 0 50 ~ 0
~ACK
Text Label 5950 4000 0 50 ~ 0
~RST
Text Label 5950 3900 0 50 ~ 0
~MSG
Text Label 5950 3800 0 50 ~ 0
~SEL
Text Label 5950 3700 0 50 ~ 0
~C~\D
Text Label 5950 3600 0 50 ~ 0
~REQ
Text Label 5950 3500 0 50 ~ 0
~I~\O
Wire Wire Line
6500 3100 5950 3100
Text Label 5950 3100 0 50 ~ 0
GND
Wire Wire Line
6500 3200 5950 3200
Wire Wire Line
6500 3300 5950 3300
Text Label 5950 3200 0 50 ~ 0
~DB0
Text Label 5950 3300 0 50 ~ 0
~DB1
Wire Wire Line
6500 4900 5950 4900
Wire Wire Line
6500 5000 5950 5000
Text Label 5950 4900 0 50 ~ 0
~DB2
Text Label 5950 5000 0 50 ~ 0
~DB3
Wire Wire Line
6500 5200 5950 5200
Text Label 5950 5200 0 50 ~ 0
~DBP
Wire Wire Line
7750 4700 7200 4700
Wire Wire Line
7750 5000 7200 5000
Wire Wire Line
7750 4800 7200 4800
Wire Wire Line
7750 4900 7200 4900
Text Label 7200 4700 0 50 ~ 0
~DB4
Text Label 7200 5000 0 50 ~ 0
~DB5
Text Label 7200 4800 0 50 ~ 0
~DB6
Text Label 7200 4900 0 50 ~ 0
~DB7
$Comp
L Connector_Generic:Conn_01x02 J1
U 1 1 619D027D
P 6700 2150
F 0 "J1" H 6780 2142 50 0000 L CNN
F 1 "Conn_01x02" H 6780 2051 50 0000 L CNN
F 2 "Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical" H 6700 2150 50 0001 C CNN
F 3 "~" H 6700 2150 50 0001 C CNN
1 6700 2150
1 0 0 -1
$EndComp
Wire Wire Line
5950 2150 6500 2150
Text Label 5950 2150 0 50 ~ 0
TERMPWR
Wire Wire Line
5950 2250 6500 2250
Text Label 5950 2250 0 50 ~ 0
+5V
Wire Wire Line
9000 3100 8450 3100
Text Label 9000 3100 2 50 ~ 0
+5V
$EndSCHEMATC

Binary file not shown.

BIN
hardware/mvp/Schematic.pdf Normal file

Binary file not shown.

1947
hardware/mvp/fp-info-cache Normal file

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@ int scriptlevel = -1;
char cmd_prefix[256] = "/";
extern uint8_t mbr_bin[];
uint8_t zero[512];
void cmdDisplay() {
if(cmd_prefix[0] != 0) {
@ -125,6 +126,7 @@ cmdvar_t cmdenv[ENVIRONMENT_SIZE];
int getvar(const char *varname, int defaultvalue) {
if(!strcasecmp(varname, "ERRORLEVEL")) return errorlevel;
if(!strcasecmp(varname, "DEBUG")) return debuglog;
for(int i = 0; i < ENVIRONMENT_SIZE; i++) {
if(!strcmp(cmdenv[i].key, varname)) {
@ -136,6 +138,7 @@ int getvar(const char *varname, int defaultvalue) {
char* getvar(const char *varname, char *defaultvalue) {
if(!strcasecmp(varname, "ERRORLEVEL")) return NULL;
if(!strcasecmp(varname, "DEBUG")) return NULL;
for(int i = 0; i < ENVIRONMENT_SIZE; i++) {
if(!strcasecmp(cmdenv[i].key, varname)) {
@ -157,6 +160,7 @@ void setvarcmd(int argc, char **argv) {
}
if(!strcasecmp(argv[1], "ERRORLEVEL")) return;
if(!strcasecmp(argv[1], "DEBUG")) { debuglog = strtoul(argv[2], NULL, 0); return; }
// Find existing variable matching name and replace it
for(i = 0; i < ENVIRONMENT_SIZE; i++) {
@ -199,6 +203,7 @@ void unsetvarcmd(int argc, char **argv) {
}
if(!strcasecmp(argv[1], "ERRORLEVEL")) return;
if(!strcasecmp(argv[1], "DEBUG")) { debuglog = 0; return; }
// Find existing variable matching name and delete it
for(i = 0; i < ENVIRONMENT_SIZE; i++) {
@ -229,6 +234,11 @@ void getvarcmd(int argc, char **argv) {
return;
}
if(!strcasecmp(argv[1], "DEBUG")) {
Serial.printf("%d\r\n", debuglog);
return;
}
for(i = 0; i < ENVIRONMENT_SIZE; i++) {
if(!strcasecmp(cmdenv[i].key, argv[1])) {
Serial.printf("%s=%s\r\n", cmdenv[i].key, cmdenv[i].value);
@ -714,7 +724,7 @@ void changeDirectory(int argc, char **argv) {
goto e_invalidpath;
}
if(!strcmp(new_prefix, "/") || !strcmp(new_prefix, "/tgts") || !strcmp(new_prefix, "/vdevs")
if(!strcmp(new_prefix, "/") || !strcmp(new_prefix, "/tgts") || !strcmp(new_prefix, "/vdevs") || !strcmp(new_prefix, "/nv") || !strcmp(new_prefix, "/raw")
|| !strcmp(new_prefix, "/sd") || !strcmp(new_prefix, "/diag")|| !strcmp(new_prefix, "/diag/sd")
) {
strcpy(cmd_prefix, new_prefix);
@ -854,6 +864,7 @@ void showDirectory(int argc, char **argv) {
printDirectory(0, 0, "/ ", " [...]");
printDirectory(1, 0, "diag/ ", " [...]");
printDirectory(1, 0, "sd/ ", " [...]");
printDirectory(1, 0, "raw/ ", " [...]");
sprintf(tmp_right, " [%d Target%s]", NUM_SCSIID, (NUM_SCSIID != 1) ? "s" : "");
printDirectory(1, 0, "tgts/ ", tmp_right);
sprintf(tmp_right, " [%d Storage Object%s]", m_vdevcnt, (m_vdevcnt != 1) ? "s" : "");
@ -865,6 +876,33 @@ void showDirectory(int argc, char **argv) {
printDirectory(1, 0, "sd/ ", " [...]");
return;
}
if(!strcmp(local_prefix, "/raw")) {
mbr_t *mbr = (mbr_t *)cardMBR;
printDirectory(0, 0, "/raw/ ", " [...]");
sd.card()->readSector(0, cardMBR);
for(uint8_t partIndex = 0; partIndex < 4; partIndex++) {
sprintf(tmp_left, "part%d", partIndex);
switch(mbr->part[partIndex].type) {
case 0x04:
case 0x06:
case 0x0B:
case 0x0C:
case 0x0E:
printDirectory(1, 0, tmp_left, "[FAT Filesystem]");
break;
case 0x07:
printDirectory(1, 0, tmp_left, "[EXFAT/NTFS Filesystem]");
break;
case 0x87:
sprintf(tmp_right, "[Emulated %dMB Drive]", (int)(mbr->part[partIndex].totalSectors / 2048));
printDirectory(1, 0, tmp_left, tmp_right);
break;
}
}
return;
}
if(!strcmp(local_prefix, "/diag/sd")) {
printDirectory(0, 0, "/diag/sd/ ", " [...]");
@ -987,6 +1025,31 @@ void showDirectory(int argc, char **argv) {
return;
}
}
if(!strcmp(local_prefix, "/nv") || !strncmp(local_prefix, "/nv/", 4)) {
File root = lfs.open("/");
while(true) {
File entry = root.openNextFile();
if(! entry) {
break;
}
if(!entry.isDirectory()) {
sprintf(tmp_left, "%s ", entry.name());
if(entry.size() >= 8192) {
sprintf(tmp_right, " [%llu KB]", entry.size() >> 10);
} else {
sprintf(tmp_right, " [%llu Bytes]", entry.size());
}
printDirectory(1, 0, tmp_left, tmp_right);
}
entry.close();
}
root.close();
}
if(!strcmp(local_prefix, "/sd") || !strncmp(local_prefix, "/sd/", 4)) {
char name[MAX_FILE_PATH+1];
SdFile root;
@ -1126,85 +1189,132 @@ void makeimagecmd(int argc, char **argv) {
FsFile file;
char tmp_path[MAX_FILE_PATH+1];
uint64_t fileSize = 0;
int i;
bool write_mbr = 0;
uint64_t cylinders = 0;
uint64_t heads = 16;
uint64_t sectors = 63;
uint64_t blocksize = 512;
if(argc < 4) {
return;
}
fixupPath(tmp_path, argv[1]);
if(strncmp(tmp_path, "/sd/", 4)) {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": Can only create images on the SD Card.\r\n");
return;
}
if(!strcmp(argv[2], "msdos") || !strcmp(argv[2], "generic")) {
char *suffix = NULL;
fileSize = strtoul(argv[3], &suffix, 0);
if(suffix && suffix[0] != 0) {
if(!strcmp(suffix, "KB")) fileSize *= 1000ull;
if(!strcmp(suffix, "KiB")) fileSize *= 1024ull;
if(!strcmp(suffix, "MB")) fileSize *= 1000000ull;
if(!strcmp(suffix, "MiB")) fileSize *= 1024ull * 1024ull;
if(!strcmp(suffix, "GB")) fileSize *= 1000000000ull;
if(!strcmp(suffix, "GiB")) fileSize *= 1024ull * 1024ull * 1024ull;
}
if(sd.exists(tmp_path+3)) {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": file '%s' already exists.\r\n", tmp_path);
return;
}
if(fileSize < (5ull * 1024ull * 1024ull)) {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": Image would be less than 5 MiB.\r\n");
return;
}
if(fileSize > (2048ull * 1024ull * 1024ull)) {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": Image would be larger than 2 GiB.\r\n");
return;
}
// Fixup image size to our 64 Head 32 Sector X Cylinders formula
uint64_t cyl = fileSize / (512ull * 64ull * 32ull);
if(fileSize & 0xFFFFF) cyl++;
if(cyl > 2048) cyl = 2048;
fileSize = cyl * (512ull * 64ull * 32ull);
if(!file.open(tmp_path+3, O_WRONLY | O_CREAT | O_TRUNC)) {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": Unable to open '%s'.\r\n", tmp_path);
} else {
// Take advantage of our cylinders being 1MB
if(!file.preAllocate(cyl)) {
file.close();
sd.remove(tmp_path+3);
tmp_path[0] = 0;
for(i = 1; i < argc; i++) {
if(argv[i][0] == '/') {
fixupPath(tmp_path, argv[i]);
if(strncmp(tmp_path, "/sd/", 4)) {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": Pre-allocate failed, SD Card must be formatted as ExFat.\r\n");
Serial.printf(": Can only create images on the SD Card.\r\n");
return;
}
if(!strcmp(argv[2], "msdos")) {
file.write(mbr_bin, 512);
}
file.close();
return;
}
if(!strcmp(argv[i], "-msdos")) {
write_mbr = 1;
} else
if(!strcmp(argv[i], "-b") && (i+1 < argc)) {
i++;
blocksize = strtoul(argv[i], NULL, 0);
} else
if(!strcmp(argv[i], "-c") && (i+1 < argc)) {
i++;
cylinders = strtoul(argv[i], NULL, 0);
} else
if(!strcmp(argv[i], "-h") && (i+1 < argc)) {
i++;
heads = strtoul(argv[i], NULL, 0);
} else
if(!strcmp(argv[i], "-s") && (i+1 < argc)) {
i++;
sectors = strtoul(argv[i], NULL, 0);
} else
{
char *suffix = NULL;
fileSize = strtoul(argv[i], &suffix, 0);
if(suffix && suffix[0] != 0) {
if(!strcmp(suffix, "KB")) fileSize *= 1000ull;
if(!strcmp(suffix, "KiB")) fileSize *= 1024ull;
if(!strcmp(suffix, "MB")) fileSize *= 1000000ull;
if(!strcmp(suffix, "MiB")) fileSize *= 1024ull * 1024ull;
if(!strcmp(suffix, "GB")) fileSize *= 1000000000ull;
if(!strcmp(suffix, "GiB")) fileSize *= 1024ull * 1024ull * 1024ull;
}
}
}
if(tmp_path[0] == 0) {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": no path specified.\r\n");
return;
}
if((fileSize == 0) && (cylinders != 0)) {
fileSize = cylinders * heads * sectors * blocksize;
} else if(fileSize != 0){
// Fixup image size to our CHS formula
// Capping out at ~2GB
cylinders = fileSize / (blocksize * heads * sectors);
if(fileSize & 0xFFFFF) cylinders++;
if(cylinders > 4095) cylinders = 4095;
fileSize = cylinders * (blocksize * heads * sectors);
} else {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": no image size specified.\r\n");
return;
}
if(sd.exists(tmp_path+3)) {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": file '%s' already exists.\r\n", tmp_path);
return;
}
if(fileSize < (5ull * 1024ull * 1024ull)) {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": Image would be less than 5 MiB.\r\n");
return;
}
if(fileSize > (2048ull * 1024ull * 1024ull)) {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": Image would be larger than 2 GiB.\r\n");
return;
}
if(!file.open(tmp_path+3, O_WRONLY | O_CREAT | O_TRUNC)) {
errorlevel = -1;
Serial.print("ERROR");
if(scriptlevel >= 0) Serial.printf(" on line %d of '%s'", exec_line, exec_filename);
Serial.printf(": Unable to open '%s'.\r\n", tmp_path);
} else {
if(write_mbr) {
file.write(mbr_bin, 512);
fileSize -= 512;
}
memset(zero, 0, 512);
while(fileSize) {
if((fileSize & 0x1FFF) == 0)
Serial.printf(".");
if((fileSize & 0x7FFFF) == 0)
Serial.printf("\r\n");
file.write(zero, (fileSize < 512) ? fileSize : 512);
fileSize -= (fileSize < 512) ? fileSize : 512;
}
Serial.printf("\r\n");
file.close();
return;
}
errorlevel = -1;
@ -1225,7 +1335,9 @@ void catcmd(int argc, char **argv) {
}
fixupPath(tmp_path, argv[1]);
if(!strncmp(filename, "/sd/", 4)) {
if(!strncmp(filename, "/nv/", 4)) {
filename += 3;
} else if(!strncmp(filename, "/sd/", 4)) {
filename += 3;
} else {
errorlevel = -1;
@ -1366,9 +1478,44 @@ void setcmd(int argc, char **argv) {
return;
}
if((param_name) && !strcasecmp(param_name, "/sectors")) {
if(argc<3) {
Serial.printf("%d\r\n", h->m_sectors);
} else {
h->m_blocksize = strtol(argv[2], NULL, 0);
}
return;
}
if((param_name) && !strcasecmp(param_name, "/heads")) {
if(argc<3) {
Serial.printf("%d\r\n", h->m_heads);
} else {
h->m_blocksize = strtol(argv[2], NULL, 0);
}
return;
}
if((param_name) && !strcasecmp(param_name, "/cylinders")) {
if(argc<3) {
Serial.printf("%d\r\n", h->m_cylinders);
} else {
h->m_blocksize = strtol(argv[2], NULL, 0);
}
return;
}
if((param_name) && !strcasecmp(param_name, "/quirks")) {
if(argc<3) {
Serial.printf("0x%02x\r\n", h->m_quirks);
} if(!strcasecmp(argv[2], "SASI") || !strcasecmp(argv[2], "+SASI")) {
h->m_quirks |= QUIRKS_SASI;
} if(!strcasecmp(argv[2], "-SASI")) {
h->m_quirks &= ~QUIRKS_SASI;
} if(!strcasecmp(argv[2], "APPLE") || !strcasecmp(argv[2], "+APPLE")) {
h->m_quirks |= QUIRKS_APPLE;
} if(!strcasecmp(argv[2], "-APPLE")) {
h->m_quirks &= ~QUIRKS_APPLE;
} else {
h->m_quirks = strtol(argv[2], NULL, 0);
}
@ -1497,6 +1644,12 @@ void createcmd(int argc, char **argv) {
goto success;
}
#endif /* SUPPORT_TAPE */
#if SUPPORT_CONTROL
if(!strcasecmp(argv[1], "control")) {
ConfigureControl(h, NULL);
goto success;
}
#endif /* SUPPORT_CONTROL */
//failure:
errorlevel = -1;
@ -1562,6 +1715,14 @@ void mountcmd(int argc, char **argv) {
return;
}
}
if(!strncmp(tmp_path, "/raw/", 5)) {
if(OpenDiskImage(h, tmp_path, 512)) {
strcpy(h->m_filename, tmp_path);
h->m_enabled = true;
return;
}
}
h->m_fileSize = 0;
h->m_blocksize = 0;
@ -1702,6 +1863,9 @@ void saveconfig(int argc, char **argv) {
if(h->m_enabled) {
// The create command automatically changes directory to the created object
switch(h->m_type) {
case DEV_PROCESSOR:
config_file.print("create control\r\n");
break;
case DEV_DISK:
config_file.print("create disk\r\n");
break;
@ -1736,6 +1900,14 @@ void saveconfig(int argc, char **argv) {
config_file.close();
}
char helponSelfTest[] =
"\r\n"
"selftest\r\n"
"\r\n"
" Use the selftest command to check for miswired boards and shorts.\r\n"
"\r\n"
;
char helponSave[] =
"\r\n"
"saveconfig\r\n"
@ -1850,15 +2022,21 @@ char helponVar[] =
char helponMkImg[] =
"\r\n"
"mkimg <file> <type> <size>\r\n"
"mkimg <file> [-msdos] [-b blocksize] [-c cylinders] [-h heads] [-s sectors] [size]\r\n"
"\r\n"
" The mkimg command creates image files on ExFat volumes.\r\n"
" The mkimg command creates image files on FAT or ExFat volumes.\r\n"
"This command is limited to 4095 cylinders or approximately 2GB.\r\n"
"To create larger images, use a USB card reader.\r\n"
"\r\n"
"<type> specifies the partitioning scheme to preload the image with.\r\n"
" generic creates a blank disk ready for partitioning.\r\n"
" msdos preloads an MBR boot menu, and in the future may pre-partition and format.\r\n"
" -msdos preloads an msdos compatible MBR.\r\n"
" -b sets the sector size (default=512).\r\n"
" -c sets the number of cylinders.\r\n"
" -h sets the heads (default=16).\r\n"
" -s sets the sectors per track (default=63).\r\n"
"\r\n"
"<size> specifies file size and supports a KB,MB,GB (1000) or KiB,MiB,GiB (1024) suffix.\r\n"
"You can specify the size either via the combination of -c -h -s parameters, or\r\n"
"specify the file size with optional KB,MB,GB (1000) or KiB,MiB,GiB (1024) suffix\r\n"
"and a cylinder count close to your desired size will be chosen for you.\r\n"
"\r\n"
;
@ -1873,6 +2051,7 @@ char helponHelp[] =
Commands_t GlobalCommands[] = {
// Command Valid From Path Req. Params Short Help Long Help Handler Dispatch
{ "selftest", "/", 0, "Execute Self Test.", helponSelfTest, SelfTest, NULL },
{ "cd", "/", 1, "change current directory", NULL, changeDirectory, NULL },
{ "sl", "/", 0, NULL, NULL, slcmd, NULL },
{ "dir", "/", 0, NULL, NULL, punishDirectory, NULL },
@ -1885,7 +2064,7 @@ Commands_t GlobalCommands[] = {
{ "mount", "/vdevs/vdev", 1, "<path>", helponMount, mountcmd, NULL },
{ "map", "/vdevs/vdev", 1, "<lun>", helponMapV, mapcmd, NULL },
{ "cat", "/sd", 1, "<file>", helponCat, catcmd, NULL },
{ "mkimg", "/sd", 1, "<file>", helponMkImg, makeimagecmd, NULL },
{ "mkimg", "/sd", 1, "<file> <size>", helponMkImg, makeimagecmd, NULL },
{ "unlink", "/", 1, "<path>", helponUnlink, unlinkcmd, NULL },
{ "exec", "/", 1, "<script>", helponExec, execcmd, NULL },
{ "goto", "/", 1, NULL, NULL, gotocmd, NULL },

View File

@ -9,12 +9,14 @@
#define ACK_INTERRUPTS false
#define READ_SPEED_OPTIMIZE true //
#define WRITE_SPEED_OPTIMIZE true //
#define READ_SPEED_OPTIMIZE_RAW true //
#define WRITE_SPEED_OPTIMIZE_RAW true //
#define USE_DB2ID_TABLE true // Use table to get ID from SEL-DB
// SCSI config
#define NUM_SCSIID 8 // Maximum number of supported SCSI-IDs (The minimum is 1)
#define NUM_SCSILUN 8 // Maximum number of LUNs supported (The minimum is 1)
#define NUM_VDEV 8 // Maximum number of VDEVs supported (The minimum is 1)
#define NUM_VDEV 16 // Maximum number of VDEVs supported (The minimum is 1)
#define READ_PARITY_CHECK 0 // Perform read parity check (unverified)
@ -22,6 +24,7 @@
#define MAX_BLOCKSIZE (1 << 15) // Maximum BLOCK size (2048 to 8192 tested, 16384 had issues)
#define SCSI_INQUIRY_RESPONSE_SIZE 96
extern uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE];
// Supported Device Types
#define SUPPORT_DISK true
@ -29,6 +32,7 @@
#define SUPPORT_TAPE false
#define SUPPORT_MO false
#define SUPPORT_INITIATOR true
#define SUPPORT_CONTROL true
// Compatibility Settings
#define SUPPORT_SASI false // Enable SASI compatiblity for Sharp X68000

111
src/control.ino Normal file
View File

@ -0,0 +1,111 @@
#include "config.h"
#include "scsi_defs.h"
#if SUPPORT_CONTROL
/*
* RECEIVE Command processing.
*/
void onControlReceiveCommand(uint32_t adds, uint32_t len)
{
LOG("-R ");
LOGHEX4N(len);
if(!m_sel) {
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
switch(m_cmd[1] & 0x3) {
case 0:
if(len == 0) return;
break;
case 1: // Fixed
break;
case 2: // SILI
break;
case 3: // Illegal Request
m_sts = 0x02;
m_sel->m_sense.m_key = ILLEGAL_REQUEST;
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 1" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x01;
m_phase = PHASE_STATUSIN;
return;
}
LED_ON();
writeDataPhase(len, m_responsebuffer);
LED_OFF();
m_phase = PHASE_STATUSIN;
}
/*
* SEND Command processing.
*/
void onControlSendCommand(uint32_t adds, uint32_t len)
{
LOG("-W ");
LOGHEX4N(len);
if(!m_sel) {
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
if(len > MAX_BLOCKSIZE) {
m_sel->m_sense.m_key = ILLEGAL_REQUEST;
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 4" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x04;
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
LED_ON();
readDataPhase(len, m_responsebuffer);
LED_OFF();
m_phase = PHASE_STATUSIN;
}
void ControlReceive6CommandHandler() {
LOG("[Receive6]");
onControlReceiveCommand((((uint32_t)m_cmd[1] & 0x1F) << 16) | ((uint32_t)m_cmd[2] << 8) | m_cmd[3], (m_cmd[4] == 0) ? 0x100 : m_cmd[4]);
}
void ControlSend6CommandHandler() {
LOG("[Send6]");
onControlSendCommand((((uint32_t)m_cmd[1] & 0x1F) << 16) | ((uint32_t)m_cmd[2] << 8) | m_cmd[3], (m_cmd[4] == 0) ? 0x100 : m_cmd[4]);
}
void ConfigureControlHandlers(VirtualDevice_t *vdev) {
for(int c = 0; c < 256; c++)
vdev->m_handler[c] = &UnknownCommandHandler;
vdev->m_handler[CMD_TEST_UNIT_READY] = &TestUnitCommandHandler;
vdev->m_handler[CMD_REQUEST_SENSE] = &RequestSenseCommandHandler;
vdev->m_handler[CMD_READ6] = &ControlReceive6CommandHandler;
vdev->m_handler[CMD_WRITE6] = &ControlSend6CommandHandler;
vdev->m_handler[CMD_INQUIRY] = &InquiryCommandHandler;
vdev->m_handler[CMD_SEND_DIAGNOSTIC] = &SendDiagnosticCommandHandler;
}
// If config file exists, read the first three lines and copy the contents.
// File must be well formed or you will get junk in the SCSI Vendor fields.
void ConfigureControl(VirtualDevice_t *vdev, const char *image_name) {
for(int i = 0; SCSI_INQUIRY_RESPONSE[i][0] != 0xff; i++) {
if(SCSI_INQUIRY_RESPONSE[i][0] == DEV_PROCESSOR) {
memcpy(vdev->m_inquiryresponse, SCSI_INQUIRY_RESPONSE[i], SCSI_INQUIRY_RESPONSE_SIZE);
break;
}
}
vdev->m_type = DEV_PROCESSOR;
ConfigureControlHandlers(vdev);
}
#endif

View File

@ -2,10 +2,10 @@
// SCSI Drive Vendor information
static uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
#if SUPPORT_SASI
{
0x00, //Device type
DEV_DISK, //Device type
0x00, //RMB = 0
0x01, //ISO,ECMA,ANSI version
0x01, //Response data format
@ -21,7 +21,7 @@ static uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
#if SUPPORT_DISK
{
0x00, //device type
DEV_DISK, //device type
0x00, //RMB = 0
0x05, //ISO, ECMA, ANSI version
0x02, //Response data format
@ -39,7 +39,7 @@ static uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
},
{
0x00, //device type
DEV_DISK, //device type
0x00, //RMB = 0
0x05, //ISO, ECMA, ANSI version
0x02, //Response data format
@ -59,7 +59,7 @@ static uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
#if SUPPORT_OPTICAL
{
0x05, //device type
DEV_OPTICAL, //device type
0x80, //RMB = 0
0x05, //ISO, ECMA, ANSI version
0x02, //Response data format
@ -76,7 +76,7 @@ static uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
0
},
{
0x05, //device type
DEV_OPTICAL, //device type
0x80, //RMB = 0
0x05, //ISO, ECMA, ANSI version
0x02, //Response data format
@ -93,7 +93,7 @@ static uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
0
},
{
0x05, //device type
DEV_OPTICAL, //device type
0x80, //RMB = 0
0x05, //ISO, ECMA, ANSI version
0x02, //Response data format
@ -106,7 +106,7 @@ static uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
0
},
{
0x05, //device type
DEV_OPTICAL, //device type
0x80, //RMB = 0
0x05, //ISO, ECMA, ANSI version
0x02, //Response data format
@ -119,7 +119,7 @@ static uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
0
},
{
0x05, //device type
DEV_OPTICAL, //device type
0x80, //RMB = 0
0x05, //ISO, ECMA, ANSI version
0x02, //Response data format
@ -132,7 +132,7 @@ static uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
0
},
{
0x05, //device type
DEV_OPTICAL, //device type
0x80, //RMB = 0
0x05, //ISO, ECMA, ANSI version
0x02, //Response data format
@ -148,7 +148,7 @@ static uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
#if SUPPORT_TAPE
{
0x01, //device type
DEV_TAPE, //device type
0x80, //RMB = 0
0x03, //ISO, ECMA, ANSI version
0x02, //Response data format
@ -163,6 +163,24 @@ static uint8_t SCSI_INQUIRY_RESPONSE[][SCSI_INQUIRY_RESPONSE_SIZE] = {
},
#endif /* SUPPORT_TAPE */
#if SUPPORT_CONTROL
{
DEV_PROCESSOR, //device type
0x80, //RMB = 0
0x03, //ISO, ECMA, ANSI version
0x02, //Response data format
37 - 4, //Additional data length
0, //Reserve
0x00, // Support function
0x00, // Support function
'G', 'R', 'N', 'S', 'C', 'S', 'I', ' ', // vendor 8
'G', 'R', 'E', 'E', 'N', 'S', 'C', 'S', 'I', 'C', 'T','R', 'L', ' ', ' ', ' ', // product 16
'G', 'S', 'C', '0', // version 4
0
},
#endif /* SUPPORT_CONTROL */
// Invalid entry to mark end of data
{
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,

View File

@ -1,6 +1,31 @@
#include "config.h"
#include "scsi_defs.h"
/*
* Check that the image file is present and the block range is valid.
*/
byte checkBlockCommand(uint32_t adds, uint32_t len)
{
// Check that image file is present
if(!m_sel) {
return STATUS_CHECK;
}
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
m_sel->m_sense.m_key = NOT_READY; // Not ready
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
m_sel->m_sense.m_key_specific[0] = 0x03;
return STATUS_CHECK;
}
// Check block range is valid
uint32_t bc = m_sel->m_fileSize / m_sel->m_blocksize;
if (adds >= bc || (adds + len) > bc) {
m_sel->m_sense.m_key = 5; // Illegal request
m_sel->m_sense.m_code = INVALID_LBA; // Logical block address out of range
return STATUS_CHECK;
}
return 0x00;
}
void Read6CommandHandler() {
LOG("[Read6]");
m_sts |= onReadCommand((((uint32_t)m_cmd[1] & 0x1F) << 16) | ((uint32_t)m_cmd[2] << 8) | m_cmd[3], (m_cmd[4] == 0) ? 0x100 : m_cmd[4]);
@ -24,7 +49,15 @@ void Seek6CommandHandler() {
void ReadCapacityCommandHandler() {
LOGN("[ReadCapacity]");
if(!m_sel) {
m_sts |= 0x02; // Image file absent
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
m_sts |= STATUS_CHECK;
m_sel->m_sense.m_key = NOT_READY; // Not ready
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
m_sel->m_sense.m_key_specific[0] = 0x03;
m_phase = PHASE_STATUSIN;
return;
}
@ -56,20 +89,33 @@ void Seek10CommandHandler() {
m_phase = PHASE_STATUSIN;
}
void Verify10CommandHandler() {
LOG("[Verify10]");
m_sts |= onVerifyCommand(((uint32_t)m_cmd[2] << 24) | ((uint32_t)m_cmd[3] << 16) | ((uint32_t)m_cmd[4] << 8) | m_cmd[5], ((uint32_t)m_cmd[7] << 8) | m_cmd[8]);
m_phase = PHASE_STATUSIN;
}
/*
* READ6 / 10 Command processing.
*/
uint8_t onReadCommand(uint32_t adds, uint32_t len)
{
uint8_t sts;
LOG("-R ");
LOGHEX6(adds);
LOG(" ");
LOGHEX4N(len);
if(!m_sel) return 0x02; // Image file absent
sts = checkBlockCommand(adds, len);
if(sts) return sts;
LED_ON();
writeDataPhaseSD(adds, len);
if(m_sel->m_rawPart) {
writeDataPhaseRaw(adds, len);
} else {
writeDataPhaseSD(adds, len);
}
LED_OFF();
return 0x00; //sts
}
@ -79,15 +125,47 @@ uint8_t onReadCommand(uint32_t adds, uint32_t len)
*/
uint8_t onWriteCommand(uint32_t adds, uint32_t len)
{
uint8_t sts;
LOG("-W ");
LOGHEX6(adds);
LOG(" ");
LOGHEX4N(len);
if(!m_sel) return 0x02; // Image file absent
sts = checkBlockCommand(adds, len);
if(sts) return sts;
LED_ON();
if(m_sel->m_rawPart) {
readDataPhaseRaw(adds, len);
} else {
readDataPhaseSD(adds, len);
}
LED_OFF();
return 0; //sts
}
/*
* VERIFY6 / 10 Command processing.
*/
uint8_t onVerifyCommand(uint32_t adds, uint32_t len)
{
uint8_t sts;
LOG("-V ");
LOGHEX6(adds);
LOG(" ");
LOGHEX4N(len);
sts = checkBlockCommand(adds, len);
if(sts) return sts;
LED_ON();
readDataPhaseSD(adds, len);
if(m_sel->m_rawPart) {
verifyDataPhaseRaw(adds, len);
} else {
verifyDataPhaseSD(adds, len);
}
LED_OFF();
return 0; //sts
}
@ -114,9 +192,13 @@ void ConfigureDiskHandlers(VirtualDevice_t *vdev) {
vdev->m_handler[CMD_READ10] = &Read10CommandHandler;
vdev->m_handler[CMD_WRITE10] = &Write10CommandHandler;
vdev->m_handler[CMD_SEEK10] = &Seek10CommandHandler;
vdev->m_handler[CMD_VERIFY10] = &Verify10CommandHandler;
vdev->m_handler[CMD_MODE_SENSE10] = &ModeSenseCommandHandler;
vdev->m_handler[CMD_SEARCH_DATA_EQUAL] = &SearchDataEqualCommandHandler;
vdev->m_handler[CMD_READ_DEFECT_DATA] = &ReadDefectCommandHandler;
vdev->m_handler[CMD_SEND_DIAGNOSTIC] = &SendDiagnosticCommandHandler;
vdev->m_handler[CMD_PREFETCH_CACHE10] = &PrefetchCommandHandler;
vdev->m_handler[CMD_SYNCHRONIZE_CACHE10] = &SyncCacheCommandHandler;
#if SUPPORT_SASI
if(vdev->m_quirks & QUIRKS_SASI)
vdev->m_handler[CMD_SET_DRIVE_PARAMETER] = &DTCsetDriveParameterCommandHandler;
@ -137,6 +219,10 @@ void ConfigureDisk(VirtualDevice_t *vdev, const char *image_name) {
}
}
vdev->m_sectors = 63;
vdev->m_heads = 16;
vdev->m_cylinders = (uint32_t)((uint64_t)vdev->m_fileSize / ((uint64_t)vdev->m_blocksize * (uint64_t)vdev->m_heads * (uint64_t)vdev->m_sectors));
if(image_name) {
char configname[MAX_FILE_PATH+1];
memcpy(configname, image_name, MAX_FILE_PATH+1);

View File

@ -40,13 +40,23 @@ void RequestSenseCommandHandler() {
};
if(!m_sel) {
// Image file absent
buf[2] = 0x02; // NOT_READY
buf[12] = 0x25; // Logical Unit Not Supported
buf[2] = 2; // Not ready
buf[12] = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
buf[13] = 0x03;
} else {
buf[2] = m_sel->m_sense.m_key;
buf[12] = m_sel->m_sense.m_code;
buf[13] = m_sel->m_sense.m_key_specific[0];
buf[14] = m_sel->m_sense.m_key_specific[1];
buf[15] = m_sel->m_sense.m_key_specific[2];
m_sel->m_sense.m_key = 0;
m_sel->m_sense.m_code = 0;
m_sel->m_sense.m_key_specific[0] = 0;
m_sel->m_sense.m_key_specific[1] = 0;
m_sel->m_sense.m_key_specific[2] = 0;
}
writeDataPhase(len < 18 ? len : 18, buf);
m_phase = PHASE_STATUSIN;
}
@ -54,25 +64,68 @@ void RequestSenseCommandHandler() {
void TestUnitCommandHandler() {
LOGN("[TestUnit]");
if(!m_sel) {
// Image file absent
m_sel->m_sense.m_key = NOT_READY; // NOT_READY
m_sel->m_sense.m_code = NO_MEDIA; // Logical Unit Not Supported
m_sts |= STATUS_CHECK;
return;
}
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
m_sts |= STATUS_CHECK;
m_sel->m_sense.m_key = NOT_READY; // Not ready
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
m_sel->m_sense.m_key_specific[0] = 0x03;
return;
}
m_phase = PHASE_STATUSIN;
}
void RezeroUnitCommandHandler() {
LOGN("[RezeroUnit]");
if(!m_sel) {
m_sts |= STATUS_CHECK;
return;
}
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
m_sts |= STATUS_CHECK;
m_sel->m_sense.m_key = NOT_READY; // Not ready
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
m_sel->m_sense.m_key_specific[0] = 0x03;
return;
}
m_phase = PHASE_STATUSIN;
}
void FormatUnitCommandHandler() {
LOGN("[FormatUnit]");
if(!m_sel) {
m_sts |= STATUS_CHECK;
return;
}
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
m_sts |= STATUS_CHECK;
m_sel->m_sense.m_key = NOT_READY; // Not ready
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
m_sel->m_sense.m_key_specific[0] = 0x03;
return;
}
m_phase = PHASE_STATUSIN;
}
void ReassignBlocksCommandHandler() {
LOGN("[ReassignBlocks]");
if(!m_sel) {
m_sts |= STATUS_CHECK;
return;
}
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
m_sts |= STATUS_CHECK;
m_sel->m_sense.m_key = NOT_READY; // Not ready
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
m_sel->m_sense.m_key_specific[0] = 0x03;
return;
}
m_phase = PHASE_STATUSIN;
}
@ -103,97 +156,28 @@ void ModeSenseCommandHandler()
len = 2;
break;
default:
m_sts |= 0x02;
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
/* Check whether medium is present */
if(!m_sel) {
m_sts |= 0x02;
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
m_sts |= STATUS_CHECK;
m_sel->m_sense.m_key = NOT_READY; // Not ready
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
m_sel->m_sense.m_key_specific[0] = 0x03;
m_phase = PHASE_STATUSIN;
return;
}
memset(m_responsebuffer, 0, sizeof(m_responsebuffer));
#if 0
if(m_sel->m_quirks & QUIRKS_SASI) {
int pageCode = cmd2 & 0x3F;
// Assuming sector size 512, number of sectors 25, number of heads 8 as default settings
int size = m_sel->m_fileSize;
int cylinders = (int)(size >> 9);
cylinders >>= 3;
cylinders /= 25;
int sectorsize = 512;
int sectors = 25;
int heads = 8;
// Sector size
int disksize = 0;
for(disksize = 16; disksize > 0; --(disksize)) {
if ((1 << disksize) == sectorsize)
break;
}
// Number of blocks
uint32_t diskblocks = (uint32_t)(size >> disksize);
int a = 4;
if(dbd == 0) {
uint32_t bl = m_sel->m_blocksize;
uint32_t bc = m_sel->m_fileSize / bl;
uint8_t c[8] = {
0,// Density code
bc >> 16, bc >> 8, bc,
0, //Reserve
bl >> 16, bl >> 8, bl
};
memcpy(&m_responsebuffer[4], c, 8);
a += 8;
m_responsebuffer[3] = 0x08;
}
switch(pageCode) {
case 0x3F:
{
m_responsebuffer[len + 0] = 0x01;
m_responsebuffer[len + 1] = 0x06;
a += 8;
}
case 0x03: // drive parameters
{
m_responsebuffer[len + 0] = 0x80 | 0x03; // Page code
m_responsebuffer[len + 1] = 0x16; // Page length
m_responsebuffer[len + 2] = (uint8_t)(heads >> 8);// number of sectors / track
m_responsebuffer[len + 3] = (uint8_t)(heads);// number of sectors / track
m_responsebuffer[len + 10] = (uint8_t)(sectors >> 8);// number of sectors / track
m_responsebuffer[len + 11] = (uint8_t)(sectors);// number of sectors / track
int size = 1 << disksize;
m_responsebuffer[len + 12] = (uint8_t)(size >> 8);// number of sectors / track
m_responsebuffer[len + 13] = (uint8_t)(size);// number of sectors / track
a += 24;
if(pageCode != 0x3F) {
break;
}
}
case 0x04: // drive parameters
{
LOGN("AddDrive");
m_responsebuffer[len + 0] = 0x04; // Page code
m_responsebuffer[len + 1] = 0x12; // Page length
m_responsebuffer[len + 2] = (cylinders >> 16);// Cylinder length
m_responsebuffer[len + 3] = (cylinders >> 8);
m_responsebuffer[len + 4] = cylinders;
m_responsebuffer[len + 5] = heads; // Number of heads
a += 20;
if(pageCode != 0x3F) {
break;
}
}
default:
break;
}
m_responsebuffer[0] = a - 1;
writeDataPhase(len < a ? len : a, m_responsebuffer);
} else
#endif
{
/* Default medium type */
m_responsebuffer[len++] = (m_sel->m_type == DEV_OPTICAL) ? 0xf0 : 0x00;
@ -221,7 +205,7 @@ void ModeSenseCommandHandler()
m_responsebuffer[len++] = 0x04;
m_responsebuffer[len++] = 0x00;
} else {
uint32_t capacity = (m_sel->m_fileSize / m_sel->m_blocksize);
uint32_t capacity = (m_sel->m_fileSize / m_sel->m_blocksize) - 1;
m_responsebuffer[len++] = 8; /* Block descriptor length */
m_responsebuffer[len++] = (capacity >> 24) & 0xff;
m_responsebuffer[len++] = (capacity >> 16) & 0xff;
@ -337,19 +321,40 @@ void ModeSenseCommandHandler()
#endif
case MODEPAGE_FORMAT_PARAMETERS:
m_responsebuffer[len + 0] = MODEPAGE_FORMAT_PARAMETERS; //Page code
m_responsebuffer[len + 1] = 0x16; // Page length
m_responsebuffer[len + 11] = 0x3F;//Number of sectors / track
m_responsebuffer[len + 1] = 0x16; // Page length
if((m_cmd[2] >> 6) != 1) {
m_responsebuffer[len + 11] = 0x3F; // Number of sectors / track
m_responsebuffer[len + 12] = (m_sel->m_blocksize >> 8) & 0xff; // Blocksize MSB
m_responsebuffer[len + 13] = (m_sel->m_blocksize >> 0) & 0xff; // Blocksize LSB
m_responsebuffer[len + 15] = 0x1; // Interleave
}
len += 24;
break;
case MODEPAGE_RIGID_GEOMETRY:
m_responsebuffer[len + 0] = MODEPAGE_RIGID_GEOMETRY; //Page code
m_responsebuffer[len + 1] = 0x16; // Page length
if((m_cmd[2] >> 6) != 1) {
m_responsebuffer[len + 2] = m_sel->m_cylinders >> 16; // Number of cylinders
m_responsebuffer[len + 3] = m_sel->m_cylinders >> 8;
m_responsebuffer[len + 4] = m_sel->m_cylinders;
m_responsebuffer[len + 5] = m_sel->m_heads; // Number of heads
memcpy(&m_responsebuffer[len + 6], &m_responsebuffer[len + 2], 3); // Write Precomp Cyl
memcpy(&m_responsebuffer[len + 9], &m_responsebuffer[len + 2], 3); // Reduced Write Current Cyl
m_responsebuffer[len + 20] = 0x1C; // 7200 RPM
m_responsebuffer[len + 21] = 0x20;
}
len += 24;
break;
case MODEPAGE_FLEXIBLE_GEOMETRY:
{
uint32_t bc = m_sel->m_fileSize / m_sel->m_file;
m_responsebuffer[len + 0] = MODEPAGE_RIGID_GEOMETRY; //Page code
m_responsebuffer[len + 1] = 0x16; // Page length
m_responsebuffer[len + 2] = bc >> 16;// Cylinder length
m_responsebuffer[len + 3] = bc >> 8;
m_responsebuffer[len + 4] = bc;
m_responsebuffer[len + 5] = 1; //Number of heads
m_responsebuffer[len + 0] = MODEPAGE_FLEXIBLE_GEOMETRY; //Page code
m_responsebuffer[len + 1] = 0x1E; // Page length
m_responsebuffer[len + 2] = 0x03; // Transfer rate 1mbit/s (MSB)
m_responsebuffer[len + 3] = 0xE8; // Transfer rate 1mbit/s (LSB)
m_responsebuffer[len + 4] = 16; // Number of heads
m_responsebuffer[len + 5] = 18; // Sectors per track
m_responsebuffer[len + 6] = 0x20; // Data bytes per sector (MSB)
m_responsebuffer[len + 6] = 0x00; // Data bytes per sector (LSB)
len += 24;
}
break;
@ -387,16 +392,27 @@ void ModeSenseCommandHandler()
}
uint8_t onModeSelectCommand() {
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 2" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x04;
return 0x02;
return STATUS_GOOD;
}
void ModeSelect6CommandHandler() {
LOG("[ModeSelect6] ");
uint16_t len = m_cmd[4];
if(!m_sel) {
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
if(len > MAX_BLOCKSIZE) {
m_sel->m_sense.m_key = ILLEGAL_REQUEST;
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 4" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x04;
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
readDataPhase(len, m_responsebuffer);
for(int i = 1; i < len; i++ ) {
@ -404,13 +420,28 @@ void ModeSelect6CommandHandler() {
LOGHEX2(m_responsebuffer[i]);
}
LOGN("");
// m_sts |= onModeSelectCommand();
m_sts |= onModeSelectCommand();
m_phase = PHASE_STATUSIN;
}
void ModeSelect10CommandHandler() {
LOGN("[ModeSelect10]");
uint16_t len = ((uint16_t)m_cmd[7] << 8) | m_cmd[8];
if(!m_sel) {
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
if(len > MAX_BLOCKSIZE) {
m_sel->m_sense.m_key = ILLEGAL_REQUEST;
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 7" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x07;
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
readDataPhase(len, m_responsebuffer);
for(int i = 1; i < len; i++ ) {
@ -418,7 +449,7 @@ void ModeSelect10CommandHandler() {
LOGHEX2(m_responsebuffer[i]);
}
LOGN("");
// m_sts |= onModeSelectCommand();
m_sts |= onModeSelectCommand();
m_phase = PHASE_STATUSIN;
}
@ -427,12 +458,30 @@ void SearchDataEqualCommandHandler() {
m_phase = PHASE_STATUSIN;
}
void SendDiagnosticCommandHandler() {
LOGN("[SendDiagnostic]");
if(!m_sel) {
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
if(m_cmd[1] & 0x04) {
} else {
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 1" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x01;
m_sts |= STATUS_CHECK;
}
m_phase = PHASE_STATUSIN;
}
void ReadDefectCommandHandler() {
LOGN("[ReadDefect]");
m_responsebuffer[0] = 0x00;
m_responsebuffer[1] = m_cmd[2];
m_responsebuffer[2] = 0x00; // List Length MSB
m_responsebuffer[3] = 0x00; // List Length LSB
m_responsebuffer[2] = m_cmd[7]; // List Length MSB
m_responsebuffer[3] = m_cmd[8]; // List Length LSB
writeDataPhase(4, m_responsebuffer);
m_phase = PHASE_STATUSIN;
@ -448,15 +497,27 @@ void PreAllowMediumRemovalCommandHandler() {
m_phase = PHASE_STATUSIN;
}
void PrefetchCommandHandler() {
LOGN("[Prefetch]");
m_phase = PHASE_STATUSIN;
}
void SyncCacheCommandHandler() {
LOGN("[SyncCache]");
m_phase = PHASE_STATUSIN;
}
void UnknownCommandHandler() {
LOGN("[*Unknown]");
m_sts |= 0x02;
m_sel->m_sense.m_key = 5;
m_sts |= STATUS_CHECK;
if(m_sel) {
m_sel->m_sense.m_key = 5;
}
m_phase = PHASE_STATUSIN;
}
void BadLunCommandHandler() {
LOGN("[Bad LUN]");
m_sts |= 0x02;
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
}

View File

@ -40,6 +40,7 @@
#include <Arduino.h> // For Platform.IO
#include <SPI.h>
#include <LittleFS.h>
#include <SdFat.h>
#include "sdios.h"
#include "config.h"
@ -48,18 +49,39 @@
// SDFAT
SdFs sd;
LittleFS_Program lfs;
struct part_s {
uint8_t boot;
uint8_t beginCHS[3];
uint8_t type;
uint8_t endCHS[3];
uint32_t firstSector;
uint32_t totalSectors;
} __attribute__((packed));
typedef struct part_s part_t;
//-----------------------------------------------------------------------------
struct mbr_s {
uint8_t bootCode[446];
part_t part[4];
uint8_t signature[2];
} __attribute__((packed));
typedef struct mbr_s mbr_t;
boolean debuglog = 0;
#if DEBUG == 1
#define LOG(XX) Serial.print(XX)
#define LOGHEX2(XX) Serial.printf("%02x", XX)
#define LOGHEX4(XX) Serial.printf("%04x", XX)
#define LOGHEX6(XX) Serial.printf("%06x", XX)
#define LOGHEX8(XX) Serial.printf("%08x", XX)
#define LOGN(XX) Serial.println(XX)
#define LOGHEX2N(XX) Serial.printf("%02x\r\n", XX)
#define LOGHEX4N(XX) Serial.printf("%04x\r\n", XX)
#define LOGHEX6N(XX) Serial.printf("%06x\r\n", XX)
#define LOGHEX8N(XX) Serial.printf("%08x\r\n", XX)
#define LOG(XX) if(debuglog) Serial.print(XX)
#define LOGHEX2(XX) if(debuglog) Serial.printf("%02x", XX)
#define LOGHEX4(XX) if(debuglog) Serial.printf("%04x", XX)
#define LOGHEX6(XX) if(debuglog) Serial.printf("%06x", XX)
#define LOGHEX8(XX) if(debuglog) Serial.printf("%08x", XX)
#define LOGN(XX) if(debuglog) Serial.println(XX)
#define LOGHEX2N(XX) if(debuglog) Serial.printf("%02x\r\n", XX)
#define LOGHEX4N(XX) if(debuglog) Serial.printf("%04x\r\n", XX)
#define LOGHEX6N(XX) if(debuglog) Serial.printf("%06x\r\n", XX)
#define LOGHEX8N(XX) if(debuglog) Serial.printf("%08x\r\n", XX)
#elif DEBUG == 2
#define LOG(XX) LOG_FILE.print(XX); LOG_FILE.sync();
#define LOGHEX2(XX) LOG_FILE.printf("%02x", XX); LOG_FILE.sync();
@ -191,7 +213,12 @@ typedef struct VirtualDevice_s
char m_filename[MAX_FILE_PATH+1];
FsFile m_file; // File object
uint64_t m_fileSize; // File size
uint8_t m_sectors;
uint8_t m_heads;
uint32_t m_cylinders;
size_t m_blocksize; // SCSI BLOCK size
uint32_t m_firstSector; // First sector for partition
boolean m_rawPart; // Raw Partition (True) or Image File (False)
#if SUPPORT_TAPE
size_t m_filemarks; // Tape position counter (file marks since BOM)
#endif
@ -223,6 +250,8 @@ uint16_t default_quirks = (SUPPORT_SASI_DEFAULT ? QUIRKS_SASI : 0) | (SUPPO
uint16_t ledbits = 0;
uint8_t ledbit = 0;
uint8_t cardMBR[512];
typedef enum {
PHASE_BUSFREE = 0,
PHASE_SELECTION,
@ -234,7 +263,7 @@ typedef enum {
phase_t m_phase = PHASE_BUSFREE;
// Log File
#define VERSION "1.2-20211204"
#define VERSION "1.4-20230529"
#if DEBUG == 2
#define LOG_FILENAME "LOG.txt"
FsFile LOG_FILE;
@ -267,6 +296,8 @@ boolean OpenImage(VirtualDevice_t *h, const char *image_name)
h->m_file = sd.open(image_name, O_RDWR);
if(h->m_file.isOpen()) {
h->m_fileSize = h->m_file.size();
h->m_cylinders = (uint32_t)((uint64_t)h->m_fileSize / ((uint64_t)h->m_blocksize * (uint64_t)h->m_heads * (uint64_t)h->m_sectors));
return true; // File opened
}
return false;
@ -278,6 +309,60 @@ boolean OpenImage(VirtualDevice_t *h, const char *image_name)
*/
boolean OpenDiskImage(VirtualDevice_t *h, const char *image_name, int blocksize)
{
if(!strncmp(image_name, "/tgts/", 6)) {
LOGN("/tgts/ path is not supported for disk images.");
return false;
}
if(!strncmp(image_name, "/vdevs/", 7)) {
LOGN("/vdevs/ path is not supported for disk images.");
return false;
}
if(!strncmp(image_name, "/diag/", 6)) {
LOGN("/diag/ path is not supported for disk images.");
return false;
}
if(!strncmp(image_name, "/nv/", 4)) {
LOGN("/nv/ path is not supported for disk images.");
return false;
}
h->m_rawPart = false;
if(!strncmp(image_name, "/raw/part", 9)) {
int partIndex = image_name[9] - '0';
mbr_t *mbr = (mbr_t *)cardMBR;
if((partIndex < 0) || (partIndex > 3)) {
LOGN("partition index is outside the allowed range.");
return false;
}
sd.card()->readSector(0, cardMBR);
if(mbr->part[partIndex].type != 0x87) {
LOGN("partition is of the wrong type.");
return false;
}
h->m_blocksize = blocksize;
h->m_fileSize = ((uint64_t)mbr->part[partIndex].totalSectors) * ((uint64_t)512);
h->m_cylinders = (uint32_t)((uint64_t)h->m_fileSize / ((uint64_t)h->m_blocksize * (uint64_t)h->m_heads * (uint64_t)h->m_sectors));
h->m_rawPart = true;
h->m_firstSector = mbr->part[partIndex].firstSector;
LOG(" Imagefile: ");
LOG(image_name);
LOG(" / ");
LOG(h->m_fileSize / h->m_blocksize);
LOG(" sectors / ");
LOG(h->m_fileSize / 1024);
LOG(" KiB / ");
LOG(h->m_fileSize / 1024 / 1024);
LOGN(" MiB");
return true; // File opened
}
if(!strncmp(image_name, "/sd/", 4))
image_name += 3;
@ -287,6 +372,7 @@ boolean OpenDiskImage(VirtualDevice_t *h, const char *image_name, int blocksize)
if(h->m_file.isOpen())
{
h->m_fileSize = h->m_file.size();
h->m_cylinders = (uint32_t)((uint64_t)h->m_fileSize / ((uint64_t)h->m_blocksize * (uint64_t)h->m_heads * (uint64_t)h->m_sectors));
LOG(" Imagefile: ");
LOG(image_name);
if(h->m_fileSize>0)
@ -318,6 +404,29 @@ boolean OpenDiskImage(VirtualDevice_t *h, const char *image_name, int blocksize)
*/
boolean OpenTapeImage(VirtualDevice_t *h, const char *image_name)
{
if(!strncmp(image_name, "/tgts/", 6)) {
LOGN("/tgts/ path is not supported for tape images.");
return false;
}
if(!strncmp(image_name, "/vdevs/", 7)) {
LOGN("/vdevs/ path is not supported for tape images.");
return false;
}
if(!strncmp(image_name, "/diag/", 6)) {
LOGN("/diag/ path is not supported for tape images.");
return false;
}
if(!strncmp(image_name, "/nv/", 4)) {
LOGN("/nv/ path is not supported for tape images.");
return false;
}
if(!strncmp(image_name, "/sd/", 4))
image_name += 3;
h->m_fileSize = 0;
h->m_blocksize = 0;
h->m_filemarks = 0;
@ -404,6 +513,9 @@ void setup()
LED_ON();
// Filesystems
lfs.begin(256 * 1024); // 256KB of program memory to be used as nonvolatile storage
if(!sd.begin(SdioConfig(FIFO_SDIO))) {
#if DEBUG > 0
Serial.println("SD initialization failed!");
@ -418,10 +530,14 @@ void setup()
//HD image file open
scsi_id_mask = 0x00;
// If greenscsi.cfg exists, run it
// If greenscsi.cfg exists, run it (try first from SD, otherwise from flash)
if(sd.exists("/greenscsi.cfg")) {
execscript((char*)"/sd/greenscsi.cfg");
execLoop();
} else
if(lfs.exists("/greenscsi.cfg")) {
execscript((char*)"/nv/greenscsi.cfg");
execLoop();
}
// Scan for images if we haven't defined any targets yet.
@ -909,3 +1025,235 @@ void BusFreePhaseHandler() {
// Reset back to waiting for selection phase.
m_phase = PHASE_SELECTION;
}
typedef struct SelfTestPins_s {
int A;
int B;
int pA;
int pB;
char nA[4];
char nB[4];
} SelfTestPins_t;
SelfTestPins_t SelfTestPins[] = {
{ IO, DB0, 50, 2, "I/O", "DB0" },
{ IO, DB0, 48, 4, "REQ", "DB1" },
{ IO, DB0, 46, 6, "C/D", "DB2" },
{ IO, DB0, 44, 8, "SEL", "DB3" },
{ IO, DB0, 42, 10, "MSG", "DB4" },
{ IO, DB0, 50, 12, "RST", "DB5" },
{ IO, DB0, 38, 14, "ACK", "DB6" },
{ IO, DB0, 36, 16, "BSY", "DB7" },
{ IO, DB0, 32, 18, "ATN", "DBP" },
};
void SelfTest(int argc, char **argv) {
int i, x;
char c;
Serial.printf("Are you sure you wish to run the self test? ");
for(;;) {
if (Serial.available()) {
c = Serial.read();
switch(c) {
default:
return;
case 'y': case 'Y':
goto ConnectHarness;
}
}
}
ConnectHarness:
// Clear any extra characters
while (Serial.available()) {
c = Serial.read();
}
// Disable normal operation and prepare the self test.
detachInterrupt(RST);
detachInterrupt(SEL);
Serial.printf("Self Test starting...\r\n");
// Delay for 3 seconds
delay(3000);
while (Serial.available()) {
c = Serial.read();
}
Serial.printf("Connect the Loopback test adapter and press Enter.");
for(;;) {
if (Serial.available()) {
c = Serial.read();
switch(c) {
case 0xA: case 0xD:
goto ExecuteSelfTest;
}
}
}
ExecuteSelfTest:
// Clear any extra characters
while (Serial.available()) {
c = Serial.read();
}
// All pins input
for(i = 0; i < 9; i++) {
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
}
for(i = 0; i < 9; i++) {
// Test A -> B
pinMode(SelfTestPins[i].A, OUTPUT_OPENDRAIN);
digitalWrite(SelfTestPins[i].A, LOW);
delay(10);
if(digitalRead(SelfTestPins[i].B) != LOW) {
Serial.printf("Self Test Failed. Pin %d (%s) was unable to pull Pin %d (%s) LOW.\r\n", SelfTestPins[i].pA, SelfTestPins[i].nA, SelfTestPins[i].pB, SelfTestPins[i].nB);
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
return;
}
for(x = 0; x < 9; x++) {
if(x != i) {
if(digitalRead(SelfTestPins[x].A) == LOW) {
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pA, SelfTestPins[i].nA, SelfTestPins[x].pA, SelfTestPins[x].nA);
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
return;
}
if(digitalRead(SelfTestPins[x].B) == LOW) {
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pA, SelfTestPins[i].nA, SelfTestPins[x].pB, SelfTestPins[x].nB);
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
return;
}
}
}
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
delay(10);
// Test B -> A
pinMode(SelfTestPins[i].B, OUTPUT_OPENDRAIN);
digitalWrite(SelfTestPins[i].B, LOW);
delay(10);
if(digitalRead(SelfTestPins[i].A) != LOW) {
Serial.printf("Self Test Failed. Pin %d (%s) was unable to pull Pin %d (%s) LOW.\r\n", SelfTestPins[i].pB, SelfTestPins[i].nB, SelfTestPins[i].pA, SelfTestPins[i].nA);
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
return;
}
for(x = 0; x < 9; x++) {
if(x != i) {
if(digitalRead(SelfTestPins[x].A) == LOW) {
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pB, SelfTestPins[i].nB, SelfTestPins[x].pA, SelfTestPins[x].nA);
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
return;
}
if(digitalRead(SelfTestPins[x].B) == LOW) {
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pB, SelfTestPins[i].nB, SelfTestPins[x].pB, SelfTestPins[x].nB);
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
return;
}
}
}
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
delay(10);
}
while (Serial.available()) {
c = Serial.read();
}
Serial.printf("Disconnect the Loopback test adapter and press Enter.");
for(;;) {
if (Serial.available()) {
c = Serial.read();
switch(c) {
case 0xA: case 0xD:
goto DisconnectHarness;
}
}
}
DisconnectHarness:
// Clear any extra characters
while (Serial.available()) {
c = Serial.read();
}
for(i = 0; i < 9; i++) {
// Test A -> B
pinMode(SelfTestPins[i].A, OUTPUT_OPENDRAIN);
digitalWrite(SelfTestPins[i].A, LOW);
delay(10);
if(digitalRead(SelfTestPins[i].B) == LOW) {
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pA, SelfTestPins[i].nA, SelfTestPins[i].pB, SelfTestPins[i].nB);
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
return;
}
// Test B -> A
pinMode(SelfTestPins[i].B, OUTPUT_OPENDRAIN);
digitalWrite(SelfTestPins[i].B, LOW);
delay(10);
if(digitalRead(SelfTestPins[i].A) == LOW) {
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pB, SelfTestPins[i].nB, SelfTestPins[i].pA, SelfTestPins[i].nA);
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
return;
}
}
//SelfTestComplete:
// Clear any extra characters
while (Serial.available()) {
c = Serial.read();
}
Serial.printf("Self Test Passed.\r\n");
// On success, restore normal operation
// Input port
pinMode(ATN, INPUT_PULLUP);
pinMode(ACK, INPUT_PULLUP);
pinMode(RST, INPUT_PULLUP);
pinMode(SEL, INPUT_PULLUP);
// Output port
pinModeFastSlew(BSY, OUTPUT_OPENDRAIN);
pinModeFastSlew(MSG, OUTPUT_OPENDRAIN);
pinModeFastSlew(CD, OUTPUT_OPENDRAIN);
pinModeFastSlew(IO, OUTPUT_OPENDRAIN);
pinModeFastSlew(REQ, OUTPUT_OPENDRAIN);
pinModeFastSlew(DB0, OUTPUT_OPENDRAIN);
pinModeFastSlew(DB1, OUTPUT_OPENDRAIN);
pinModeFastSlew(DB2, OUTPUT_OPENDRAIN);
pinModeFastSlew(DB3, OUTPUT_OPENDRAIN);
pinModeFastSlew(DB4, OUTPUT_OPENDRAIN);
pinModeFastSlew(DB5, OUTPUT_OPENDRAIN);
pinModeFastSlew(DB6, OUTPUT_OPENDRAIN);
pinModeFastSlew(DB7, OUTPUT_OPENDRAIN);
pinModeFastSlew(DB8, OUTPUT_OPENDRAIN);
// Turn off the output port
SCSI_TARGET_INACTIVE();
attachInterrupt(RST, onBusReset, FALLING);
attachInterrupt(SEL, SelectionPhaseISR, FALLING);
LED_OFF();
}

View File

@ -152,7 +152,7 @@ void OpticalReadSimpleTOC()
uint8_t len = 0;
if(!m_sel) {
m_sts |= 0x02;
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
@ -496,7 +496,11 @@ void OpticalLockTrayCommandHandler() {
void OpticalReadCapacityCommandHandler() {
LOGN("[ReadCapacity]");
if(!m_sel) {
m_sts |= 0x02; // Image file absent
m_sts |= STATUS_CHECK; // Image file absent
m_sel->m_sense.m_key_specific[0] = 0x04;
m_sel->m_sense.m_key_specific[1] = 0x03;
m_sel->m_sense.m_key_specific[2] = 0x00;
m_sel->m_sense.m_key_specific[3] = 0x00;
m_phase = PHASE_STATUSIN;
return;
}
@ -531,6 +535,7 @@ void ConfigureOpticalHandlers(VirtualDevice_t *vdev) {
vdev->m_handler[CMD_READ_TOC] = &OpticalReadTOCCommandHandler;
vdev->m_handler[CMD_READ_HEADER] = &OpticalHeaderCommandHandler;
//vdev->m_handler[CMD_GET_CONFIGURATION] = &OpticalGetConfigurationCommandHandler;
vdev->m_handler[CMD_SEND_DIAGNOSTIC] = &SendDiagnosticCommandHandler;
vdev->m_handler[CMD_GET_EVENT_STATUS_NOTIFICATION] = &OpticalEventStatusCommandHandler;
vdev->m_handler[CMD_READ_DISC_INFORMATION] = &OpticalReadDiscInfoCommandHandler;
vdev->m_handler[CMD_MODE_SELECT10] = &ModeSelect10CommandHandler;

View File

@ -7,6 +7,7 @@
#define MODEPAGE_DCRC_PARAMETERS 0x02
#define MODEPAGE_FORMAT_PARAMETERS 0x03
#define MODEPAGE_RIGID_GEOMETRY 0x04
#define MODEPAGE_FLEXIBLE_GEOMETRY 0x05
#define MODEPAGE_APPLE 0x30
#define MODEPAGE_ALL_PAGES 0x3F
@ -93,7 +94,14 @@
*/
#define DEV_DISK 0x00
#define DEV_TAPE 0x01
#define DEV_PRINTER 0x02
#define DEV_PROCESSOR 0x03
#define DEV_WORM 0x04
#define DEV_OPTICAL 0x05
#define DEV_SCANNER 0x06
#define DEV_OMS 0x07
#define DEV_CHANGER 0x08
#define DEV_COMM 0x09
/*
* SCSI MESSAGE CODES
@ -155,7 +163,8 @@
/* Additional Sense Information */
#define NO_ADDITIONAL_SENSE_INFORMATION 0x00
#define INVALID_LBA 0x21
#define LUN_NOT_READY 0x04
#define INVALID_LBA 0x21
#define INVALID_FIELD_IN_CDB 0x24
#define NOTREADY_TO_READY_CHANGE 0x28
#define UNIT_POWERON_RESET 0x29

View File

@ -211,6 +211,55 @@ void writeDataPhaseSD(uint32_t adds, uint32_t len)
}
}
/*
* Data in phase.
* Send len block while reading from SD card.
*/
void writeDataPhaseRaw(uint32_t adds, uint32_t len)
{
#if READ_SPEED_OPTIMIZE_RAW
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
#endif
uint32_t i = 0;
//LOGN("DATAIN PHASE(RAW)");
uint32_t pos = ((adds * m_sel->m_blocksize) / 512) + m_sel->m_firstSector;
SET_MSG_INACTIVE();
SET_CD_INACTIVE();
SET_IO_ACTIVE();
while(i < len) {
// Asynchronous reads will make it faster ...
#if READ_SPEED_OPTIMIZE_RAW
if((len-i) >= bigread) {
sd.card()->readSectors(pos, m_buf, (MAX_BLOCKSIZE / 512));
writeHandshakeBlock(m_buf, MAX_BLOCKSIZE);
i += bigread;
pos += (MAX_BLOCKSIZE / 512);
} else {
sd.card()->readSectors(pos, m_buf, ((m_sel->m_blocksize * (len-i)) / 512));
writeHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
i = len;
}
#else
sd.card()->readSectors(pos, m_buf, (m_sel->m_blocksize / 512));
pos++;
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
if(m_isBusReset) {
m_phase = PHASE_BUSFREE;
return;
}
writeHandshake(m_buf[j]);
}
#endif
if(m_isBusReset) {
m_phase = PHASE_BUSFREE;
return;
}
}
}
/*
* Data out phase.
* len block read
@ -274,3 +323,127 @@ void readDataPhaseSD(uint32_t adds, uint32_t len)
}
m_sel->m_file.flush();
}
/*
* Data out phase.
* Write to SD card while reading len block.
*/
void readDataPhaseRaw(uint32_t adds, uint32_t len)
{
#if WRITE_SPEED_OPTIMIZE_RAW
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
#endif
uint32_t i = 0;
//LOGN("DATAOUT PHASE(RAW)");
uint32_t pos = ((adds * m_sel->m_blocksize) / 512) + m_sel->m_firstSector;
SET_MSG_INACTIVE();
SET_CD_INACTIVE();
SET_IO_INACTIVE();
while(i < len) {
#if WRITE_SPEED_OPTIMIZE_RAW
if((len-i) >= bigread) {
readHandshakeBlock(m_buf, MAX_BLOCKSIZE);
sd.card()->writeSectors(pos, m_buf, (MAX_BLOCKSIZE / 512));
i += bigread;
pos += (MAX_BLOCKSIZE / 512);
} else {
readHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
sd.card()->writeSectors(pos, m_buf, ((m_sel->m_blocksize * (len-i)) / 512));
i = len;
}
#else
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
if(m_isBusReset) {
return;
}
m_buf[j] = readHandshake();
}
sd.card()->writeSectors(pos, m_buf, (m_sel->m_blocksize / 512));
i++;
pos += (m_sel->m_blocksize / 512);
#endif
}
m_sel->m_file.flush();
}
/*
* Data out phase.
* Verify SD card while reading len block.
*/
void verifyDataPhaseSD(uint32_t adds, uint32_t len)
{
#if WRITE_SPEED_OPTIMIZE
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
#endif
uint32_t i = 0;
//LOGN("DATAOUT PHASE(SD)");
uint32_t pos = adds * m_sel->m_blocksize;
m_sel->m_file.seek(pos);
SET_MSG_INACTIVE();
SET_CD_INACTIVE();
SET_IO_INACTIVE();
while(i < len) {
#if WRITE_SPEED_OPTIMIZE
if((len-i) >= bigread) {
readHandshakeBlock(m_buf, MAX_BLOCKSIZE);
//m_sel->m_file.verify(m_buf, MAX_BLOCKSIZE);
i += bigread;
} else {
readHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
//m_sel->m_file.verify(m_buf, m_sel->m_blocksize * (len-i));
i = len;
}
#else
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
if(m_isBusReset) {
return;
}
m_buf[j] = readHandshake();
}
//m_sel->m_file.verify(m_buf, m_sel->m_blocksize);
#endif
}
}
/*
* Data out phase.
* Verify SD card while reading len block.
*/
void verifyDataPhaseRaw(uint32_t adds, uint32_t len)
{
#if WRITE_SPEED_OPTIMIZE_RAW
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
#endif
uint32_t i = 0;
//LOGN("DATAOUT PHASE(RAW)");
//uint32_t pos = ((adds * m_sel->m_blocksize) / 512) + m_sel->m_firstSector;
SET_MSG_INACTIVE();
SET_CD_INACTIVE();
SET_IO_INACTIVE();
while(i < len) {
#if WRITE_SPEED_OPTIMIZE_RAW
if((len-i) >= bigread) {
readHandshakeBlock(m_buf, MAX_BLOCKSIZE);
i += bigread;
} else {
readHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
i = len;
}
#else
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
if(m_isBusReset) {
return;
}
m_buf[j] = readHandshake();
}
#endif
}
}

View File

@ -5,12 +5,17 @@
/*
* READ6 / 10 Command processing.
*/
void TapeReadCommandHandler()
void onTapeReadCommand(uint32_t adds, uint32_t len)
{
uint32_t len;
LOG("-R ");
LOGHEX4N(len);
LOG("[Read6]");
len = (m_cmd[4] << 16) | (m_cmd[3] << 8) | m_cmd[2];
if(!m_sel) {
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
switch(m_cmd[1] & 0x3) {
case 0:
if(len == 0) return;
@ -29,11 +34,7 @@ void TapeReadCommandHandler()
m_phase = PHASE_STATUSIN;
return;
}
LOG("-R ");
LOGHEX4N(len);
if(!m_sel) return 0x02; // Image file absent
LED_ON();
writeDataPhaseTape(len);
LED_OFF();
@ -44,14 +45,16 @@ void TapeReadCommandHandler()
/*
* WRITE6 / 10 Command processing.
*/
void TapeWriteCommandHandler()
void onTapeWriteCommand(uint32_t adds, uint32_t len)
{
uint32_t len;
LOG("[Write6]-W ");
LOG("-W ");
LOGHEX4N(len);
if(!m_sel) return 0x02; // Image file absent
if(!m_sel) {
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
LED_ON();
m_sel->m_file.write(&len, 4);
@ -62,6 +65,40 @@ void TapeWriteCommandHandler()
m_phase = PHASE_STATUSIN;
}
void TapeRead6CommandHandler() {
LOG("[Read6]");
m_sts |= onTapeReadCommand((((uint32_t)m_cmd[1] & 0x1F) << 16) | ((uint32_t)m_cmd[2] << 8) | m_cmd[3], (m_cmd[4] == 0) ? 0x100 : m_cmd[4]);
m_phase = PHASE_STATUSIN;
}
void TapeWrite6CommandHandler() {
LOG("[Write6]");
m_sts |= onTapeWriteCommand((((uint32_t)m_cmd[1] & 0x1F) << 16) | ((uint32_t)m_cmd[2] << 8) | m_cmd[3], (m_cmd[4] == 0) ? 0x100 : m_cmd[4]);
m_phase = PHASE_STATUSIN;
}
void TapeSeek6CommandHandler() {
LOG("[Seek6]");
m_phase = PHASE_STATUSIN;
}
void TapeRead10CommandHandler() {
LOG("[Read10]");
m_sts |= onTapeReadCommand(((uint32_t)m_cmd[2] << 24) | ((uint32_t)m_cmd[3] << 16) | ((uint32_t)m_cmd[4] << 8) | m_cmd[5], ((uint32_t)m_cmd[7] << 8) | m_cmd[8]);
m_phase = PHASE_STATUSIN;
}
void TapeWrite10CommandHandler() {
LOG("[Write10]");
m_sts |= onTapeWriteCommand(((uint32_t)m_cmd[2] << 24) | ((uint32_t)m_cmd[3] << 16) | ((uint32_t)m_cmd[4] << 8) | m_cmd[5], ((uint32_t)m_cmd[7] << 8) | m_cmd[8]);
m_phase = PHASE_STATUSIN;
}
void TapeSeek10CommandHandler() {
LOG("[Seek10]");
m_phase = PHASE_STATUSIN;
}
void TapeModeSense6CommandHandler() {
uint8_t len;
int page, pagemax, pagemin;
@ -69,7 +106,7 @@ void TapeModeSense6CommandHandler() {
LOGN("[ModeSense6]");
/* Check whether medium is present */
if(!m_sel) {
m_sts |= 0x02;
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
@ -139,6 +176,12 @@ void TapeLoadUnloadCommandHandler() {
} else {
LOGN("[Unload]");
}
if(!m_sel) {
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
m_phase = PHASE_STATUSIN;
}
@ -148,13 +191,19 @@ void TapePreventRemovalCommandHandler() {
} else {
LOGN("[Allow Removal]");
}
if(!m_sel) {
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
m_phase = PHASE_STATUSIN;
}
void TapeReadCapacityCommandHandler() {
LOGN("[ReadCapacity]");
if(!m_sel) {
m_sts |= 0x02; // Image file absent
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
@ -172,7 +221,7 @@ void TapeReadCapacityCommandHandler() {
void TapeEraseCommandHandler() {
LOGN("[Erase]");
if(!m_sel) {
m_sts |= 0x02; // Image file absent
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
@ -183,7 +232,7 @@ void TapeReadBlockLimitsCommandHandler() {
uint16_t len = 0;
LOGN("[ReadBlockLimits]");
if(!m_sel) {
m_sts |= 0x02; // Image file absent
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
@ -201,7 +250,7 @@ void TapeReadBlockLimitsCommandHandler() {
void TapeRewindUnitCommandHandler() {
LOGN("[Rewind]");
if(!m_sel) {
m_sts |= 0x02; // Image file absent
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
@ -214,10 +263,11 @@ void TapeReadPositionCommandHandler() {
uint16_t len = 0;
LOGN("[ReadPosition]");
if(!m_sel) {
m_sts |= 0x02; // Image file absent
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
m_responsebuffer[len++] = (m_sel->m_filemarks == 0) ? (1 << 7) : 0;
m_responsebuffer[len++] = 0x00; // Partition(0)
m_responsebuffer[len++] = 0x00; // Reserved
@ -252,18 +302,18 @@ void ConfigureTapeHandlers(VirtualDevice_t *vdev) {
vdev->m_handler[CMD_REZERO_UNIT] = &TapeRewindUnitCommandHandler;
vdev->m_handler[CMD_REQUEST_SENSE] = &RequestSenseCommandHandler;
vdev->m_handler[CMD_READ_BLOCK_LIMITS] = &TapeReadBlockLimitsCommandHandler;
vdev->m_handler[CMD_READ6] = &TapeReadCommandHandler;
vdev->m_handler[CMD_WRITE6] = &TapeWriteCommandHandler;
vdev->m_handler[CMD_SEEK6] = &TapeSeekCommandHandler;
vdev->m_handler[CMD_READ6] = &TapeRead6CommandHandler;
vdev->m_handler[CMD_WRITE6] = &TapeWrite6CommandHandler;
vdev->m_handler[CMD_SEEK6] = &TapeSeek6CommandHandler;
vdev->m_handler[CMD_INQUIRY] = &InquiryCommandHandler;
vdev->m_handler[CMD_MODE_SELECT6] = &ModeSelect6CommandHandler;
vdev->m_handler[CMD_MODE_SENSE6] = &TapeModeSense6CommandHandler;
vdev->m_handler[CMD_START_STOP_UNIT] = &TapeLoadUnloadCommandHandler;
vdev->m_handler[CMD_PREVENT_REMOVAL] = &TapePreventRemovalCommandHandler;
vdev->m_handler[CMD_READ_CAPACITY10] = &TapeReadCapacityCommandHandler;
vdev->m_handler[CMD_READ10] = &TapeReadCommandHandler;
vdev->m_handler[CMD_WRITE10] = &TapeWriteCommandHandler;
vdev->m_handler[CMD_SEEK10] = &TapeSeekCommandHandler;
vdev->m_handler[CMD_READ10] = &TapeRead10CommandHandler;
vdev->m_handler[CMD_WRITE10] = &TapeWrite10CommandHandler;
vdev->m_handler[CMD_SEEK10] = &TapeSeek10CommandHandler;
vdev->m_handler[CMD_READPOSITION10] = &TapeReadPositionCommandHandler;
vdev->m_handler[CMD_MODE_SELECT10] = &ModeSelect10CommandHandler;
vdev->m_handler[CMD_MODE_SENSE10] = &TapeModeSense10CommandHandler;