Beispiel #1
0
static int sg_ioctl(struct inode * inode,struct file * file,
                    unsigned int cmd_in, unsigned long arg)
{
    int                         dev = MINOR(inode->i_rdev);
    int                         result;

    if ((dev<0) || (dev>=sg_template.dev_max))
        return -ENXIO;

    /*
     * If we are in the middle of error recovery, then don't allow any
     * access to this device.  Also, error recovery *may* have taken the
     * device offline, in which case all further access is prohibited.
     */
    if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
    {
        return -ENXIO;
    }

    switch(cmd_in)
    {
    case SG_SET_TIMEOUT:
        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
        if (result) return result;

        get_user(scsi_generics[dev].timeout, (int *) arg);
        return 0;
    case SG_GET_TIMEOUT:
        return scsi_generics[dev].timeout;
    case SG_EMULATED_HOST:
        return put_user(scsi_generics[dev].device->host->hostt->emulated, (int *) arg);
    case SCSI_IOCTL_SEND_COMMAND:
        /*
          Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
          user already has read/write access to the generic device and so
          can execute arbitrary SCSI commands.
        */
        return scsi_ioctl_send_command(scsi_generics[dev].device, (void *) arg);
    default:
        return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
    }
}
Beispiel #2
0
/*
 * 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 scsi_devices[] element, a structure. 
 */
int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
{
	char scsi_cmd[MAX_COMMAND_SIZE];
	char cmd_byte1;

	/* No idea how this happens.... */
	if (!dev)
		return -ENXIO;

	/*
	 * If we are in the middle of error recovery, don't let anyone
	 * else try and use this device.  Also, if error recovery fails, it
	 * may try and take the device offline, in which case all further
	 * access to the device is prohibited.
	 */
	if (!scsi_block_when_processing_errors(dev)) {
		return -ENODEV;
	}
	cmd_byte1 = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0;

	switch (cmd) {
	case SCSI_IOCTL_GET_IDLUN:
		if (verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun)))
			return -EFAULT;

		__put_user((dev->id & 0xff)
			 + ((dev->lun & 0xff) << 8)
			 + ((dev->channel & 0xff) << 16)
			 + ((dev->host->host_no & 0xff) << 24),
			 &((Scsi_Idlun *) arg)->dev_id);
		__put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id);
		return 0;
	case SCSI_IOCTL_GET_BUS_NUMBER:
		return put_user(dev->host->host_no, (int *) arg);
	case SCSI_IOCTL_TAGGED_ENABLE:
		if (!capable(CAP_SYS_ADMIN))
			return -EACCES;
		if (!dev->tagged_supported)
			return -EINVAL;
		dev->tagged_queue = 1;
		dev->current_tag = 1;
		return 0;
	case SCSI_IOCTL_TAGGED_DISABLE:
		if (!capable(CAP_SYS_ADMIN))
			return -EACCES;
		if (!dev->tagged_supported)
			return -EINVAL;
		dev->tagged_queue = 0;
		dev->current_tag = 0;
		return 0;
	case SCSI_IOCTL_PROBE_HOST:
		return ioctl_probe(dev->host, arg);
	case SCSI_IOCTL_SEND_COMMAND:
		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
			return -EACCES;
		return scsi_ioctl_send_command((Scsi_Device *) dev,
					     (Scsi_Ioctl_Command *) arg);
	case SCSI_IOCTL_DOORLOCK:
		if (!dev->removable || !dev->lockable)
			return 0;
		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
		scsi_cmd[1] = cmd_byte1;
		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
		scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
				   IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
		break;
	case SCSI_IOCTL_DOORUNLOCK:
		if (!dev->removable || !dev->lockable)
			return 0;
		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
		scsi_cmd[1] = cmd_byte1;
		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
		scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
				   IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
	case SCSI_IOCTL_TEST_UNIT_READY:
		scsi_cmd[0] = TEST_UNIT_READY;
		scsi_cmd[1] = cmd_byte1;
		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
		scsi_cmd[4] = 0;
		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
				   IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
		break;
	case SCSI_IOCTL_START_UNIT:
		scsi_cmd[0] = START_STOP;
		scsi_cmd[1] = cmd_byte1;
		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
		scsi_cmd[4] = 1;
		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
				     START_STOP_TIMEOUT, NORMAL_RETRIES);
		break;
	case SCSI_IOCTL_STOP_UNIT:
		scsi_cmd[0] = START_STOP;
		scsi_cmd[1] = cmd_byte1;
		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
		scsi_cmd[4] = 0;
		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
				     START_STOP_TIMEOUT, NORMAL_RETRIES);
		break;
        case SCSI_IOCTL_GET_PCI:
                return scsi_ioctl_get_pci(dev, arg);
                break;
	default:
		if (dev->host->hostt->ioctl)
			return dev->host->hostt->ioctl(dev, cmd, arg);
		return -EINVAL;
	}
	return -EINVAL;
}
/*
 * 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 scsi_devices[] element, a structure. 
 */
int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
{
	char scsi_cmd[MAX_COMMAND_SIZE];

	/* No idea how this happens.... */
	if (!sdev)
		return -ENXIO;

	/*
	 * If we are in the middle of error recovery, don't let anyone
	 * else try and use this device.  Also, if error recovery fails, it
	 * may try and take the device offline, in which case all further
	 * access to the device is prohibited.
	 */
	if (!scsi_block_when_processing_errors(sdev))
		return -ENODEV;

	/* 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;
		return scsi_ioctl_send_command(sdev, arg);
	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,
					    NORMAL_RETRIES);
	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);
	default:
		if (sdev->host->hostt->ioctl)
			return sdev->host->hostt->ioctl(sdev, cmd, arg);
	}
	return -EINVAL;
}
/*
 * 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 scsi_devices[] element, a structure. 
 */
int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
{
	char scsi_cmd[MAX_COMMAND_SIZE];

	/* No idea how this happens.... */
	if (!sdev)
		return -ENXIO;

	/*
	 * If we are in the middle of error recovery, don't let anyone
	 * else try and use this device.  Also, if error recovery fails, it
	 * may try and take the device offline, in which case all further
	 * access to the device is prohibited.
	 */
	if (!scsi_block_when_processing_errors(sdev))
		return -ENODEV;

	switch (cmd) {
	case SCSI_IOCTL_GET_IDLUN:
		if (verify_area(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;
		return scsi_ioctl_send_command(sdev, arg);
	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:
		scsi_cmd[0] = TEST_UNIT_READY;
		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,
				   IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
	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);
	default:
		if (sdev->host->hostt->ioctl)
			return sdev->host->hostt->ioctl(sdev, cmd, arg);
	}
	return -EINVAL;
}