--- previous/src/scsi.c 2018/04/24 19:29:53 1.1.1.3 +++ previous/src/scsi.c 2018/04/24 19:31:17 1.1.1.4 @@ -111,7 +111,7 @@ void SCSI_FormatDrive(Uint8 *cdb); /* Helpers */ int SCSI_GetCommandLength(Uint8 opcode); int SCSI_GetTransferLength(Uint8 opcode, Uint8 *cdb); -unsigned long SCSI_GetOffset(Uint8 opcode, Uint8 *cdb); +Uint64 SCSI_GetOffset(Uint8 opcode, Uint8 *cdb); int SCSI_GetCount(Uint8 opcode, Uint8 *cdb); void scsi_read_sector(void); @@ -122,7 +122,7 @@ void scsi_write_sector(void); struct { SCSI_DEVTYPE devtype; FILE* dsk; - Uint32 size; + Uint64 size; bool readonly; Uint8 lun; Uint8 status; @@ -137,6 +137,9 @@ struct { Uint32 lba; Uint32 blockcounter; + Uint32 lastlba; + + Uint8** shadow; } SCSIdisk[ESP_MAX_DEVS]; @@ -158,28 +161,10 @@ MODEPAGE SCSI_GetModePage(Uint8 pagecode void SCSI_Init(void) { Log_Printf(LOG_WARN, "Loading SCSI disks:\n"); - /* Check if files exist. Present dialog to re-select missing files. */ int i; for (i = 0; i < ESP_MAX_DEVS; i++) { - if (File_Exists(ConfigureParams.SCSI.target[i].szImageName) && ConfigureParams.SCSI.target[i].bDiskInserted) { - SCSIdisk[i].size = File_Length(ConfigureParams.SCSI.target[i].szImageName); - SCSIdisk[i].dsk = ConfigureParams.SCSI.target[i].bWriteProtected ? - File_Open(ConfigureParams.SCSI.target[i].szImageName, "rb") : - File_Open(ConfigureParams.SCSI.target[i].szImageName, "rb+"); - } else { - SCSIdisk[i].size = 0; - SCSIdisk[i].dsk = NULL; - } SCSIdisk[i].devtype = ConfigureParams.SCSI.target[i].nDeviceType; - SCSIdisk[i].readonly = (ConfigureParams.SCSI.target[i].nDeviceType==DEVTYPE_CD) ? - true : ConfigureParams.SCSI.target[i].bWriteProtected; - - SCSIdisk[i].lun = SCSIdisk[i].status = SCSIdisk[i].message = 0; - SCSIdisk[i].sense.code = SCSIdisk[i].sense.key = SCSIdisk[i].sense.info = 0; - SCSIdisk[i].sense.valid = false; - SCSIdisk[i].lba = SCSIdisk[i].blockcounter = 0; - - Log_Printf(LOG_WARN, "SCSI Disk%i: %s\n",i,ConfigureParams.SCSI.target[i].szImageName); + SCSI_Insert(i); } } @@ -187,8 +172,7 @@ void SCSI_Uninit(void) { int i; for (i = 0; i < ESP_MAX_DEVS; i++) { if (SCSIdisk[i].dsk) { - File_Close(SCSIdisk[i].dsk); - SCSIdisk[i].dsk = NULL; + SCSI_Eject(i); } } } @@ -198,10 +182,75 @@ void SCSI_Reset(void) { SCSI_Init(); } -void SCSI_Eject(Uint8 target) { - ConfigureParams.SCSI.target[target].bDiskInserted = false; - ConfigureParams.SCSI.target[target].szImageName[0] = '\0'; - SCSI_Reset(); +void SCSI_Eject(Uint8 i) { + File_Close(SCSIdisk[i].dsk); + SCSIdisk[i].dsk = NULL; + SCSIdisk[i].size = 0; + SCSIdisk[i].readonly = false; + SCSIdisk[i].shadow = NULL; +} + +void SCSI_EjectDisk(Uint8 i) { + ConfigureParams.SCSI.target[i].bDiskInserted = false; + ConfigureParams.SCSI.target[i].szImageName[0] = '\0'; + + SCSI_Eject(i); +} + +void SCSI_Insert(Uint8 i) { + SCSIdisk[i].lun = SCSIdisk[i].status = SCSIdisk[i].message = 0; + SCSIdisk[i].sense.code = SCSIdisk[i].sense.key = SCSIdisk[i].sense.info = 0; + SCSIdisk[i].sense.valid = false; + SCSIdisk[i].lba = SCSIdisk[i].lastlba = SCSIdisk[i].blockcounter = 0; + + SCSIdisk[i].shadow = NULL; + + Log_Printf(LOG_WARN, "SCSI Disk%i: %s\n",i,ConfigureParams.SCSI.target[i].szImageName); + + if (File_Exists(ConfigureParams.SCSI.target[i].szImageName) && + ConfigureParams.SCSI.target[i].bDiskInserted) { + if (ConfigureParams.SCSI.target[i].bWriteProtected || + ConfigureParams.SCSI.target[i].nDeviceType==DEVTYPE_CD) { + SCSIdisk[i].dsk = File_Open(ConfigureParams.SCSI.target[i].szImageName, "rb"); + if (SCSIdisk[i].dsk == NULL) { + Log_Printf(LOG_WARN, "SCSI Disk%i: Cannot open image file %s\n", + i, ConfigureParams.SCSI.target[i].szImageName); + SCSIdisk[i].size = 0; + SCSIdisk[i].readonly = false; + if (SCSIdisk[i].devtype == DEVTYPE_HARDDISK) { + SCSIdisk[i].devtype = DEVTYPE_NONE; + } + } else { + SCSIdisk[i].size = File_Length(ConfigureParams.SCSI.target[i].szImageName); + SCSIdisk[i].readonly = true; + } + } else { + SCSIdisk[i].dsk = File_Open(ConfigureParams.SCSI.target[i].szImageName, "rb+"); + if (SCSIdisk[i].dsk == NULL) { + SCSIdisk[i].dsk = File_Open(ConfigureParams.SCSI.target[i].szImageName, "rb"); + if (SCSIdisk[i].dsk == NULL) { + Log_Printf(LOG_WARN, "SCSI Disk%i: Cannot open image file %s\n", + i, ConfigureParams.SCSI.target[i].szImageName); + SCSIdisk[i].size = 0; + SCSIdisk[i].readonly = false; + if (SCSIdisk[i].devtype == DEVTYPE_HARDDISK) { + SCSIdisk[i].devtype = DEVTYPE_NONE; + } + } else { + SCSIdisk[i].size = File_Length(ConfigureParams.SCSI.target[i].szImageName); + SCSIdisk[i].readonly = true; + Log_Printf(LOG_WARN, "SCSI Disk%i: Image file is not writable. Enabling write protection.\n", i); + } + } else { + SCSIdisk[i].size = File_Length(ConfigureParams.SCSI.target[i].szImageName); + SCSIdisk[i].readonly = false; + } + } + } else { + SCSIdisk[i].size = 0; + SCSIdisk[i].dsk = NULL; + SCSIdisk[i].readonly = false; + } } @@ -387,7 +436,7 @@ int SCSI_GetTransferLength(Uint8 opcode, COMMAND_ReadInt16(cdb, 7); } -unsigned long SCSI_GetOffset(Uint8 opcode, Uint8 *cdb) +Uint64 SCSI_GetOffset(Uint8 opcode, Uint8 *cdb) { return opcode < 0x20? // class 0 @@ -406,7 +455,7 @@ int SCSI_GetCount(Uint8 opcode, Uint8 *c COMMAND_ReadInt16(cdb, 7); } -void SCSI_GuessGeometry(Uint32 size, Uint32 *cylinders, Uint32 *heads, Uint32 *sectors) +static void SCSI_GuessGeometry(Uint32 size, Uint32 *cylinders, Uint32 *heads, Uint32 *sectors) { Uint32 c,h,s; @@ -434,6 +483,78 @@ void SCSI_GuessGeometry(Uint32 size, Uin *sectors=s; } +#define SCSI_SEEK_TIME_HD 20000 /* 20 ms max seek time */ +#define SCSI_SECTOR_TIME_HD 350 /* 1.4 MB/sec */ +#define SCSI_SEEK_TIME_FD 200000 /* 200 ms max seek time */ +#define SCSI_SECTOR_TIME_FD 5500 /* 90 kB/sec */ +#define SCSI_SEEK_TIME_CD 500000 /* 500 ms max seek time */ +#define SCSI_SECTOR_TIME_CD 3250 /* 150 kB/sec */ + +Sint64 SCSI_Seek_Time(void) { + Uint8 target = SCSIbus.target; + Sint64 seektime, seekoffset, disksize; + + if (scsi_buffer.disk) { + switch (SCSIdisk[target].devtype) { + case DEVTYPE_HARDDISK: + seektime = SCSI_SEEK_TIME_HD; + break; + case DEVTYPE_CD: + seektime = SCSI_SEEK_TIME_CD; + break; + case DEVTYPE_FLOPPY: + seektime = SCSI_SEEK_TIME_FD; + break; + default: + return 0; + } + if (SCSIdisk[target].lba < SCSIdisk[target].lastlba) { + seekoffset = SCSIdisk[target].lastlba - SCSIdisk[target].lba; + } else { + seekoffset = SCSIdisk[target].lba - SCSIdisk[target].lastlba; + } + disksize = SCSIdisk[target].size/BLOCKSIZE; + + if (disksize <= 0) { /* make sure no zero divide occurs */ + return 0; + } + seektime *= seekoffset; + seektime /= disksize; + + if (seektime > 500000) { + seektime = 500000; + } + + return seektime; + } else { + return 0; + } +} + +Sint64 SCSI_Sector_Time(void) { + int target = SCSIbus.target; + Sint64 sectors = SCSIdisk[target].blockcounter; + + if (sectors <= 0) { + sectors = 1; + } + + if (scsi_buffer.disk) { + switch (SCSIdisk[target].devtype) { + case DEVTYPE_HARDDISK: + return sectors * SCSI_SECTOR_TIME_HD; + case DEVTYPE_CD: + return sectors * SCSI_SECTOR_TIME_CD; + case DEVTYPE_FLOPPY: + return sectors * SCSI_SECTOR_TIME_FD; + default: + return 1000; + } + } else { + return 100; + } +} + MODEPAGE SCSI_GetModePage(Uint8 pagecode) { Uint8 target = SCSIbus.target; @@ -542,7 +663,7 @@ void SCSI_TestUnitReady(Uint8 *cdb) { void SCSI_ReadCapacity(Uint8 *cdb) { Uint8 target = SCSIbus.target; - Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Read disk image: size = %i byte\n", SCSIdisk[target].size); + Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Read disk image: size = %llu byte\n", SCSIdisk[target].size); Uint32 sectors = (SCSIdisk[target].size / BLOCKSIZE) - 1; /* last LBA */ @@ -570,6 +691,7 @@ void SCSI_ReadCapacity(Uint8 *cdb) { void SCSI_WriteSector(Uint8 *cdb) { Uint8 target = SCSIbus.target; + SCSIdisk[target].lastlba = SCSIdisk[target].lba; SCSIdisk[target].lba = SCSI_GetOffset(cdb[0], cdb); SCSIdisk[target].blockcounter = SCSI_GetCount(cdb[0], cdb); @@ -591,26 +713,32 @@ void SCSI_WriteSector(Uint8 *cdb) { void scsi_write_sector(void) { Uint8 target = SCSIbus.target; - int n=0; - + Uint64 offset = 0; + Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Writing block at offset %i (%i blocks remaining).", SCSIdisk[target].lba,SCSIdisk[target].blockcounter-1); - /* seek to the position */ - if ((SCSIdisk[target].dsk==NULL) || (fseek(SCSIdisk[target].dsk, SCSIdisk[target].lba*BLOCKSIZE, SEEK_SET) != 0)) { - n = 0; - } else { -#if 1 - n = fwrite(scsi_buffer.data, BLOCKSIZE, 1, SCSIdisk[target].dsk); -#else - n=1; - Log_Printf(LOG_SCSI_LEVEL, "[SCSI] WARNING: File write disabled!"); -#endif + offset = ((Uint64)SCSIdisk[target].lba)*BLOCKSIZE; + + if (offset < SCSIdisk[target].size) { + if (ConfigureParams.SCSI.nWriteProtection != WRITEPROT_ON) { + File_Write(scsi_buffer.data, BLOCKSIZE, offset, SCSIdisk[target].dsk); + } else { + Log_Printf(LOG_SCSI_LEVEL, "[SCSI] WARNING: File write disabled!"); + if(SCSIdisk[target].shadow) { + if(!(SCSIdisk[target].shadow[SCSIdisk[target].lba])) + SCSIdisk[target].shadow[SCSIdisk[target].lba] = malloc(BLOCKSIZE); + memcpy(SCSIdisk[target].shadow[SCSIdisk[target].lba], scsi_buffer.data, BLOCKSIZE); + } else { + Uint32 blocks = SCSIdisk[target].size / BLOCKSIZE; + SCSIdisk[target].shadow = malloc(sizeof(Uint8*) * blocks); + for(int i = blocks; --i >= 0;) + SCSIdisk[target].shadow[i] = NULL; + } + } scsi_buffer.limit=BLOCKSIZE; scsi_buffer.size=0; - } - - if (n == 1) { + SCSIdisk[target].status = STAT_GOOD; SCSIdisk[target].sense.code = SC_NO_ERROR; SCSIdisk[target].sense.valid = false; @@ -646,6 +774,7 @@ void SCSIdisk_Receive_Data(Uint8 val) { void SCSI_ReadSector(Uint8 *cdb) { Uint8 target = SCSIbus.target; + SCSIdisk[target].lastlba = SCSIdisk[target].lba; SCSIdisk[target].lba = SCSI_GetOffset(cdb[0], cdb); SCSIdisk[target].blockcounter = SCSI_GetCount(cdb[0], cdb); scsi_buffer.disk=true; @@ -658,26 +787,26 @@ void SCSI_ReadSector(Uint8 *cdb) { void scsi_read_sector(void) { Uint8 target = SCSIbus.target; + Uint64 offset = 0; if (SCSIdisk[target].blockcounter==0) { SCSIbus.phase = PHASE_ST; return; } - int n; - Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Reading block at offset %i (%i blocks remaining).", SCSIdisk[target].lba,SCSIdisk[target].blockcounter-1); - /* seek to the position */ - if ((SCSIdisk[target].dsk==NULL) || (fseek(SCSIdisk[target].dsk, SCSIdisk[target].lba*BLOCKSIZE, SEEK_SET) != 0)) { - n = 0; - } else { - n = fread(scsi_buffer.data, BLOCKSIZE, 1, SCSIdisk[target].dsk); - scsi_buffer.limit=scsi_buffer.size=BLOCKSIZE; - } + offset = ((Uint64)SCSIdisk[target].lba)*BLOCKSIZE; - if (n == 1) { + if (offset < SCSIdisk[target].size) { + if (SCSIdisk[target].shadow && SCSIdisk[target].shadow[SCSIdisk[target].lba]) { + memcpy(scsi_buffer.data, SCSIdisk[target].shadow[SCSIdisk[target].lba], BLOCKSIZE); + } else { + File_Read(scsi_buffer.data, BLOCKSIZE, offset, SCSIdisk[target].dsk); + } + scsi_buffer.limit=scsi_buffer.size=BLOCKSIZE; + SCSIdisk[target].status = STAT_GOOD; SCSIdisk[target].sense.code = SC_NO_ERROR; SCSIdisk[target].sense.valid = false; @@ -785,7 +914,7 @@ void SCSI_StartStop(Uint8 *cdb) { case 2: Log_Printf(LOG_WARN, "[SCSI] Eject disk %i", target); if (SCSIdisk[target].devtype!=DEVTYPE_HARDDISK) { - SCSI_Eject(target); + SCSI_EjectDisk(target); Statusbar_AddMessage("Ejecting SCSI media.", 0); } break;