Added SCSI hard drive emulation.
Added NCR 58c400-based SCSI adapters : - Longshine LCS-6821N - Ranco RT1000B - Trantor T130B
This commit is contained in:
parent
06f7cd3c6c
commit
50a874c287
18 changed files with 2116 additions and 17 deletions
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
|||
356
src/scsi.c
Normal file
356
src/scsi.c
Normal file
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
103
src/scsi.h
Normal file
103
src/scsi.h
Normal file
|
|
@ -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)
|
||||
826
src/scsi_53c400.c
Normal file
826
src/scsi_53c400.c
Normal file
|
|
@ -0,0 +1,826 @@
|
|||
#include <stdlib.h>
|
||||
#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
|
||||
};
|
||||
3
src/scsi_53c400.h
Normal file
3
src/scsi_53c400.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
extern device_t scsi_lcs6821n_device;
|
||||
extern device_t scsi_rt1000b_device;
|
||||
extern device_t scsi_t130b_device;
|
||||
806
src/scsi_hd.c
Normal file
806
src/scsi_hd.c
Normal file
|
|
@ -0,0 +1,806 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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,
|
||||
};
|
||||
1
src/scsi_hd.h
Normal file
1
src/scsi_hd.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern scsi_device_t scsi_hd;
|
||||
Loading…
Reference in a new issue