diff --git a/src/Makefile.am b/src/Makefile.am index 0f1d680..7a9de4f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,8 +19,8 @@ dells200.c device.c disc.c disc_fdi.c disc_img.c disc_sector.c dma.c esdi_at.c f hdd.c hdd_esdi.c hdd_file.c headland.c i430lx.c i430fx.c i430vx.c ide.c intel.c intel_flash.c io.c jim.c joystick_ch_flightstick_pro.c joystick_standard.c joystick_sw_pad.c \ joystick_tm_fcs.c keyboard.c keyboard_amstrad.c keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \ laserxt.c lpt.c lpt_dac.c lpt_dss.c mca.c mcr.c mem.c mfm_at.c mfm_xebec.c model.c mouse.c mouse_msystems.c mouse_ps2.c mouse_serial.c neat.c nmi.c nvr.c olivetti_m24.c \ -opti495.c paths.c pc.c pci.c pic.c piix.c pit.c ppi.c ps1.c ps2.c ps2_mca.c ps2_nvr.c rom.c rtc.c scat.c serial.c sio.c sis496.c sound.c \ -sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_cms.c sound_emu8k.c sound_gus.c \ +opti495.c paths.c pc.c pci.c pic.c piix.c pit.c ppi.c ps1.c ps2.c ps2_mca.c ps2_nvr.c rom.c rtc.c scat.c scsi.c scsi_53c400.c scsi_hd.c \ +serial.c sio.c sis496.c sound.c sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_cms.c sound_emu8k.c sound_gus.c \ sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c sound_sb.c sound_sb_dsp.c sound_sn76489.c \ sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c tandy_eeprom.c tandy_rom.c \ timer.c um8669f.c um8881f.c vid_ati_eeprom.c vid_ati_mach64.c vid_ati18800.c vid_ati28800.c \ diff --git a/src/Makefile.linux32 b/src/Makefile.linux32 index 5e620c1..bc74fcd 100644 --- a/src/Makefile.linux32 +++ b/src/Makefile.linux32 @@ -11,8 +11,8 @@ dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o f hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \ laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o \ -opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o serial.o sio.o sis496.o sound.o \ -sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ +opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o scsi.o scsi_53c400.o scsi_hd.o +serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \ sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o thread-pthread.o \ timer.o um8669f.o um8881f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o \ diff --git a/src/Makefile.linux32-wx-sdl2 b/src/Makefile.linux32-wx-sdl2 index feb4453..fabb34b 100644 --- a/src/Makefile.linux32-wx-sdl2 +++ b/src/Makefile.linux32-wx-sdl2 @@ -10,8 +10,8 @@ dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o f hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \ laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o \ -opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o serial.o sio.o sis496.o sound.o \ -sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ +opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o scsi.o scsi_53c400.o scsi_hd.o \ +serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \ sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o \ timer.o um8669f.o um8881f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o \ diff --git a/src/Makefile.linux64 b/src/Makefile.linux64 index 336cdfc..b41b86f 100644 --- a/src/Makefile.linux64 +++ b/src/Makefile.linux64 @@ -10,8 +10,8 @@ dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o f hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \ laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o \ -opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o serial.o sio.o sis496.o sound.o \ -sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ +opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o scsi.o scsi_53c400.o scsi_hd.o \ +serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \ sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o thread-pthread.o \ timer.o um8669f.o um8881f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o \ diff --git a/src/Makefile.linux64-wx-sdl2 b/src/Makefile.linux64-wx-sdl2 index 8a99245..1ae689f 100644 --- a/src/Makefile.linux64-wx-sdl2 +++ b/src/Makefile.linux64-wx-sdl2 @@ -10,8 +10,8 @@ dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o f hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \ laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o \ -opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o serial.o sio.o sis496.o sound.o \ -sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ +opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o scsi.o scsi_53c400.o scsi_hd.o \ +serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \ sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o \ timer.o um8669f.o um8881f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o \ diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 2593924..b11a52c 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -9,7 +9,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o \ - scat.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ + scat.o scsi.o scsi_53c400.o scsi_hd.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ diff --git a/src/Makefile.mingw-network b/src/Makefile.mingw-network index 67b7239..b95bbf5 100644 --- a/src/Makefile.mingw-network +++ b/src/Makefile.mingw-network @@ -10,7 +10,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o \ - scat.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ + scat.o scsi.o scsi_53c400.o scsi_hd.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ diff --git a/src/Makefile.mingw-wx-sdl2 b/src/Makefile.mingw-wx-sdl2 index e207c89..09f850d 100644 --- a/src/Makefile.mingw-wx-sdl2 +++ b/src/Makefile.mingw-wx-sdl2 @@ -12,7 +12,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o \ - scat.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ + scat.o scsi.o scsi_53c400.o scsi_hd.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ diff --git a/src/Makefile.mingw-wx-sdl2-network b/src/Makefile.mingw-wx-sdl2-network index 93e7d23..95f7d81 100644 --- a/src/Makefile.mingw-wx-sdl2-network +++ b/src/Makefile.mingw-wx-sdl2-network @@ -12,7 +12,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o \ - scat.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ + scat.o scsi.o scsi_53c400.o scsi_hd.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ diff --git a/src/Makefile.mingw64 b/src/Makefile.mingw64 index b0f64b1..7681945 100644 --- a/src/Makefile.mingw64 +++ b/src/Makefile.mingw64 @@ -9,7 +9,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o \ - scat.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ + scat.o scsi.o scsi_53c400.o scsi_hd.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o \ soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ diff --git a/src/Makefile.osx64-wx-sdl2 b/src/Makefile.osx64-wx-sdl2 index a96aa59..f432c30 100644 --- a/src/Makefile.osx64-wx-sdl2 +++ b/src/Makefile.osx64-wx-sdl2 @@ -9,8 +9,8 @@ device.o dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o f hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \ laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o \ -opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o serial.o sio.o sis496.o sound.o \ -sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ +opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o scsi.o scsi_53c400.o scsi_hd.o \ +serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \ sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o \ timer.o um8669f.o um8881f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o \ diff --git a/src/hdd.c b/src/hdd.c index f342592..83f939e 100644 --- a/src/hdd.c +++ b/src/hdd.c @@ -7,6 +7,7 @@ #include "ide.h" #include "mfm_at.h" #include "mfm_xebec.h" +#include "scsi_53c400.h" #include "xtide.h" char hdd_controller_name[16]; @@ -33,6 +34,9 @@ static struct {"[IDE] Standard IDE", "ide", &ide_device, 0, 1}, {"[IDE] XTIDE", "xtide", &xtide_device, 0, 1}, {"[IDE] XTIDE (AT)", "xtide_at", &xtide_at_device, 0, 1}, + {"[SCSI] Longshine LCS-6821N", "lcs6821n", &scsi_lcs6821n_device, 0, 0}, + {"[SCSI] Rancho RT1000B", "rt1000b", &scsi_rt1000b_device, 0, 0}, + {"[SCSI] Trantor T130B", "t130b", &scsi_t130b_device, 0, 0}, {"", "", NULL, 0, 0} }; diff --git a/src/scsi.c b/src/scsi.c new file mode 100644 index 0000000..01d4c98 --- /dev/null +++ b/src/scsi.c @@ -0,0 +1,356 @@ +#include "ibm.h" +#include "ide.h" +#include "scsi.h" +#include "scsi_cd.h" +#include "scsi_hd.h" + +#define STATE_IDLE 0 +#define STATE_COMMAND 1 +#define STATE_COMMANDWAIT 2 +#define STATE_DATAIN 3 +#define STATE_DATAOUT 4 +#define STATE_STATUS 5 +#define STATE_MESSAGEIN 6 +#define STATE_PHASESEL 7 + +#define SET_BUS_STATE(bus, state) bus->bus_out = (bus->bus_out & ~(BUS_CD | BUS_IO | BUS_MSG)) | (state & (BUS_CD | BUS_IO | BUS_MSG)) + +static int cmd_len[8] = {6, 10, 10, 6, 16, 12, 6, 6}; + +static int get_dev_id(uint8_t data) +{ + int c; + + for (c = 0; c < 8; c++) + { + if (data & (1 << c)) + return c; + } + + return -1; +} + +int scsi_bus_update(scsi_bus_t *bus, int bus_assert) +{ + scsi_device_t *dev = NULL; + void *dev_data = NULL; + +// pclog("scsi_hd_bus_update: state=%d bus_assert=%04x bus_in=%02x %i %02x %p\n", bus->state, bus_assert, bus->bus_in, bus->clear_req, bus->bus_out, bus); + + if (bus_assert & BUS_ARB) + bus->state = STATE_IDLE; + + if (bus->dev_id != -1) + { + dev = bus->devices[bus->dev_id]; + dev_data = bus->device_data[bus->dev_id]; + } + + switch (bus->state) + { + case STATE_IDLE: + bus->clear_req = bus->change_state_delay = bus->new_req_delay = 0; + if ((bus_assert & BUS_SEL) && !(bus_assert & BUS_BSY)) + { + uint8_t sel_data = BUS_GETDATA(bus_assert); + + //bus->state = STATE_PHASESEL; + bus->dev_id = get_dev_id(sel_data); +// pclog("PHASESEL %02x %2x %i %p\n", sel_data, bus->bus_out, bus->dev_id, bus->devices[bus->dev_id]); + if (bus->dev_id != -1 && bus->devices[bus->dev_id]) + { + bus->bus_out |= BUS_BSY; + bus->state = STATE_PHASESEL; +// pclog("Move to phase sel\n"); + } + break; + } + break; + case STATE_PHASESEL: + if (!(bus_assert & BUS_SEL)) + { + if (!(bus_assert & BUS_ATN)) + { +/* uint8_t sel_data = BUS_GETDATA(bus_assert); + + bus->dev_id = get_dev_id(sel_data);*/ +// pclog("STATE_PHASESEL: %i %p\n", bus->dev_id, bus->devices[bus->dev_id]); + if (bus->dev_id != -1 && bus->devices[bus->dev_id]) + { + bus->state = STATE_COMMAND; + bus->bus_out = BUS_BSY | BUS_REQ; + bus->command_pos = 0; + SET_BUS_STATE(bus, BUS_CD); + } + else + { + bus->state = STATE_IDLE; + bus->bus_out = 0; + } + } + else + fatal("dropped sel %x\n", bus_assert & BUS_ATN); + } + break; + case STATE_COMMAND: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { +// pclog(" get data %02x\n", BUS_GETDATA(bus_assert)); + bus->command[bus->command_pos++] = BUS_GETDATA(bus_assert); + bus->clear_req = 3; + bus->new_state = bus->bus_out & (BUS_IO | BUS_CD | BUS_MSG); + bus->bus_out &= ~BUS_REQ; + + if (cmd_len[bus->command[0] >> 5] == bus->command_pos) + { + int new_state; + + dev->start_command(dev_data); + new_state = dev->command(bus->command, dev_data); +// pclog("COMMAND new_state = %x\n", new_state); + if ((new_state & (BUS_IO | BUS_CD | BUS_MSG)) == BUS_CD) + { + bus->state = STATE_COMMANDWAIT; + bus->clear_req = 0; + } + else + { +// pclog("Set change_state_delay COMMAND\n"); + bus->new_state = new_state; + bus->change_state_delay = 4; + } + } + } + break; + + case STATE_COMMANDWAIT: + { + int new_state; + +// pclog("COMMANDWAIT\n"); + new_state = dev->command(bus->command, dev_data); +// pclog("new_state=%x\n", new_state); + if ((new_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_CD) + { +// pclog("Set change_state_delay\n"); + bus->new_state = new_state; + bus->change_state_delay = 4; + bus->clear_req = 4; + } + } + break; + + case STATE_DATAIN: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { + if (dev->read_complete(dev_data)) + { +// pclog("Read complete\n"); + bus->bus_out &= ~BUS_REQ; + //bus->clear_req = 3; + bus->new_state = BUS_CD | BUS_IO; +// pclog("change_state_delay STATE_DATAIN\n"); + bus->change_state_delay = 4; + bus->new_req_delay = 8; +// SET_BUS_STATE(data, BUS_CD | BUS_IO); + } + else + { + uint8_t val = dev->read(dev_data); + +// pclog(" Read data pos %04x %02x %x %x\n", bus->data_pos_read, bus->data_in[bus->data_pos_read], bus->data_pos_read, bus->data_pos_write); + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP | BUS_REQ; +// bus->bus_out |= BUS_REQ; + bus->clear_req = 3; + bus->bus_out &= ~BUS_REQ; + bus->new_state = BUS_IO; + } +// scsi_hd_command(bus->command, data); + } + break; + + case STATE_DATAOUT: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { + dev->write(BUS_GETDATA(bus_assert), dev_data); +// pclog("Got data %02x\n", BUS_GETDATA(bus_assert)); +// pclog(" Write data pos %04x %02x %08x %08x\n", bus->data_pos_write-1, bus->data_out[bus->data_pos_write-1], cpu_getd(5), cpu_getd(6)); + + if (dev->write_complete(dev_data)) + { + int new_state; + //pclog(" Write data, command complete\n"); + bus->bus_out &= ~BUS_REQ; + new_state = dev->command(bus->command, dev_data); + + bus->new_state = new_state; +// pclog("change_state_delay STATE_DATAOUT\n"); + bus->change_state_delay = 4; + bus->new_req_delay = 8; + } + else + { + bus->bus_out |= BUS_REQ; + } + } + break; + + case STATE_STATUS: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { + bus->bus_out &= ~BUS_REQ; +/* bus->clear_req = 3;*/ + bus->new_state = BUS_CD | BUS_IO | BUS_MSG; +// pclog("change_state_delay STATE_STATUS\n"); + bus->change_state_delay = 4; + bus->new_req_delay = 8; +/* bus->state = STATE_MESSAGEIN;*/ + } + break; + + case STATE_MESSAGEIN: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { +// pclog("Scheduling change to idle\n"); + bus->bus_out &= ~BUS_REQ; + bus->new_state = BUS_IDLE; +// pclog("change_state_delay STATE_MESSAGEIN\n"); + bus->change_state_delay = 4; +/* bus->bus_out &= ~BUS_BSY; + SET_BUS_STATE(bus, BUS_CD | BUS_IO); + bus->state = STATE_IDLE;*/ + } + break; + } + bus->bus_in = bus_assert; + + return bus->bus_out | bus->bus_in; +} + +int scsi_bus_read(scsi_bus_t *bus) +{ + scsi_device_t *dev = NULL; + void *dev_data = NULL; + + if (bus->dev_id != -1) + { + dev = bus->devices[bus->dev_id]; + dev_data = bus->device_data[bus->dev_id]; + } + +// pclog("scsi_hd_bus_read: bus_out=%02x bus_in=%02x %i %i %i\n", bus->bus_out, bus->bus_in, bus->clear_req, bus->change_state_delay, bus->new_req_delay); + + if (bus->clear_req) + { + bus->clear_req--; + if (!bus->clear_req) + { + SET_BUS_STATE(bus, bus->new_state); +// pclog("clear_req\n"); + bus->bus_out |= BUS_REQ; + } + } + + if (bus->change_state_delay) + { + bus->change_state_delay--; + if (!bus->change_state_delay) + { + uint8_t val; + +// pclog("change_state_delay %08x\n", bus->bus_out & (BUS_IO | BUS_CD | BUS_MSG | BUS_IDLE)); + SET_BUS_STATE(bus, bus->new_state); + + switch (bus->bus_out & (BUS_IO | BUS_CD | BUS_MSG)) + { + case BUS_IO: + bus->state = STATE_DATAIN; + val = dev->read(dev_data); + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP; + break; + + case 0: + if (bus->new_state & BUS_IDLE) + { + bus->state = STATE_IDLE; + bus->bus_out &= ~BUS_BSY; + } + else + bus->state = STATE_DATAOUT; + break; + + case (BUS_IO | BUS_CD): + bus->state = STATE_STATUS; + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(dev->get_status(dev_data)) | BUS_DBP; + break; + + case (BUS_CD | BUS_IO | BUS_MSG): + bus->state = STATE_MESSAGEIN; + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; + break; + + default: + fatal("change_state_delay bad state %x\n", bus->bus_out); + } + + } + } + if (bus->new_req_delay) + { + bus->new_req_delay--; + if (!bus->new_req_delay) + { +// pclog("new_req_delay\n"); + bus->bus_out |= BUS_REQ; + } + } + +// pclog(" bus_out now %02x\n", bus->bus_out); + return bus->bus_out;// | bus->bus_in; +} + +int scsi_bus_match(scsi_bus_t *bus, int bus_assert) +{ +// pclog("bus_match %02x %02x\n", bus_assert & (BUS_CD | BUS_IO | BUS_MSG), bus->bus_out & (BUS_CD | BUS_IO | BUS_MSG)); + + return (bus_assert & (BUS_CD | BUS_IO | BUS_MSG)) == (bus->bus_out & (BUS_CD | BUS_IO | BUS_MSG)); +} + +void scsi_bus_kick(scsi_bus_t *bus) +{ +// pclog("scsi_bus_kick\n"); + scsi_bus_update(bus, 0); +} + +void scsi_bus_init(scsi_bus_t *bus) +{ + int c; + + memset(bus->devices, 0, sizeof(bus->devices)); + memset(bus->device_data, 0, sizeof(bus->device_data)); + + for (c = 0; c < 4; c++) + { + if (cdrom_channel != c) + { + bus->devices[c] = &scsi_hd; + bus->device_data[c] = bus->devices[c]->init(bus, c); + if (!bus->device_data[c]) + bus->devices[c] = NULL; + } + } +} + +void scsi_bus_close(scsi_bus_t *bus) +{ + int c; + + memset(bus->devices, 0, sizeof(bus->devices)); + memset(bus->device_data, 0, sizeof(bus->device_data)); + + for (c = 0; c < 8; c++) + { + if (bus->device_data[c]) + bus->devices[c]->close(bus->device_data[c]); + } +} diff --git a/src/scsi.h b/src/scsi.h new file mode 100644 index 0000000..4c2bdab --- /dev/null +++ b/src/scsi.h @@ -0,0 +1,103 @@ +struct scsi_bus_t; + +typedef struct scsi_device_t +{ + void *(*init)(struct scsi_bus_t *bus, int id); + void (*close)(void *p); + + void (*start_command)(void *p); + int (*command)(uint8_t *cdb, void *p); + + uint8_t (*get_status)(void *p); + + uint8_t (*read)(void *p); + void (*write)(uint8_t val, void *p); + int (*read_complete)(void *p); + int (*write_complete)(void *p); +} scsi_device_t; + +typedef struct scsi_bus_t +{ + int state; + int new_state; + int clear_req; + uint32_t bus_in, bus_out; + int dev_id; + + int command_pos; + uint8_t command[20]; + + scsi_device_t *devices[8]; + void *device_data[8]; + + int change_state_delay; + int new_req_delay; +} scsi_bus_t; + +//int scsi_add_data(uint8_t val); +//int scsi_get_data(); +void scsi_set_phase(uint8_t phase); +void scsi_set_irq(uint8_t status); + +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_REZERO_UNIT 0x01 +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_FORMAT 0x04 +#define SCSI_READ_6 0x08 +#define SCSI_WRITE_6 0x0a +#define SCSI_SEEK_6 0x0b +#define SCSI_INQUIRY 0x12 +#define SCSI_MODE_SELECT_6 0x15 +#define SCSI_MODE_SENSE_6 0x1a +#define SCSI_START_STOP_UNIT 0x1b +#define SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define SCSI_READ_CAPACITY_10 0x25 +#define SCSI_READ_10 0x28 +#define SCSI_WRITE_10 0x2a +#define SCSI_SEEK_10 0x2b +#define SCSI_VERIFY_10 0x2f +#define SCSI_READ_BUFFER 0x3c + +#define SCSI_RESERVE 0x16 +#define SCSI_RELEASE 0x17 +#define SEND_DIAGNOSTIC 0x1d + +#define STATUS_GOOD 0x00 +#define STATUS_CHECK_CONDITION 0x02 + +#define MSG_COMMAND_COMPLETE 0x00 + +#define BUS_DBP 0x01 +#define BUS_SEL 0x02 +#define BUS_IO 0x04 +#define BUS_CD 0x08 +#define BUS_MSG 0x10 +#define BUS_REQ 0x20 +#define BUS_BSY 0x40 +#define BUS_RST 0x80 +#define BUS_ACK 0x200 +#define BUS_ATN 0x200 +#define BUS_ARB 0x8000 +#define BUS_SETDATA(val) ((uint32_t)val << 16) +#define BUS_GETDATA(val) ((val >> 16) & 0xff) +#define BUS_DATAMASK 0xff0000 + +#define BUS_IDLE (1 << 31) + +int scsi_bus_update(scsi_bus_t *bus, int bus_assert); +int scsi_bus_read(scsi_bus_t *bus); +int scsi_bus_match(scsi_bus_t *bus, int bus_assert); +void scsi_bus_kick(scsi_bus_t *bus); +void scsi_bus_init(scsi_bus_t *bus); +void scsi_bus_close(scsi_bus_t *bus); + +#define KEY_ILLEGAL_REQ 5 + +#define ASC_INVALID_LUN 0x25 + +#define SCSI_PHASE_DATA_OUT 0 +#define SCSI_PHASE_DATA_IN BUS_IO +#define SCSI_PHASE_COMMAND BUS_CD +#define SCSI_PHASE_STATUS (BUS_CD | BUS_IO) +#define SCSI_PHASE_MESSAGE_OUT (BUS_MSG | BUS_CD) +#define SCSI_PHASE_MESSAGE_IN (BUS_MSG | BUS_CD | BUS_IO) diff --git a/src/scsi_53c400.c b/src/scsi_53c400.c new file mode 100644 index 0000000..ad90245 --- /dev/null +++ b/src/scsi_53c400.c @@ -0,0 +1,826 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "scsi.h" +#include "scsi_53c400.h" +#include "timer.h" + +#define POLL_TIME_US 10 +#define MAX_BYTES_TRANSFERRED_PER_POLL 50 +/*10us poll period with 50 bytes transferred per poll = 5MB/sec*/ + +typedef struct ncr5380_t +{ + uint8_t output_data; + uint8_t icr; + uint8_t mode; + uint8_t tcr; + uint8_t ser; + uint8_t isr; + + int target_id; + int target_bsy; + int target_req; + + uint8_t bus_status; + + int dma_mode; + + void (*dma_changed)(struct ncr5380_t *ncr, int mode, int enable); + void *p; + + scsi_bus_t bus; +} ncr5380_t; + +typedef struct lcs6821n_t +{ + rom_t bios_rom; + + mem_mapping_t mapping; + + uint8_t block_count; + int block_count_loaded; + + uint8_t status_ctrl; + + uint8_t buffer[0x80]; + int buffer_pos; + int buffer_host_pos; + + uint8_t int_ram[0x40]; + uint8_t ext_ram[0x600]; + + ncr5380_t ncr; + + int ncr5380_dma_enabled; + + int dma_callback; + int dma_enabled; + + int ncr_busy; +} lcs6821n_t; + +#define ICR_DBP 0x01 +#define ICR_ATN 0x02 +#define ICR_SEL 0x04 +#define ICR_BSY 0x08 +#define ICR_ACK 0x10 +#define ICR_ARB_LOST 0x20 +#define ICR_ARB_IN_PROGRESS 0x40 + +#define MODE_ARBITRATE 0x01 +#define MODE_DMA 0x02 +#define MODE_MONITOR_BUSY 0x04 +#define MODE_ENA_EOP_INT 0x08 + +#define STATUS_ACK 0x01 +#define STATUS_BUSY_ERROR 0x04 +#define STATUS_INT 0x10 +#define STATUS_DRQ 0x40 +#define STATUS_END_OF_DMA 0x80 + +#define TCR_IO 0x01 +#define TCR_CD 0x02 +#define TCR_MSG 0x04 +#define TCR_REQ 0x08 +#define TCR_LAST_BYTE_SENT 0x80 + +enum +{ + DMA_IDLE = 0, + DMA_SEND, + DMA_TARGET_RECEIVE, + DMA_INITIATOR_RECEIVE +}; + +static void ncr53c400_dma_changed(ncr5380_t *ncr, int mode, int enable) +{ + lcs6821n_t *scsi = (lcs6821n_t *)ncr->p; + + scsi->ncr5380_dma_enabled = (mode && enable); + + scsi->dma_enabled = (scsi->ncr5380_dma_enabled && scsi->block_count_loaded); +} + +void ncr5380_reset(ncr5380_t *ncr) +{ + memset(ncr, 0, sizeof(ncr)); +} + +static uint32_t get_bus_host(ncr5380_t *ncr) +{ + uint32_t bus_host = 0; + + if (ncr->icr & ICR_DBP) + bus_host |= BUS_DBP; + if (ncr->icr & ICR_SEL) + bus_host |= BUS_SEL; + if (ncr->icr & ICR_ATN) + bus_host |= BUS_ATN; + if (ncr->tcr & TCR_IO) + bus_host |= BUS_IO; + if (ncr->tcr & TCR_CD) + bus_host |= BUS_CD; + if (ncr->tcr & TCR_MSG) + bus_host |= BUS_MSG; + if (ncr->tcr & TCR_REQ) + bus_host |= BUS_REQ; + if (ncr->icr & ICR_BSY) + bus_host |= BUS_BSY; + if (ncr->icr & ICR_ACK) + bus_host |= BUS_ACK; + if (ncr->mode & MODE_ARBITRATE) + bus_host |= BUS_ARB; +// pclog("get_bus_host %02x %08x\n", ncr->output_data, BUS_SETDATA(ncr->output_data)); + return bus_host | BUS_SETDATA(ncr->output_data); +} + +void ncr5380_write(uint32_t addr, uint8_t val, void *p) +{ + ncr5380_t *ncr = (ncr5380_t *)p; + int bus_host = 0; + +// pclog("ncr5380_write: addr=%06x val=%02x %04x:%04x\n", addr, val, CS,cpu_state.pc); + switch (addr & 7) + { + case 0: /*Output data register*/ + ncr->output_data = val; + break; + + case 1: /*Initiator Command Register*/ + if ((val & (ICR_BSY | ICR_SEL)) == (ICR_BSY | ICR_SEL) && + (ncr->icr & (ICR_BSY | ICR_SEL)) == ICR_SEL) + { + uint8_t temp = ncr->output_data & 0x7f; + + ncr->target_id = -1; + while (temp) + { + temp >>= 1; + ncr->target_id++; + } +// pclog("Select - target ID = %i\n", ncr->target_id); + + if (!ncr->target_id) + ncr->target_bsy = 1; + } + + ncr->icr = val; + break; + + case 2: /*Mode register*/ + if ((val & MODE_ARBITRATE) && !(ncr->mode & MODE_ARBITRATE)) + { + ncr->icr &= ~ICR_ARB_LOST; + ncr->icr |= ICR_ARB_IN_PROGRESS; + } + +// output = 1; + ncr->mode = val; + ncr->dma_changed(ncr, ncr->dma_mode, ncr->mode & MODE_DMA); + if (!(ncr->mode & MODE_DMA)) + { + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + ncr->dma_mode = DMA_IDLE; + } + break; + + case 3: /*Target Command Register*/ + ncr->tcr = val; +/* switch (val & (TCR_MSG | TCR_CD | TCR_IO)) + { + case TCR_CD: + ncr->target_req = 1; + break; + }*/ + break; + case 4: /*Select Enable Register*/ + ncr->ser = val; + break; + + case 5: /*Start DMA Send*/ + ncr->dma_mode = DMA_SEND; + ncr->dma_changed(ncr, ncr->dma_mode, ncr->mode & MODE_DMA); + break; + + case 7: /*Start DMA Initiator Receive*/ + ncr->dma_mode = DMA_INITIATOR_RECEIVE; + ncr->dma_changed(ncr, ncr->dma_mode, ncr->mode & MODE_DMA); + break; + + default: + pclog("Bad NCR5380 write %06x %02x\n", addr, val); + } + + bus_host = get_bus_host(ncr); + + scsi_bus_update(&ncr->bus, bus_host); +} + +uint8_t ncr5380_read(uint32_t addr, void *p) +{ + ncr5380_t *ncr = (ncr5380_t *)p; + uint32_t bus = 0; + uint8_t temp = 0xff; + + switch (addr & 7) + { + case 0: /*Current SCSI Data*/ + //output = 3; + //fatal("Here\n"); + if (ncr->icr & ICR_DBP) + temp = ncr->output_data; + else + { + bus = scsi_bus_read(&ncr->bus); + temp = BUS_GETDATA(bus); + } + break; + case 1: /*Initiator Command Register*/ + temp = ncr->icr; + break; + case 2: /*Mode Register*/ + temp = ncr->mode; + break; + case 3: /*Target Command Register*/ + temp = ncr->tcr; + break; + + case 4: /*Current SCSI Bus Status*/ + temp = 0;//get_bus_host(ncr); + bus = scsi_bus_read(&ncr->bus); +// pclog(" SCSI bus status = %02x %02x\n", temp, bus); + temp |= (bus & 0xff); +// pclog(" SCSI bus status = %02x\n", temp); + break; + + case 5: /*Bus and Status Register*/ + temp = 0; + + bus = get_bus_host(ncr); + if (scsi_bus_match(&ncr->bus, bus)) + temp |= 8; + bus = scsi_bus_read(&ncr->bus); + + if (bus & BUS_ACK) + temp |= STATUS_ACK; + if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) + temp |= STATUS_DRQ; + if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) + { + int bus_state = 0; + if (bus & BUS_IO) + bus_state |= TCR_IO; + if (bus & BUS_CD) + bus_state |= TCR_CD; + if (bus & BUS_MSG) + bus_state |= TCR_MSG; + if ((ncr->tcr & 7) != bus_state) + ncr->isr |= STATUS_INT; + } + if (!(bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) + temp |= STATUS_BUSY_ERROR; + temp |= (ncr->isr & (STATUS_INT | STATUS_END_OF_DMA)); + +// pclog(" bus and status register = %02x\n", temp); + break; + + case 7: /*Reset Parity/Interrupt*/ + ncr->isr &= ~STATUS_INT; + break; + + default: + pclog("Bad NCR5380 read %06x\n", addr); + } +// pclog("ncr5380_read: addr=%06x temp=%02x pc=%04x:%04x\n", addr, temp, CS,cpu_state.pc); + return temp; +} + +#define CTRL_DATA_DIR (1 << 6) + +#define STATUS_BUFFER_NOT_READY (1 << 2) +#define STATUS_53C80_ACCESSIBLE (1 << 7) + +static uint8_t lcs6821n_read(uint32_t addr, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + uint8_t temp = 0xff; +//if (addr >= 0xca000) + addr &= 0x3fff; +// pclog("lcs6821n_read %08x\n", addr); + if (addr < 0x2000) + temp = scsi->bios_rom.rom[addr & 0x1fff]; + else if (addr < 0x3800) + temp = 0xff; + else if (addr >= 0x3a00) + temp = scsi->ext_ram[addr - 0x3a00]; + else switch (addr & 0x3f80) + { + case 0x3800: +// pclog("Read intRAM %02x %02x\n", addr & 0x3f, scsi->int_ram[addr & 0x3f]); + temp = scsi->int_ram[addr & 0x3f]; + break; + + case 0x3880: +// pclog("Read 53c80 %04x\n", addr); + temp = ncr5380_read(addr, &scsi->ncr); + break; + + case 0x3900: +//pclog(" Read 3900 %i %02x\n", scsi->buffer_host_pos, scsi->status_ctrl); + if (scsi->buffer_host_pos >= 128 || !(scsi->status_ctrl & CTRL_DATA_DIR)) + temp = 0xff; + else + { + temp = scsi->buffer[scsi->buffer_host_pos++]; + + if (scsi->buffer_host_pos == 128) + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + break; + + case 0x3980: + switch (addr) + { + case 0x3980: /*Status*/ + temp = scsi->status_ctrl;// | 0x80; + if (!scsi->ncr_busy) + temp |= STATUS_53C80_ACCESSIBLE; + break; + case 0x3981: /*Block counter register*/ + temp = scsi->block_count; + break; + case 0x3982: /*Switch register read*/ +// temp = 7 | (7 << 3); + temp = 0xff; + break; + case 0x3983: + temp = 0xff; + break; + } + break; + } + +// if (addr >= 0x3880) pclog("lcs6821n_read: addr=%05x val=%02x %04x:%04x\n", addr, temp, CS,cpu_state.pc); + + return temp; +} + +static void lcs6821n_write(uint32_t addr, uint8_t val, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + addr &= 0x3fff; + +// /*if (addr >= 0x3880) */pclog("lcs6821n_write: addr=%05x val=%02x %04x:%04x %i %02x\n", addr, val, CS,cpu_state.pc, scsi->buffer_host_pos, scsi->status_ctrl); + + if (addr >= 0x3a00) + scsi->ext_ram[addr - 0x3a00] = val; + else switch (addr & 0x3f80) + { + case 0x3800: +// pclog("Write intram %02x %02x\n", addr & 0x3f, val); + scsi->int_ram[addr & 0x3f] = val; + break; + + case 0x3880: +// pclog("Write 53c80 %04x %02x\n", addr, val); + ncr5380_write(addr, val, &scsi->ncr); + break; + + case 0x3900: + if (!(scsi->status_ctrl & CTRL_DATA_DIR) && scsi->buffer_host_pos < 128) + { +// pclog(" Write %i %02x\n", scsi->buffer_host_pos, val); + scsi->buffer[scsi->buffer_host_pos++] = val; + if (scsi->buffer_host_pos == 128) + { + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + scsi->ncr_busy = 1; + } + } + break; + + case 0x3980: + switch (addr) + { + case 0x3980: /*Control*/ + if ((val & CTRL_DATA_DIR) && !(scsi->status_ctrl & CTRL_DATA_DIR)) + { + scsi->buffer_host_pos = 128; + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + else if (!(val & CTRL_DATA_DIR) && (scsi->status_ctrl & CTRL_DATA_DIR)) + { + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + } + scsi->status_ctrl = (scsi->status_ctrl & 0x87) | (val & 0x78); + break; + case 0x3981: /*Block counter register*/ + scsi->block_count = val; + scsi->block_count_loaded = 1; + scsi->dma_enabled = (scsi->ncr5380_dma_enabled && scsi->block_count_loaded); + if (scsi->status_ctrl & CTRL_DATA_DIR) + { + scsi->buffer_host_pos = 128; + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + else + { + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + } + break; + } + break; + } +} + +static uint8_t t130b_read(uint32_t addr, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + uint8_t temp = 0xff; +//if (addr >= 0xca000) + addr &= 0x3fff; + + if (addr < 0x1800) + temp = scsi->bios_rom.rom[addr & 0x1fff]; + else if (addr < 0x1880) + temp = scsi->ext_ram[addr & 0x7f]; +// else +// pclog("Bad T130B read %04x\n", addr); + +// if (addr >= 0x3880) pclog("lcs6821n_read: addr=%05x val=%02x %04x:%04x\n", addr, temp, CS,cpu_state.pc); + + return temp; +} +static void t130b_write(uint32_t addr, uint8_t val, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + addr &= 0x3fff; + +// if (addr >= 0x3880) pclog("lcs6821n_write: addr=%05x val=%02x %04x:%04x %i %02x\n", addr, val, CS,cpu_state.pc, scsi->buffer_host_pos, scsi->status_ctrl); + + if (addr >= 0x1800 && addr < 0x1880) + scsi->ext_ram[addr & 0x7f] = val; +// else +// pclog("Bad T130B write %04x %02x\n", addr, val); +} + +static uint8_t t130b_in(uint16_t port, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + uint8_t temp = 0xff; + + switch (port & 0xf) + { + case 0x0: case 0x1: case 0x2: case 0x3: + temp = lcs6821n_read((port & 7) | 0x3980, scsi); + break; + + case 0x4: case 0x5: + temp = lcs6821n_read(0x3900, scsi); + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + temp = ncr5380_read(port, &scsi->ncr); + break; + } + + if (CS != 0xdc00) + { + //pclog("t130b_in: port=%04x val=%02x %04x:%04x\n", port, temp, CS,cpu_state.pc); + //output = 3; + //fatal("Here\n"); + } + return temp; +} +static void t130b_out(uint16_t port, uint8_t val, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + //if (CS != 0xdc00) pclog("t130b_out: port=%04x val=%02x %04x:%04x\n", port, val, CS,cpu_state.pc); + + switch (port & 0xf) + { + case 0x0: case 0x1: case 0x2: case 0x3: + lcs6821n_write((port & 7) | 0x3980, val, scsi); + break; + + case 0x4: case 0x5: + lcs6821n_write(0x3900, val, scsi); + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + ncr5380_write(port, val, &scsi->ncr); + break; + } +} + +static void ncr53c400_dma_callback(void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + ncr5380_t *ncr = &scsi->ncr; + int c; + int bytes_transferred = 0; + +//pclog("dma_Callback poll\n"); + scsi->dma_callback += POLL_TIME_US; + + switch (scsi->ncr.dma_mode) + { + case DMA_SEND: + if (scsi->status_ctrl & CTRL_DATA_DIR) + { + pclog("DMA_SEND with DMA direction set wrong\n"); + break; + } + +// if (!device_data[ncr->target_id]) +// fatal("DMA with no device\n"); + + if (!(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)) + { +// pclog(" !(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)\n"); + break; + } + + if (!scsi->block_count_loaded) + { +// pclog("!scsi->block_count_loaded\n"); + break; + } + + while (bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int bus; + uint8_t data; + + for (c = 0; c < 10; c++) + { + uint8_t status = scsi_bus_read(&ncr->bus); + + if (status & BUS_REQ) + break; + } + if (c == 10) + { +// pclog(" No req\n"); + break; + } + + /*Data ready*/ + data = scsi->buffer[scsi->buffer_pos]; + bus = get_bus_host(ncr) & ~BUS_DATAMASK; + bus |= BUS_SETDATA(data); + + scsi_bus_update(&ncr->bus, bus | BUS_ACK); + scsi_bus_update(&ncr->bus, bus & ~BUS_ACK); +// pclog(" Sent data %02x %i\n", data, scsi->buffer_pos); + + scsi->buffer_pos++; + bytes_transferred++; + + if (scsi->buffer_pos == 128) + { + scsi->buffer_pos = 0; + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + scsi->block_count = (scsi->block_count - 1) & 255; + scsi->ncr_busy = 0; +// pclog("Sent buffer %i\n", scsi->block_count); + if (!scsi->block_count) + { + scsi->block_count_loaded = 0; + scsi->dma_enabled = 0; +// scsi->buffer_host_pos = 128; +// scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + ncr->isr |= STATUS_INT; + } + break; + } + } + break; + + case DMA_INITIATOR_RECEIVE: + if (!(scsi->status_ctrl & CTRL_DATA_DIR)) + { + pclog("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); + break; + } + + if (!(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)) + break; + + if (!scsi->block_count_loaded) + break; + + while (bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int bus; + uint8_t temp; + + for (c = 0; c < 10; c++) + { + uint8_t status = scsi_bus_read(&ncr->bus); + + if (status & BUS_REQ) + break; + } + if (c == 10) + break; + + /*Data ready*/ + bus = scsi_bus_read(&ncr->bus); + temp = BUS_GETDATA(bus); +// pclog(" Got data %02x %i\n", temp, scsi->buffer_pos); + + bus = get_bus_host(ncr); + + scsi_bus_update(&ncr->bus, bus | BUS_ACK); + scsi_bus_update(&ncr->bus, bus & ~BUS_ACK); + + scsi->buffer[scsi->buffer_pos++] = temp; + bytes_transferred++; + + if (scsi->buffer_pos == 128) + { + scsi->buffer_pos = 0; + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + scsi->block_count = (scsi->block_count - 1) & 255; +// pclog("Got buffer %i\n", scsi->block_count); + if (!scsi->block_count) + { + scsi->block_count_loaded = 0; + scsi->dma_enabled = 0; + +// output=3; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + ncr->isr |= STATUS_INT; + } + break; + } + } + break; + + default: + pclog("DMA callback bad mode %i\n", scsi->ncr.dma_mode); + break; + } + + { + int bus = scsi_bus_read(&ncr->bus); + + if (!(bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) + { + ncr->mode &= ~MODE_DMA; + ncr->dma_mode = DMA_IDLE; + ncr->dma_changed(ncr, ncr->dma_mode, ncr->mode & MODE_DMA); + } + } +} + +static void *scsi_53c400_init(char *bios_fn) +{ + lcs6821n_t *scsi = malloc(sizeof(lcs6821n_t)); + memset(scsi, 0, sizeof(lcs6821n_t)); + + scsi->ncr.dma_changed = ncr53c400_dma_changed; + scsi->ncr.p = scsi; + + rom_init(&scsi->bios_rom, bios_fn, 0xdc000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&scsi->bios_rom.mapping); + + mem_mapping_add(&scsi->mapping, 0xdc000, 0x4000, + lcs6821n_read, NULL, NULL, + lcs6821n_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + + ncr5380_reset(&scsi->ncr); + + scsi->status_ctrl = STATUS_BUFFER_NOT_READY; + scsi->buffer_host_pos = 128; + + scsi_bus_init(&scsi->ncr.bus); + + timer_add(ncr53c400_dma_callback, &scsi->dma_callback, &scsi->dma_enabled, scsi); + + return scsi; +} + +static void *scsi_lcs6821n_init() +{ + return scsi_53c400_init("Longshine LCS-6821N - BIOS version 1.04.bin"); +} +static void *scsi_rt1000b_init() +{ + return scsi_53c400_init("Rancho_RT1000_RTBios_version_8.10R.bin"); +} + +static void *scsi_t130b_init(char *bios_fn) +{ + lcs6821n_t *scsi = malloc(sizeof(lcs6821n_t)); + memset(scsi, 0, sizeof(lcs6821n_t)); + + scsi->ncr.dma_changed = ncr53c400_dma_changed; + scsi->ncr.p = scsi; + + rom_init(&scsi->bios_rom, "trantor_t130b_bios_v2.14.bin", 0xdc000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_add(&scsi->mapping, 0xdc000, 0x4000, + t130b_read, NULL, NULL, + t130b_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + io_sethandler(0x0350, 0x0010, + t130b_in, NULL, NULL, + t130b_out, NULL, NULL, + scsi); + + ncr5380_reset(&scsi->ncr); + + scsi->status_ctrl = STATUS_BUFFER_NOT_READY; + scsi->buffer_host_pos = 128; + + scsi_bus_init(&scsi->ncr.bus); + + timer_add(ncr53c400_dma_callback, &scsi->dma_callback, &scsi->dma_enabled, scsi); + + return scsi; +} + +static void scsi_53c400_close(void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + scsi_bus_close(&scsi->ncr.bus); + + free(scsi); +} + +static int scsi_lcs6821n_available() +{ + return rom_present("Longshine LCS-6821N - BIOS version 1.04.bin"); +} + +static int scsi_rt1000b_available() +{ + return rom_present("Rancho_RT1000_RTBios_version_8.10R.bin"); +} + +static int scsi_t130b_available() +{ + return rom_present("trantor_t130b_bios_v2.14.bin"); +} + +device_t scsi_lcs6821n_device = +{ + "Longshine LCS-6821N (SCSI)", + 0, + scsi_lcs6821n_init, + scsi_53c400_close, + scsi_lcs6821n_available, + NULL, + NULL, + NULL, + NULL +}; + +device_t scsi_rt1000b_device = +{ + "Ranco RT1000B (SCSI)", + 0, + scsi_rt1000b_init, + scsi_53c400_close, + scsi_rt1000b_available, + NULL, + NULL, + NULL, + NULL +}; + +device_t scsi_t130b_device = +{ + "Trantor T130B (SCSI)", + 0, + scsi_t130b_init, + scsi_53c400_close, + scsi_t130b_available, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/scsi_53c400.h b/src/scsi_53c400.h new file mode 100644 index 0000000..d1dc52d --- /dev/null +++ b/src/scsi_53c400.h @@ -0,0 +1,3 @@ +extern device_t scsi_lcs6821n_device; +extern device_t scsi_rt1000b_device; +extern device_t scsi_t130b_device; diff --git a/src/scsi_hd.c b/src/scsi_hd.c new file mode 100644 index 0000000..c03d87a --- /dev/null +++ b/src/scsi_hd.c @@ -0,0 +1,806 @@ +#include +#include +#include +#include +#include "ibm.h" +#include "hdd_file.h" +#include "scsi.h" +#include "scsi_hd.h" +#include "timer.h" + +extern char ide_fn[4][512]; + +#define BUFFER_SIZE (256*1024) + +#define RW_DELAY (TIMER_USEC * 500) + +enum +{ + CMD_POS_IDLE = 0, + CMD_POS_WAIT, + CMD_POS_START_SECTOR, + CMD_POS_TRANSFER +}; + +typedef struct scsi_hd_data +{ + int blocks; + + int cmd_pos, new_cmd_pos; + + int addr, len; + int sector_pos; + + uint8_t buf[512]; + + uint8_t status; + + uint8_t data_in[BUFFER_SIZE]; + uint8_t data_out[BUFFER_SIZE]; + int data_pos_read, data_pos_write; + + int bytes_received, bytes_required; + + hdd_file_t hdd; + + int sense_key, asc, ascq; + + int hd_id; + + int callback; + + scsi_bus_t *bus; +} scsi_hd_data; + +static void scsi_hd_callback(void *p) +{ + scsi_hd_data *data = p; + + data->callback = 0; + + if (data->cmd_pos == CMD_POS_WAIT) + { + data->cmd_pos = data->new_cmd_pos; + scsi_bus_kick(data->bus); + } +} + +static void *scsi_hd_init(scsi_bus_t *bus, int id) +{ + scsi_hd_data *data = malloc(sizeof(scsi_hd_data)); + memset(data, 0, sizeof(scsi_hd_data)); + + hdd_load(&data->hdd, id, ide_fn[id]); + + if (!data->hdd.f) + { + free(data); + return NULL; + } + + data->hd_id = id; + data->bus = bus; + timer_add(scsi_hd_callback, &data->callback, &data->callback, data); + + return data; +} + +static void scsi_hd_close(void *p) +{ + scsi_hd_data *data = p; + + hdd_close(&data->hdd); + free(data); +} + +static int scsi_add_data(uint8_t val, void *p) +{ + scsi_hd_data *data = p; + +// pclog("scsi_add_data : %04x %02x\n", data->data_pos_write, val); + + data->data_in[data->data_pos_write++] = val; + +// if (data->bus_out & BUS_REQ) +// return -1; + +// data->bus_out = (data->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP | BUS_REQ; + + return 0; +} + +static int scsi_get_data(void *p) +{ + scsi_hd_data *data = p; + uint8_t val = data->data_out[data->data_pos_read++]; + + if (data->data_pos_read > BUFFER_SIZE) + fatal("scsi_get_data beyond buffer limits\n"); + + return val; +} + +static void scsi_hd_illegal(scsi_hd_data *data) +{ + data->status = STATUS_CHECK_CONDITION; + data->sense_key = KEY_ILLEGAL_REQ; + data->asc = ASC_INVALID_LUN; + data->ascq = 0; +} + +#define add_data_len(v) \ + if (i < len) \ + scsi_add_data(v, data); \ + i++; + + +static int scsi_hd_command(uint8_t *cdb, void *p) +{ + scsi_hd_data *data = p; + int /*addr, */len; + int i = 0; + int desc; + int bus_state = 0; + +// if (data->cmd_pos == CMD_POS_IDLE) +// pclog("SCSI HD command %02x\n", cdb[0]); + data->status = STATUS_GOOD; + data->data_pos_read = data->data_pos_write = 0; + + if ((cdb[0] != SCSI_REQUEST_SENSE/* && cdb[0] != SCSI_INQUIRY*/) && (cdb[1] & 0xe0)) + { +// pclog("non-zero LUN\n"); + /*Non-zero LUN - abort command*/ + scsi_hd_illegal(data); + bus_state = BUS_CD | BUS_IO; + return bus_state; + } + + switch (cdb[0]) + { + case SCSI_TEST_UNIT_READY: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_REZERO_UNIT: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_REQUEST_SENSE: + desc = cdb[1] & 1; + len = cdb[4]; + + if (!desc) + { + add_data_len(0x70); + add_data_len(0); + add_data_len(data->sense_key); /*Sense key*/ + add_data_len(0); /*Information (4 bytes)*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); /*Additional sense length*/ + add_data_len(0); /*Command specific information (4 bytes)*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(data->asc); /*ASC*/ + add_data_len(data->ascq); /*ASCQ*/ + add_data_len(0); /*FRU code*/ + add_data_len(0); /*Sense key specific (3 bytes)*/ + add_data_len(0); + add_data_len(0); + } + else + { + add_data_len(0x72); + add_data_len(data->sense_key); /*Sense Key*/ + add_data_len(data->asc); /*ASC*/ + add_data_len(data->ascq); /*ASCQ*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); /*additional sense length*/ + } + + data->sense_key = data->asc = data->ascq = 0; + + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + + case SCSI_INQUIRY: + len = cdb[4] | (cdb[3] << 8); +// pclog("INQUIRY %d %02x %02x %02x %02x %02x %02x %i\n", len, cdb[0],cdb[1],cdb[2],cdb[3],cdb[4],cdb[5], data->hd_id); + + if (cdb[1] & 0xe0) + { + add_data_len(0 | (3 << 5)); /*No physical device on this LUN*/ + } + else + { + add_data_len(0 | (0 << 5)); /*Hard disc*/ + } + add_data_len(0); /*Not removeable*/ + add_data_len(0); /*No version*/ + add_data_len(2); /*Response data*/ + add_data_len(0); /*Additional length*/ + add_data_len(0); + add_data_len(0); + add_data_len(2); + + add_data_len('P'); + add_data_len('C'); + add_data_len('e'); + add_data_len('m'); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + + add_data_len('S'); + add_data_len('C'); + add_data_len('S'); + add_data_len('I'); + add_data_len('_'); + add_data_len('H'); + add_data_len('D'); + add_data_len(' '); + + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + + add_data_len(0); /*Product revision level*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + + add_data_len(0); /*Drive serial number*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + add_data_len(0); /*Vendor unique*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + add_data_len(0); + add_data_len(0); + + add_data_len(0); /*Vendor descriptor*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + add_data_len(0); /*Reserved*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_MODE_SENSE_6: + len = cdb[4]; + + add_data_len(0); + add_data_len(0); + + add_data_len(0x08); + add_data_len(0); + + add_data_len((data->hdd.sectors >> 24) & 0xff); + add_data_len((data->hdd.sectors >> 16) & 0xff); + add_data_len((data->hdd.sectors >> 8) & 0xff); + add_data_len( data->hdd.sectors & 0xff); + add_data_len((512 >> 24) & 0xff); + add_data_len((512 >> 16) & 0xff); + add_data_len((512 >> 8) & 0xff); + add_data_len( 512 & 0xff); + + if ((cdb[2] & 0x3f) == 0x03 || (cdb[2] & 0x3f) == 0x3f) + { + add_data_len(3); + add_data_len(0x16); + add_data_len(0); add_data_len(1); /*Tracks per zone*/ + add_data_len(0); add_data_len(1); /*Alternate sectors per zone*/ + add_data_len(0); add_data_len(1); /*Alternate tracks per zone*/ + add_data_len(0); add_data_len(1); /*Alternate tracks per volume*/ + add_data_len(1); add_data_len(0); /*Sectors per track*/ + add_data_len(2); add_data_len(0); /*Data bytes per physical sector*/ + add_data_len(0); add_data_len(0); /*Interleave*/ + add_data_len(0); add_data_len(0); /*Track skew*/ + add_data_len(0); add_data_len(0); /*Cylinder skew*/ + add_data_len(0); /*Drive type*/ + add_data_len(0); add_data_len(0); add_data_len(0); + } + + if ((cdb[2] & 0x3f) == 0x04 || (cdb[2] & 0x3f) == 0x3f) + { + add_data_len(4); + add_data_len(0x16); + add_data_len(0); add_data_len(0x10); add_data_len(0); /*Cylinder count*/ + add_data_len(64); /*Heads*/ + add_data_len(0); add_data_len(0); add_data_len(0); /*Write recomp*/ + add_data_len(0); add_data_len(0); add_data_len(0); /*Reduced write current*/ + add_data_len(0); add_data_len(0); /*Drive step rate*/ + add_data_len(0); add_data_len(0); add_data_len(0); /*Landing zone cylinder*/ + add_data_len(0); /*RPL*/ + add_data_len(0); /*Rotational offset*/ + add_data_len(0); + add_data_len(0x10); add_data_len(0); /*Rotain rate*/ + add_data_len(0); add_data_len(0); + } + + if ((cdb[2] & 0x3f) == 0x30 || (cdb[2] & 0x3f) == 0x3f) + { + add_data_len(0xb0); + add_data_len(0x16); + add_data_len('P'); + add_data_len('C'); + add_data_len('E'); + add_data_len('M'); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + } + + for (; len >= 0; len--) + add_data_len(0); + +// scsi_illegal_field(); + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_READ_CAPACITY_10: + scsi_add_data((data->hdd.sectors >> 24) & 0xff, data); + scsi_add_data((data->hdd.sectors >> 16) & 0xff, data); + scsi_add_data((data->hdd.sectors >> 8) & 0xff, data); + scsi_add_data( data->hdd.sectors & 0xff, data); + scsi_add_data((512 >> 24) & 0xff, data); + scsi_add_data((512 >> 16) & 0xff, data); + scsi_add_data((512 >> 8) & 0xff, data); + scsi_add_data( 512 & 0xff, data); + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_READ_6: +// pclog("SCSI_READ_6 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + + if (data->cmd_pos == CMD_POS_IDLE) + { + readflash_set(READFLASH_HDC, data->hd_id); + data->addr = cdb[3] | (cdb[2] << 8) | ((cdb[1] & 0x1f) << 16); + data->len = cdb[4]; + if (!data->len) + data->len = 256; +// pclog("SCSI_READ_6: addr=%08x len=%04x\n", data->addr, data->len); + + data->cmd_pos = CMD_POS_WAIT; + data->callback = RW_DELAY; + data->new_cmd_pos = CMD_POS_START_SECTOR; + data->sector_pos = 0; + + bus_state = BUS_CD; + break; + } +// else +// pclog("SCSI_READ_6 continue addr=%08x len=%04x sector_pos=%02x\n", data->addr, data->len, data->sector_pos); + while (data->len) + { + if (data->cmd_pos == CMD_POS_START_SECTOR) + { + hdd_read_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + } + + data->cmd_pos = CMD_POS_TRANSFER; + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_add_data(data->buf[data->sector_pos], data); + + if (ret == -1) + { + fatal("scsi_add_data -1\n"); + break; + } + if (ret & 0x100) + { + fatal("scsi_add_data 0x100\n"); + data->len = 1; + break; + } + } + data->cmd_pos = CMD_POS_START_SECTOR; + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_READ_10: +// pclog("SCSI_READ_10 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + + if (data->cmd_pos == CMD_POS_IDLE) + { + readflash_set(READFLASH_HDC, data->hd_id); + data->addr = cdb[5] | (cdb[4] << 8) | (cdb[3] << 16) | (cdb[2] << 24); + data->len = cdb[8] | (cdb[7] << 8); +// pclog("SCSI_READ_10: addr=%08x len=%04x\n", data->addr, data->len); + + data->cmd_pos = CMD_POS_WAIT; + data->callback = RW_DELAY; + data->new_cmd_pos = CMD_POS_START_SECTOR; + data->sector_pos = 0; + + bus_state = BUS_CD; + break; + } +// else +// pclog("SCSI_READ_10 continue addr=%08x len=%04x sector_pos=%02x\n", data->addr, data->len, data->sector_pos); + while (data->len) + { + if (data->cmd_pos == CMD_POS_START_SECTOR) + { + hdd_read_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + } + data->cmd_pos = CMD_POS_TRANSFER; + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_add_data(data->buf[data->sector_pos], data); +// pclog("SCSI_READ_10 sector_pos=%i\n", data->sector_pos); + if (ret == -1) + { + fatal("scsi_add_data -1\n"); + break; + } + if (ret & 0x100) + { + fatal("scsi_add_data 0x100\n"); + data->len = 1; + break; + } + } + data->cmd_pos = CMD_POS_START_SECTOR; + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_WRITE_6: +// pclog("SCSI_WRITE_6 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + if (data->cmd_pos == CMD_POS_IDLE) + { + data->addr = cdb[3] | (cdb[2] << 8) | ((cdb[1] & 0x1f) << 16); + data->len = cdb[4]; + if (!data->len) + data->len = 256; + readflash_set(READFLASH_HDC, data->hd_id); +// pclog("SCSI_WRITE_6: addr=%08x len=%04x\n", data->addr, data->len); + data->bytes_required = data->len * 512; + + data->cmd_pos = CMD_POS_WAIT; + data->callback = RW_DELAY; + data->new_cmd_pos = CMD_POS_TRANSFER; + data->sector_pos = 0; + + bus_state = BUS_CD; + break; + } + if (data->cmd_pos == CMD_POS_TRANSFER && data->bytes_received != data->bytes_required) + { + bus_state = 0; + break; + } + + while (data->len) + { + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_get_data(data); + if (ret == -1) + { + fatal("scsi_get_data -1\n"); + break; + } + data->buf[data->sector_pos] = ret & 0xff; + if (ret & 0x100) + { + fatal("scsi_get_data 0x100\n"); + data->len = 1; + break; + } + } + + hdd_write_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_WRITE_10: +// pclog("SCSI_WRITE_10 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + if (data->cmd_pos == CMD_POS_IDLE) + { + data->addr = cdb[5] | (cdb[4] << 8) | (cdb[3] << 16) | (cdb[2] << 24); + data->len = cdb[8] | (cdb[7] << 8); + readflash_set(READFLASH_HDC, data->hd_id); +// pclog("SCSI_WRITE_10: addr=%08x len=%04x\n", data->addr, data->len); + data->bytes_required = data->len * 512; + + data->cmd_pos = CMD_POS_WAIT; + data->callback = RW_DELAY; + data->new_cmd_pos = CMD_POS_TRANSFER; + data->sector_pos = 0; + + bus_state = BUS_CD; + break; + } + if (data->cmd_pos == CMD_POS_TRANSFER && data->bytes_received != data->bytes_required) + { + bus_state = 0; + break; + } + + while (data->len) + { + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_get_data(data); +// pclog("SCSI_WRITE_10 sector_pos=%i\n", data->sector_pos); + if (ret == -1) + { + fatal("scsi_get_data -1\n"); + break; + } + data->buf[data->sector_pos] = ret & 0xff; + if (ret & 0x100) + { + fatal("scsi_get_data 0x100\n"); + data->len = 1; + break; + } + } + + hdd_write_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; +// output = 3; + break; + + case SCSI_VERIFY_10: + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_MODE_SELECT_6: + if (!data->bytes_received) + { + data->bytes_required = cdb[4]; +// pclog("SCSI_MODE_SELECT_6 bytes_required=%i\n", data->bytes_required); + bus_state = 0; + break; + } +// pclog("SCSI_MODE_SELECT_6 complete\n"); + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_FORMAT: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_START_STOP_UNIT: + bus_state = BUS_CD | BUS_IO; + break; + + /*These aren't really meaningful in a single initiator system, so just return*/ + case SCSI_RESERVE: + case SCSI_RELEASE: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_SEEK_6: + case SCSI_SEEK_10: + bus_state = BUS_CD | BUS_IO; + break; + + case SEND_DIAGNOSTIC: + if (cdb[1] & (1 << 2)) + { + /*Self-test*/ + /*Always passes*/ + bus_state = BUS_CD | BUS_IO; + } + else + { + /*Treat all other diagnostic requests as illegal*/ + scsi_hd_illegal(data); + bus_state = BUS_CD | BUS_IO; + } + break; + + default: + pclog("Bad SCSI HD command %02x\n", cdb[0]); + scsi_hd_illegal(data); + bus_state = BUS_CD | BUS_IO; + break; + } + + return bus_state; +} + +static uint8_t scsi_hd_read(void *p) +{ + scsi_hd_data *data = p; + + return data->data_in[data->data_pos_read++]; +} + +static void scsi_hd_write(uint8_t val, void *p) +{ + scsi_hd_data *data = p; + + data->data_out[data->data_pos_write++] = val; + + data->bytes_received++; + + if (data->data_pos_write > BUFFER_SIZE) + fatal("Exceeded data_out buffer size\n"); +} + +static int scsi_hd_read_complete(void *p) +{ + scsi_hd_data *data = p; + + return (data->data_pos_read == data->data_pos_write); +} +static int scsi_hd_write_complete(void *p) +{ + scsi_hd_data *data = p; + + return (data->bytes_received == data->bytes_required); +} + +static void scsi_hd_start_command(void *p) +{ + scsi_hd_data *data = p; + + data->bytes_received = 0; + data->bytes_required = 0; + data->data_pos_read = data->data_pos_write = 0; +} + +static uint8_t scsi_hd_get_status(void *p) +{ + scsi_hd_data *data = p; + + return data->status; +} + +scsi_device_t scsi_hd = +{ + scsi_hd_init, + scsi_hd_close, + + scsi_hd_start_command, + scsi_hd_command, + + scsi_hd_get_status, + + scsi_hd_read, + scsi_hd_write, + scsi_hd_read_complete, + scsi_hd_write_complete, +}; diff --git a/src/scsi_hd.h b/src/scsi_hd.h new file mode 100644 index 0000000..9f0bdf5 --- /dev/null +++ b/src/scsi_hd.h @@ -0,0 +1 @@ +extern scsi_device_t scsi_hd;