2000-03-08 20:41:49 +01:00
/**************************************************************************
2002-03-10 00:29:33 +01:00
* ASPI routines
* Copyright ( C ) 2000 David Elliott < dfe @ infinite - internet . net >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2000-03-08 20:41:49 +01:00
/* These routines are to be called from either WNASPI32 or WINASPI */
/* FIXME:
* - Registry format is stupid for now . . fix that later
* - No way to override automatic / proc detection , maybe provide an
* HKEY_LOCAL_MACHINE \ Software \ Wine \ Wine \ Scsi regkey
* - Somewhat debating an # ifdef linux . . . technically all this code will
* run on another UNIX . . it will fail nicely .
* - Please add support for mapping multiple channels on host adapters to
* aspi controllers , e - mail me if you need help .
*/
/*
Registry format is currently :
HKEY_DYN_DATA
WineScsi
( default ) = number of host adapters
hHHcCCtTTdDD = linux device name
*/
2002-05-21 20:33:56 +02:00
# include "config.h"
2000-03-08 20:41:49 +01:00
# include <stdio.h>
2003-08-22 07:05:56 +02:00
# include <stdarg.h>
2000-03-08 20:41:49 +01:00
# include <sys/types.h>
2002-06-01 01:06:46 +02:00
# ifdef HAVE_SYS_IOCTL_H
2000-03-08 20:41:49 +01:00
# include <sys/ioctl.h>
2002-05-21 20:33:56 +02:00
# endif
2000-03-08 20:41:49 +01:00
# include <fcntl.h>
2000-09-06 21:42:19 +02:00
# include <dirent.h>
2002-08-17 02:43:16 +02:00
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
2000-03-08 20:41:49 +01:00
# include <errno.h>
2001-01-22 03:17:29 +01:00
# include <string.h>
2000-03-08 20:41:49 +01:00
2003-08-22 07:05:56 +02:00
# include "windef.h"
# include "winbase.h"
2000-03-08 20:41:49 +01:00
# include "winreg.h"
# include "winerror.h"
# include "winescsi.h"
2003-08-22 07:05:56 +02:00
# include "wine/debug.h"
2002-03-10 00:29:33 +01:00
WINE_DEFAULT_DEBUG_CHANNEL ( aspi ) ;
2000-03-08 20:41:49 +01:00
/* Internal function prototypes */
static void
2004-12-13 22:19:01 +01:00
SCSI_GetProcinfo ( void ) ;
2000-03-08 20:41:49 +01:00
2000-07-15 23:33:38 +02:00
# ifdef linux
2000-07-08 13:44:48 +02:00
static void
2004-12-13 22:19:01 +01:00
SCSI_MapHCtoController ( void ) ;
2000-07-15 23:33:38 +02:00
# endif
2000-07-08 13:44:48 +02:00
2000-11-30 02:17:55 +01:00
static void set_last_error ( void )
{
int save_errno = errno ; /* errno gets overwritten by printf */
switch ( errno )
{
case EAGAIN :
SetLastError ( ERROR_SHARING_VIOLATION ) ;
break ;
case EBADF :
SetLastError ( ERROR_INVALID_HANDLE ) ;
break ;
case ENOSPC :
SetLastError ( ERROR_HANDLE_DISK_FULL ) ;
break ;
case EACCES :
case EPERM :
case EROFS :
SetLastError ( ERROR_ACCESS_DENIED ) ;
break ;
case EBUSY :
SetLastError ( ERROR_LOCK_VIOLATION ) ;
break ;
case ENOENT :
SetLastError ( ERROR_FILE_NOT_FOUND ) ;
break ;
case EISDIR :
SetLastError ( ERROR_CANNOT_MAKE ) ;
break ;
case ENFILE :
case EMFILE :
SetLastError ( ERROR_NO_MORE_FILES ) ;
break ;
case EEXIST :
SetLastError ( ERROR_FILE_EXISTS ) ;
break ;
case EINVAL :
case ESPIPE :
SetLastError ( ERROR_SEEK ) ;
break ;
case ENOTEMPTY :
SetLastError ( ERROR_DIR_NOT_EMPTY ) ;
break ;
case ENOEXEC :
SetLastError ( ERROR_BAD_FORMAT ) ;
break ;
default :
2001-05-09 19:31:31 +02:00
WARN ( " unknown file error: %s \n " , strerror ( save_errno ) ) ;
2000-11-30 02:17:55 +01:00
SetLastError ( ERROR_GEN_FAILURE ) ;
break ;
}
errno = save_errno ;
}
2000-03-08 20:41:49 +01:00
/* Exported functions */
void
SCSI_Init ( )
{
/* For now we just call SCSI_GetProcinfo */
SCSI_GetProcinfo ( ) ;
2000-07-15 23:33:38 +02:00
# ifdef linux
2000-07-08 13:44:48 +02:00
SCSI_MapHCtoController ( ) ;
2000-07-15 23:33:38 +02:00
# endif
2000-03-08 20:41:49 +01:00
}
int
ASPI_GetNumControllers ( )
{
HKEY hkeyScsi ;
2000-07-08 13:44:48 +02:00
HKEY hkeyControllerMap ;
DWORD error ;
2000-03-08 20:41:49 +01:00
DWORD type = REG_DWORD ;
DWORD num_ha = 0 ;
DWORD cbData = sizeof ( num_ha ) ;
if ( RegOpenKeyExA ( HKEY_DYN_DATA , KEYNAME_SCSI , 0 , KEY_ALL_ACCESS , & hkeyScsi ) ! = ERROR_SUCCESS )
{
2000-09-06 21:42:19 +02:00
ERR ( " Could not open HKEY_DYN_DATA \\ %s \n " , KEYNAME_SCSI ) ;
2000-03-08 20:41:49 +01:00
return 0 ;
}
2000-07-08 13:44:48 +02:00
if ( ( error = RegOpenKeyExA ( hkeyScsi , KEYNAME_SCSI_CONTROLLERMAP , 0 , KEY_ALL_ACCESS , & hkeyControllerMap ) ) ! = ERROR_SUCCESS )
{
ERR ( " Could not open HKEY_DYN_DATA \\ %s \\ %s \n " , KEYNAME_SCSI , KEYNAME_SCSI_CONTROLLERMAP ) ;
RegCloseKey ( hkeyScsi ) ;
SetLastError ( error ) ;
return 0 ;
}
if ( RegQueryValueExA ( hkeyControllerMap , NULL , NULL , & type , ( LPBYTE ) & num_ha , & cbData ) ! = ERROR_SUCCESS )
2000-03-08 20:41:49 +01:00
{
2000-09-06 21:42:19 +02:00
ERR ( " Could not query value HKEY_DYN_DATA \\ %s \n " , KEYNAME_SCSI ) ;
2000-03-08 20:41:49 +01:00
num_ha = 0 ;
}
2000-07-08 13:44:48 +02:00
RegCloseKey ( hkeyControllerMap ) ;
2000-03-08 20:41:49 +01:00
RegCloseKey ( hkeyScsi ) ;
TRACE ( " Returning %ld host adapters \n " , num_ha ) ;
return num_ha ;
}
BOOL
SCSI_GetDeviceName ( int h , int c , int t , int d , LPSTR devstr , LPDWORD lpcbData )
{
char idstr [ 20 ] ;
HKEY hkeyScsi ;
DWORD type ;
if ( RegOpenKeyExA ( HKEY_DYN_DATA , KEYNAME_SCSI , 0 , KEY_ALL_ACCESS , & hkeyScsi ) ! = ERROR_SUCCESS )
{
2000-09-06 21:42:19 +02:00
ERR ( " Could not open HKEY_DYN_DATA \\ %s \n " , KEYNAME_SCSI ) ;
2000-03-08 20:41:49 +01:00
return FALSE ;
}
sprintf ( idstr , " h%02dc%02dt%02dd%02d " , h , c , t , d ) ;
if ( RegQueryValueExA ( hkeyScsi , idstr , NULL , & type , devstr , lpcbData ) ! = ERROR_SUCCESS )
{
WARN ( " Could not query value HKEY_DYN_DATA \\ %s \\ %s \n " , KEYNAME_SCSI , idstr ) ;
RegCloseKey ( hkeyScsi ) ;
return FALSE ;
}
RegCloseKey ( hkeyScsi ) ;
TRACE ( " scsi %s: Device name: %s \n " , idstr , devstr ) ;
return TRUE ;
}
/* SCSI_GetHCforController
* RETURNS
* HIWORD : Host Adapter
* LOWORD : Channel
*/
DWORD
ASPI_GetHCforController ( int controller )
{
2000-07-08 13:44:48 +02:00
DWORD hc = 0xFFFFFFFF ;
char cstr [ 20 ] ;
DWORD error ;
HKEY hkeyScsi ;
HKEY hkeyControllerMap ;
DWORD type = REG_DWORD ;
DWORD cbData = sizeof ( DWORD ) ;
DWORD disposition ;
#if 0
2000-03-08 20:41:49 +01:00
FIXME ( " Please fix to map each channel of each host adapter to the proper ASPI controller number! \n " ) ;
2000-07-08 13:44:48 +02:00
hc = ( controller < < 16 ) ;
return hc ;
# endif
if ( ( error = RegCreateKeyExA ( HKEY_DYN_DATA , KEYNAME_SCSI , 0 , NULL , REG_OPTION_VOLATILE , KEY_ALL_ACCESS , NULL , & hkeyScsi , & disposition ) ) ! = ERROR_SUCCESS )
{
2000-09-06 21:42:19 +02:00
ERR ( " Could not open HKEY_DYN_DATA \\ %s \n " , KEYNAME_SCSI ) ;
2000-07-08 13:44:48 +02:00
SetLastError ( error ) ;
return hc ;
}
if ( disposition ! = REG_OPENED_EXISTING_KEY )
{
WARN ( " Created HKEY_DYN_DATA \\ %s \n " , KEYNAME_SCSI ) ;
}
if ( ( error = RegCreateKeyExA ( hkeyScsi , KEYNAME_SCSI_CONTROLLERMAP , 0 , NULL , REG_OPTION_VOLATILE , KEY_ALL_ACCESS , NULL , & hkeyControllerMap , & disposition ) ) ! = ERROR_SUCCESS )
{
ERR ( " Could not open HKEY_DYN_DATA \\ %s \\ %s \n " , KEYNAME_SCSI , KEYNAME_SCSI_CONTROLLERMAP ) ;
RegCloseKey ( hkeyScsi ) ;
SetLastError ( error ) ;
return hc ;
}
if ( disposition ! = REG_OPENED_EXISTING_KEY )
{
WARN ( " Created HKEY_DYN_DATA \\ %s \\ %s \n " , KEYNAME_SCSI , KEYNAME_SCSI_CONTROLLERMAP ) ;
}
sprintf ( cstr , " c%02d " , controller ) ;
if ( ( error = RegQueryValueExA ( hkeyControllerMap , cstr , 0 , & type , ( LPBYTE ) & hc , & cbData ) ) ! = ERROR_SUCCESS )
{
ERR ( " Could not open HKEY_DYN_DATA \\ %s \\ %s \\ %s, error=%lx \n " , KEYNAME_SCSI , KEYNAME_SCSI_CONTROLLERMAP , cstr , error ) ;
SetLastError ( error ) ;
}
RegCloseKey ( hkeyControllerMap ) ;
RegCloseKey ( hkeyScsi ) ;
return hc ;
2000-03-08 20:41:49 +01:00
} ;
int
SCSI_OpenDevice ( int h , int c , int t , int d )
{
char devstr [ 20 ] ;
DWORD cbData = 20 ;
int fd = - 1 ;
2000-09-06 21:42:19 +02:00
char dainbread_linux_hack = 1 ;
2000-03-08 20:41:49 +01:00
if ( ! SCSI_GetDeviceName ( h , c , t , d , devstr , & cbData ) )
{
WARN ( " Could not get device name for h%02dc%02dt%02dd%02d \n " , h , c , t , d ) ;
return - 1 ;
}
2000-09-06 21:42:19 +02:00
linux_hack :
2000-03-08 20:41:49 +01:00
TRACE ( " Opening device %s mode O_RDWR \n " , devstr ) ;
fd = open ( devstr , O_RDWR ) ;
if ( fd < 0 )
{
2000-09-06 21:42:19 +02:00
int len = strlen ( devstr ) ;
2000-11-30 02:17:55 +01:00
set_last_error ( ) ; /* SetLastError() to errno */
2000-09-06 21:42:19 +02:00
TRACE ( " Open failed (%s) \n " , strerror ( errno ) ) ;
/* in case of "/dev/sgX", convert from sga to sg0
* and the other way around .
* FIXME : remove it if the distributions
* finally manage to agree on something .
* The best would probably be a complete
* rewrite of the Linux SCSI layer
* to use CAM + devfs : - ) */
if ( ( dainbread_linux_hack ) & &
( len > = 3 ) & &
( devstr [ len - 3 ] = = ' s ' ) & & ( devstr [ len - 2 ] = = ' g ' ) )
{
char * p = & devstr [ len - 1 ] ;
* p = ( * p > = ' a ' ) ? * p - ' a ' + ' 0 ' : * p - ' 0 ' + ' a ' ;
dainbread_linux_hack = 0 ;
TRACE ( " Retry with \" equivalent \" Linux device '%s' \n " , devstr ) ;
goto linux_hack ;
}
2000-03-08 20:41:49 +01:00
}
return fd ;
}
2000-03-12 21:19:23 +01:00
# ifdef linux
2000-07-15 17:15:31 +02:00
/* SCSI_Fix_CMD_LEN
* Checks to make sure the CMD_LEN is correct
*/
void
SCSI_Fix_CMD_LEN ( int fd , int cmd , int len )
{
2003-11-09 01:31:08 +01:00
/* This is what the linux kernel thinks.... */
static const unsigned char scsi_command_size [ 8 ] =
{
6 , 10 , 10 , 12 ,
12 , 12 , 10 , 10
} ;
2000-07-15 17:15:31 +02:00
int index = ( cmd > > 5 ) & 7 ;
if ( len ! = scsi_command_size [ index ] )
{
TRACE ( " CDBLen for command %d claims to be %d, expected %d \n " ,
cmd , len , scsi_command_size [ index ] ) ;
ioctl ( fd , SG_NEXT_CMD_LEN , & len ) ;
}
}
2000-03-08 20:41:49 +01:00
int
SCSI_LinuxSetTimeout ( int fd , int timeout )
{
int retval ;
TRACE ( " Setting timeout to %d jiffies \n " , timeout ) ;
retval = ioctl ( fd , SG_SET_TIMEOUT , & timeout ) ;
if ( retval )
{
2000-09-06 21:42:19 +02:00
WARN ( " Could not set timeout ! (%s) \n " , strerror ( errno ) ) ;
2000-03-08 20:41:49 +01:00
}
return retval ;
2002-06-01 01:06:46 +02:00
2000-03-08 20:41:49 +01:00
}
/* This function takes care of the write/read to the linux sg device.
2000-11-30 02:17:55 +01:00
* It returns TRUE or FALSE and uses set_last_error ( ) to convert
2000-03-08 20:41:49 +01:00
* UNIX errno to Windows GetLastError ( ) . The reason for that is that
* several programs will check that error and we might as well set
* it here . We also return the value of the read call in
* lpcbBytesReturned .
*/
BOOL /* NOTE: This function SHOULD BLOCK */
SCSI_LinuxDeviceIo ( int fd ,
struct sg_header * lpInBuffer , DWORD cbInBuffer ,
struct sg_header * lpOutBuffer , DWORD cbOutBuffer ,
LPDWORD lpcbBytesReturned )
{
DWORD dwBytes ;
DWORD save_error ;
2000-09-06 21:42:19 +02:00
TRACE ( " Writing to Linux sg device \n " ) ;
2000-03-08 20:41:49 +01:00
dwBytes = write ( fd , lpInBuffer , cbInBuffer ) ;
if ( dwBytes ! = cbInBuffer )
{
2000-11-30 02:17:55 +01:00
set_last_error ( ) ;
2000-03-08 20:41:49 +01:00
save_error = GetLastError ( ) ;
WARN ( " Not enough bytes written to scsi device. bytes=%ld .. %ld \n " , cbInBuffer , dwBytes ) ;
2000-11-30 02:17:55 +01:00
/* FIXME: set_last_error() never sets error to ERROR_NOT_ENOUGH_MEMORY... */
2000-03-08 20:41:49 +01:00
if ( save_error = = ERROR_NOT_ENOUGH_MEMORY )
2000-09-06 21:42:19 +02:00
MESSAGE ( " Your Linux kernel was not able to handle the amount of data sent to the scsi device. Try recompiling with a larger SG_BIG_BUFF value (kernel 2.0.x sg.h) " ) ;
2000-03-08 20:41:49 +01:00
WARN ( " error= %ld \n " , save_error ) ;
* lpcbBytesReturned = 0 ;
return FALSE ;
}
2002-06-01 01:06:46 +02:00
2000-03-08 20:41:49 +01:00
TRACE ( " Reading reply from Linux sg device \n " ) ;
* lpcbBytesReturned = read ( fd , lpOutBuffer , cbOutBuffer ) ;
if ( * lpcbBytesReturned ! = cbOutBuffer )
{
2000-11-30 02:17:55 +01:00
set_last_error ( ) ;
2000-03-08 20:41:49 +01:00
save_error = GetLastError ( ) ;
WARN ( " Not enough bytes read from scsi device. bytes=%ld .. %ld \n " , cbOutBuffer , * lpcbBytesReturned ) ;
WARN ( " error= %ld \n " , save_error ) ;
return FALSE ;
}
return TRUE ;
}
/* Internal functions */
struct LinuxProcScsiDevice
{
int host ;
int channel ;
int target ;
int lun ;
char vendor [ 9 ] ;
char model [ 17 ] ;
char rev [ 5 ] ;
char type [ 33 ] ;
int ansirev ;
} ;
2000-11-07 21:26:14 +01:00
/*
* we need to declare white spaces explicitly via % * 1 [ ] ,
* as there are very dainbread CD - ROM devices out there
* which have their manufacturer name blanked out via spaces ,
* which confuses fscanf ' s parsing ( skips all blank spaces )
*/
2000-03-08 20:41:49 +01:00
static int
SCSI_getprocentry ( FILE * procfile , struct LinuxProcScsiDevice * dev )
{
int result ;
result = fscanf ( procfile ,
2000-11-07 21:26:14 +01:00
" Host:%*1[ ]scsi%d%*1[ ]Channel:%*1[ ]%d%*1[ ]Id:%*1[ ]%d%*1[ ]Lun:%*1[ ]%d \n " ,
2000-03-08 20:41:49 +01:00
& dev - > host ,
& dev - > channel ,
& dev - > target ,
& dev - > lun ) ;
if ( result = = EOF )
2000-11-07 21:26:14 +01:00
{
/* "end of entries" return, so no TRACE() here */
2000-03-08 20:41:49 +01:00
return EOF ;
2000-11-07 21:26:14 +01:00
}
2000-03-08 20:41:49 +01:00
if ( result ! = 4 )
2000-11-07 21:26:14 +01:00
{
ERR ( " bus id line scan count error \n " ) ;
2000-03-08 20:41:49 +01:00
return 0 ;
2000-11-07 21:26:14 +01:00
}
2000-03-08 20:41:49 +01:00
result = fscanf ( procfile ,
2000-11-07 21:26:14 +01:00
" Vendor:%*1[ ]%8c%*1[ ]Model:%*1[ ]%16c%*1[ ]Rev:%*1[ ]%4c \n " ,
2000-03-08 20:41:49 +01:00
dev - > vendor ,
dev - > model ,
dev - > rev ) ;
if ( result ! = 3 )
2000-11-07 21:26:14 +01:00
{
ERR ( " model line scan count error \n " ) ;
2000-03-08 20:41:49 +01:00
return 0 ;
2000-11-07 21:26:14 +01:00
}
2000-03-08 20:41:49 +01:00
result = fscanf ( procfile ,
2000-11-07 21:26:14 +01:00
" Type:%*3[ ]%32c%*1[ ]ANSI%*1[ ]SCSI%*1[ ]revision:%*1[ ]%d \n " ,
2000-03-08 20:41:49 +01:00
dev - > type ,
& dev - > ansirev ) ;
if ( result ! = 2 )
2000-11-07 21:26:14 +01:00
{
ERR ( " SCSI type line scan count error \n " ) ;
2000-03-08 20:41:49 +01:00
return 0 ;
2000-11-07 21:26:14 +01:00
}
2000-03-08 20:41:49 +01:00
/* Since we fscanf with %XXc instead of %s.. put a NULL at end */
dev - > vendor [ 8 ] = 0 ;
dev - > model [ 16 ] = 0 ;
dev - > rev [ 4 ] = 0 ;
dev - > type [ 32 ] = 0 ;
return 1 ;
}
static void
SCSI_printprocentry ( const struct LinuxProcScsiDevice * dev )
{
TRACE ( " Host: scsi%d Channel: %02d Id: %02d Lun: %02d \n " ,
dev - > host ,
dev - > channel ,
dev - > target ,
dev - > lun ) ;
TRACE ( " Vendor: %s Model: %s Rev: %s \n " ,
dev - > vendor ,
dev - > model ,
dev - > rev ) ;
TRACE ( " Type: %s ANSI SCSI revision: %02d \n " ,
dev - > type ,
dev - > ansirev ) ;
}
2000-07-08 13:44:48 +02:00
static BOOL
SCSI_PutRegControllerMap ( HKEY hkeyControllerMap , int num_controller , int ha , int chan )
{
DWORD error ;
char cstr [ 20 ] ;
DWORD hc ;
hc = ( ha < < 16 ) + chan ;
sprintf ( cstr , " c%02d " , num_controller ) ;
if ( ( error = RegSetValueExA ( hkeyControllerMap , cstr , 0 , REG_DWORD , ( LPBYTE ) & hc , sizeof ( DWORD ) ) ) ! = ERROR_SUCCESS )
{
ERR ( " Could not create HKEY_DYN_DATA \\ %s \\ %s \\ %s \n " , KEYNAME_SCSI , KEYNAME_SCSI_CONTROLLERMAP , cstr ) ;
}
return error ;
}
static void
SCSI_MapHCtoController ( )
{
HKEY hkeyScsi ;
HKEY hkeyControllerMap ;
DWORD disposition ;
char idstr [ 20 ] ;
2001-01-09 21:52:53 +01:00
DWORD cbIdStr ;
2000-07-08 13:44:48 +02:00
int i = 0 ;
DWORD type = 0 ;
DWORD error ;
DWORD num_controller = 0 ;
int last_ha = - 1 ;
int last_chan = - 1 ;
int ha = 0 ;
int chan = 0 ;
if ( RegCreateKeyExA ( HKEY_DYN_DATA , KEYNAME_SCSI , 0 , NULL , REG_OPTION_VOLATILE , KEY_ALL_ACCESS , NULL , & hkeyScsi , & disposition ) ! = ERROR_SUCCESS )
{
2000-09-06 21:42:19 +02:00
ERR ( " Could not open HKEY_DYN_DATA \\ %s \n " , KEYNAME_SCSI ) ;
2000-07-08 13:44:48 +02:00
return ;
}
if ( disposition ! = REG_OPENED_EXISTING_KEY )
{
WARN ( " Created HKEY_DYN_DATA \\ %s \n " , KEYNAME_SCSI ) ;
}
if ( RegCreateKeyExA ( hkeyScsi , KEYNAME_SCSI_CONTROLLERMAP , 0 , NULL , REG_OPTION_VOLATILE , KEY_ALL_ACCESS , NULL , & hkeyControllerMap , & disposition ) ! = ERROR_SUCCESS )
{
ERR ( " Could not create HKEY_DYN_DATA \\ %s \\ %s \n " , KEYNAME_SCSI , KEYNAME_SCSI_CONTROLLERMAP ) ;
RegCloseKey ( hkeyScsi ) ;
return ;
}
2002-06-01 01:06:46 +02:00
2001-01-09 21:52:53 +01:00
for ( i = 0 ; cbIdStr = sizeof ( idstr ) , ( error = RegEnumValueA ( hkeyScsi , i , idstr , & cbIdStr , NULL , & type , NULL , NULL ) ) = = ERROR_SUCCESS ; i + + )
2000-07-08 13:44:48 +02:00
{
2001-01-09 21:52:53 +01:00
if ( idstr [ 0 ] = = ' \0 ' ) continue ; /* skip the default value */
if ( sscanf ( idstr , " h%02dc%02dt%*02dd%*02d " , & ha , & chan ) ! = 2 ) {
ERR ( " incorrect reg. value %s \n " , debugstr_a ( idstr ) ) ;
continue ;
}
2000-07-08 13:44:48 +02:00
if ( last_ha < ha )
{ /* Next HA */
last_ha = ha ;
last_chan = chan ;
SCSI_PutRegControllerMap ( hkeyControllerMap , num_controller , ha , chan ) ;
num_controller + + ;
}
else if ( last_ha > ha )
{
FIXME ( " Expected registry to be sorted \n " ) ;
}
/* last_ha == ha */
else if ( last_chan < chan )
{
last_chan = chan ;
SCSI_PutRegControllerMap ( hkeyControllerMap , num_controller , ha , chan ) ;
num_controller + + ;
}
else if ( last_chan > chan )
{
FIXME ( " Expected registry to be sorted \n " ) ;
}
/* else last_ha == ha && last_chan == chan so do nothing */
}
/* Set (default) value to number of controllers */
if ( RegSetValueExA ( hkeyControllerMap , NULL , 0 , REG_DWORD , ( LPBYTE ) & num_controller , sizeof ( DWORD ) ) ! = ERROR_SUCCESS )
{
2000-09-06 21:42:19 +02:00
ERR ( " Could not set value HKEY_DYN_DATA \\ %s \\ %s \n " , KEYNAME_SCSI , KEYNAME_SCSI_CONTROLLERMAP ) ;
2000-07-08 13:44:48 +02:00
}
RegCloseKey ( hkeyControllerMap ) ;
RegCloseKey ( hkeyScsi ) ;
return ;
}
2000-03-19 13:42:31 +01:00
# endif
2000-03-08 20:41:49 +01:00
2000-09-06 21:42:19 +02:00
int SCSI_Linux_CheckDevices ( void )
{
DIR * devdir ;
struct dirent * dent = NULL ;
devdir = opendir ( " /dev " ) ;
for ( dent = readdir ( devdir ) ; dent ; dent = readdir ( devdir ) )
{
if ( ! ( strncmp ( dent - > d_name , " sg " , 2 ) ) )
break ;
}
closedir ( devdir ) ;
if ( dent = = NULL )
{
2002-02-22 22:21:09 +01:00
TRACE ( " WARNING: You don't have any /dev/sgX generic scsi devices ! \" man MAKEDEV \" ! \n " ) ;
2000-09-06 21:42:19 +02:00
return 0 ;
}
return 1 ;
}
2000-03-08 20:41:49 +01:00
static void
SCSI_GetProcinfo ( )
/* I'll admit, this function is somewhat of a mess... it was originally
* designed to make some sort of linked list then I realized that
* HKEY_DYN_DATA would be a lot less messy
*/
{
2000-03-19 13:42:31 +01:00
# ifdef linux
2000-09-06 21:42:19 +02:00
static const char procname [ ] = " /proc/scsi/scsi " ;
2000-03-08 20:41:49 +01:00
FILE * procfile = NULL ;
2000-09-06 21:42:19 +02:00
char read_line [ 40 ] , read1 [ 10 ] = " \0 " , read2 [ 10 ] = " \0 " ;
2000-03-08 20:41:49 +01:00
int result = 0 ;
struct LinuxProcScsiDevice dev ;
char idstr [ 20 ] ;
char devstr [ 20 ] ;
int devnum = 0 ;
int num_ha = 0 ;
HKEY hkeyScsi ;
DWORD disposition ;
2000-09-06 21:42:19 +02:00
/* Check whether user has generic scsi devices at all */
if ( ! ( SCSI_Linux_CheckDevices ( ) ) )
return ;
2002-06-01 01:06:46 +02:00
2000-09-06 21:42:19 +02:00
procfile = fopen ( procname , " r " ) ;
2000-03-08 20:41:49 +01:00
if ( ! procfile )
{
2000-09-06 21:42:19 +02:00
ERR ( " Could not open %s \n " , procname ) ;
return ;
}
fgets ( read_line , 40 , procfile ) ;
sscanf ( read_line , " Attached %9s %9s " , read1 , read2 ) ;
if ( strcmp ( read1 , " devices: " ) )
{
ERR ( " Incorrect %s format \n " , procname ) ;
2000-03-08 20:41:49 +01:00
return ;
}
2000-09-06 21:42:19 +02:00
if ( ! ( strcmp ( read2 , " none " ) ) )
2000-03-08 20:41:49 +01:00
{
2000-09-06 21:42:19 +02:00
ERR ( " No devices found in %s. Make sure you loaded your SCSI driver or set up ide-scsi emulation for your IDE device if this app needs it ! \n " , procname ) ;
2000-03-08 20:41:49 +01:00
return ;
}
if ( RegCreateKeyExA ( HKEY_DYN_DATA , KEYNAME_SCSI , 0 , NULL , REG_OPTION_VOLATILE , KEY_ALL_ACCESS , NULL , & hkeyScsi , & disposition ) ! = ERROR_SUCCESS )
{
2000-09-06 21:42:19 +02:00
ERR ( " Could not create HKEY_DYN_DATA \\ %s \n " , KEYNAME_SCSI ) ;
2000-03-08 20:41:49 +01:00
return ;
}
/* Read info for one device */
while ( ( result = SCSI_getprocentry ( procfile , & dev ) ) > 0 )
{
/* Add to registry */
sprintf ( idstr , " h%02dc%02dt%02dd%02d " , dev . host , dev . channel , dev . target , dev . lun ) ;
sprintf ( devstr , " /dev/sg%c " , ' a ' + devnum ) ;
if ( RegSetValueExA ( hkeyScsi , idstr , 0 , REG_SZ , devstr , strlen ( devstr ) + 1 ) ! = ERROR_SUCCESS )
{
2000-09-06 21:42:19 +02:00
ERR ( " Could not set value HKEY_DYN_DATA \\ %s \\ %s \n " , KEYNAME_SCSI , idstr ) ;
2000-03-08 20:41:49 +01:00
}
/* Debug output */
SCSI_printprocentry ( & dev ) ;
/* FIXME: We *REALLY* need number of controllers.. not ha */
/* num of hostadapters is highest ha + 1 */
if ( dev . host > = num_ha )
num_ha = dev . host + 1 ;
devnum + + ;
} /* while(1) */
if ( result ! = EOF )
{
2000-09-06 21:42:19 +02:00
ERR ( " Sorry, incorrect %s format \n " , procname ) ;
2000-03-08 20:41:49 +01:00
}
fclose ( procfile ) ;
if ( RegSetValueExA ( hkeyScsi , NULL , 0 , REG_DWORD , ( LPBYTE ) & num_ha , sizeof ( num_ha ) ) ! = ERROR_SUCCESS )
{
2000-09-06 21:42:19 +02:00
ERR ( " Could not set value HKEY_DYN_DATA \\ %s \n " , KEYNAME_SCSI ) ;
2000-03-08 20:41:49 +01:00
}
RegCloseKey ( hkeyScsi ) ;
return ;
2000-03-12 21:19:23 +01:00
# endif
2000-03-19 13:42:31 +01:00
}