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;
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)
}
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;
{
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;
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 */
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");
int changenum;
uaecptr changeint;
struct scsi_data *sd;
+ bool directorydrive;
};
#define HFD_CHD_OTHER 5
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);
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;
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
#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) {
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 {
#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 {
#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);
#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:
{
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);
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;
#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) {
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;
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)
{
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)
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)
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)
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;