From 1fd8ec19226d8b0b66ce9d1da33a24ce5e735612 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Thu, 8 Mar 2018 18:22:42 +0200 Subject: [PATCH] Directory hardfile fake device driver now can be opened and supports minimal command set. --- filesys.cpp | 102 ++++++++++++++++++++++++++++++++++++++----------- hardfile.cpp | 106 ++++++++++++++++++++++++++++++++++++++++++--------- scsi.cpp | 48 +++++++++++++++++++++-- 3 files changed, 212 insertions(+), 44 deletions(-) diff --git a/filesys.cpp b/filesys.cpp index f2d0dd16..6e632631 100644 --- a/filesys.cpp +++ b/filesys.cpp @@ -593,6 +593,61 @@ void uci_set_defaults (struct uaedev_config_info *uci, bool rdb) uci->device_emu_unit = -1; } +static void get_usedblocks(struct fs_usage *fsu, bool fs, int *pblocksize, uae_s64 *pnumblocks, uae_s64 *pinuse) +{ + uae_s64 numblocks = 0, inuse; + int blocksize = *pblocksize; + + if (fs && currprefs.filesys_limit) { + if (fsu->total > (uae_s64)currprefs.filesys_limit * 1024) { + uae_s64 oldtotal = fsu->total; + fsu->total = currprefs.filesys_limit * 1024; + fsu->avail = ((fsu->avail / 1024) * (fsu->total / 1024)) / (oldtotal / 1024); + fsu->avail *= 1024; + } + } + while (blocksize < 32768 || numblocks == 0) { + numblocks = fsu->total / blocksize; + if (numblocks <= 10) + numblocks = 10; + if (numblocks <= 0x7fffffff) + break; + blocksize *= 2; + } + inuse = (numblocks * blocksize - fsu->avail) / blocksize; + if (inuse > numblocks) + inuse = numblocks; + if (pnumblocks) + *pnumblocks = numblocks; + if (pinuse) + *pinuse = inuse; + if (pblocksize) + *pblocksize = blocksize; +} + +static bool get_blocks(const TCHAR *rootdir, int unit, int flags, int *pblocksize, uae_s64 *pnumblocks, uae_s64 *pinuse) +{ + struct fs_usage fsu; + int ret; + bool fs = false; + int blocksize; + + blocksize = 512; + if (flags & MYVOLUMEINFO_ARCHIVE) { + ret = zfile_fs_usage_archive(rootdir, 0, &fsu); + fs = true; + } else { + ret = get_fs_usage(rootdir, 0, &fsu); + fs = true; + } + if (ret) + return false; + get_usedblocks(&fsu, fs, &blocksize, pnumblocks, pinuse); + if (pblocksize) + *pblocksize = blocksize; + return ret == 0; +} + static int set_filesys_unit_1 (int nr, struct uaedev_config_info *ci) { UnitInfo *ui; @@ -668,6 +723,8 @@ static int set_filesys_unit_1 (int nr, struct uaedev_config_info *ci) c.readonly = true; } else if (c.volname[0]) { int flags = 0; + uae_s64 numblocks; + emptydrive = 1; if (c.rootdir[0]) { if (set_filesys_volume (c.rootdir, &flags, &c.readonly, &emptydrive, &ui->zarchive) < 0) @@ -675,6 +732,25 @@ static int set_filesys_unit_1 (int nr, struct uaedev_config_info *ci) } ui->volname = filesys_createvolname (c.volname, c.rootdir, ui->zarchive, _T("harddrive")); ui->volflags = flags; + TCHAR *vs = au(UAEFS_VERSION); + TCHAR *vsp = vs + _tcslen(vs) - 1; + while (vsp != vs) { + if (*vsp == ' ') { + *vsp++ = 0; + break; + } + vsp--; + } + _tcscpy(ui->hf.vendor_id, _T("UAE")); + _tcscpy(ui->hf.product_id, vs); + _tcscpy(ui->hf.product_rev, vsp); + xfree(vs); + ui->hf.ci.unit_feature_level = HD_LEVEL_SCSI_2; + if (get_blocks(c.rootdir, nr, flags, &ui->hf.ci.blocksize, &numblocks, NULL)) + ui->hf.ci.max_lba = numblocks > 0xffffffff ? 0xffffffff : numblocks; + else + ui->hf.ci.max_lba = 0x00ffffff; + } else { ui->unit_type = UNIT_FILESYSTEM; ui->hf.unitnum = nr; @@ -1053,7 +1129,7 @@ struct hardfiledata *get_hardfile_data_controller(int nr) { UnitInfo *uip = mountinfo.ui; for (int i = 0; i < MAX_FILESYSTEM_UNITS; i++) { - if (uip[i].open == 0 || is_virtual(i)) + if (uip[i].open == 0) continue; if (uip[i].hf.ci.controller_unit == nr) return &uip[i].hf; @@ -3301,26 +3377,8 @@ static void do_info(TrapContext *ctx, Unit *unit, dpacket *packet, uaecptr info, put_long_host(buf + 24, -1); /* ID_NO_DISK_PRESENT */ put_long_host(buf + 28, 0); } else { - if (fs && currprefs.filesys_limit) { - if (fsu.total > (uae_s64)currprefs.filesys_limit * 1024) { - uae_s64 oldtotal = fsu.total; - fsu.total = currprefs.filesys_limit * 1024; - fsu.avail = ((fsu.avail / 1024) * (fsu.total / 1024)) / (oldtotal / 1024); - fsu.avail *= 1024; - } - } - uae_s64 numblocks = 0; - while (blocksize < 32768 || numblocks == 0) { - numblocks = fsu.total / blocksize; - if (numblocks <= 10) - numblocks = 10; - if (numblocks <= 0x7fffffff) - break; - blocksize *= 2; - } - uae_s64 inuse = (numblocks * blocksize - fsu.avail) / blocksize; - if (inuse > numblocks) - inuse = numblocks; + uae_s64 numblocks, inuse; + get_usedblocks(&fsu, fs, &blocksize, &numblocks, &inuse); //write_log(_T("total %lld avail %lld Blocks %lld Inuse %lld blocksize %d\n"), fsu.total, fsu.avail, numblocks, inuse, blocksize); put_long_host(buf + 12, (uae_u32)numblocks); /* numblocks */ put_long_host(buf + 16, (uae_u32)inuse); /* inuse */ @@ -8964,7 +9022,7 @@ void filesys_install (void) ROM_filesys_resname = ds_ansi ("UAEfs.resource"); ROM_filesys_resid = ds_ansi (UAEFS_VERSION); - fsdevname = ds_ansi ("uae.device"); /* does not really exist */ + fsdevname = ROM_hardfile_resname; fshandlername = ds_bstr_ansi ("uaefs"); cdfs_devname = ds_ansi ("uaescsi.device"); diff --git a/hardfile.cpp b/hardfile.cpp index 19826079..947c6aaf 100644 --- a/hardfile.cpp +++ b/hardfile.cpp @@ -80,6 +80,7 @@ struct hardfileprivdata { int changenum; uaecptr changeint; struct scsi_data *sd; + bool directorydrive; }; #define HFD_CHD_OTHER 5 @@ -2440,18 +2441,35 @@ static uae_u32 REGPARAM2 hardfile_open (TrapContext *ctx) if (unit >= 0 && unit < MAX_FILESYSTEM_UNITS) { struct hardfileprivdata *hfpd = &hardfpd[unit]; struct hardfiledata *hfd = get_hardfile_data_controller(unit); - if (hfd && (hfd->handle_valid || hfd->drive_empty) && start_thread (ctx, unit)) { - trap_put_word(ctx, hfpd->base + 32, trap_get_word(ctx, hfpd->base + 32) + 1); - trap_put_long(ctx, ioreq + 24, unit); /* io_Unit */ - trap_put_byte(ctx, ioreq + 31, 0); /* io_Error */ - trap_put_byte(ctx, ioreq + 8, 7); /* ln_type = NT_REPLYMSG */ - if (!hfpd->sd) - hfpd->sd = scsi_alloc_generic(hfd, UAEDEV_HDF); - hf_log (_T("hardfile_open, unit %d (%d), OK\n"), unit, trap_get_dreg (ctx, 0)); - return 0; + if (hfd) { + if (is_hardfile(hfd->ci.controller_type_unit) == FILESYS_VIRTUAL) { + if (start_thread(ctx, unit)) { + hfpd->directorydrive = true; + trap_put_word(ctx, hfpd->base + 32, trap_get_word(ctx, hfpd->base + 32) + 1); + trap_put_long(ctx, ioreq + 24, unit); /* io_Unit */ + trap_put_byte(ctx, ioreq + 31, 0); /* io_Error */ + trap_put_byte(ctx, ioreq + 8, 7); /* ln_type = NT_REPLYMSG */ + if (!hfpd->sd) + hfpd->sd = scsi_alloc_generic(hfd, UAEDEV_DIR); + hf_log(_T("virtual hardfile_open, unit %d (%d), OK\n"), unit, trap_get_dreg(ctx, 0)); + return 0; + } + } else { + if ((hfd->handle_valid || hfd->drive_empty) && start_thread(ctx, unit)) { + hfpd->directorydrive = false; + trap_put_word(ctx, hfpd->base + 32, trap_get_word(ctx, hfpd->base + 32) + 1); + trap_put_long(ctx, ioreq + 24, unit); /* io_Unit */ + trap_put_byte(ctx, ioreq + 31, 0); /* io_Error */ + trap_put_byte(ctx, ioreq + 8, 7); /* ln_type = NT_REPLYMSG */ + if (!hfpd->sd) + hfpd->sd = scsi_alloc_generic(hfd, UAEDEV_HDF); + hf_log(_T("hardfile_open, unit %d (%d), OK\n"), unit, trap_get_dreg(ctx, 0)); + return 0; + } + } } } - if (unit < 1000 || is_hardfile (unit) == FILESYS_VIRTUAL || is_hardfile (unit) == FILESYS_CD) + if (unit < 1000) err = 50; /* HFERR_NoBoard */ hf_log (_T("hardfile_open, unit %d (%d), ERR=%d\n"), unit, trap_get_dreg(ctx, 0), err); trap_put_long(ctx, ioreq + 20, (uae_u32)err); @@ -2514,6 +2532,11 @@ static bool isbadblock(struct hardfiledata *hfd, uae_u64 offset, uae_u64 len) return false; } +static bool vdisk(struct hardfileprivdata *hfdp) +{ + return hfdp->directorydrive; +} + static uae_u32 hardfile_do_io (TrapContext *ctx, struct hardfiledata *hfd, struct hardfileprivdata *hfpd, uae_u8 *iobuf, uaecptr request) { uae_u32 dataptr, offset, actual = 0, cmd; @@ -2541,14 +2564,24 @@ static uae_u32 hardfile_do_io (TrapContext *ctx, struct hardfiledata *hfd, struc unaligned (cmd, offset, len, hfd->ci.blocksize); goto bad_len; } - if (len + offset > hfd->virtsize) { - outofbounds (cmd, offset, len, hfd->virtsize); - goto bad_len; - } - if (isbadblock(hfd, offset, len)) { - goto bad_block; + if (vdisk(hfpd)) { + for (int i = 0; i < len; i++) { + put_byte(dataptr + i, 0); + } + if (offset == 0) { + put_long(dataptr, 0x444f5301); + } + actual = len; + } else { + if (len + offset > hfd->virtsize) { + outofbounds(cmd, offset, len, hfd->virtsize); + goto bad_len; + } + if (isbadblock(hfd, offset, len)) { + goto bad_block; + } + actual = (uae_u32)cmd_read(ctx, hfd, dataptr, offset, len); } - actual = (uae_u32)cmd_read(ctx, hfd, dataptr, offset, len); break; #if HDF_SUPPORT_TD64 @@ -2560,6 +2593,8 @@ static uae_u32 hardfile_do_io (TrapContext *ctx, struct hardfiledata *hfd, struc #if defined(HDF_SUPPORT_NSD) || defined(HDF_SUPPORT_TD64) if (nodisk (hfd)) goto no_disk; + if (vdisk(hfpd)) + goto v_disk; offset64 = get_long_host(iobuf + 44) | ((uae_u64)get_long_host(iobuf + 32) << 32); len = get_long_host(iobuf + 36); /* io_Length */ if (offset64 & bmask) { @@ -2585,6 +2620,8 @@ static uae_u32 hardfile_do_io (TrapContext *ctx, struct hardfiledata *hfd, struc case CMD_FORMAT: /* Format */ if (nodisk (hfd)) goto no_disk; + if (vdisk(hfpd)) + goto v_disk; if (is_writeprotected(hfd)) { error = 28; /* write protect */ } else { @@ -2620,6 +2657,8 @@ static uae_u32 hardfile_do_io (TrapContext *ctx, struct hardfiledata *hfd, struc #if defined(HDF_SUPPORT_NSD) || defined(HDF_SUPPORT_TD64) if (nodisk (hfd)) goto no_disk; + if (vdisk(hfpd)) + goto v_disk; if (is_writeprotected(hfd)) { error = 28; /* write protect */ } else { @@ -2647,6 +2686,8 @@ static uae_u32 hardfile_do_io (TrapContext *ctx, struct hardfiledata *hfd, struc #if HDF_SUPPORT_NSD case NSCMD_DEVICEQUERY: + if (vdisk(hfpd)) + goto v_disk; trap_put_long(ctx, dataptr + 0, 0); trap_put_long(ctx, dataptr + 4, 16); /* size */ trap_put_word(ctx, dataptr + 8, NSDEVTYPE_TRACKDISK); @@ -2657,8 +2698,14 @@ static uae_u32 hardfile_do_io (TrapContext *ctx, struct hardfiledata *hfd, struc #endif case CMD_GETDRIVETYPE: + if (vdisk(hfpd)) + goto v_disk; +#if HDF_SUPPORT_NSD actual = DRIVE_NEWSTYLE; break; +#else + goto no_cmd; +#endif case CMD_GETNUMTRACKS: { @@ -2704,9 +2751,20 @@ static uae_u32 hardfile_do_io (TrapContext *ctx, struct hardfiledata *hfd, struc case CMD_CLEAR: case CMD_MOTOR: case CMD_SEEK: + break; + +#if HDF_SUPPORT_TD64 case TD_SEEK64: + if (vdisk(hfpd)) + goto v_disk; + break; +#endif +#ifdef HDF_SUPPORT_NSD case NSCMD_TD_SEEK64: + if (vdisk(hfpd)) + goto v_disk; break; +#endif case CMD_REMOVE: hfpd->changeint = get_long (request + 40); @@ -2717,17 +2775,23 @@ static uae_u32 hardfile_do_io (TrapContext *ctx, struct hardfiledata *hfd, struc break; case CMD_ADDCHANGEINT: + if (vdisk(hfpd)) + goto v_disk; error = add_async_request (hfpd, iobuf, request, ASYNC_REQUEST_CHANGEINT, get_long_host(iobuf + 40)); if (!error) async = 1; break; case CMD_REMCHANGEINT: + if (vdisk(hfpd)) + goto v_disk; release_async_request (hfpd, request); break; #if HDF_SUPPORT_DS case HD_SCSICMD: /* SCSI */ - if (HDF_SUPPORT_DS_PARTITION || enable_ds_partition_hdf || (!hfd->ci.sectors && !hfd->ci.surfaces && !hfd->ci.reserved)) { + if (vdisk(hfpd)) { + error = handle_scsi(ctx, iobuf, request, hfd, hfpd->sd); + } else if (HDF_SUPPORT_DS_PARTITION || enable_ds_partition_hdf || (!hfd->ci.sectors && !hfd->ci.surfaces && !hfd->ci.reserved)) { error = handle_scsi(ctx, iobuf, request, hfd, hfpd->sd); } else { /* we don't want users trashing their "partition" hardfiles with hdtoolbox */ error = IOERR_NOCMD; @@ -2737,6 +2801,8 @@ static uae_u32 hardfile_do_io (TrapContext *ctx, struct hardfiledata *hfd, struc #endif case CD_EJECT: + if (vdisk(hfpd)) + goto v_disk; if (hfd->ci.sectors && hfd->ci.surfaces) { int len = get_long_host(iobuf + 36); if (len) { @@ -2764,11 +2830,15 @@ bad_command: bad_len: error = IOERR_BADLENGTH; break; +v_disk: + error = IOERR_BadDriveType; + break; no_disk: error = 29; /* no disk */ break; default: +no_cmd: /* Command not understood. */ error = IOERR_NOCMD; break; diff --git a/scsi.cpp b/scsi.cpp index 0ec87122..b13d6ea8 100644 --- a/scsi.cpp +++ b/scsi.cpp @@ -73,10 +73,11 @@ extern int log_scsiemu; -static const int outcmd[] = { 0x04, 0x0a, 0x0c, 0x11, 0x2a, 0xaa, 0x15, 0x55, 0x0f, -1 }; -static const int incmd[] = { 0x01, 0x03, 0x08, 0x0e, 0x12, 0x1a, 0x5a, 0x25, 0x28, 0x34, 0x37, 0x42, 0x43, 0xa8, 0x51, 0x52, 0xb9, 0xbd, 0xd8, 0xd9, 0xbe, -1 }; -static const int nonecmd[] = { 0x00, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x10, 0x16, 0x17, 0x19, 0x1b, 0x1d, 0x1e, 0x2b, 0x35, 0x45, 0x47, 0x48, 0x49, 0x4b, 0x4e, 0xa5, 0xa9, 0xba, 0xbc, 0xe0, 0xe3, 0xe4, -1 }; -static const int scsicmdsizes[] = { 6, 10, 10, 12, 16, 12, 10, 6 }; +static const uae_s16 outcmd[] = { 0x04, 0x0a, 0x0c, 0x11, 0x2a, 0xaa, 0x15, 0x55, 0x0f, -1 }; +static const uae_s16 incmd[] = { 0x01, 0x03, 0x08, 0x0e, 0x12, 0x1a, 0x5a, 0x25, 0x28, 0x34, 0x37, 0x42, 0x43, 0xa8, 0x51, 0x52, 0xb9, 0xbd, 0xd8, 0xd9, 0xbe, -1 }; +static const uae_s16 nonecmd[] = { 0x00, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x10, 0x16, 0x17, 0x19, 0x1b, 0x1d, 0x1e, 0x2b, 0x35, 0x45, 0x47, 0x48, 0x49, 0x4b, 0x4e, 0xa5, 0xa9, 0xba, 0xbc, 0xe0, 0xe3, 0xe4, -1 }; +static const uae_s16 dirscsi[] = { 0x00, 0x01, 0x03, 0x0e, 0x0f, 0x12, 0x1a, 0x1b, 0x25, 0x35, 0x5a, -1 }; +static const uae_s16 scsicmdsizes[] = { 6, 10, 10, 12, 16, 12, 10, 6 }; static void scsi_illegal_command(struct scsi_data *sd) { @@ -385,6 +386,7 @@ void scsi_emulate_cmd(struct scsi_data *sd) sd->device_type, sd->nativescsiunit); #endif if (sd->device_type == UAEDEV_CD && sd->cd_emu_unit >= 0) { + uae_u32 ua = 0; ua = scsi_cd_emulate(sd->cd_emu_unit, NULL, 0, 0, 0, 0, 0, 0, 0, sd->atapi); if (ua) @@ -398,7 +400,9 @@ void scsi_emulate_cmd(struct scsi_data *sd) copyreply(sd); } } + } else if (sd->device_type == UAEDEV_HDF && sd->nativescsiunit < 0) { + uae_u32 ua = 0; ua = scsi_hd_emulate(sd->hfd, sd->hdhfd, NULL, 0, 0, 0, 0, 0, 0, 0); if (ua) @@ -413,7 +417,9 @@ void scsi_emulate_cmd(struct scsi_data *sd) copyreply(sd); } } + } else if (sd->device_type == UAEDEV_TAPE && sd->nativescsiunit < 0) { + uae_u32 ua = 0; ua = scsi_tape_emulate(sd->tape, NULL, 0, 0, 0, 0, 0, 0, 0); if (ua) @@ -428,6 +434,40 @@ void scsi_emulate_cmd(struct scsi_data *sd) copyreply(sd); } } + + } else if (sd->device_type == UAEDEV_DIR) { + + uae_u32 ua = 0; + ua = scsi_hd_emulate(sd->hfd, sd->hdhfd, NULL, 0, 0, 0, 0, 0, 0, 0); + if (ua) + sd->unit_attention = ua; + if (handle_ca(sd)) { + bool allowed = false; + for (int i = 0; dirscsi[i] >= 0; i++) { + if (dirscsi[i] == sd->cmd[0]) { + allowed = true; + break; + } + } + if (allowed) { + if (sd->cmd[0] == 0x03) { /* REQUEST SENSE */ + scsi_hd_emulate(sd->hfd, sd->hdhfd, sd->cmd, 0, 0, 0, 0, 0, sd->sense, &sd->sense_len); + copysense(sd); + } else { + sd->status = scsi_hd_emulate(sd->hfd, sd->hdhfd, + sd->cmd, sd->cmd_len, sd->buffer, &sd->data_len, sd->reply, &sd->reply_len, sd->sense, &sd->sense_len); + copyreply(sd); + } + } else { + sd->sense[0] = 0x70; + sd->sense[2] = 5; /* Illegal Request */ + sd->sense[12] = 0x20; /* Invalid/unsupported command code */ + sd->sense_len = 18; + sd->status = 2; + copyreply(sd); + } + } + } else if (sd->nativescsiunit >= 0) { struct amigascsi as; -- 2.47.3