mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-24 19:32:06 +00:00
Show version includes the other configuration info, including READLINE and ASPI. Fix a memory leak in Unix show devices. Start using valgrind. Add VLD support for Windows. Fix memory leaks in main command processing. add command line arguments to history if USEing_READLINE Add atexit() and rundown support to dismount volumes at exit. Update makefiles for READLINE - some versions require you to link with termcap or ncurses as well. Fix memory leak in set default (including implicit set default on mount) Free WCCFILE on search NAM$M_SYNCHK as VMS does. Also release when returning RMS$_NMF. Add nam$l_rlf field to NAM Implement show devices for VMS. When reusing a WCB for large file, ensure that the file header pointer is valid. Add show cwd so it's easy to find out default for local files. Add set cwd Add spawn cmd so it's easy to inspect copied files. Handle condition codes properly. Finish sysmsg. Add standard macros to stsdef.h Deal with strerror on windows.
1156 lines
47 KiB
C
1156 lines
47 KiB
C
/* PHYNT.C V2.1 Physical I/O module for Windows NT */
|
|
|
|
/* Win9X code now included with code to automatically determine
|
|
if we are running under WinNT...
|
|
|
|
W98 seems to have a performance problem where the
|
|
INT25 call are VERY slow!!! */
|
|
|
|
|
|
|
|
/* This version built and tested under Visual C++ 6.0 and LCC.
|
|
To support CD drives this version requires ASPI run-time
|
|
support.. Windows 95/98 come with ASPI but NT/2000 require
|
|
that a version of ASPI be install and started before running
|
|
this program!! (One verion is NTASPI available from
|
|
www.symbios.com)
|
|
|
|
Note: As of 2016, www.symbios.com is a financial site. You
|
|
may be able to obtain ASPI from someplace else, but the code
|
|
to use it may be stale. On more recent windows, you can simply
|
|
use the NT drive letter, which will do physical I/O to the device.
|
|
*/
|
|
|
|
|
|
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <io.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <windows.h>
|
|
#include <winioctl.h>
|
|
#include <shlwapi.h> /* PathSearchAndQualify() */
|
|
|
|
#include "ods2.h"
|
|
#include "device.h"
|
|
#include "phyio.h"
|
|
#include "ssdef.h"
|
|
#include "stsdef.h"
|
|
#include "compat.h"
|
|
#include "phyvirt.h"
|
|
#include "sysmsg.h"
|
|
|
|
#ifdef USE_ASPI
|
|
#include "scsidefs.h"
|
|
#include "wnaspi32.h"
|
|
#endif
|
|
|
|
/* Some NT definitions... */
|
|
|
|
/* #include "Ntddcdrm.h" */
|
|
#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
|
|
#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, \
|
|
METHOD_OUT_DIRECT, FILE_READ_ACCESS)
|
|
#define IOCTL_CDROM_GET_DRIVE_GEOMETRY \
|
|
CTL_CODE(IOCTL_CDROM_BASE, 0x0013, \
|
|
METHOD_BUFFERED, FILE_READ_ACCESS)
|
|
|
|
/* Windows 9X I/O definitions... */
|
|
#define VWIN32_DIOC_DOS_IOCTL 1
|
|
#define VWIN32_DIOC_DOS_DRIVEINFO 6
|
|
|
|
#pragma pack(1)
|
|
|
|
typedef struct _DIOC_REGISTERS {
|
|
DWORD reg_EBX;
|
|
DWORD reg_EDX;
|
|
DWORD reg_ECX;
|
|
DWORD reg_EAX;
|
|
DWORD reg_EDI;
|
|
DWORD reg_ESI;
|
|
DWORD reg_Flags;
|
|
} DIOC_REGISTERS;
|
|
|
|
typedef struct _DISKIO {
|
|
DWORD dwStartSector; /* starting logical sector number */
|
|
WORD wSectors; /* number of sectors */
|
|
DWORD dwBuffer; /* address of read/write buffer */
|
|
} DISKIO, *PDISKIO;
|
|
|
|
#pragma pack()
|
|
|
|
static unsigned init_count = 0; /* Some counters so we can report */
|
|
static unsigned read_count = 0; /* How often we get called */
|
|
static unsigned write_count = 0;
|
|
|
|
static unsigned is_NT = 2;
|
|
|
|
/*
|
|
To read from CD ASPI run-time support is required (wnaspi32.dll).
|
|
NT does not come with ASPI support so you need to install it first.
|
|
(ASPI is also required for things like Digital Audio Extraction
|
|
and was origionally loaded on my machine to make MP3 audio files.)
|
|
One downside is that ASPI on NT does not have a way to match SCSI
|
|
adapters and units to a system device. So this program works by
|
|
finding the first CD like unit on the system and using it - that
|
|
may NOT be what you want if you have several CD drives! And finally
|
|
there are CD drives and there are CD drives. From what I can tell
|
|
many simply won't work with this (or other!) code. Naturally if
|
|
you find a better way please let me know... Paulnank@au1.ibm.com
|
|
*/
|
|
|
|
#ifdef USE_ASPI
|
|
#define DEV_USES_ASPI( dev ) ( dev->drive > 2 )
|
|
#else
|
|
#define DEV_USES_ASPI( dev ) FALSE
|
|
#endif
|
|
|
|
#ifdef USE_ASPI
|
|
static unsigned ASPI_adapters = 0; /* Count of ASPI adapters */
|
|
static unsigned ASPI_devices = 0; /* Count of ASPI devices accessed */
|
|
|
|
static unsigned ASPI_status = 0; /* Temporary status indicator */
|
|
static unsigned ASPI_HaStat = 0; /* Temporary status indicator */
|
|
static unsigned ASPI_TargStat = 0; /* Temporary status indicator */
|
|
|
|
static HANDLE ASPI_event; /* Windows event for ASPI wait */
|
|
static SRB_ExecSCSICmd ASPI_srb; /* SRB buffer for ASPI commands */
|
|
|
|
static unsigned aspi_execute( short bus, short id, BYTE Flags, DWORD BufLen,
|
|
BYTE *BufPointer, BYTE CDBLen, BYTE CDBByte );
|
|
static unsigned aspi_read( short bus, short id, unsigned sector,
|
|
unsigned bytespersector, char *buffer );
|
|
static unsigned aspi_write( short bus, short id, unsigned sector,
|
|
unsigned bytespersector, char *buffer );
|
|
static unsigned aspi_identify( short bus, short id, unsigned *sectors,
|
|
unsigned *bytespersector );
|
|
static unsigned aspi_initialize( short *dev_type, short *dev_bus,
|
|
short *dev_id );
|
|
#endif
|
|
|
|
static BOOL GetDiskGeometry( struct DEV *dev, unsigned *sectors,
|
|
unsigned *bytespersector );
|
|
|
|
static BOOL LockVolume( struct DEV *dev );
|
|
static BOOL UnlockVolume( struct DEV *dev );
|
|
static void getsysversion( void );
|
|
static unsigned phy_getsect( struct DEV *dev, unsigned sector );
|
|
static unsigned phy_putsect( struct DEV *dev, unsigned sector );
|
|
|
|
|
|
#ifdef USE_ASPI
|
|
/************************************************************* aspi_execute() */
|
|
|
|
static unsigned aspi_execute( short bus, short id, BYTE Flags, DWORD BufLen,
|
|
BYTE *BufPointer, BYTE CDBLen, BYTE CDBByte ) {
|
|
|
|
ASPI_srb.SRB_Cmd = SC_EXEC_SCSI_CMD;
|
|
ASPI_srb.SRB_Status = SS_PENDING;
|
|
ASPI_srb.SRB_HaId = bus;
|
|
ASPI_srb.SRB_Flags = Flags | SRB_EVENT_NOTIFY;
|
|
ASPI_srb.SRB_Hdr_Rsvd = 0;
|
|
ASPI_srb.SRB_Target = id;
|
|
ASPI_srb.SRB_Lun = 0;
|
|
ASPI_srb.SRB_Rsvd1 = 0;
|
|
ASPI_srb.SRB_BufLen = BufLen;
|
|
ASPI_srb.SRB_BufPointer = BufPointer;
|
|
ASPI_srb.SRB_SenseLen = SENSE_LEN;
|
|
ASPI_srb.SRB_CDBLen = CDBLen;
|
|
ASPI_srb.SRB_HaStat = 0;
|
|
ASPI_srb.SRB_TargStat = 0;
|
|
ASPI_srb.SRB_PostProc = ASPI_event;
|
|
ASPI_srb.SRB_Rsvd2 = NULL;
|
|
memset( ASPI_srb.SRB_Rsvd3, 0 ,sizeof( ASPI_srb.SRB_Rsvd3 ) );
|
|
ASPI_srb.CDBByte[0] = CDBByte;
|
|
SendASPI32Command( &ASPI_srb ); /* Perform the command... */
|
|
while ( ASPI_srb.SRB_Status == SS_PENDING ) {
|
|
WaitForSingleObject( ASPI_event, INFINITE );
|
|
}
|
|
ResetEvent( ASPI_event );
|
|
ASPI_status = ASPI_srb.SRB_Status;
|
|
ASPI_HaStat = ASPI_srb.SRB_HaStat;
|
|
ASPI_TargStat = ASPI_srb.SRB_TargStat;
|
|
if ( ASPI_srb.SRB_Status != SS_COMP ) {
|
|
return SS$_PARITY;
|
|
}
|
|
return SS$_NORMAL;
|
|
}
|
|
|
|
/**************************************************************** aspi_read() */
|
|
|
|
/* Read a sector using ASPI... */
|
|
|
|
static unsigned aspi_read( short bus, short id, unsigned sector,
|
|
unsigned bytespersector, char *buffer ) {
|
|
|
|
ASPI_srb.CDBByte[1] = 0;
|
|
ASPI_srb.CDBByte[2] = ( sector >> 24 ) ;
|
|
ASPI_srb.CDBByte[3] = ( sector >> 16 ) & 0xff;
|
|
ASPI_srb.CDBByte[4] = ( sector >> 8 ) & 0xff;
|
|
ASPI_srb.CDBByte[5] = sector & 0xff;
|
|
ASPI_srb.CDBByte[6] = 0;
|
|
ASPI_srb.CDBByte[7] = 0;
|
|
ASPI_srb.CDBByte[8] = 1; /* Read a single sector */
|
|
ASPI_srb.CDBByte[9] = 0;
|
|
return aspi_execute( bus, id, SRB_DIR_IN, bytespersector, buffer, 10,
|
|
SCSI_READ10 );
|
|
}
|
|
|
|
/*************************************************************** aspi_write() */
|
|
|
|
/* Write a sector using ASPI... */
|
|
|
|
static unsigned aspi_write( short bus, short id, unsigned sector,
|
|
unsigned bytespersector, char *buffer ) {
|
|
|
|
ASPI_srb.CDBByte[1] = 0;
|
|
ASPI_srb.CDBByte[2] = ( sector >> 24 ) ;
|
|
ASPI_srb.CDBByte[3] = ( sector >> 16 ) & 0xff;
|
|
ASPI_srb.CDBByte[4] = ( sector >> 8 ) & 0xff;
|
|
ASPI_srb.CDBByte[5] = sector & 0xff;
|
|
ASPI_srb.CDBByte[6] = 0;
|
|
ASPI_srb.CDBByte[7] = 0;
|
|
ASPI_srb.CDBByte[8] = 1; /* Write a single sector */
|
|
ASPI_srb.CDBByte[9] = 0;
|
|
return aspi_execute( bus, id, SRB_DIR_OUT, bytespersector, buffer, 10,
|
|
SCSI_WRITE10 );
|
|
}
|
|
|
|
/************************************************************ aspi_identify() */
|
|
|
|
/* Routine to identify a device found by ASPI */
|
|
|
|
static unsigned aspi_identify( short bus, short id, unsigned *sectors,
|
|
unsigned *bytespersector ) {
|
|
|
|
unsigned sts;
|
|
struct SCSI_Inquiry {
|
|
unsigned char device;
|
|
unsigned char dev_qual2;
|
|
unsigned char version;
|
|
unsigned char response_format;
|
|
unsigned char additional_length;
|
|
unsigned char unused[2];
|
|
unsigned char flags;
|
|
char vendor[8];
|
|
char product[16];
|
|
char revision[4];
|
|
unsigned char extra[60];
|
|
} InquiryBuffer;
|
|
|
|
ASPI_srb.CDBByte[1] = 0; /* SCSI Inquiry packet */
|
|
ASPI_srb.CDBByte[2] = 0;
|
|
ASPI_srb.CDBByte[3] = 0;
|
|
ASPI_srb.CDBByte[4] = sizeof( InquiryBuffer );
|
|
ASPI_srb.CDBByte[5] = 0;
|
|
sts = aspi_execute( bus, id, SRB_DIR_IN, sizeof( InquiryBuffer ),
|
|
(BYTE *) &InquiryBuffer, 6, SCSI_INQUIRY );
|
|
if ( sts & STS$M_SUCCESS ) {
|
|
ASPI_srb.CDBByte[1] = 0;/* SCSI TEST if ready packet */
|
|
ASPI_srb.CDBByte[2] = 0;
|
|
ASPI_srb.CDBByte[3] = 0;
|
|
ASPI_srb.CDBByte[4] = 0;
|
|
ASPI_srb.CDBByte[5] = 0;
|
|
sts = aspi_execute( bus, id, 0, 0, NULL, 6, SCSI_TST_U_RDY );
|
|
if ( !( sts & STS$M_SUCCESS ) ) {
|
|
ASPI_srb.CDBByte[1] = 0; /* SCSI START STOP packet */
|
|
ASPI_srb.CDBByte[2] = 0;
|
|
ASPI_srb.CDBByte[3] = 0;
|
|
ASPI_srb.CDBByte[4] = 1; /* Start unit */
|
|
ASPI_srb.CDBByte[5] = 0;
|
|
sts = aspi_execute( bus, id, 0, 0, NULL, 6 ,SCSI_START_STP );
|
|
}
|
|
if ( sts & STS$M_SUCCESS ) {
|
|
struct {
|
|
unsigned char blocks[4];
|
|
unsigned char sectsz[4];
|
|
} CapBuffer;
|
|
memset( ASPI_srb.CDBByte, 0, sizeof( ASPI_srb.CDBByte ) );
|
|
sts = aspi_execute( bus, id, SRB_DIR_IN, sizeof( CapBuffer ),
|
|
(BYTE *) &CapBuffer, 10, SCSI_RD_CAPAC );
|
|
if ( sts & STS$M_SUCCESS ) {
|
|
*sectors = ( CapBuffer.blocks[0] << 24 ) |
|
|
( CapBuffer.blocks[1] << 16 ) |
|
|
( CapBuffer.blocks[2] << 8 ) |
|
|
CapBuffer.blocks[3] ;
|
|
*bytespersector = ( CapBuffer.sectsz[0] << 24 ) |
|
|
( CapBuffer.sectsz[1] << 16 ) |
|
|
( CapBuffer.sectsz[2] << 8 ) |
|
|
CapBuffer.sectsz[3] ;
|
|
}
|
|
}
|
|
printf( "ASPI (Bus %d,ID %d) %8.8s %16.16s %4.4s %s %d\n",
|
|
bus, id, InquiryBuffer.vendor,InquiryBuffer.product,
|
|
InquiryBuffer.revision,
|
|
( InquiryBuffer.dev_qual2 & 0x80 ) ? "Removable" : "Fixed",
|
|
*bytespersector );
|
|
|
|
}
|
|
if ( !( sts & STS$M_SUCCESS ) ) {
|
|
int i;
|
|
printf( "ASPI Error sense %x %x %x - ",
|
|
ASPI_status, ASPI_HaStat, ASPI_TargStat );
|
|
for ( i = 0; i < SENSE_LEN; i++ ) {
|
|
printf( " %x", ASPI_srb.SenseArea[i] );
|
|
}
|
|
printf( "\n" );
|
|
}
|
|
return sts;
|
|
}
|
|
|
|
/********************************************************** aspi_initialize() */
|
|
|
|
/* Get ASPI ready and locate the next ASPI drive... */
|
|
|
|
static unsigned aspi_initialize( short *dev_type, short *dev_bus,
|
|
short *dev_id ) {
|
|
|
|
short aspi_bus, aspi_id;
|
|
unsigned aspi_devcount;
|
|
DWORD ASPIStatus;
|
|
SRB_GDEVBlock Ssrb;
|
|
|
|
aspi_devcount = 0;
|
|
if ( ASPI_adapters == 0 ) {
|
|
ASPIStatus = GetASPI32SupportInfo();
|
|
ASPI_status = ASPIStatus;
|
|
if ( HIBYTE( LOWORD( ASPIStatus ) ) != SS_COMP ) {
|
|
printf( "Could not initialize ASPI (%x)\n", ASPIStatus );
|
|
printf( "Please check that ASPI is installed and started "
|
|
"properly\n" );
|
|
return 8;
|
|
} else {
|
|
ASPI_adapters = LOWORD( LOBYTE( ASPIStatus ) );
|
|
ASPI_event = CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
if ( ASPI_event == NULL ) {
|
|
return 8;
|
|
}
|
|
}
|
|
}
|
|
Ssrb.SRB_Cmd = SC_GET_DEV_TYPE;
|
|
Ssrb.SRB_HaId = 0;
|
|
Ssrb.SRB_Flags = SRB_EVENT_NOTIFY;
|
|
Ssrb.SRB_Hdr_Rsvd = 0;
|
|
Ssrb.SRB_Lun = 0;
|
|
for ( aspi_bus = 0; aspi_bus < ASPI_adapters; aspi_bus++ ) {
|
|
for ( aspi_id = 0; aspi_id <= 7; aspi_id++ ) {
|
|
Ssrb.SRB_HaId = aspi_bus;
|
|
Ssrb.SRB_Target = aspi_id;
|
|
ASPIStatus = SendASPI32Command( &Ssrb );
|
|
ASPI_status = ASPIStatus;
|
|
if ( ASPIStatus == SS_COMP ) {
|
|
if ( Ssrb.SRB_DeviceType == DTYPE_CROM ||
|
|
Ssrb.SRB_DeviceType == DTYPE_OPTI ) {
|
|
if ( ++aspi_devcount > ASPI_devices ) {
|
|
*dev_type = Ssrb.SRB_DeviceType;
|
|
*dev_bus = aspi_bus;
|
|
*dev_id = aspi_id;
|
|
ASPI_devices++;
|
|
return SS$_NORMAL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
printf( "Could not find a suitable ASPI device\n" );
|
|
return 8;
|
|
}
|
|
#endif
|
|
|
|
/********************************************************** GetDiskGeometry() */
|
|
|
|
/* NT Get disk or CD geometry... */
|
|
|
|
static BOOL GetDiskGeometry( struct DEV *dev, unsigned *sectors,
|
|
unsigned *bytespersector ) {
|
|
|
|
BOOL result;
|
|
|
|
#ifdef USE_ASPI
|
|
if ( DEV_USES_ASPI( dev ) ) {
|
|
unsigned sts;
|
|
sts = aspi_identify( dev->API.ASPI.bus, dev->API.ASPI.id,
|
|
sectors, bytespersector );
|
|
result = sts & STS$M_SUCCESS;
|
|
} else
|
|
#endif
|
|
{
|
|
DWORD ReturnedByteCount;
|
|
if ( is_NT ) {
|
|
|
|
/* WinNT */
|
|
|
|
DISK_GEOMETRY Geometry;
|
|
result =
|
|
DeviceIoControl( dev->API.Win32.handle, /* hDevice */
|
|
/* dwIoControlCode */
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL, /* lpInBuffer */
|
|
0, /* nInBufferSize */
|
|
&Geometry, /* lpOutBuffer */
|
|
sizeof( Geometry ), /* nOutBufferSize */
|
|
&ReturnedByteCount, /* lpBytesReturned */
|
|
NULL /* lpOverlapped */
|
|
);
|
|
if ( !result ) {
|
|
result =
|
|
DeviceIoControl( dev->API.Win32.handle,/* hDevice */
|
|
/* dwIoControlCode */
|
|
IOCTL_CDROM_GET_DRIVE_GEOMETRY,
|
|
NULL, /* lpInBuffer */
|
|
0, /* nInBufferSize */
|
|
&Geometry, /* lpOutBuffer */
|
|
sizeof( Geometry ), /* nOutBufferSize */
|
|
&ReturnedByteCount, /* lpBytesReturned */
|
|
NULL /* lpOverlapped */
|
|
);
|
|
}
|
|
if ( result ) {
|
|
*sectors = Geometry.Cylinders.QuadPart *
|
|
Geometry.TracksPerCylinder *
|
|
Geometry.SectorsPerTrack;
|
|
*bytespersector = Geometry.BytesPerSector;
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Win9X */
|
|
|
|
char RootPathName[4] = "X:\\";
|
|
DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters,
|
|
TotalNumberOfClusters;
|
|
ULARGE_INTEGER FreeBytesAvailable, TotalNumberOfBytes,
|
|
TotalNumberOfFreeBytes;
|
|
RootPathName[0] = dev->drive + 'A';
|
|
result =
|
|
GetDiskFreeSpace( RootPathName, /* lpRootPathName */
|
|
/* lpSectorsPerCluster */
|
|
&SectorsPerCluster,
|
|
&BytesPerSector, /* lpBytesPerSector */
|
|
/* lpNumberOfFreeClusters */
|
|
&NumberOfFreeClusters,
|
|
/* lpTotalNumberOfClusters */
|
|
&TotalNumberOfClusters
|
|
);
|
|
if ( result ) {
|
|
*sectors = TotalNumberOfClusters * SectorsPerCluster;
|
|
*bytespersector = BytesPerSector;
|
|
/* Note: GetDiskFreeSpace() returns incorrect values for */
|
|
/* volumes over 2 GB. We don't really care, as long as */
|
|
/* the bytes per sector is correct. */
|
|
if ( GetDiskFreeSpaceEx( RootPathName,
|
|
&FreeBytesAvailable,
|
|
&TotalNumberOfBytes,
|
|
&TotalNumberOfFreeBytes
|
|
) ) {
|
|
*sectors = TotalNumberOfBytes.QuadPart / BytesPerSector;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*************************************************************** LockVolume() */
|
|
|
|
/* NT drive lock - we don't want any interference... */
|
|
|
|
static BOOL LockVolume( struct DEV *dev ) {
|
|
|
|
DWORD ReturnedByteCount;
|
|
BOOL result;
|
|
|
|
if ( is_NT ) {
|
|
|
|
/* WinNT */
|
|
|
|
result =
|
|
DeviceIoControl( dev->API.Win32.handle, /* hDevice */
|
|
FSCTL_LOCK_VOLUME, /* dwIoControlCode */
|
|
NULL, /* lpInBuffer */
|
|
0, /* nInBufferSize */
|
|
NULL, /* lpOutBuffer */
|
|
0, /* nOutBufferSize */
|
|
&ReturnedByteCount, /* lpBytesReturned */
|
|
NULL /* lpOverlapped */
|
|
);
|
|
} else {
|
|
|
|
/* Win9X */
|
|
|
|
DIOC_REGISTERS reg = { 0 }; /* Win9X DIOC registers */
|
|
reg.reg_EAX = 0x440d; /* IOCTL for block devices */
|
|
reg.reg_EBX = dev->drive + 1; /* 0=default, 1=A, ... */
|
|
reg.reg_ECX = 0x084b; /* Lock physical volume */
|
|
/* Permission */
|
|
reg.reg_EDX = ( dev->access & MOU_WRITE ) ? 0x1 : 0x0 ;
|
|
reg.reg_Flags = 0x0001; /* Set carry flag */
|
|
result =
|
|
DeviceIoControl( dev->API.Win32.handle, /* hDevice */
|
|
VWIN32_DIOC_DOS_IOCTL, /* dwIoControlCode */
|
|
®, /* lpInBuffer */
|
|
sizeof( reg ), /* nInBufferSize */
|
|
®, /* lpOutBuffer */
|
|
sizeof( reg ), /* nOutBufferSize */
|
|
&ReturnedByteCount, /* lpBytesReturned */
|
|
NULL /* lpOverlapped */
|
|
) && !( reg.reg_Flags & 0x0001 );
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/************************************************************* UnlockVolume() */
|
|
|
|
static BOOL UnlockVolume( struct DEV *dev ) {
|
|
|
|
DWORD ReturnedByteCount;
|
|
BOOL result;
|
|
|
|
if ( is_NT ) {
|
|
|
|
/* WinNT */
|
|
|
|
result =
|
|
DeviceIoControl( dev->API.Win32.handle, /* hDevice */
|
|
FSCTL_UNLOCK_VOLUME, /* dwIoControlCode */
|
|
NULL, /* lpInBuffer */
|
|
0, /* nInBufferSize */
|
|
NULL, /* lpOutBuffer */
|
|
0, /* nOutBufferSize */
|
|
&ReturnedByteCount, /* lpBytesReturned */
|
|
NULL /* lpOverlapped */
|
|
);
|
|
} else {
|
|
|
|
/* Win9X */
|
|
|
|
DIOC_REGISTERS reg = { 0 }; /* Win9X DIOC registers */
|
|
reg.reg_EAX = 0x440d; /* IOCTL for block devices */
|
|
reg.reg_EBX = dev->drive + 1; /* 0=default, 1=A, ... */
|
|
reg.reg_ECX = 0x086b; /* Unlock physical volume */
|
|
reg.reg_EDX = 0;
|
|
reg.reg_Flags = 0x0001; /* Set carry flag */
|
|
result =
|
|
DeviceIoControl( dev->API.Win32.handle, /* hDevice */
|
|
VWIN32_DIOC_DOS_IOCTL, /* dwIoControlCode */
|
|
®, /* lpInBuffer */
|
|
sizeof( reg ), /* nInBufferSize */
|
|
®, /* lpOutBuffer */
|
|
sizeof( reg ), /* nOutBufferSize */
|
|
&ReturnedByteCount, /* lpBytesReturned */
|
|
NULL /* lpOverlapped */
|
|
) && !( reg.reg_Flags & 0x0001 );
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/************************************************************ getsysversion() */
|
|
|
|
/* This routine figures out whether this is an NT system or not... */
|
|
|
|
static void getsysversion( void ) {
|
|
|
|
OSVERSIONINFO sysver;
|
|
|
|
memset( &sysver, 0, sizeof( sysver ) );
|
|
#pragma warning (disable : 4996)
|
|
sysver.dwOSVersionInfoSize = sizeof( sysver );
|
|
GetVersionEx( &sysver /* lpVersionInfo */
|
|
);
|
|
#pragma warning (default : 4996)
|
|
is_NT = ( sysver.dwPlatformId == VER_PLATFORM_WIN32_NT ) ? 1 : 0 ;
|
|
}
|
|
|
|
/************************************************************** phy_getsect() */
|
|
|
|
/* Read a physical sector... */
|
|
|
|
static unsigned phy_getsect( struct DEV *dev, unsigned sector ) {
|
|
|
|
register unsigned sts;
|
|
|
|
sts = SS$_NORMAL;
|
|
if ( sector != dev->last_sector || dev->last_sector == 0 ) {
|
|
#ifdef USE_ASPI
|
|
if ( DEV_USES_ASPI( dev ) ) {
|
|
sts = aspi_read( dev->API.ASPI.bus, dev->API.ASPI.id,
|
|
sector, dev->bytespersector, dev->IoBuffer );
|
|
} else
|
|
#endif
|
|
{
|
|
if ( dev->access & MOU_VIRTUAL || is_NT ) {
|
|
DWORD BytesRead;
|
|
__int64 distance;
|
|
LARGE_INTEGER li;
|
|
distance = (((__int64)sector) * dev->blockspersector) << 9;
|
|
li.QuadPart = distance;
|
|
if( SetFilePointer( dev->API.Win32.handle,/* hFile */
|
|
li.LowPart, /* lDistanceToMove */
|
|
&li.HighPart, /* lpDistanceToMoveHigh */
|
|
FILE_BEGIN /* dwMoveMethod */
|
|
) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ) {
|
|
TCHAR *msg = w32_errstr(NO_ERROR);
|
|
printf( "PHYIO_READ: SetFilePointer() failed at sector %lu: %s\n",
|
|
sector, msg );
|
|
LocalFree(msg);
|
|
sts = SS$_PARITY;
|
|
}
|
|
if ( sts & STS$M_SUCCESS ) {
|
|
/* hFile */
|
|
if ( !ReadFile( dev->API.Win32.handle,
|
|
dev->IoBuffer, /* lpBuffer */
|
|
/* nNumberOfBytesToRead */
|
|
dev->bytespersector,
|
|
&BytesRead, /* lpNumberOfBytesRead */
|
|
NULL /* lpOverlapped */
|
|
) || BytesRead != dev->bytespersector ) {
|
|
TCHAR *msg;
|
|
|
|
if( BytesRead == 0 )
|
|
return SS$_ENDOFFILE;
|
|
|
|
msg = w32_errstr(NO_ERROR);
|
|
printf( "PHYIO_READ: ReadFile() failed at sector %lu: %s\n",
|
|
sector, msg );
|
|
LocalFree(msg);
|
|
sts = SS$_PARITY;
|
|
}
|
|
}
|
|
} else {
|
|
DIOC_REGISTERS reg = { 0 }; /* Win9X DIOC registers */
|
|
DISKIO dio;
|
|
BOOL result;
|
|
DWORD cb = 0;
|
|
dio.dwStartSector = sector; /* sector number */
|
|
dio.wSectors = 1; /* sector count */
|
|
dio.dwBuffer = (DWORD) dev->IoBuffer; /* sector buffer */
|
|
reg.reg_EAX = 0x7305; /* Ext_ABSDiskReadWrite */
|
|
reg.reg_EBX = (DWORD) &dio; /* parameter block */
|
|
reg.reg_ECX = -1; /* use dio */
|
|
reg.reg_EDX = dev->drive + 1; /* 0=default, 1=A, ... */
|
|
reg.reg_EDI = 0;
|
|
reg.reg_ESI = 0x0; /* read */
|
|
reg.reg_Flags = 0x0001; /* Set carry flag */
|
|
result =
|
|
DeviceIoControl( dev->API.Win32.handle,/* hDevice */
|
|
/* dwIoControlCode */
|
|
VWIN32_DIOC_DOS_DRIVEINFO,
|
|
®, /* lpInBuffer */
|
|
sizeof( reg ), /* nInBufferSize */
|
|
®, /* lpOutBuffer */
|
|
sizeof( reg ), /* nOutBufferSize */
|
|
&cb, /* lpBytesReturned */
|
|
NULL /* lpOverlapped */
|
|
) && !( reg.reg_Flags & 0x0001 );
|
|
if ( !result ) {
|
|
TCHAR *msg = w32_errstr(NO_ERROR);
|
|
printf( "PHYIO_READ: Read sector %d failed: %s\n",
|
|
sector, msg );
|
|
LocalFree(msg);
|
|
sts = SS$_PARITY;
|
|
}
|
|
}
|
|
}
|
|
dev->last_sector = ( sts & STS$M_SUCCESS ) ? sector : 0 ;
|
|
}
|
|
return sts;
|
|
}
|
|
|
|
/************************************************************** phy_putsect() */
|
|
|
|
/* Write a physical sector... */
|
|
|
|
static unsigned phy_putsect( struct DEV *dev, unsigned sector ) {
|
|
|
|
register unsigned sts;
|
|
|
|
sts = SS$_NORMAL;
|
|
dev->last_sector = sector;
|
|
#ifdef USE_ASPI
|
|
if ( DEV_USES_ASPI( dev ) ) {
|
|
sts = aspi_write( dev->API.ASPI.bus, dev->API.ASPI.id,
|
|
sector, dev->bytespersector, dev->IoBuffer );
|
|
} else
|
|
#endif
|
|
{
|
|
if ( dev->access & MOU_VIRTUAL || is_NT ) {
|
|
DWORD BytesWritten;
|
|
__int64 distance;
|
|
LARGE_INTEGER li;
|
|
distance = (((__int64)sector) * dev->blockspersector) << 9;
|
|
li.QuadPart = distance;
|
|
if( SetFilePointer( dev->API.Win32.handle,/* hFile */
|
|
li.LowPart, /* lDistanceToMove */
|
|
&li.HighPart, /* lpDistanceToMoveHigh */
|
|
FILE_BEGIN /* dwMoveMethod */
|
|
) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ) {
|
|
TCHAR *msg = w32_errstr(NO_ERROR);
|
|
printf( "PHYIO_WRITE: SetFilePointer() failed at sector %lu: %s\n",
|
|
sector, msg );
|
|
LocalFree(msg);
|
|
sts = SS$_PARITY;
|
|
}
|
|
if ( sts & STS$M_SUCCESS ) {
|
|
if ( !WriteFile( dev->API.Win32.handle, /* hFile */
|
|
dev->IoBuffer, /* lpBuffer */
|
|
/* nNumberOfBytesToWrite */
|
|
dev->bytespersector,
|
|
&BytesWritten, /* lpNumberOfBytesWritten */
|
|
NULL /* lpOverlapped */
|
|
) || BytesWritten != dev->bytespersector ) {
|
|
TCHAR *msg = w32_errstr(NO_ERROR);
|
|
printf( "PHYIO_WRITE: WriteFile() failed at sector %lu: %s\n",
|
|
sector, msg );
|
|
LocalFree(msg);
|
|
sts = SS$_PARITY;
|
|
}
|
|
}
|
|
} else {
|
|
DIOC_REGISTERS reg = { 0 }; /* Win9X DIOC registers */
|
|
DISKIO dio;
|
|
BOOL result;
|
|
DWORD cb = 0;
|
|
dio.dwStartSector = sector; /* sector number */
|
|
dio.wSectors = 1; /* sector count */
|
|
dio.dwBuffer = (DWORD) dev->IoBuffer; /* sector buffer */
|
|
reg.reg_EAX = 0x7305; /* Ext_ABSDiskReadWrite */
|
|
reg.reg_EBX = (DWORD) &dio; /* parameter block */
|
|
reg.reg_ECX = -1; /* use dio */
|
|
reg.reg_EDX = dev->drive + 1; /* 0=default, 1=A, ... */
|
|
reg.reg_EDI = 0;
|
|
reg.reg_ESI = 0x1; /* write */
|
|
reg.reg_Flags = 0x0001; /* Set carry flag */
|
|
result =
|
|
DeviceIoControl( dev->API.Win32.handle, /* hDevice */
|
|
VWIN32_DIOC_DOS_DRIVEINFO,/* dwIoControlCode */
|
|
®, /* lpInBuffer */
|
|
sizeof( reg ), /* nInBufferSize */
|
|
®, /* lpOutBuffer */
|
|
sizeof( reg ), /* nOutBufferSize */
|
|
&cb, /* lpBytesReturned */
|
|
NULL /* lpOverlapped */
|
|
) && !( reg.reg_Flags & 0x0001 );
|
|
if ( !result ) {
|
|
TCHAR *msg = w32_errstr(NO_ERROR);
|
|
printf( "PHYIO_WRITE: Write sector %d failed: %s\n",
|
|
sector, msg );
|
|
LocalFree(msg);
|
|
sts = SS$_PARITY;
|
|
}
|
|
}
|
|
}
|
|
return sts;
|
|
}
|
|
|
|
/*************************************************************** phyio_show() */
|
|
|
|
void phyio_show( showtype_t type ) {
|
|
|
|
switch( type ) {
|
|
case SHOW_STATS:
|
|
printf( "PHYIO_SHOW Initializations: %d Reads: %d Writes: %d\n",
|
|
init_count, read_count, write_count );
|
|
return;
|
|
case SHOW_FILE64:
|
|
printf( "Large ODS-2 image files (>2GB) are %ssupported.\n", "" );
|
|
return;
|
|
case SHOW_DEVICES: {
|
|
TCHAR *namep = NULL, *dname = NULL;
|
|
TCHAR devname[sizeof("Z:")];
|
|
int n = 0;
|
|
TCHAR l;
|
|
|
|
for( l = 'A'; l <= 'Z'; l++ ) {
|
|
snprintf( devname, sizeof( devname ), "%c:", l );
|
|
dname = namep = driveFromLetter( devname );
|
|
if( namep != NULL ) {
|
|
const char *type = NULL;
|
|
#define WINDEVPFX "\\Device\\"
|
|
if( strncmp( dname, WINDEVPFX, sizeof(WINDEVPFX)-1 ) == 0 )
|
|
dname += sizeof( WINDEVPFX ) -1;
|
|
#undef WINDEVPFX
|
|
if( !n++ )
|
|
printf( " Physical devices\n"
|
|
" Drv Type PhysicalName\n"
|
|
" --- --------- ------------\n" );
|
|
printf( " %s ", devname );
|
|
switch( GetDriveType( devname ) ) {
|
|
case DRIVE_REMOVABLE:
|
|
type = "Removable"; break;
|
|
case DRIVE_FIXED:
|
|
type = "Fixed"; break;
|
|
case DRIVE_REMOTE:
|
|
type = "Network";
|
|
dname = NULL; break;
|
|
case DRIVE_CDROM:
|
|
type = "CDROM"; break;
|
|
case DRIVE_RAMDISK:
|
|
type = "RAMdisk"; break;
|
|
default:
|
|
type = "Other";
|
|
dname = NULL; break;
|
|
}
|
|
printf( "%-9s %s\n", type, (dname? dname: "") );
|
|
free(namep);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
|
|
/*************************************************************** phyio_help() */
|
|
|
|
void phyio_help(FILE *fp ) {
|
|
fprintf( fp, " mount D:\n" );
|
|
fprintf( fp, "Any drive letter mapped to a physical drive can be used\n" );
|
|
#ifdef USE_ASPI
|
|
fprintf( fp, "If the drive letter is C: or higher, commands are\n" );
|
|
fprintf( fp, "sent directly to the drive, bypassing system drivers.\n" );
|
|
fprintf( fp, "The drive must be a SCSI device\n" );
|
|
#endif
|
|
fprintf( fp, "The drive is accessed as a physical device, which may require privileges.\n" );
|
|
fprintf( fp, "For a list of devices, see SHOW DEVICES\n\n" );
|
|
return;
|
|
}
|
|
|
|
/*************************************************************** phyio_path() */
|
|
|
|
char *phyio_path( const char *filnam ) {
|
|
|
|
size_t n;
|
|
char *path, resultant_path[MAX_PATH];
|
|
|
|
if ( filnam == NULL || strpbrk( filnam, "*?" ) != NULL ||
|
|
!PathSearchAndQualify( filnam, /* pcszPath */
|
|
resultant_path, /* pszFullyQualifiedPath */
|
|
/* cchFullyQualifiedPath */
|
|
sizeof( resultant_path )
|
|
) ) {
|
|
return NULL;
|
|
}
|
|
n = strlen( resultant_path );
|
|
path = (char *) malloc( n + 1 );
|
|
if ( path != NULL ) {
|
|
memcpy( path, resultant_path, n + 1 );
|
|
}
|
|
return path;
|
|
}
|
|
|
|
/*************************************************************** phyio_init() */
|
|
|
|
/* Initialize device by opening it, locking it and getting it ready.. */
|
|
|
|
unsigned phyio_init( struct DEV *dev ) {
|
|
const char *virtual;
|
|
|
|
if ( is_NT > 1 ) {
|
|
getsysversion();
|
|
}
|
|
|
|
init_count++;
|
|
|
|
dev->access &= ~MOU_VIRTUAL;
|
|
dev->API.Win32.handle = INVALID_HANDLE_VALUE;
|
|
dev->drive = -1;
|
|
dev->sectors = 0;
|
|
dev->bytespersector = 0;
|
|
dev->blockspersector = 0;
|
|
dev->last_sector = 0;
|
|
dev->IoBuffer = NULL;
|
|
|
|
virtual = virt_lookup( dev->devnam );
|
|
if ( virtual == NULL ) {
|
|
if ( strlen( dev->devnam ) != 2 ||
|
|
!isalpha( dev->devnam[0] ) || dev->devnam[1] != ':' ) {
|
|
return SS$_IVDEVNAM;
|
|
}
|
|
dev->drive = toupper( dev->devnam[0] ) - 'A';
|
|
|
|
/* Use ASPI for devices past C... */
|
|
|
|
#ifdef USE_ASPI
|
|
if ( DEV_USES_ASPI( dev ) ) {
|
|
dev->API.ASPI.dtype = -1;
|
|
dev->API.ASPI.bus = -1;
|
|
dev->API.ASPI.id = -1;
|
|
sts = aspi_initialize( &dev->API.ASPI.dtype, &dev->API.ASPI.bus,
|
|
&dev->API.ASPI.id );
|
|
if ( !( sts & STS$M_SUCCESS ) ) {
|
|
return sts;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
|
|
/* WinNT stuff */
|
|
|
|
if ( is_NT ) {
|
|
char ntname[7] = "\\\\.\\"; /* 7 = sizeof \\.\a:\0 */
|
|
memcpy( ntname+4, dev->devnam, 3 ); /* Copy a:\0 */
|
|
ntname[4] = toupper( ntname[4] );
|
|
dev->API.Win32.handle =
|
|
CreateFile( ntname, /* lpFileName */
|
|
GENERIC_READ | /* dwDesiredAccess */
|
|
( dev->access & MOU_WRITE ? GENERIC_WRITE : 0 ),
|
|
/* dwShareMode */
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, /* lpSecurityAttributes */
|
|
OPEN_EXISTING, /* dwCreationDisposition */
|
|
/* dwFlagsAndAttributes */
|
|
FILE_FLAG_NO_BUFFERING,
|
|
NULL /* hTemplateFile */
|
|
);
|
|
if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE &&
|
|
dev->access & MOU_WRITE ) {
|
|
dev->access &= ~MOU_WRITE;
|
|
dev->API.Win32.handle =
|
|
CreateFile( ntname, /* lpFileName */
|
|
GENERIC_READ, /* dwDesiredAccess */
|
|
/* dwShareMode */
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, /* lpSecurityAttributes */
|
|
OPEN_EXISTING, /* dwCreationDisposition */
|
|
/* dwFlagsAndAttributes */
|
|
FILE_FLAG_NO_BUFFERING,
|
|
NULL /* hTemplateFile */
|
|
);
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Win9X stuff */
|
|
|
|
dev->API.Win32.handle =
|
|
CreateFile( "\\\\.\\vwin32", /* lpFileName */
|
|
0, /* dwDesiredAccess */
|
|
0, /* dwShareMode */
|
|
NULL, /* lpSecurityAttributes */
|
|
0, /* dwCreationDisposition */
|
|
/* dwFlagsAnd Attributes */
|
|
FILE_FLAG_DELETE_ON_CLOSE,
|
|
NULL /* hTemplateFile */
|
|
);
|
|
}
|
|
if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE ) {
|
|
TCHAR *msg = w32_errstr(NO_ERROR);
|
|
printf( "PHYIO_INIT: Open( \"%s\" ) failed: %s\n",
|
|
dev->devnam, msg );
|
|
LocalFree(msg);
|
|
return SS$_NOSUCHDEV;
|
|
}
|
|
if ( !LockVolume( dev ) ) {
|
|
TCHAR *msg = w32_errstr(NO_ERROR);
|
|
printf( "PHYIO_INIT: LockVolume( \"%s\" ) failed: %s\n",
|
|
dev->devnam, msg );
|
|
LocalFree(msg);
|
|
phyio_done( dev );
|
|
return SS$_DEVNOTALLOC;
|
|
}
|
|
}
|
|
if ( !GetDiskGeometry( dev, &dev->sectors, &dev->bytespersector ) ) {
|
|
TCHAR *msg = w32_errstr(NO_ERROR);
|
|
printf( "PHYIO_INIT: GetDiskGeometry( \"%s\" ) failed: %s\n",
|
|
dev->devnam, msg );
|
|
LocalFree(msg);
|
|
phyio_done( dev );
|
|
return 80;
|
|
}
|
|
dev->blockspersector = dev->bytespersector / 512;
|
|
} else { /* Virtual device */
|
|
DWORD FileSizeLow, FileSizeHigh;
|
|
dev->access |= MOU_VIRTUAL;
|
|
dev->API.Win32.handle =
|
|
CreateFile( virtual, /* lpFileName */
|
|
GENERIC_READ | /* dwDesiredAccess */
|
|
( dev->access & MOU_WRITE ? GENERIC_WRITE : 0 ),
|
|
0, /* dwShareMode */
|
|
NULL, /* lpSecurityAttributes */
|
|
OPEN_EXISTING, /* dwCreationDisposition */
|
|
/* dwFlagsAndAttributes */
|
|
FILE_FLAG_RANDOM_ACCESS |
|
|
( dev->access & MOU_WRITE ?
|
|
FILE_FLAG_WRITE_THROUGH : 0 ),
|
|
NULL /* hTemplateFile */
|
|
);
|
|
if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE &&
|
|
dev->access & MOU_WRITE ) {
|
|
dev->access &= ~MOU_WRITE;
|
|
dev->API.Win32.handle =
|
|
CreateFile( virtual, /* lpFileName */
|
|
GENERIC_READ, /* dwDesiredAccess */
|
|
0, /* dwShareMode */
|
|
NULL, /* lpSecurityAttributes */
|
|
OPEN_EXISTING, /* dwCreationDisposition */
|
|
/* dwFlagsAndAttributes */
|
|
FILE_FLAG_RANDOM_ACCESS,
|
|
NULL /* hTemplateFile */
|
|
);
|
|
}
|
|
if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE ) {
|
|
TCHAR *msg = w32_errstr(NO_ERROR);
|
|
printf( "PHYIO_INIT: CreateFile() failed for %s: %s\n",
|
|
virtual, msg );
|
|
LocalFree(msg);
|
|
return SS$_NOSUCHFILE;
|
|
}
|
|
SetLastError( 0 );
|
|
FileSizeLow = GetFileSize( dev->API.Win32.handle, /* hFile */
|
|
&FileSizeHigh /* lpFileSizeHigh */
|
|
);
|
|
if ( GetLastError() == NO_ERROR ) {
|
|
dev->sectors = ( FileSizeHigh << 23 ) |
|
|
( ( ( FileSizeLow + 511 ) >> 9 ) & 0x007FFFFF ) ;
|
|
dev->bytespersector = 512;
|
|
dev->blockspersector = 1;
|
|
}
|
|
}
|
|
dev->IoBuffer = VirtualAlloc( NULL, /* lpAddress */
|
|
dev->bytespersector, /* dwSize */
|
|
MEM_COMMIT, /* flAllocationType */
|
|
PAGE_READWRITE /* flProtect */
|
|
);
|
|
if ( dev->IoBuffer == NULL ) {
|
|
phyio_done( dev );
|
|
return SS$_INSFMEM;
|
|
}
|
|
#ifdef DEBUG
|
|
printf( "--->phyio_init(): sectors = %u, bytespersector = %u\n",
|
|
dev->sectors, dev->bytespersector );
|
|
#endif
|
|
return SS$_NORMAL;
|
|
}
|
|
|
|
/*************************************************************** phyio_done() */
|
|
|
|
unsigned phyio_done( struct DEV *dev ) {
|
|
|
|
if ( !DEV_USES_ASPI( dev ) &&
|
|
dev->API.Win32.handle != INVALID_HANDLE_VALUE ) {
|
|
UnlockVolume( dev );
|
|
CloseHandle( dev->API.Win32.handle /* hObject */
|
|
);
|
|
dev->API.Win32.handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
if( dev->access & MOU_VIRTUAL )
|
|
virt_device( dev->devnam, NULL );
|
|
if ( dev->IoBuffer != NULL ) {
|
|
VirtualFree( dev->IoBuffer, /* lpAddress */
|
|
dev->bytespersector, /* dwSize */
|
|
MEM_RELEASE /* dwFreeType */
|
|
);
|
|
dev->IoBuffer = NULL;
|
|
}
|
|
return SS$_NORMAL;
|
|
}
|
|
|
|
/*************************************************************** phyio_read() */
|
|
|
|
/* Handle a read request ... need to read the approriate sectors to
|
|
complete the request... */
|
|
|
|
unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
|
|
char *buffer ) {
|
|
|
|
register unsigned sts, transfer, sectno, offset;
|
|
char *sectbuff;
|
|
|
|
#ifdef DEBUG
|
|
printf( "Phyio read block: %d into %x (%d bytes)\n",
|
|
block, buffer, length );
|
|
#endif
|
|
|
|
sts = SS$_NORMAL;
|
|
read_count++;
|
|
sectno = block / dev->blockspersector;
|
|
offset = block % dev->blockspersector;
|
|
sectbuff = dev->IoBuffer;
|
|
while ( length > 0 ) {
|
|
transfer = ( dev->blockspersector - offset ) * 512;
|
|
if ( transfer > length ) {
|
|
transfer = length;
|
|
}
|
|
sts = phy_getsect( dev, sectno );
|
|
if ( !( sts & STS$M_SUCCESS ) ) {
|
|
break;
|
|
}
|
|
memcpy( buffer, sectbuff + ( offset * 512 ), transfer );
|
|
buffer += transfer;
|
|
length -= transfer;
|
|
sectno++;
|
|
offset = 0;
|
|
}
|
|
if ( !( sts & STS$M_SUCCESS ) ) {
|
|
printf( "PHYIO_READ Error %s Block %d Length %d",
|
|
getmsg(sts, MSG_TEXT), block, length );
|
|
#ifdef USE_ASPI
|
|
printf( " (ASPI: %x %x %x)",
|
|
ASPI_status, ASPI_HaStat, ASPI_TargStat );
|
|
#endif
|
|
printf( "\n" );
|
|
}
|
|
return sts;
|
|
}
|
|
|
|
/************************************************************** phyio_write() */
|
|
|
|
/* Handle a write request ... need to read the approriate sectors to
|
|
complete the request... */
|
|
|
|
unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
|
|
const char *buffer) {
|
|
|
|
register unsigned sts, transfer, sectno, offset;
|
|
char *sectbuff;
|
|
|
|
#ifdef DEBUG
|
|
printf( "Phyio write block: %d from %x (%d bytes)\n",
|
|
block, buffer, length );
|
|
#endif
|
|
|
|
sts = SS$_NORMAL;
|
|
write_count++;
|
|
sectno = block / dev->blockspersector;
|
|
offset = block % dev->blockspersector;
|
|
sectbuff = dev->IoBuffer;
|
|
while ( length > 0 ) {
|
|
transfer = ( dev->blockspersector - offset ) * 512;
|
|
if ( transfer > length ) {
|
|
transfer = length;
|
|
}
|
|
if ( transfer != dev->blockspersector * 512 ) {
|
|
sts = phy_getsect( dev, sectno );
|
|
if ( !( sts & STS$M_SUCCESS ) ) {
|
|
break;
|
|
}
|
|
}
|
|
memcpy( sectbuff + ( offset * 512 ), buffer, transfer );
|
|
sts = phy_putsect( dev, sectno );
|
|
if ( !( sts & STS$M_SUCCESS ) ) {
|
|
break;
|
|
}
|
|
buffer += transfer;
|
|
length -= transfer;
|
|
sectno++;
|
|
offset = 0;
|
|
}
|
|
if ( !( sts & STS$M_SUCCESS ) ) {
|
|
printf( "PHYIO_WRITE Error %d Block %d Length %d",
|
|
sts, block, length );
|
|
#ifdef USE_ASPI
|
|
printf( " (ASPI: %x %x %x)",
|
|
ASPI_status, ASPI_HaStat, ASPI_TargStat );
|
|
#endif
|
|
printf( "\n" );
|
|
}
|
|
return sts;
|
|
}
|