.. | .. |
---|
| 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 | |
---|