| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying |
|---|
| 3 | | - file Documentation/scsi/st.txt for more information. |
|---|
| 4 | + file Documentation/scsi/st.rst for more information. |
|---|
| 4 | 5 | |
|---|
| 5 | 6 | History: |
|---|
| 6 | 7 | Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. |
|---|
| .. | .. |
|---|
| 21 | 22 | |
|---|
| 22 | 23 | #include <linux/module.h> |
|---|
| 23 | 24 | |
|---|
| 25 | +#include <linux/compat.h> |
|---|
| 24 | 26 | #include <linux/fs.h> |
|---|
| 25 | 27 | #include <linux/kernel.h> |
|---|
| 26 | 28 | #include <linux/sched/signal.h> |
|---|
| .. | .. |
|---|
| 43 | 45 | |
|---|
| 44 | 46 | #include <linux/uaccess.h> |
|---|
| 45 | 47 | #include <asm/dma.h> |
|---|
| 48 | +#include <asm/unaligned.h> |
|---|
| 46 | 49 | |
|---|
| 47 | 50 | #include <scsi/scsi.h> |
|---|
| 48 | 51 | #include <scsi/scsi_dbg.h> |
|---|
| .. | .. |
|---|
| 169 | 172 | |
|---|
| 170 | 173 | /* Remove mode bits and auto-rewind bit (7) */ |
|---|
| 171 | 174 | #define TAPE_NR(x) ( ((iminor(x) & ~255) >> (ST_NBR_MODE_BITS + 1)) | \ |
|---|
| 172 | | - (iminor(x) & ~(-1 << ST_MODE_SHIFT)) ) |
|---|
| 175 | + (iminor(x) & ((1 << ST_MODE_SHIFT)-1))) |
|---|
| 173 | 176 | #define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) |
|---|
| 174 | 177 | |
|---|
| 175 | 178 | /* Construct the minor number from the device (d), mode (m), and non-rewind (n) data */ |
|---|
| .. | .. |
|---|
| 227 | 230 | |
|---|
| 228 | 231 | |
|---|
| 229 | 232 | |
|---|
| 230 | | -#include "osst_detect.h" |
|---|
| 231 | 233 | #ifndef SIGS_FROM_OSST |
|---|
| 232 | 234 | #define SIGS_FROM_OSST \ |
|---|
| 233 | 235 | {"OnStream", "SC-", "", "osst"}, \ |
|---|
| .. | .. |
|---|
| 337 | 339 | switch (sense[0] & 0x7f) { |
|---|
| 338 | 340 | case 0x71: |
|---|
| 339 | 341 | s->deferred = 1; |
|---|
| 342 | + fallthrough; |
|---|
| 340 | 343 | case 0x70: |
|---|
| 341 | 344 | s->fixed_format = 1; |
|---|
| 342 | 345 | s->flags = sense[2] & 0xe0; |
|---|
| 343 | 346 | break; |
|---|
| 344 | 347 | case 0x73: |
|---|
| 345 | 348 | s->deferred = 1; |
|---|
| 349 | + fallthrough; |
|---|
| 346 | 350 | case 0x72: |
|---|
| 347 | 351 | s->fixed_format = 0; |
|---|
| 348 | 352 | ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4); |
|---|
| .. | .. |
|---|
| 530 | 534 | complete(SRpnt->waiting); |
|---|
| 531 | 535 | |
|---|
| 532 | 536 | blk_rq_unmap_user(tmp); |
|---|
| 533 | | - __blk_put_request(req->q, req); |
|---|
| 537 | + blk_put_request(req); |
|---|
| 534 | 538 | } |
|---|
| 535 | 539 | |
|---|
| 536 | 540 | static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, |
|---|
| .. | .. |
|---|
| 1453 | 1457 | accessing this tape. */ |
|---|
| 1454 | 1458 | static int st_release(struct inode *inode, struct file *filp) |
|---|
| 1455 | 1459 | { |
|---|
| 1456 | | - int result = 0; |
|---|
| 1457 | 1460 | struct scsi_tape *STp = filp->private_data; |
|---|
| 1458 | 1461 | |
|---|
| 1459 | 1462 | if (STp->door_locked == ST_LOCKED_AUTO) |
|---|
| .. | .. |
|---|
| 1466 | 1469 | scsi_autopm_put_device(STp->device); |
|---|
| 1467 | 1470 | scsi_tape_put(STp); |
|---|
| 1468 | 1471 | |
|---|
| 1469 | | - return result; |
|---|
| 1472 | + return 0; |
|---|
| 1470 | 1473 | } |
|---|
| 1471 | | - |
|---|
| 1474 | + |
|---|
| 1472 | 1475 | /* The checks common to both reading and writing */ |
|---|
| 1473 | 1476 | static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count) |
|---|
| 1474 | 1477 | { |
|---|
| .. | .. |
|---|
| 2677 | 2680 | if (!debugging) |
|---|
| 2678 | 2681 | return; |
|---|
| 2679 | 2682 | |
|---|
| 2680 | | - sc = cmd[2] & 0x80 ? 0xff000000 : 0; |
|---|
| 2681 | | - sc |= (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; |
|---|
| 2683 | + sc = sign_extend32(get_unaligned_be24(&cmd[2]), 23); |
|---|
| 2682 | 2684 | if (direction) |
|---|
| 2683 | 2685 | sc = -sc; |
|---|
| 2684 | 2686 | st_printk(ST_DEB_MSG, STp, "Spacing tape %s over %d %s.\n", |
|---|
| .. | .. |
|---|
| 2721 | 2723 | switch (cmd_in) { |
|---|
| 2722 | 2724 | case MTFSFM: |
|---|
| 2723 | 2725 | chg_eof = 0; /* Changed from the FSF after this */ |
|---|
| 2726 | + fallthrough; |
|---|
| 2724 | 2727 | case MTFSF: |
|---|
| 2725 | 2728 | cmd[0] = SPACE; |
|---|
| 2726 | 2729 | cmd[1] = 0x01; /* Space FileMarks */ |
|---|
| .. | .. |
|---|
| 2735 | 2738 | break; |
|---|
| 2736 | 2739 | case MTBSFM: |
|---|
| 2737 | 2740 | chg_eof = 0; /* Changed from the FSF after this */ |
|---|
| 2741 | + fallthrough; |
|---|
| 2738 | 2742 | case MTBSF: |
|---|
| 2739 | 2743 | cmd[0] = SPACE; |
|---|
| 2740 | 2744 | cmd[1] = 0x01; /* Space FileMarks */ |
|---|
| .. | .. |
|---|
| 3496 | 3500 | |
|---|
| 3497 | 3501 | |
|---|
| 3498 | 3502 | /* The ioctl command */ |
|---|
| 3499 | | -static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) |
|---|
| 3503 | +static long st_ioctl_common(struct file *file, unsigned int cmd_in, void __user *p) |
|---|
| 3500 | 3504 | { |
|---|
| 3501 | 3505 | int i, cmd_nr, cmd_type, bt; |
|---|
| 3502 | 3506 | int retval = 0; |
|---|
| .. | .. |
|---|
| 3504 | 3508 | struct scsi_tape *STp = file->private_data; |
|---|
| 3505 | 3509 | struct st_modedef *STm; |
|---|
| 3506 | 3510 | struct st_partstat *STps; |
|---|
| 3507 | | - void __user *p = (void __user *)arg; |
|---|
| 3508 | 3511 | |
|---|
| 3509 | 3512 | if (mutex_lock_interruptible(&STp->lock)) |
|---|
| 3510 | 3513 | return -ERESTARTSYS; |
|---|
| .. | .. |
|---|
| 3796 | 3799 | if (STp->cleaning_req) |
|---|
| 3797 | 3800 | mt_status.mt_gstat |= GMT_CLN(0xffffffff); |
|---|
| 3798 | 3801 | |
|---|
| 3799 | | - i = copy_to_user(p, &mt_status, sizeof(struct mtget)); |
|---|
| 3800 | | - if (i) { |
|---|
| 3801 | | - retval = (-EFAULT); |
|---|
| 3802 | + retval = put_user_mtget(p, &mt_status); |
|---|
| 3803 | + if (retval) |
|---|
| 3802 | 3804 | goto out; |
|---|
| 3803 | | - } |
|---|
| 3804 | 3805 | |
|---|
| 3805 | 3806 | STp->recover_reg = 0; /* Clear after read */ |
|---|
| 3806 | | - retval = 0; |
|---|
| 3807 | 3807 | goto out; |
|---|
| 3808 | 3808 | } /* End of MTIOCGET */ |
|---|
| 3809 | 3809 | if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { |
|---|
| .. | .. |
|---|
| 3817 | 3817 | goto out; |
|---|
| 3818 | 3818 | } |
|---|
| 3819 | 3819 | mt_pos.mt_blkno = blk; |
|---|
| 3820 | | - i = copy_to_user(p, &mt_pos, sizeof(struct mtpos)); |
|---|
| 3821 | | - if (i) |
|---|
| 3822 | | - retval = (-EFAULT); |
|---|
| 3820 | + retval = put_user_mtpos(p, &mt_pos); |
|---|
| 3823 | 3821 | goto out; |
|---|
| 3824 | 3822 | } |
|---|
| 3825 | 3823 | mutex_unlock(&STp->lock); |
|---|
| 3826 | 3824 | switch (cmd_in) { |
|---|
| 3825 | + case SCSI_IOCTL_STOP_UNIT: |
|---|
| 3826 | + /* unload */ |
|---|
| 3827 | + retval = scsi_ioctl(STp->device, cmd_in, p); |
|---|
| 3828 | + if (!retval) { |
|---|
| 3829 | + STp->rew_at_close = 0; |
|---|
| 3830 | + STp->ready = ST_NO_TAPE; |
|---|
| 3831 | + } |
|---|
| 3832 | + return retval; |
|---|
| 3833 | + |
|---|
| 3827 | 3834 | case SCSI_IOCTL_GET_IDLUN: |
|---|
| 3828 | 3835 | case SCSI_IOCTL_GET_BUS_NUMBER: |
|---|
| 3829 | 3836 | break; |
|---|
| 3837 | + |
|---|
| 3830 | 3838 | default: |
|---|
| 3831 | 3839 | if ((cmd_in == SG_IO || |
|---|
| 3832 | 3840 | cmd_in == SCSI_IOCTL_SEND_COMMAND || |
|---|
| .. | .. |
|---|
| 3840 | 3848 | return i; |
|---|
| 3841 | 3849 | break; |
|---|
| 3842 | 3850 | } |
|---|
| 3843 | | - retval = scsi_ioctl(STp->device, cmd_in, p); |
|---|
| 3844 | | - if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { /* unload */ |
|---|
| 3845 | | - STp->rew_at_close = 0; |
|---|
| 3846 | | - STp->ready = ST_NO_TAPE; |
|---|
| 3847 | | - } |
|---|
| 3848 | | - return retval; |
|---|
| 3851 | + return -ENOTTY; |
|---|
| 3849 | 3852 | |
|---|
| 3850 | 3853 | out: |
|---|
| 3851 | 3854 | mutex_unlock(&STp->lock); |
|---|
| 3852 | 3855 | return retval; |
|---|
| 3853 | 3856 | } |
|---|
| 3854 | 3857 | |
|---|
| 3855 | | -#ifdef CONFIG_COMPAT |
|---|
| 3856 | | -static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
|---|
| 3858 | +static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) |
|---|
| 3857 | 3859 | { |
|---|
| 3860 | + void __user *p = (void __user *)arg; |
|---|
| 3858 | 3861 | struct scsi_tape *STp = file->private_data; |
|---|
| 3859 | | - struct scsi_device *sdev = STp->device; |
|---|
| 3860 | | - int ret = -ENOIOCTLCMD; |
|---|
| 3861 | | - if (sdev->host->hostt->compat_ioctl) { |
|---|
| 3862 | + int ret; |
|---|
| 3862 | 3863 | |
|---|
| 3863 | | - ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); |
|---|
| 3864 | + ret = st_ioctl_common(file, cmd_in, p); |
|---|
| 3865 | + if (ret != -ENOTTY) |
|---|
| 3866 | + return ret; |
|---|
| 3864 | 3867 | |
|---|
| 3868 | + return scsi_ioctl(STp->device, cmd_in, p); |
|---|
| 3869 | +} |
|---|
| 3870 | + |
|---|
| 3871 | +#ifdef CONFIG_COMPAT |
|---|
| 3872 | +static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) |
|---|
| 3873 | +{ |
|---|
| 3874 | + void __user *p = compat_ptr(arg); |
|---|
| 3875 | + struct scsi_tape *STp = file->private_data; |
|---|
| 3876 | + int ret; |
|---|
| 3877 | + |
|---|
| 3878 | + /* argument conversion is handled using put_user_mtpos/put_user_mtget */ |
|---|
| 3879 | + switch (cmd_in) { |
|---|
| 3880 | + case MTIOCPOS32: |
|---|
| 3881 | + return st_ioctl_common(file, MTIOCPOS, p); |
|---|
| 3882 | + case MTIOCGET32: |
|---|
| 3883 | + return st_ioctl_common(file, MTIOCGET, p); |
|---|
| 3865 | 3884 | } |
|---|
| 3866 | | - return ret; |
|---|
| 3885 | + |
|---|
| 3886 | + ret = st_ioctl_common(file, cmd_in, p); |
|---|
| 3887 | + if (ret != -ENOTTY) |
|---|
| 3888 | + return ret; |
|---|
| 3889 | + |
|---|
| 3890 | + return scsi_compat_ioctl(STp->device, cmd_in, p); |
|---|
| 3867 | 3891 | } |
|---|
| 3868 | 3892 | #endif |
|---|
| 3869 | 3893 | |
|---|
| .. | .. |
|---|
| 4262 | 4286 | if (SDp->type != TYPE_TAPE) |
|---|
| 4263 | 4287 | return -ENODEV; |
|---|
| 4264 | 4288 | if ((stp = st_incompatible(SDp))) { |
|---|
| 4265 | | - sdev_printk(KERN_INFO, SDp, "Found incompatible tape\n"); |
|---|
| 4266 | 4289 | sdev_printk(KERN_INFO, SDp, |
|---|
| 4267 | | - "st: The suggested driver is %s.\n", stp); |
|---|
| 4290 | + "OnStream tapes are no longer supported;\n"); |
|---|
| 4291 | + sdev_printk(KERN_INFO, SDp, |
|---|
| 4292 | + "please mail to linux-scsi@vger.kernel.org.\n"); |
|---|
| 4268 | 4293 | return -ENODEV; |
|---|
| 4269 | 4294 | } |
|---|
| 4270 | 4295 | |
|---|
| .. | .. |
|---|
| 4896 | 4921 | unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; |
|---|
| 4897 | 4922 | unsigned long start = uaddr >> PAGE_SHIFT; |
|---|
| 4898 | 4923 | const int nr_pages = end - start; |
|---|
| 4899 | | - int res, i, j; |
|---|
| 4924 | + int res, i; |
|---|
| 4900 | 4925 | struct page **pages; |
|---|
| 4901 | 4926 | struct rq_map_data *mdata = &STbp->map_data; |
|---|
| 4902 | 4927 | |
|---|
| .. | .. |
|---|
| 4918 | 4943 | |
|---|
| 4919 | 4944 | /* Try to fault in all of the necessary pages */ |
|---|
| 4920 | 4945 | /* rw==READ means read from drive, write into memory area */ |
|---|
| 4921 | | - res = get_user_pages_fast(uaddr, nr_pages, rw == READ, pages); |
|---|
| 4946 | + res = pin_user_pages_fast(uaddr, nr_pages, rw == READ ? FOLL_WRITE : 0, |
|---|
| 4947 | + pages); |
|---|
| 4922 | 4948 | |
|---|
| 4923 | 4949 | /* Errors and no page mapped should return here */ |
|---|
| 4924 | 4950 | if (res < nr_pages) |
|---|
| .. | .. |
|---|
| 4937 | 4963 | return nr_pages; |
|---|
| 4938 | 4964 | out_unmap: |
|---|
| 4939 | 4965 | if (res > 0) { |
|---|
| 4940 | | - for (j=0; j < res; j++) |
|---|
| 4941 | | - put_page(pages[j]); |
|---|
| 4966 | + unpin_user_pages(pages, res); |
|---|
| 4942 | 4967 | res = 0; |
|---|
| 4943 | 4968 | } |
|---|
| 4944 | 4969 | kfree(pages); |
|---|
| .. | .. |
|---|
| 4950 | 4975 | static int sgl_unmap_user_pages(struct st_buffer *STbp, |
|---|
| 4951 | 4976 | const unsigned int nr_pages, int dirtied) |
|---|
| 4952 | 4977 | { |
|---|
| 4953 | | - int i; |
|---|
| 4978 | + /* FIXME: cache flush missing for rw==READ */ |
|---|
| 4979 | + unpin_user_pages_dirty_lock(STbp->mapped_pages, nr_pages, dirtied); |
|---|
| 4954 | 4980 | |
|---|
| 4955 | | - for (i=0; i < nr_pages; i++) { |
|---|
| 4956 | | - struct page *page = STbp->mapped_pages[i]; |
|---|
| 4957 | | - |
|---|
| 4958 | | - if (dirtied) |
|---|
| 4959 | | - SetPageDirty(page); |
|---|
| 4960 | | - /* FIXME: cache flush missing for rw==READ |
|---|
| 4961 | | - * FIXME: call the correct reference counting function |
|---|
| 4962 | | - */ |
|---|
| 4963 | | - put_page(page); |
|---|
| 4964 | | - } |
|---|
| 4965 | 4981 | kfree(STbp->mapped_pages); |
|---|
| 4966 | 4982 | STbp->mapped_pages = NULL; |
|---|
| 4967 | 4983 | |
|---|