/** * scsi_nonblockable_ioctl() - Handle SG_SCSI_RESET * @sdev: scsi device receiving ioctl * @cmd: Must be SC_SCSI_RESET * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST} * @ndelay: file mode O_NDELAY flag */ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, void __user *arg, int ndelay) { int val, result; /* The first set of iocts may be executed even if we're doing * error processing, as long as the device was opened * non-blocking */ if (ndelay) { if (scsi_host_in_recovery(sdev->host)) return -ENODEV; } else if (!scsi_block_when_processing_errors(sdev)) return -ENODEV; switch (cmd) { case SG_SCSI_RESET: result = get_user(val, (int __user *)arg); if (result) return result; if (val == SG_SCSI_RESET_NOTHING) return 0; switch (val) { case SG_SCSI_RESET_DEVICE: val = SCSI_TRY_RESET_DEVICE; break; case SG_SCSI_RESET_TARGET: val = SCSI_TRY_RESET_TARGET; break; case SG_SCSI_RESET_BUS: val = SCSI_TRY_RESET_BUS; break; case SG_SCSI_RESET_HOST: val = SCSI_TRY_RESET_HOST; break; default: return -EINVAL; } if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; return (scsi_reset_provider(sdev, val) == SUCCESS) ? 0 : -EIO; } return -ENODEV; }
/* * the scsi_nonblock_ioctl() function is designed for ioctls which may * be executed even if the device is in recovery. */ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, void __user *arg, struct file *filp) { int val, result; /* The first set of iocts may be executed even if we're doing * error processing, as long as the device was opened * non-blocking */ if (filp && filp->f_flags & O_NONBLOCK) { if (test_bit(SHOST_RECOVERY, &sdev->host->shost_state)) return -ENODEV; } else if (!scsi_block_when_processing_errors(sdev)) return -ENODEV; switch (cmd) { case SG_SCSI_RESET: result = get_user(val, (int __user *)arg); if (result) return result; if (val == SG_SCSI_RESET_NOTHING) return 0; switch (val) { case SG_SCSI_RESET_DEVICE: val = SCSI_TRY_RESET_DEVICE; break; case SG_SCSI_RESET_BUS: val = SCSI_TRY_RESET_BUS; break; case SG_SCSI_RESET_HOST: val = SCSI_TRY_RESET_HOST; break; default: return -EINVAL; } if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; return (scsi_reset_provider(sdev, val) == SUCCESS) ? 0 : -EIO; } return -ENODEV; }