2005-04-17 02:20:36 +04:00
/*
* Changes :
* Arnaldo Carvalho de Melo < acme @ conectiva . com . br > 08 / 23 / 2000
* - get rid of some verify_areas and use __copy * user and __get / put_user
* for the ones that remain
*/
# include <linux/module.h>
# include <linux/blkdev.h>
# include <linux/interrupt.h>
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/mm.h>
# include <linux/string.h>
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <scsi/scsi.h>
2006-06-10 20:01:03 +04:00
# include <scsi/scsi_cmnd.h>
2005-04-17 02:20:36 +04:00
# include <scsi/scsi_device.h>
# include <scsi/scsi_eh.h>
# include <scsi/scsi_host.h>
# include <scsi/scsi_ioctl.h>
# include <scsi/sg.h>
# include <scsi/scsi_dbg.h>
# include "scsi_logging.h"
# define NORMAL_RETRIES 5
# define IOCTL_NORMAL_TIMEOUT (10 * HZ)
# define MAX_BUF PAGE_SIZE
2005-09-06 16:03:44 +04:00
/**
* ioctl_probe - - return host identification
* @ host : host to identify
* @ buffer : userspace buffer for identification
*
* Return an identifying string at @ buffer , if @ buffer is non - NULL , filling
* to the length stored at * ( int * ) @ buffer .
2005-04-17 02:20:36 +04:00
*/
static int ioctl_probe ( struct Scsi_Host * host , void __user * buffer )
{
unsigned int len , slen ;
const char * string ;
2005-09-06 16:03:44 +04:00
if ( buffer ) {
2005-04-17 02:20:36 +04:00
if ( get_user ( len , ( unsigned int __user * ) buffer ) )
return - EFAULT ;
if ( host - > hostt - > info )
string = host - > hostt - > info ( host ) ;
else
string = host - > hostt - > name ;
if ( string ) {
slen = strlen ( string ) ;
if ( len > slen )
len = slen + 1 ;
if ( copy_to_user ( buffer , string , len ) )
return - EFAULT ;
}
}
2005-09-06 16:03:44 +04:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
/*
* The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host .
* The IOCTL_NORMAL_TIMEOUT and NORMAL_RETRIES variables are used .
*
* dev is the SCSI device struct ptr , * ( int * ) arg is the length of the
* input data , if any , not including the command string & counts ,
* * ( ( int * ) arg + 1 ) is the output buffer size in bytes .
*
* * ( char * ) ( ( int * ) arg ) [ 2 ] the actual command byte .
*
* Note that if more than MAX_BUF bytes are requested to be transferred ,
* the ioctl will fail with error EINVAL .
*
* This size * does not * include the initial lengths that were passed .
*
* The SCSI command is read from the memory location immediately after the
* length words , and the input data is right after the command . The SCSI
* routines know the command size based on the opcode decode .
*
* The output area is then filled in starting from the command byte .
*/
static int ioctl_internal_command ( struct scsi_device * sdev , char * cmd ,
int timeout , int retries )
{
int result ;
struct scsi_sense_hdr sshdr ;
2014-06-25 18:39:58 +04:00
SCSI_LOG_IOCTL ( 1 , sdev_printk ( KERN_INFO , sdev ,
" Trying ioctl with scsi command %d \n " , * cmd ) ) ;
2005-04-17 02:20:36 +04:00
2005-08-28 20:27:01 +04:00
result = scsi_execute_req ( sdev , cmd , DMA_NONE , NULL , 0 ,
2008-12-04 08:24:39 +03:00
& sshdr , timeout , retries , NULL ) ;
2005-04-17 02:20:36 +04:00
2014-06-25 18:39:58 +04:00
SCSI_LOG_IOCTL ( 2 , sdev_printk ( KERN_INFO , sdev ,
" Ioctl returned 0x%x \n " , result ) ) ;
2005-04-17 02:20:36 +04:00
2005-08-28 20:27:01 +04:00
if ( ( driver_byte ( result ) & DRIVER_SENSE ) & &
2005-08-28 20:33:52 +04:00
( scsi_sense_valid ( & sshdr ) ) ) {
2005-04-17 02:20:36 +04:00
switch ( sshdr . sense_key ) {
case ILLEGAL_REQUEST :
if ( cmd [ 0 ] = = ALLOW_MEDIUM_REMOVAL )
sdev - > lockable = 0 ;
else
2014-06-25 18:39:58 +04:00
sdev_printk ( KERN_INFO , sdev ,
" ioctl_internal_command: "
" ILLEGAL REQUEST "
" asc=0x%x ascq=0x%x \n " ,
sshdr . asc , sshdr . ascq ) ;
2005-04-17 02:20:36 +04:00
break ;
case NOT_READY : /* This happens if there is no disc in drive */
2006-07-28 11:04:09 +04:00
if ( sdev - > removable )
2005-04-17 02:20:36 +04:00
break ;
2017-08-25 23:46:29 +03:00
/* FALLTHROUGH */
2005-04-17 02:20:36 +04:00
case UNIT_ATTENTION :
if ( sdev - > removable ) {
sdev - > changed = 1 ;
2005-08-28 20:27:01 +04:00
result = 0 ; /* This is no longer considered an error */
2005-04-17 02:20:36 +04:00
break ;
}
2017-08-25 23:46:29 +03:00
/* FALLTHROUGH -- for non-removable media */
default :
2005-10-02 20:45:08 +04:00
sdev_printk ( KERN_INFO , sdev ,
" ioctl_internal_command return code = %x \n " ,
result ) ;
2014-10-24 16:26:45 +04:00
scsi_print_sense_hdr ( sdev , NULL , & sshdr ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
2014-06-25 18:39:58 +04:00
SCSI_LOG_IOCTL ( 2 , sdev_printk ( KERN_INFO , sdev ,
" IOCTL Releasing command \n " ) ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
int scsi_set_medium_removal ( struct scsi_device * sdev , char state )
{
char scsi_cmd [ MAX_COMMAND_SIZE ] ;
int ret ;
if ( ! sdev - > removable | | ! sdev - > lockable )
return 0 ;
scsi_cmd [ 0 ] = ALLOW_MEDIUM_REMOVAL ;
scsi_cmd [ 1 ] = 0 ;
scsi_cmd [ 2 ] = 0 ;
scsi_cmd [ 3 ] = 0 ;
scsi_cmd [ 4 ] = state ;
scsi_cmd [ 5 ] = 0 ;
ret = ioctl_internal_command ( sdev , scsi_cmd ,
IOCTL_NORMAL_TIMEOUT , NORMAL_RETRIES ) ;
if ( ret = = 0 )
sdev - > locked = ( state = = SCSI_REMOVAL_PREVENT ) ;
return ret ;
}
EXPORT_SYMBOL ( scsi_set_medium_removal ) ;
/*
* The scsi_ioctl_get_pci ( ) function places into arg the value
* pci_dev : : slot_name ( 8 characters ) for the PCI device ( if any ) .
* Returns : 0 on success
* - ENXIO if there isn ' t a PCI device pointer
* ( could be because the SCSI driver hasn ' t been
* updated yet , or because it isn ' t a SCSI
* device )
* any copy_to_user ( ) error on failure there
*/
static int scsi_ioctl_get_pci ( struct scsi_device * sdev , void __user * arg )
{
struct device * dev = scsi_get_device ( sdev - > host ) ;
2008-12-04 00:41:36 +03:00
const char * name ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
return - ENXIO ;
2008-12-04 00:41:36 +03:00
name = dev_name ( dev ) ;
/* compatibility with old ioctl which only returned
* 20 characters */
return copy_to_user ( arg , name , min ( strlen ( name ) , ( size_t ) 20 ) )
? - EFAULT : 0 ;
2005-04-17 02:20:36 +04:00
}
2007-11-03 21:30:39 +03:00
/**
* scsi_ioctl - Dispatch ioctl to scsi device
* @ sdev : scsi device receiving ioctl
* @ cmd : which ioctl is it
* @ arg : data associated with ioctl
*
* Description : The scsi_ioctl ( ) function differs from most ioctls in that it
* does not take a major / minor number as the dev field . Rather , it takes
* a pointer to a & struct scsi_device .
2005-04-17 02:20:36 +04:00
*/
int scsi_ioctl ( struct scsi_device * sdev , int cmd , void __user * arg )
{
char scsi_cmd [ MAX_COMMAND_SIZE ] ;
2017-02-14 22:15:57 +03:00
struct scsi_sense_hdr sense_hdr ;
2005-04-17 02:20:36 +04:00
/* Check for deprecated ioctls ... all the ioctls which don't
* follow the new unique numbering scheme are deprecated */
switch ( cmd ) {
case SCSI_IOCTL_SEND_COMMAND :
case SCSI_IOCTL_TEST_UNIT_READY :
case SCSI_IOCTL_BENCHMARK_COMMAND :
case SCSI_IOCTL_SYNC :
case SCSI_IOCTL_START_UNIT :
case SCSI_IOCTL_STOP_UNIT :
printk ( KERN_WARNING " program %s is using a deprecated SCSI "
" ioctl, please convert it to SG_IO \n " , current - > comm ) ;
break ;
default :
break ;
}
switch ( cmd ) {
case SCSI_IOCTL_GET_IDLUN :
if ( ! access_ok ( VERIFY_WRITE , arg , sizeof ( struct scsi_idlun ) ) )
return - EFAULT ;
__put_user ( ( sdev - > id & 0xff )
+ ( ( sdev - > lun & 0xff ) < < 8 )
+ ( ( sdev - > channel & 0xff ) < < 16 )
+ ( ( sdev - > host - > host_no & 0xff ) < < 24 ) ,
& ( ( struct scsi_idlun __user * ) arg ) - > dev_id ) ;
__put_user ( sdev - > host - > unique_id ,
& ( ( struct scsi_idlun __user * ) arg ) - > host_unique_id ) ;
return 0 ;
case SCSI_IOCTL_GET_BUS_NUMBER :
return put_user ( sdev - > host - > host_no , ( int __user * ) arg ) ;
case SCSI_IOCTL_PROBE_HOST :
return ioctl_probe ( sdev - > host , arg ) ;
case SCSI_IOCTL_SEND_COMMAND :
if ( ! capable ( CAP_SYS_ADMIN ) | | ! capable ( CAP_SYS_RAWIO ) )
return - EACCES ;
2008-09-03 01:16:41 +04:00
return sg_scsi_ioctl ( sdev - > request_queue , NULL , 0 , arg ) ;
2005-04-17 02:20:36 +04:00
case SCSI_IOCTL_DOORLOCK :
return scsi_set_medium_removal ( sdev , SCSI_REMOVAL_PREVENT ) ;
case SCSI_IOCTL_DOORUNLOCK :
return scsi_set_medium_removal ( sdev , SCSI_REMOVAL_ALLOW ) ;
case SCSI_IOCTL_TEST_UNIT_READY :
return scsi_test_unit_ready ( sdev , IOCTL_NORMAL_TIMEOUT ,
2017-02-14 22:15:57 +03:00
NORMAL_RETRIES , & sense_hdr ) ;
2005-04-17 02:20:36 +04:00
case SCSI_IOCTL_START_UNIT :
scsi_cmd [ 0 ] = START_STOP ;
scsi_cmd [ 1 ] = 0 ;
scsi_cmd [ 2 ] = scsi_cmd [ 3 ] = scsi_cmd [ 5 ] = 0 ;
scsi_cmd [ 4 ] = 1 ;
return ioctl_internal_command ( sdev , scsi_cmd ,
START_STOP_TIMEOUT , NORMAL_RETRIES ) ;
case SCSI_IOCTL_STOP_UNIT :
scsi_cmd [ 0 ] = START_STOP ;
scsi_cmd [ 1 ] = 0 ;
scsi_cmd [ 2 ] = scsi_cmd [ 3 ] = scsi_cmd [ 5 ] = 0 ;
scsi_cmd [ 4 ] = 0 ;
return ioctl_internal_command ( sdev , scsi_cmd ,
START_STOP_TIMEOUT , NORMAL_RETRIES ) ;
case SCSI_IOCTL_GET_PCI :
return scsi_ioctl_get_pci ( sdev , arg ) ;
2014-10-11 18:25:31 +04:00
case SG_SCSI_RESET :
return scsi_ioctl_reset ( sdev , arg ) ;
2005-04-17 02:20:36 +04:00
default :
if ( sdev - > host - > hostt - > ioctl )
return sdev - > host - > hostt - > ioctl ( sdev , cmd , arg ) ;
}
return - EINVAL ;
}
EXPORT_SYMBOL ( scsi_ioctl ) ;
2014-10-11 18:25:31 +04:00
/*
* We can process a reset even when a device isn ' t fully operable .
2005-04-17 02:20:36 +04:00
*/
2014-10-11 18:25:31 +04:00
int scsi_ioctl_block_when_processing_errors ( struct scsi_device * sdev , int cmd ,
bool ndelay )
2005-04-17 02:20:36 +04:00
{
2014-10-11 18:25:31 +04:00
if ( cmd = = SG_SCSI_RESET & & ndelay ) {
2005-09-19 00:05:20 +04:00
if ( scsi_host_in_recovery ( sdev - > host ) )
2014-10-27 18:28:13 +03:00
return - EAGAIN ;
2014-10-11 18:25:31 +04:00
} else {
if ( ! scsi_block_when_processing_errors ( sdev ) )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2014-10-11 18:25:31 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2014-10-11 18:25:31 +04:00
EXPORT_SYMBOL_GPL ( scsi_ioctl_block_when_processing_errors ) ;