From: Toni Wilen Date: Sat, 10 Feb 2018 18:05:24 +0000 (+0200) Subject: Improved IDE CHS-only drive support. X-Git-Tag: 4000~195 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=656bb2b07369b9390596e03d77e57488f13efa1b;p=francis%2Fwinuae.git Improved IDE CHS-only drive support. --- diff --git a/cfgfile.cpp b/cfgfile.cpp index d3f0a219..bd350f8b 100644 --- a/cfgfile.cpp +++ b/cfgfile.cpp @@ -4359,14 +4359,14 @@ static bool parse_geo (const TCHAR *tname, struct uaedev_config_info *uci, struc ret = true; } - void ata_parse_identity(uae_u8 *out, struct uaedev_config_info *uci, bool *lba48, int *max_multiple); + void ata_parse_identity(uae_u8 *out, struct uaedev_config_info *uci, bool *lba, bool *lba48, int *max_multiple); bool ata_get_identity(struct ini_data *ini, uae_u8 *out, bool overwrite); uae_u8 ident[512]; if (ata_get_identity(ini, ident, true)) { - bool lba48; + bool lba, lba48; int max_multiple; - ata_parse_identity(ident, uci, &lba48, &max_multiple); + ata_parse_identity(ident, uci, &lba, &lba48, &max_multiple); ret = true; } diff --git a/ide.cpp b/ide.cpp index 330094d4..ef255676 100644 --- a/ide.cpp +++ b/ide.cpp @@ -48,16 +48,17 @@ #define ATAPI_MAX_TRANSFER 32768 -void ata_parse_identity(uae_u8 *out, struct uaedev_config_info *uci, bool *lba48, int *max_multiple) +void ata_parse_identity(uae_u8 *out, struct uaedev_config_info *uci, bool *lba, bool *lba48, int *max_multiple) { - *lba48 = false; - *max_multiple = 0; struct uaedev_config_info uci2; - uae_u16 v; memcpy(&uci2, uci, sizeof(struct uaedev_config_info)); + *lba = false; + *lba48 = false; + *max_multiple = 0; + uci->blocksize = 512; uci->pcyls = (out[1 * 2 + 0] << 8) | (out[1 * 2 + 1] << 0); @@ -70,9 +71,9 @@ void ata_parse_identity(uae_u8 *out, struct uaedev_config_info *uci, bool *lba48 uci->psecs = uci2.psecs; } - v = (out[59 * 2 + 0] << 8) | (out[59 * 2 + 1] << 0); - if (v & 1) { // multiple mode? - *max_multiple = ((out[47 * 2 + 0] << 8) | (out[47 * 2 + 1] << 0)) & 0xff; + v = (out[47 * 2 + 0] << 8) | (out[47 * 2 + 1] << 0); + if (v & 255) { // multiple mode? + *max_multiple = v & 255; } v = (out[53 * 2 + 0] << 8) | (out[53 * 2 + 1] << 0); @@ -85,9 +86,10 @@ void ata_parse_identity(uae_u8 *out, struct uaedev_config_info *uci, bool *lba48 v = (out[49 * 2 + 0] << 8) | (out[49 * 2 + 1] << 0); if (v & (1 << 9)) { // LBA supported? uci->max_lba = (out[60 * 2 + 0] << 24) | (out[60 * 2 + 1] << 16) | (out[61 * 2 + 0] << 8) | (out[61 * 2 + 1] << 0); + *lba = true; } v = (out[83 * 2 + 0] << 8) | (out[83 * 2 + 1] << 0); - if ((v & 0xc000) == 0x4000 && (v & (1 << 10))) { // LBA48 supported? + if ((v & 0xc000) == 0x4000 && (v & (1 << 10)) && (*lba)) { // LBA48 supported? *lba48 = true; uci->max_lba = (out[100 * 2 + 0] << 24) | (out[100 * 2 + 1] << 16) | (out[101 * 2 + 0] << 8) | (out[101 * 2 + 1] << 0); uci->max_lba <<= 32; @@ -465,72 +467,74 @@ static void ide_identity_buffer(struct ide_hdf *ide) } else if (ide->hdhfd.hfd.ci.loadidentity && (ide->hdhfd.hfd.identity[0] || ide->hdhfd.hfd.identity[1])) { memcpy(ide->secbuf, ide->hdhfd.hfd.identity, 512); - if (ide->byteswap) { + if (!ide->byteswap) { ata_byteswapidentity(ide->secbuf); } real = true; } else { - pw (ide, 0, atapi ? 0x85c0 : (cf ? 0x848a : (1 << 6))); - pw (ide, 1, ide->hdhfd.cyls_def); - pw (ide, 2, 0xc837); - pw (ide, 3, ide->hdhfd.heads_def); - pw (ide, 4, ide->blocksize * ide->hdhfd.secspertrack_def); - pw (ide, 5, ide->blocksize); - pw (ide, 6, ide->hdhfd.secspertrack_def); - ps (ide, 10, _T("68000"), 20); /* serial */ - pw (ide, 20, 3); - pw (ide, 21, ide->blocksize); - pw (ide, 22, 4); - ps (ide, 23, _T("0.7"), 8); /* firmware revision */ + pw(ide, 0, atapi ? 0x85c0 : (cf ? 0x848a : (1 << 6))); + pw(ide, 1, ide->hdhfd.cyls_def); + pw(ide, 2, 0xc837); + pw(ide, 3, ide->hdhfd.heads_def); + pw(ide, 4, ide->blocksize * ide->hdhfd.secspertrack_def); + pw(ide, 5, ide->blocksize); + pw(ide, 6, ide->hdhfd.secspertrack_def); + ps(ide, 10, _T("68000"), 20); /* serial */ + pw(ide, 20, 3); + pw(ide, 21, ide->blocksize); + pw(ide, 22, 4); + ps(ide, 23, _T("0.7"), 8); /* firmware revision */ if (ide->atapi) _tcscpy (tmp, _T("UAE-ATAPI")); else _stprintf (tmp, _T("UAE-IDE %s"), ide->hdhfd.hfd.product_id); - ps (ide, 27, tmp, 40); /* model */ - pw (ide, 47, ide->max_multiple_mode >> (ide->blocksize / 512 - 1)); /* max sectors in multiple mode */ - pw (ide, 48, 1); - pw (ide, 49, (1 << 9) | (1 << 8)); /* LBA and DMA supported */ - pw (ide, 51, 0x200); /* PIO cycles */ - pw (ide, 52, 0x200); /* DMA cycles */ - pw (ide, 53, 1 | 2 | 4); - pw (ide, 54, ide->hdhfd.cyls); - pw (ide, 55, ide->hdhfd.heads); - pw (ide, 56, ide->hdhfd.secspertrack); + ps(ide, 27, tmp, 40); /* model */ + pw(ide, 47, ide->max_multiple_mode ? (0x8000 | (ide->max_multiple_mode >> (ide->blocksize / 512 - 1))) : 0); /* max sectors in multiple mode */ + pw(ide, 48, 1); + pw(ide, 49, (ide->lba ? (1 << 9) : 0) | (1 << 8)); /* LBA and DMA supported */ + pw(ide, 51, 0x200); /* PIO cycles */ + pw(ide, 52, 0x200); /* DMA cycles */ + pw(ide, 53, 1 | (ide->lba ? 2 | 4 : 0)); // b0 = 54-58 valid b1 = 64-70 valid b2 = 88 valid + pw(ide, 54, ide->hdhfd.cyls); + pw(ide, 55, ide->hdhfd.heads); + pw(ide, 56, ide->hdhfd.secspertrack); uae_u64 totalsecs = ide->hdhfd.cyls * ide->hdhfd.heads * ide->hdhfd.secspertrack; - pw (ide, 57, (uae_u16)totalsecs); - pw (ide, 58, (uae_u16)(totalsecs >> 16)); - pw (ide, 59, 1); /* Multiple mode supported */ - totalsecs = ide->blocksize ? ide->hdhfd.size / ide->blocksize : 0; - if (totalsecs > 0x0fffffff) - totalsecs = 0x0fffffff; - pw (ide, 60, (uae_u16)totalsecs); - pw (ide, 61, (uae_u16)(totalsecs >> 16)); - pw (ide, 62, 0x0f); - pw (ide, 63, 0x0f); - if (ide->ata_level) { - pw (ide, 64, ide->ata_level ? 0x03 : 0x00); /* PIO3 and PIO4 */ - pw (ide, 65, 120); /* MDMA2 supported */ - pw (ide, 66, 120); - pw (ide, 67, 120); - pw (ide, 68, 120); - pw (ide, 80, (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6)); /* ATA-1 to ATA-6 */ - pw (ide, 81, 0x1c); /* ATA revision */ - pw (ide, 82, (1 << 14) | (atapi ? 0x10 | 4 : 0)); /* NOP, ATAPI: PACKET and Removable media features supported */ - pw (ide, 83, (1 << 14) | (1 << 13) | (1 << 12) | (ide->lba48 ? (1 << 10) : 0)); /* cache flushes, LBA 48 supported */ - pw (ide, 84, 1 << 14); - pw (ide, 85, 1 << 14); - pw (ide, 86, (1 << 14) | (1 << 13) | (1 << 12) | (ide->lba48 ? (1 << 10) : 0)); /* cache flushes, LBA 48 enabled */ - pw (ide, 87, 1 << 14); - pw (ide, 88, (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); /* UDMA modes */ - pw (ide, 93, (1 << 14) | (1 << 13) | (1 << 0)); - if (ide->lba48) { - totalsecs = ide->hdhfd.size / ide->blocksize; - pw (ide, 100, (uae_u16)(totalsecs >> 0)); - pw (ide, 101, (uae_u16)(totalsecs >> 16)); - pw (ide, 102, (uae_u16)(totalsecs >> 32)); - pw (ide, 103, (uae_u16)(totalsecs >> 48)); + pw(ide, 57, (uae_u16)totalsecs); + pw(ide, 58, (uae_u16)(totalsecs >> 16)); + pw(ide, 59, ide->max_multiple_mode ? (0x100 | ide->max_multiple_mode >> (ide->blocksize / 512 - 1)) : 0); /* Multiple mode supported */ + pw(ide, 62, 0x0f); + pw(ide, 63, 0x0f); + if (ide->lba) { + totalsecs = ide->blocksize ? ide->hdhfd.size / ide->blocksize : 0; + if (totalsecs > 0x0fffffff) + totalsecs = 0x0fffffff; + pw(ide, 60, (uae_u16)totalsecs); + pw(ide, 61, (uae_u16)(totalsecs >> 16)); + if (ide->ata_level) { + pw(ide, 64, ide->ata_level ? 0x03 : 0x00); /* PIO3 and PIO4 */ + pw(ide, 65, 120); /* MDMA2 supported */ + pw(ide, 66, 120); + pw(ide, 67, 120); + pw(ide, 68, 120); + pw(ide, 80, (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6)); /* ATA-1 to ATA-6 */ + pw(ide, 81, 0x1c); /* ATA revision */ + pw(ide, 82, (1 << 14) | (atapi ? 0x10 | 4 : 0)); /* NOP, ATAPI: PACKET and Removable media features supported */ + pw(ide, 83, (1 << 14) | (1 << 13) | (1 << 12) | (ide->lba48 ? (1 << 10) : 0)); /* cache flushes, LBA 48 supported */ + pw(ide, 84, 1 << 14); + pw(ide, 85, 1 << 14); + pw(ide, 86, (1 << 14) | (1 << 13) | (1 << 12) | (ide->lba48 ? (1 << 10) : 0)); /* cache flushes, LBA 48 enabled */ + pw(ide, 87, 1 << 14); + pw(ide, 88, (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); /* UDMA modes */ + pw(ide, 93, (1 << 14) | (1 << 13) | (1 << 0)); + if (ide->lba48) { + totalsecs = ide->hdhfd.size / ide->blocksize; + pw(ide, 100, (uae_u16)(totalsecs >> 0)); + pw(ide, 101, (uae_u16)(totalsecs >> 16)); + pw(ide, 102, (uae_u16)(totalsecs >> 32)); + pw(ide, 103, (uae_u16)(totalsecs >> 48)); + } } } ata_get_identity(ide->hdhfd.hfd.geometry, ide->secbuf, false); @@ -682,7 +686,7 @@ static void get_lbachs (struct ide_hdf *ide, uae_u64 *lbap, unsigned int *cyl, u lba |= ((ide->regs.ide_hcyl2 << 16) | (ide->regs.ide_lcyl2 << 8) | ide->regs.ide_sector2) << 24; *lbap = lba; } else { - if (ide->regs.ide_select & 0x40) { + if ((ide->regs.ide_select & 0x40) && ide->lba) { *lbap = ((ide->regs.ide_select & 15) << 24) | (ide->regs.ide_hcyl << 16) | (ide->regs.ide_lcyl << 8) | ide->regs.ide_sector; } else { *cyl = (ide->regs.ide_hcyl << 8) | ide->regs.ide_lcyl; @@ -727,7 +731,7 @@ static void put_lbachs (struct ide_hdf *ide, uae_u64 lba, unsigned int cyl, unsi ide->regs.ide_lcyl2 = (lba >> 8) & 0xff; ide->regs.ide_sector2 = lba & 0xff; } else { - if (ide->regs.ide_select & 0x40) { + if ((ide->regs.ide_select & 0x40) && ide->lba) { lba += inc; ide->regs.ide_select &= ~15; ide->regs.ide_select |= (lba >> 24) & 15; @@ -1645,6 +1649,7 @@ struct ide_hdf *add_ide_unit (struct ide_hdf **idetable, int max, int ch, struct ide->blocksize = ide->hdhfd.hfd.ci.blocksize; ide->max_lba = ide->hdhfd.size / ide->blocksize; ide->lba48 = (ide->hdhfd.hfd.ci.unit_special_flags & 1) || ide->hdhfd.size >= 128 * (uae_u64)0x40000000 ? 1 : 0; + ide->lba = true; gui_flicker_led (LED_HD, ch, -1); ide->cd_unit_num = -1; ide->media_type = ci->controller_media_type; @@ -1656,7 +1661,7 @@ struct ide_hdf *add_ide_unit (struct ide_hdf **idetable, int max, int ch, struct if (!ide->byteswap) ata_byteswapidentity(ide->secbuf); struct uaedev_config_info ci = { 0 }; - ata_parse_identity(ide->secbuf, &ci, &ide->lba48, &ide->max_multiple_mode); + ata_parse_identity(ide->secbuf, &ci, &ide->lba, &ide->lba48, &ide->max_multiple_mode); ide->hdhfd.cyls = ide->hdhfd.cyls_def = ci.pcyls; ide->hdhfd.heads = ide->hdhfd.heads_def = ci.pheads; ide->hdhfd.secspertrack = ide->hdhfd.secspertrack_def = ci.psecs; diff --git a/include/ide.h b/include/ide.h index 0413d2fd..7d03876e 100644 --- a/include/ide.h +++ b/include/ide.h @@ -81,6 +81,7 @@ struct ide_hdf int data_multi; int direction; // 0 = read, 1 = write bool intdrq; + bool lba; bool lba48; bool lba48cmd; uae_u64 start_lba; diff --git a/include/options.h b/include/options.h index f8974723..3f23c71d 100644 --- a/include/options.h +++ b/include/options.h @@ -202,6 +202,7 @@ struct uaedev_config_info { int sectors; int reserved; int blocksize; + bool chs; uae_u64 max_lba; int controller_type; int controller_type_unit; diff --git a/od-win32/hardfile_win32.cpp b/od-win32/hardfile_win32.cpp index d96a305a..0ba28276 100644 --- a/od-win32/hardfile_win32.cpp +++ b/od-win32/hardfile_win32.cpp @@ -73,9 +73,10 @@ struct uae_driveinfo { }; -#define HDF_HANDLE_WIN32 1 -#define HDF_HANDLE_ZFILE 2 -#define HDF_HANDLE_UNKNOWN 3 +#define HDF_HANDLE_WIN32_NORMAL 1 +#define HDF_HANDLE_WIN32_CHS 2 +#define HDF_HANDLE_ZFILE 3 +#define HDF_HANDLE_UNKNOWN 4 #define CACHE_SIZE 16384 #define CACHE_FLUSH_TIME 5 @@ -263,46 +264,97 @@ static int ismounted (const TCHAR *name, HANDLE hd) return mounted; } +static void tochs(uae_u8 *data, uae_s64 offset, int *cp, int *hp, int *sp) +{ + int c, h, s; + c = (data[1 * 2 + 0] << 8) | (data[1 * 2 + 1] << 0); + h = (data[3 * 2 + 0] << 8) | (data[3 * 2 + 1] << 0); + s = (data[6 * 2 + 0] << 8) | (data[6 * 2 + 1] << 0); + if (offset >= 0) { + offset /= 512; + c = offset / (h * s); + offset -= c * h * s; + h = offset / s; + offset -= h * s; + s = offset + 1; + } + *cp = c; + *hp = h; + *sp = s; +} + +static bool ischs(uae_u8 *identity) +{ + if (!identity[0] && !identity[1]) + return false; + uae_u8 *d = identity; + // C/H/S = zeros? + if ((!d[2] && !d[3]) || (!d[6] && !d[7]) || (!d[12] && !d[13])) + return false; + // LBA = zero? + if (d[60 * 2 + 0] || d[60 * 2 + 1] || d[61 * 2 + 0] || d[61 * 2 + 1]) + return false; + uae_u16 v = (d[49 * 2 + 0] << 8) | (d[49 * 2 + 1] << 0); + if (!(v & (1 << 9))) { // LBA not supported? + return true; + } + return false; +} + #define CA "Commodore\0Amiga\0" -static int safetycheck (HANDLE h, const TCHAR *name, uae_u64 offset, uae_u8 *buf, int blocksize) +static bool do_scsi_read10_chs(HANDLE handle, uae_u32 lba, int c, int h, int s, uae_u8 *data, int cnt, bool log); +static int safetycheck (HANDLE h, const TCHAR *name, uae_u64 offset, uae_u8 *buf, int blocksize, uae_u8 *identity) { uae_u64 origoffset = offset; int i, j, blocks = 63, empty = 1; DWORD outlen; for (j = 0; j < blocks; j++) { - LARGE_INTEGER fppos; - fppos.QuadPart = offset; - if (SetFilePointer (h, fppos.LowPart, &fppos.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { - write_log (_T("hd ignored, SetFilePointer failed, error %d\n"), GetLastError ()); - return 1; - } - memset (buf, 0xaa, blocksize); - ReadFile (h, buf, blocksize, &outlen, NULL); - if (outlen != blocksize) { - write_log (_T("hd ignored, read error %d!\n"), GetLastError ()); - return 2; + memset(buf, 0xaa, blocksize); + + if (ischs(identity)) { + int cc, hh, ss; + tochs(identity, j * 512, &cc, &hh, &ss); + if (!do_scsi_read10_chs(h, -1, cc, hh, ss, buf, 1, false)) { + write_log(_T("hd ignored, do_scsi_read10_chs failed\n")); + return 1; + } + + } else { + + LARGE_INTEGER fppos; + fppos.QuadPart = offset; + if (SetFilePointer(h, fppos.LowPart, &fppos.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { + write_log(_T("hd ignored, SetFilePointer failed, error %d\n"), GetLastError()); + return 1; + } + ReadFile(h, buf, blocksize, &outlen, NULL); + if (outlen != blocksize) { + write_log(_T("hd ignored, read error %d!\n"), GetLastError()); + return 2; + } } + if (j == 0 && offset > 0) return -5; if (j == 0 && buf[0] == 0x39 && buf[1] == 0x10 && buf[2] == 0xd3 && buf[3] == 0x12) { // ADIDE "CPRM" hidden block.. if (do_rdbdump) - rdbdump (h, offset, buf, blocksize); - write_log (_T("hd accepted (adide rdb detected at block %d)\n"), j); + rdbdump(h, offset, buf, blocksize); + write_log(_T("hd accepted (adide rdb detected at block %d)\n"), j); return -3; } - if (!memcmp (buf, "RDSK", 4) || !memcmp (buf, "DRKS", 4)) { + if (!memcmp(buf, "RDSK", 4) || !memcmp(buf, "DRKS", 4)) { if (do_rdbdump) - rdbdump (h, offset, buf, blocksize); - write_log (_T("hd accepted (rdb detected at block %d)\n"), j); + rdbdump(h, offset, buf, blocksize); + write_log(_T("hd accepted (rdb detected at block %d)\n"), j); return -1; } - if (!memcmp (buf + 2, "CIS@", 4) && !memcmp (buf + 16, CA, strlen (CA))) { + if (!memcmp(buf + 2, "CIS@", 4) && !memcmp(buf + 16, CA, strlen(CA))) { if (do_rdbdump) - rdbdump (h, offset, NULL, blocksize); - write_log (_T("hd accepted (PCMCIA RAM)\n")); + rdbdump(h, offset, NULL, blocksize); + write_log(_T("hd accepted (PCMCIA RAM)\n")); return -2; } if (j == 0) { @@ -417,7 +469,8 @@ typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER { UCHAR SenseBuf[32]; } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; -static int do_scsi_in(HANDLE h, const uae_u8 *cdb, int cdblen, uae_u8 *in, int insize) + +static int do_scsi_in(HANDLE h, const uae_u8 *cdb, int cdblen, uae_u8 *in, int insize, bool fast) { SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb; DWORD status, returned; @@ -428,7 +481,7 @@ static int do_scsi_in(HANDLE h, const uae_u8 *cdb, int cdblen, uae_u8 *in, int i swb.spt.DataIn = insize > 0 ? SCSI_IOCTL_DATA_IN : 0; swb.spt.DataTransferLength = insize; swb.spt.DataBuffer = in; - swb.spt.TimeOutValue = 10; + swb.spt.TimeOutValue = fast ? 2 : 10 * 60; swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf); swb.spt.SenseInfoLength = 32; memcpy(swb.spt.Cdb, cdb, cdblen); @@ -736,7 +789,7 @@ static bool hd_meta_hack_jmicron(HANDLE h, uae_u8 *data, uae_u8 *inq) cmd[6] = 0x72; cmd[7] = 0x0f; cmd[11] = 0xfd; - if (do_scsi_in(h, cmd, 12, data + 32, 1) < 0) { + if (do_scsi_in(h, cmd, 12, data + 32, 1, true) < 0) { memset(data, 0, 512); return false; } @@ -772,7 +825,7 @@ static bool hd_meta_hack_jmicron(HANDLE h, uae_u8 *data, uae_u8 *inq) cmd[3] = 512 >> 8; cmd[10] = 0xa0 | ((data[32] & 0x40) ? 0x10 : 0x00); cmd[11] = ID_CMD; - if (do_scsi_in(h, cmd, 12, data, 512) < 0) { + if (do_scsi_in(h, cmd, 12, data, 512, true) < 0) { memset(data, 0, 512); return false; } @@ -788,7 +841,7 @@ static bool hd_get_meta_hack_realtek(HWND hDlg, HANDLE h, uae_u8 *data, uae_u8 * memset(data, 0, 512); memcpy(cmd, realtek_read, sizeof(realtek_read)); - if (do_scsi_in(h, cmd, 6, data, 512) < 0) { + if (do_scsi_in(h, cmd, 6, data, 512, true) < 0) { memset(data, 0, 512); return false; } @@ -797,7 +850,7 @@ static bool hd_get_meta_hack_realtek(HWND hDlg, HANDLE h, uae_u8 *data, uae_u8 * memset(cmd, 0, 6); // TEST UNIT READY TCHAR *infotxt; - if (do_scsi_in(h, cmd, 6, data, 0) < 0) { + if (do_scsi_in(h, cmd, 6, data, 0, true) < 0) { state = 1; infotxt = _T("Realtek hack, insert card."); } else { @@ -830,7 +883,7 @@ static bool hd_get_meta_hack_realtek(HWND hDlg, HANDLE h, uae_u8 *data, uae_u8 * tcnt++; if (tcnt >= 10) { memset(cmd, 0, 6); - if (do_scsi_in(h, cmd, 6, data, 0) >= 0) { + if (do_scsi_in(h, cmd, 6, data, 0, true) >= 0) { if (state != 0) { break; } @@ -855,7 +908,7 @@ static bool hd_get_meta_hack_realtek(HWND hDlg, HANDLE h, uae_u8 *data, uae_u8 * memset(data, 0, 512); memcpy(cmd, realtek_read, sizeof(realtek_read)); - if (do_scsi_in(h, cmd, 6, data, 512) > 0) + if (do_scsi_in(h, cmd, 6, data, 512, true) > 0) return true; return false; @@ -872,13 +925,15 @@ static bool hd_get_meta_hack(HWND hDlg, HANDLE h, uae_u8 *data, uae_u8 *inq, str if (!hDlg) return false; memcpy(cmd, realtek_inquiry_0x83, sizeof(realtek_inquiry_0x83)); - if (do_scsi_in(h, cmd, 6, data, 0xf0) >= 0 && !memcmp(data + 20, "realtek\0", 8)) { + if (do_scsi_in(h, cmd, 6, data, 0xf0, true) >= 0 && !memcmp(data + 20, "realtek\0", 8)) { return hd_get_meta_hack_realtek(hDlg, h, data, inq); } memset(data, 0, 512); return false; } +void ata_byteswapidentity(uae_u8 *d); + static bool readidentity(HANDLE h, struct uae_driveinfo *udi, struct hardfiledata *hfd) { uae_u8 cmd[16]; @@ -920,7 +975,7 @@ static bool readidentity(HANDLE h, struct uae_driveinfo *udi, struct hardfiledat cmd[2] = 0x08 | 0x04 | 0x02; // dir = from device, 512 byte block, sector count = block cnt cmd[6] = 1; // block count cmd[14] = 0xa1; // identity packet device - if (do_scsi_in(h, cmd, 16, data, 512) > 0) { + if (do_scsi_in(h, cmd, 16, data, 512, true) > 0) { ret = true; } else { write_log(_T("SAT: ATA PASSTHROUGH(16) failed\n")); @@ -935,7 +990,7 @@ static bool readidentity(HANDLE h, struct uae_driveinfo *udi, struct hardfiledat cmd[2] = 0x08 | 0x04 | 0x02; // dir = from device, 512 byte block, sector count = block cnt cmd[4] = 1; // block count cmd[9] = 0xec; // identity - if (do_scsi_in(h, cmd, 12, data, 512) > 0) { + if (do_scsi_in(h, cmd, 12, data, 512, true) > 0) { ret = true; } else { write_log(_T("SAT: ATA PASSTHROUGH(12) failed\n")); @@ -952,6 +1007,7 @@ static bool readidentity(HANDLE h, struct uae_driveinfo *udi, struct hardfiledat } if (ret) { + ata_byteswapidentity(data); memcpy(udi->identity, data, 512); if (hfd) memcpy(hfd->identity, data, 512); @@ -995,7 +1051,7 @@ static bool do_scsi_read10_chs(HANDLE handle, uae_u32 lba, int c, int h, int s, cmd[5] = s; } cmd[8] = cnt; - bool r = do_scsi_in(handle, cmd, 10, data, 512 * cnt) > 0; + bool r = do_scsi_in(handle, cmd, 10, data, 512 * cnt, false) > 0; if (r && log) { int s = 32; int o = 0; @@ -1025,7 +1081,7 @@ static bool hd_get_meta_satl(HWND hDlg, HANDLE h, uae_u8 *data, TCHAR *text, str memset(cmd, 0, sizeof(cmd)); cmd[0] = 0x12; // inquiry cmd[4] = INQUIRY_LEN; - if (do_scsi_in(h, cmd, 6, data, INQUIRY_LEN) < 0) { + if (do_scsi_in(h, cmd, 6, data, INQUIRY_LEN, true) < 0) { write_log(_T("SAT: INQUIRY failed\n")); return false; } @@ -1050,7 +1106,7 @@ static bool hd_get_meta_satl(HWND hDlg, HANDLE h, uae_u8 *data, TCHAR *text, str memset(data, 0, 512); memset(cmd, 0, sizeof(cmd)); cmd[0] = 0x25; - if (do_scsi_in(h, cmd, 10, data, 8) >= 8) { + if (do_scsi_in(h, cmd, 10, data, 8, true) >= 8) { _tcscat (text, _T("READ CAPACITY:\r\n")); bintotextline(text, data, 8); _tcscat (text, _T("\r\n")); @@ -1063,7 +1119,7 @@ static bool hd_get_meta_satl(HWND hDlg, HANDLE h, uae_u8 *data, TCHAR *text, str cmd[0] = 0x12; // inquiry cmd[1] = 1; cmd[4] = INQUIRY_LEN; - if (do_scsi_in(h, cmd, 6, data, INQUIRY_LEN) > 0) { + if (do_scsi_in(h, cmd, 6, data, INQUIRY_LEN, true) > 0) { uae_u8 evpd[256]; int cnt = 0; uae_u8 pl = data[3]; @@ -1087,7 +1143,7 @@ static bool hd_get_meta_satl(HWND hDlg, HANDLE h, uae_u8 *data, TCHAR *text, str for (int i = 0; i < cnt; i++) { cmd[2] = evpd[i]; memset(data, 0, 512); - if (do_scsi_in(h, cmd, 6, data, INQUIRY_LEN) > 0) { + if (do_scsi_in(h, cmd, 6, data, INQUIRY_LEN, true) > 0) { TCHAR tmp[256]; _stprintf(tmp, _T("INQUIRY %02X:\r\n"), evpd[i]); _tcscat (text, tmp); @@ -1114,7 +1170,7 @@ static bool hd_get_meta_satl(HWND hDlg, HANDLE h, uae_u8 *data, TCHAR *text, str cmd[2] = 0x80 | 0x3f; cmd[7] = 0xff; cmd[8] = 0; - len = do_scsi_in(h, cmd, 10, data, 0xff00); + len = do_scsi_in(h, cmd, 10, data, 0xff00, true); if (len > 0) { TCHAR tmp[4000]; int l = (data[0] << 8) | data[1]; @@ -1170,7 +1226,7 @@ static bool hd_get_meta_satl(HWND hDlg, HANDLE h, uae_u8 *data, TCHAR *text, str cmd[2] = 0x08 | 0x04 | 0x02; // dir = from device, 512 byte block, sector count = block cnt cmd[6] = 1; // block count cmd[14] = 0xa1; // identity packet device - if (do_scsi_in(h, cmd, 16, data, 512) > 0) { + if (do_scsi_in(h, cmd, 16, data, 512, true) > 0) { ret = true; *atapi = true; } else { @@ -1186,7 +1242,7 @@ static bool hd_get_meta_satl(HWND hDlg, HANDLE h, uae_u8 *data, TCHAR *text, str cmd[2] = 0x08 | 0x04 | 0x02; // dir = from device, 512 byte block, sector count = block cnt cmd[4] = 1; // block count cmd[9] = 0xec; // identity - if (do_scsi_in(h, cmd, 12, data, 512) > 0) { + if (do_scsi_in(h, cmd, 12, data, 512, true) > 0) { ret = true; } else { write_log(_T("SAT: ATA PASSTHROUGH(12) failed\n")); @@ -1249,7 +1305,7 @@ static int gethdfchs(HWND hDlg, struct uae_driveinfo *udi, HANDLE h, int *cylsp, memset(data, 0, 512); memset(cmd, 0, sizeof(cmd)); cmd[0] = 0x25; - if (do_scsi_in(h, cmd, 10, data, 8) == 8) { + if (do_scsi_in(h, cmd, 10, data, 8, true) == 8) { #if 1 if (data[0] != 0xff || data[1] != 0xff || data[2] != 0xff || data[3] != 0xff) { err = -11; @@ -1635,6 +1691,17 @@ static bool getdeviceinfo (HANDLE hDevice, struct uae_driveinfo *udi) } else { write_log (_T("IOCTL_DISK_GET_LENGTH_INFO returned size: %I64d (0x%I64x)\n"), gli.Length.QuadPart, gli.Length.QuadPart); } + + if (ischs(udi->identity)) { + int c, h, s; + tochs(udi->identity, -1, &c, &h, &s); + gli.Length.QuadPart = udi->size = c * h * s * 512; + udi->cylinders = c; + udi->heads = h; + udi->sectors = s; + geom_ok = true; + } + if (geom_ok == 0 && gli_ok == 0) { write_log (_T("Can't detect size of device\n")); return false; @@ -1849,10 +1916,12 @@ int hdf_open_target (struct hardfiledata *hfd, const TCHAR *pname) } readidentity(INVALID_HANDLE_VALUE, udi, hfd); + bool chs = ischs(udi->identity); + flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS; h = CreateFile (udi->device_path, - GENERIC_READ | (hfd->ci.readonly ? 0 : GENERIC_WRITE), - FILE_SHARE_READ | (hfd->ci.readonly ? 0 : FILE_SHARE_WRITE), + GENERIC_READ | (hfd->ci.readonly && !chs ? 0 : GENERIC_WRITE), + FILE_SHARE_READ | (hfd->ci.readonly && !chs ? 0 : FILE_SHARE_WRITE), NULL, OPEN_EXISTING, flags, NULL); hfd->handle->h = h; if (h == INVALID_HANDLE_VALUE && !hfd->ci.readonly) { @@ -1885,7 +1954,7 @@ int hdf_open_target (struct hardfiledata *hfd, const TCHAR *pname) if (udi->partitiondrive) hfd->flags |= HFD_FLAGS_REALDRIVEPARTITION; if (hfd->offset == 0 && !hfd->drive_empty) { - int sf = safetycheck (hfd->handle->h, udi->device_path, 0, hfd->cache, hfd->ci.blocksize); + int sf = safetycheck (hfd->handle->h, udi->device_path, 0, hfd->cache, hfd->ci.blocksize, hfd->identity); if (sf > 0) goto end; if (sf == 0 && !hfd->ci.readonly && harddrive_dangerous != 0x1234dead) { @@ -1922,7 +1991,16 @@ int hdf_open_target (struct hardfiledata *hfd, const TCHAR *pname) lock_drive(hfd, name, h); - hfd->handle_valid = HDF_HANDLE_WIN32; + hfd->handle_valid = HDF_HANDLE_WIN32_NORMAL; + + if (ischs(hfd->identity)) { + hfd->handle_valid = HDF_HANDLE_WIN32_CHS; + hfd->ci.chs = true; + tochs(hfd->identity, -1, &hfd->ci.pcyls, &hfd->ci.pheads, &hfd->ci.psecs); + } else { + hfd->ci.chs = false; + } + hfd->emptyname = my_strdup (name); //getstorageproperty_ataidentity(h); @@ -1985,7 +2063,7 @@ emptyreal: write_log (_T("HDF '%s' is too small\n"), name); goto end; } - hfd->handle_valid = HDF_HANDLE_WIN32; + hfd->handle_valid = HDF_HANDLE_WIN32_NORMAL; if (hfd->physsize < 64 * 1024 * 1024 && zmode) { write_log (_T("HDF '%s' re-opened in zfile-mode\n"), name); CloseHandle (h); @@ -2066,12 +2144,12 @@ int hdf_dup_target (struct hardfiledata *dhfd, const struct hardfiledata *shfd) if (!shfd->handle_valid) return 0; freehandle (dhfd->handle); - if (shfd->handle_valid == HDF_HANDLE_WIN32) { + if (shfd->handle_valid == HDF_HANDLE_WIN32_NORMAL || shfd->handle_valid == HDF_HANDLE_WIN32_CHS) { HANDLE duphandle; if (!DuplicateHandle (GetCurrentProcess (), shfd->handle->h, GetCurrentProcess () , &duphandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) return 0; dhfd->handle->h = duphandle; - dhfd->handle_valid = HDF_HANDLE_WIN32; + dhfd->handle_valid = shfd->handle_valid; } else if (shfd->handle_valid == HDF_HANDLE_ZFILE) { struct zfile *zf; zf = zfile_dup (shfd->handle->zf); @@ -2110,10 +2188,10 @@ static int hdf_seek (struct hardfiledata *hfd, uae_u64 offset) abort (); } } - if (hfd->handle_valid == HDF_HANDLE_WIN32) { + if (hfd->handle_valid == HDF_HANDLE_WIN32_NORMAL) { LARGE_INTEGER fppos; fppos.QuadPart = offset; - ret = SetFilePointer (hfd->handle->h, fppos.LowPart, &fppos.HighPart, FILE_BEGIN); + ret = SetFilePointer(hfd->handle->h, fppos.LowPart, &fppos.HighPart, FILE_BEGIN); if (ret == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) return -1; } else if (hfd->handle_valid == HDF_HANDLE_ZFILE) { @@ -2127,7 +2205,7 @@ static void poscheck (struct hardfiledata *hfd, int len) DWORD err; uae_s64 pos; - if (hfd->handle_valid == HDF_HANDLE_WIN32) { + if (hfd->handle_valid == HDF_HANDLE_WIN32_NORMAL) { LARGE_INTEGER fppos; fppos.QuadPart = 0; fppos.LowPart = SetFilePointer (hfd->handle->h, 0, &fppos.HighPart, FILE_CURRENT); @@ -2141,6 +2219,8 @@ static void poscheck (struct hardfiledata *hfd, int len) pos = fppos.QuadPart; } else if (hfd->handle_valid == HDF_HANDLE_ZFILE) { pos = zfile_ftell (hfd->handle->zf); + } else if (hfd->handle_valid == HDF_HANDLE_WIN32_CHS) { + pos = 0; } if (len < 0) { gui_message (_T("hd: poscheck failed, negative length! (%d)"), len); @@ -2292,10 +2372,11 @@ static int hdf_read_2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, i hfd->cache_offset = hfd->offset + (hfd->physsize - hfd->virtual_size) - CACHE_SIZE; hdf_seek (hfd, hfd->cache_offset); poscheck (hfd, CACHE_SIZE); - if (hfd->handle_valid == HDF_HANDLE_WIN32) - ReadFile (hfd->handle->h, hfd->cache, CACHE_SIZE, &outlen, NULL); - else if (hfd->handle_valid == HDF_HANDLE_ZFILE) - outlen = zfile_fread (hfd->cache, 1, CACHE_SIZE, hfd->handle->zf); + if (hfd->handle_valid == HDF_HANDLE_WIN32_NORMAL) { + ReadFile(hfd->handle->h, hfd->cache, CACHE_SIZE, &outlen, NULL); + } else if (hfd->handle_valid == HDF_HANDLE_ZFILE) { + outlen = zfile_fread(hfd->cache, 1, CACHE_SIZE, hfd->handle->zf); + } hfd->cache_valid = 0; if (outlen != CACHE_SIZE) return 0; @@ -2325,6 +2406,18 @@ int hdf_read_target (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int return len2; } offset -= hfd->virtual_size; + + if (hfd->handle_valid == HDF_HANDLE_WIN32_CHS) { + int len2 = len; + while (len > 0) { + int c, h, s; + tochs(hfd->identity, offset, &c, &h, &s); + do_scsi_read10_chs(hfd->handle->h, -1, c, h, s, (uae_u8*)buffer, 1, false); + len -= 512; + } + return len2; + } + while (len > 0) { int maxlen; DWORD ret; @@ -2333,7 +2426,7 @@ int hdf_read_target (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int hdf_seek (hfd, offset); if (hfd->physsize) poscheck (hfd, len); - if (hfd->handle_valid == HDF_HANDLE_WIN32) { + if (hfd->handle_valid == HDF_HANDLE_WIN32_NORMAL) { ReadFile (hfd->handle->h, hfd->cache, len, &ret, NULL); memcpy (buffer, hfd->cache, ret); } else if (hfd->handle_valid == HDF_HANDLE_ZFILE) { @@ -2364,11 +2457,12 @@ static int hdf_write_2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, return 0; if (len == 0) return 0; + hfd->cache_valid = 0; hdf_seek (hfd, offset); poscheck (hfd, len); memcpy (hfd->cache, buffer, len); - if (hfd->handle_valid == HDF_HANDLE_WIN32) { + if (hfd->handle_valid == HDF_HANDLE_WIN32_NORMAL) { TCHAR *name = hfd->emptyname == NULL ? _T("") : hfd->emptyname; if (offset == 0) { if (!hfd->handle->firstwrite && (hfd->flags & HFD_FLAGS_REALDRIVE) && !(hfd->flags & HFD_FLAGS_REALDRIVEPARTITION)) { @@ -2407,10 +2501,13 @@ int hdf_write_target (struct hardfiledata *hfd, void *buffer, uae_u64 offset, in int got = 0; uae_u8 *p = (uae_u8*)buffer; + if (hfd->handle_valid == HDF_HANDLE_WIN32_CHS) + return 0; if (hfd->drive_empty || hfd->physsize == 0) return 0; if (offset < hfd->virtual_size) return len; + offset -= hfd->virtual_size; while (len > 0) { int maxlen = len > CACHE_SIZE ? CACHE_SIZE : len; @@ -2699,9 +2796,11 @@ static BOOL GetDevicePropertyFromName(const TCHAR *DevicePath, DWORD Index, DWOR _tcscpy (udi->device_path, DevicePath); write_log (_T("opening device '%s'\n"), udi->device_path); + + // try read-write first, direct scsi needs also write access hDevice = CreateFile( udi->device_path, // device interface name - GENERIC_READ, // dwDesiredAccess + GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode NULL, // lpSecurityAttributes OPEN_EXISTING, // dwCreationDistribution @@ -2709,6 +2808,19 @@ static BOOL GetDevicePropertyFromName(const TCHAR *DevicePath, DWORD Index, DWOR NULL // hTemplateFile ); + + if (hDevice == INVALID_HANDLE_VALUE) { + hDevice = CreateFile( + udi->device_path, // device interface name + GENERIC_READ, // dwDesiredAccess + FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode + NULL, // lpSecurityAttributes + OPEN_EXISTING, // dwCreationDistribution + 0, // dwFlagsAndAttributes + NULL // hTemplateFile + ); + } + // // We have the handle to talk to the device. // So we can release the interfaceDetailData buffer @@ -2835,8 +2947,19 @@ static BOOL GetDevicePropertyFromName(const TCHAR *DevicePath, DWORD Index, DWOR udi->sectors = dg.SectorsPerTrack; udi->heads = dg.TracksPerCylinder; } + if (gli_ok && gli.Length.QuadPart) udi->size = gli.Length.QuadPart; + + if (ischs(udi->identity)) { + int c, h, s; + tochs(udi->identity, -1, &c, &h, &s); + udi->size = c * h * s * 512; + udi->cylinders = c; + udi->heads = h; + udi->sectors = s; + } + write_log (_T("device size %I64d (0x%I64x) bytes\n"), udi->size, udi->size); trim (orgname); @@ -2895,7 +3018,7 @@ static BOOL GetDevicePropertyFromName(const TCHAR *DevicePath, DWORD Index, DWOR } } if (udi->offset == 0 && udi->size) { - udi->dangerous = safetycheck (hDevice, udi->device_path, 0, buffer, dg.BytesPerSector); + udi->dangerous = safetycheck (hDevice, udi->device_path, 0, buffer, dg.BytesPerSector, udi->identity); if (udi->dangerous > 0) goto end; } @@ -3142,6 +3265,9 @@ TCHAR *hdf_getnameharddrive (int index, int flags, int *sectorsize, int *dangero case -9: dang = _T("[EMPTY]"); break; + case -4: + dang = _T("(CHS)"); + break; case -3: dang = _T("(CPRM)"); break; diff --git a/od-win32/win32gui.cpp b/od-win32/win32gui.cpp index 80f68e65..4c6d1c49 100644 --- a/od-win32/win32gui.cpp +++ b/od-win32/win32gui.cpp @@ -12735,8 +12735,16 @@ static void sethardfilegeo(HWND hDlg) if (current_hfdlg.ci.geometry[0]) { current_hfdlg.ci.physical_geometry = true; setchecked(hDlg, IDC_HDF_PHYSGEOMETRY, TRUE); - ew (hDlg, IDC_HDF_PHYSGEOMETRY, FALSE); + ew(hDlg, IDC_HDF_PHYSGEOMETRY, FALSE); get_hd_geometry(¤t_hfdlg.ci); + } else if (current_hfdlg.ci.chs) { + current_hfdlg.ci.physical_geometry = true; + setchecked(hDlg, IDC_HDF_PHYSGEOMETRY, TRUE); + ew(hDlg, IDC_HDF_PHYSGEOMETRY, FALSE); + ew(hDlg, IDC_SECTORS, FALSE); + ew(hDlg, IDC_SECTORS, FALSE); + ew(hDlg, IDC_RESERVED, FALSE); + ew(hDlg, IDC_BLOCKSIZE, FALSE); } else { ew (hDlg, IDC_HDF_PHYSGEOMETRY, TRUE); } @@ -12760,8 +12768,8 @@ static void sethardfiletypes(HWND hDlg) static void sethd(HWND hDlg) { bool rdb = is_hdf_rdb (); - bool physgeo = rdb && ischecked(hDlg, IDC_HDF_PHYSGEOMETRY); - bool enablegeo = !rdb || (physgeo && current_hfdlg.ci.geometry[0] == 0); + bool physgeo = (rdb && ischecked(hDlg, IDC_HDF_PHYSGEOMETRY)) || current_hfdlg.ci.chs; + bool enablegeo = (!rdb || (physgeo && current_hfdlg.ci.geometry[0] == 0)) && !current_hfdlg.ci.chs; const struct expansionromtype *ert = get_unit_expansion_rom(current_hfdlg.ci.controller_type); if (ert && current_hfdlg.ci.controller_unit >= 8) { if (!_tcscmp(ert->name, _T("a2091"))) { @@ -13045,6 +13053,13 @@ static void updatehdfinfo (HWND hDlg, bool force, bool defaults) hfd.ci.blocksize = blocksize; } } + if (hfd.ci.chs) { + current_hfdlg.ci.physical_geometry = true; + current_hfdlg.ci.chs = true; + current_hfdlg.ci.pcyls = hfd.ci.pcyls; + current_hfdlg.ci.pheads = hfd.ci.pheads; + current_hfdlg.ci.psecs = hfd.ci.psecs; + } if (!current_hfdlg.ci.physical_geometry) { if (current_hfdlg.ci.controller_type >= HD_CONTROLLER_TYPE_IDE_FIRST && current_hfdlg.ci.controller_type <= HD_CONTROLLER_TYPE_IDE_LAST) { getchspgeometry (bsize, ¤t_hfdlg.ci.pcyls, ¤t_hfdlg.ci.pheads, ¤t_hfdlg.ci.psecs, true);