15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
200a2430fSAndrzej Pietrasiewicz /*
300a2430fSAndrzej Pietrasiewicz * storage_common.c -- Common definitions for mass storage functionality
400a2430fSAndrzej Pietrasiewicz *
500a2430fSAndrzej Pietrasiewicz * Copyright (C) 2003-2008 Alan Stern
600a2430fSAndrzej Pietrasiewicz * Copyeight (C) 2009 Samsung Electronics
700a2430fSAndrzej Pietrasiewicz * Author: Michal Nazarewicz (mina86@mina86.com)
800a2430fSAndrzej Pietrasiewicz */
900a2430fSAndrzej Pietrasiewicz
1000a2430fSAndrzej Pietrasiewicz /*
1100a2430fSAndrzej Pietrasiewicz * This file requires the following identifiers used in USB strings to
1200a2430fSAndrzej Pietrasiewicz * be defined (each of type pointer to char):
1300a2430fSAndrzej Pietrasiewicz * - fsg_string_interface -- name of the interface
1400a2430fSAndrzej Pietrasiewicz */
1500a2430fSAndrzej Pietrasiewicz
1600a2430fSAndrzej Pietrasiewicz /*
1700a2430fSAndrzej Pietrasiewicz * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
1800a2430fSAndrzej Pietrasiewicz * sets the number of pipeline buffers (length of the fsg_buffhd array).
1900a2430fSAndrzej Pietrasiewicz * The valid range of num_buffers is: num >= 2 && num <= 4.
2000a2430fSAndrzej Pietrasiewicz */
2100a2430fSAndrzej Pietrasiewicz
2200a2430fSAndrzej Pietrasiewicz #include <linux/module.h>
2300a2430fSAndrzej Pietrasiewicz #include <linux/blkdev.h>
2400a2430fSAndrzej Pietrasiewicz #include <linux/file.h>
2500a2430fSAndrzej Pietrasiewicz #include <linux/fs.h>
26*a8bc8cc1SChristophe JAILLET #include <linux/kstrtox.h>
2700a2430fSAndrzej Pietrasiewicz #include <linux/usb/composite.h>
2800a2430fSAndrzej Pietrasiewicz
2900a2430fSAndrzej Pietrasiewicz #include "storage_common.h"
3000a2430fSAndrzej Pietrasiewicz
3100a2430fSAndrzej Pietrasiewicz /* There is only one interface. */
3200a2430fSAndrzej Pietrasiewicz
3300a2430fSAndrzej Pietrasiewicz struct usb_interface_descriptor fsg_intf_desc = {
3400a2430fSAndrzej Pietrasiewicz .bLength = sizeof fsg_intf_desc,
3500a2430fSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_INTERFACE,
3600a2430fSAndrzej Pietrasiewicz
3700a2430fSAndrzej Pietrasiewicz .bNumEndpoints = 2, /* Adjusted during fsg_bind() */
3800a2430fSAndrzej Pietrasiewicz .bInterfaceClass = USB_CLASS_MASS_STORAGE,
3900a2430fSAndrzej Pietrasiewicz .bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */
4000a2430fSAndrzej Pietrasiewicz .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */
4100a2430fSAndrzej Pietrasiewicz .iInterface = FSG_STRING_INTERFACE,
4200a2430fSAndrzej Pietrasiewicz };
4300a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_intf_desc);
4400a2430fSAndrzej Pietrasiewicz
4500a2430fSAndrzej Pietrasiewicz /*
4600a2430fSAndrzej Pietrasiewicz * Three full-speed endpoint descriptors: bulk-in, bulk-out, and
4700a2430fSAndrzej Pietrasiewicz * interrupt-in.
4800a2430fSAndrzej Pietrasiewicz */
4900a2430fSAndrzej Pietrasiewicz
5000a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = {
5100a2430fSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
5200a2430fSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
5300a2430fSAndrzej Pietrasiewicz
5400a2430fSAndrzej Pietrasiewicz .bEndpointAddress = USB_DIR_IN,
5500a2430fSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK,
5600a2430fSAndrzej Pietrasiewicz /* wMaxPacketSize set by autoconfiguration */
5700a2430fSAndrzej Pietrasiewicz };
5800a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc);
5900a2430fSAndrzej Pietrasiewicz
6000a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = {
6100a2430fSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
6200a2430fSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
6300a2430fSAndrzej Pietrasiewicz
6400a2430fSAndrzej Pietrasiewicz .bEndpointAddress = USB_DIR_OUT,
6500a2430fSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK,
6600a2430fSAndrzej Pietrasiewicz /* wMaxPacketSize set by autoconfiguration */
6700a2430fSAndrzej Pietrasiewicz };
6800a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc);
6900a2430fSAndrzej Pietrasiewicz
7000a2430fSAndrzej Pietrasiewicz struct usb_descriptor_header *fsg_fs_function[] = {
7100a2430fSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fsg_intf_desc,
7200a2430fSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
7300a2430fSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
7400a2430fSAndrzej Pietrasiewicz NULL,
7500a2430fSAndrzej Pietrasiewicz };
7600a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_fs_function);
7700a2430fSAndrzej Pietrasiewicz
7800a2430fSAndrzej Pietrasiewicz
7900a2430fSAndrzej Pietrasiewicz /*
8000a2430fSAndrzej Pietrasiewicz * USB 2.0 devices need to expose both high speed and full speed
8100a2430fSAndrzej Pietrasiewicz * descriptors, unless they only run at full speed.
8200a2430fSAndrzej Pietrasiewicz *
83cc50dc28SKrzysztof Opasiak * That means alternate endpoint descriptors (bigger packets).
8400a2430fSAndrzej Pietrasiewicz */
8500a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = {
8600a2430fSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
8700a2430fSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
8800a2430fSAndrzej Pietrasiewicz
8900a2430fSAndrzej Pietrasiewicz /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
9000a2430fSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK,
9100a2430fSAndrzej Pietrasiewicz .wMaxPacketSize = cpu_to_le16(512),
9200a2430fSAndrzej Pietrasiewicz };
9300a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc);
9400a2430fSAndrzej Pietrasiewicz
9500a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = {
9600a2430fSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
9700a2430fSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
9800a2430fSAndrzej Pietrasiewicz
9900a2430fSAndrzej Pietrasiewicz /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
10000a2430fSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK,
10100a2430fSAndrzej Pietrasiewicz .wMaxPacketSize = cpu_to_le16(512),
10200a2430fSAndrzej Pietrasiewicz .bInterval = 1, /* NAK every 1 uframe */
10300a2430fSAndrzej Pietrasiewicz };
10400a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc);
10500a2430fSAndrzej Pietrasiewicz
10600a2430fSAndrzej Pietrasiewicz
10700a2430fSAndrzej Pietrasiewicz struct usb_descriptor_header *fsg_hs_function[] = {
10800a2430fSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fsg_intf_desc,
10900a2430fSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
11000a2430fSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
11100a2430fSAndrzej Pietrasiewicz NULL,
11200a2430fSAndrzej Pietrasiewicz };
11300a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_hs_function);
11400a2430fSAndrzej Pietrasiewicz
11500a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = {
11600a2430fSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
11700a2430fSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
11800a2430fSAndrzej Pietrasiewicz
11900a2430fSAndrzej Pietrasiewicz /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
12000a2430fSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK,
12100a2430fSAndrzej Pietrasiewicz .wMaxPacketSize = cpu_to_le16(1024),
12200a2430fSAndrzej Pietrasiewicz };
12300a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc);
12400a2430fSAndrzej Pietrasiewicz
12500a2430fSAndrzej Pietrasiewicz struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
12600a2430fSAndrzej Pietrasiewicz .bLength = sizeof(fsg_ss_bulk_in_comp_desc),
12700a2430fSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
12800a2430fSAndrzej Pietrasiewicz
12900a2430fSAndrzej Pietrasiewicz /*.bMaxBurst = DYNAMIC, */
13000a2430fSAndrzej Pietrasiewicz };
13100a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc);
13200a2430fSAndrzej Pietrasiewicz
13300a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = {
13400a2430fSAndrzej Pietrasiewicz .bLength = USB_DT_ENDPOINT_SIZE,
13500a2430fSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_ENDPOINT,
13600a2430fSAndrzej Pietrasiewicz
13700a2430fSAndrzej Pietrasiewicz /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
13800a2430fSAndrzej Pietrasiewicz .bmAttributes = USB_ENDPOINT_XFER_BULK,
13900a2430fSAndrzej Pietrasiewicz .wMaxPacketSize = cpu_to_le16(1024),
14000a2430fSAndrzej Pietrasiewicz };
14100a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc);
14200a2430fSAndrzej Pietrasiewicz
14300a2430fSAndrzej Pietrasiewicz struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
14400a2430fSAndrzej Pietrasiewicz .bLength = sizeof(fsg_ss_bulk_in_comp_desc),
14500a2430fSAndrzej Pietrasiewicz .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
14600a2430fSAndrzej Pietrasiewicz
14700a2430fSAndrzej Pietrasiewicz /*.bMaxBurst = DYNAMIC, */
14800a2430fSAndrzej Pietrasiewicz };
14900a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc);
15000a2430fSAndrzej Pietrasiewicz
15100a2430fSAndrzej Pietrasiewicz struct usb_descriptor_header *fsg_ss_function[] = {
15200a2430fSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fsg_intf_desc,
15300a2430fSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
15400a2430fSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
15500a2430fSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
15600a2430fSAndrzej Pietrasiewicz (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
15700a2430fSAndrzej Pietrasiewicz NULL,
15800a2430fSAndrzej Pietrasiewicz };
15900a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_ss_function);
16000a2430fSAndrzej Pietrasiewicz
16100a2430fSAndrzej Pietrasiewicz
16200a2430fSAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
16300a2430fSAndrzej Pietrasiewicz
16400a2430fSAndrzej Pietrasiewicz /*
16500a2430fSAndrzej Pietrasiewicz * If the next two routines are called while the gadget is registered,
16600a2430fSAndrzej Pietrasiewicz * the caller must own fsg->filesem for writing.
16700a2430fSAndrzej Pietrasiewicz */
16800a2430fSAndrzej Pietrasiewicz
fsg_lun_close(struct fsg_lun * curlun)16900a2430fSAndrzej Pietrasiewicz void fsg_lun_close(struct fsg_lun *curlun)
17000a2430fSAndrzej Pietrasiewicz {
17100a2430fSAndrzej Pietrasiewicz if (curlun->filp) {
17200a2430fSAndrzej Pietrasiewicz LDBG(curlun, "close backing file\n");
17300a2430fSAndrzej Pietrasiewicz fput(curlun->filp);
17400a2430fSAndrzej Pietrasiewicz curlun->filp = NULL;
17500a2430fSAndrzej Pietrasiewicz }
17600a2430fSAndrzej Pietrasiewicz }
17700a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_lun_close);
17800a2430fSAndrzej Pietrasiewicz
fsg_lun_open(struct fsg_lun * curlun,const char * filename)17900a2430fSAndrzej Pietrasiewicz int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
18000a2430fSAndrzej Pietrasiewicz {
18100a2430fSAndrzej Pietrasiewicz int ro;
18200a2430fSAndrzej Pietrasiewicz struct file *filp = NULL;
18300a2430fSAndrzej Pietrasiewicz int rc = -EINVAL;
18400a2430fSAndrzej Pietrasiewicz struct inode *inode = NULL;
18500a2430fSAndrzej Pietrasiewicz loff_t size;
18600a2430fSAndrzej Pietrasiewicz loff_t num_sectors;
18700a2430fSAndrzej Pietrasiewicz loff_t min_sectors;
18800a2430fSAndrzej Pietrasiewicz unsigned int blkbits;
18900a2430fSAndrzej Pietrasiewicz unsigned int blksize;
19000a2430fSAndrzej Pietrasiewicz
19100a2430fSAndrzej Pietrasiewicz /* R/W if we can, R/O if we must */
19200a2430fSAndrzej Pietrasiewicz ro = curlun->initially_ro;
19300a2430fSAndrzej Pietrasiewicz if (!ro) {
19400a2430fSAndrzej Pietrasiewicz filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
19500a2430fSAndrzej Pietrasiewicz if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
19600a2430fSAndrzej Pietrasiewicz ro = 1;
19700a2430fSAndrzej Pietrasiewicz }
19800a2430fSAndrzej Pietrasiewicz if (ro)
19900a2430fSAndrzej Pietrasiewicz filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
20000a2430fSAndrzej Pietrasiewicz if (IS_ERR(filp)) {
20100a2430fSAndrzej Pietrasiewicz LINFO(curlun, "unable to open backing file: %s\n", filename);
20200a2430fSAndrzej Pietrasiewicz return PTR_ERR(filp);
20300a2430fSAndrzej Pietrasiewicz }
20400a2430fSAndrzej Pietrasiewicz
20500a2430fSAndrzej Pietrasiewicz if (!(filp->f_mode & FMODE_WRITE))
20600a2430fSAndrzej Pietrasiewicz ro = 1;
20700a2430fSAndrzej Pietrasiewicz
2084e7b5671SChristoph Hellwig inode = filp->f_mapping->host;
20900a2430fSAndrzej Pietrasiewicz if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
21000a2430fSAndrzej Pietrasiewicz LINFO(curlun, "invalid file type: %s\n", filename);
21100a2430fSAndrzej Pietrasiewicz goto out;
21200a2430fSAndrzej Pietrasiewicz }
21300a2430fSAndrzej Pietrasiewicz
21400a2430fSAndrzej Pietrasiewicz /*
21500a2430fSAndrzej Pietrasiewicz * If we can't read the file, it's no good.
21600a2430fSAndrzej Pietrasiewicz * If we can't write the file, use it read-only.
21700a2430fSAndrzej Pietrasiewicz */
21800a2430fSAndrzej Pietrasiewicz if (!(filp->f_mode & FMODE_CAN_READ)) {
21900a2430fSAndrzej Pietrasiewicz LINFO(curlun, "file not readable: %s\n", filename);
22000a2430fSAndrzej Pietrasiewicz goto out;
22100a2430fSAndrzej Pietrasiewicz }
22200a2430fSAndrzej Pietrasiewicz if (!(filp->f_mode & FMODE_CAN_WRITE))
22300a2430fSAndrzej Pietrasiewicz ro = 1;
22400a2430fSAndrzej Pietrasiewicz
2254e7b5671SChristoph Hellwig size = i_size_read(inode);
22600a2430fSAndrzej Pietrasiewicz if (size < 0) {
22700a2430fSAndrzej Pietrasiewicz LINFO(curlun, "unable to find file size: %s\n", filename);
22800a2430fSAndrzej Pietrasiewicz rc = (int) size;
22900a2430fSAndrzej Pietrasiewicz goto out;
23000a2430fSAndrzej Pietrasiewicz }
23100a2430fSAndrzej Pietrasiewicz
23200a2430fSAndrzej Pietrasiewicz if (curlun->cdrom) {
23300a2430fSAndrzej Pietrasiewicz blksize = 2048;
23400a2430fSAndrzej Pietrasiewicz blkbits = 11;
2354e7b5671SChristoph Hellwig } else if (S_ISBLK(inode->i_mode)) {
2364e7b5671SChristoph Hellwig blksize = bdev_logical_block_size(I_BDEV(inode));
23700a2430fSAndrzej Pietrasiewicz blkbits = blksize_bits(blksize);
23800a2430fSAndrzej Pietrasiewicz } else {
23900a2430fSAndrzej Pietrasiewicz blksize = 512;
24000a2430fSAndrzej Pietrasiewicz blkbits = 9;
24100a2430fSAndrzej Pietrasiewicz }
24200a2430fSAndrzej Pietrasiewicz
24300a2430fSAndrzej Pietrasiewicz num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
24400a2430fSAndrzej Pietrasiewicz min_sectors = 1;
24500a2430fSAndrzej Pietrasiewicz if (curlun->cdrom) {
24600a2430fSAndrzej Pietrasiewicz min_sectors = 300; /* Smallest track is 300 frames */
24700a2430fSAndrzej Pietrasiewicz if (num_sectors >= 256*60*75) {
24800a2430fSAndrzej Pietrasiewicz num_sectors = 256*60*75 - 1;
24900a2430fSAndrzej Pietrasiewicz LINFO(curlun, "file too big: %s\n", filename);
25000a2430fSAndrzej Pietrasiewicz LINFO(curlun, "using only first %d blocks\n",
25100a2430fSAndrzej Pietrasiewicz (int) num_sectors);
25200a2430fSAndrzej Pietrasiewicz }
25300a2430fSAndrzej Pietrasiewicz }
25400a2430fSAndrzej Pietrasiewicz if (num_sectors < min_sectors) {
25500a2430fSAndrzej Pietrasiewicz LINFO(curlun, "file too small: %s\n", filename);
25600a2430fSAndrzej Pietrasiewicz rc = -ETOOSMALL;
25700a2430fSAndrzej Pietrasiewicz goto out;
25800a2430fSAndrzej Pietrasiewicz }
25900a2430fSAndrzej Pietrasiewicz
26000a2430fSAndrzej Pietrasiewicz if (fsg_lun_is_open(curlun))
26100a2430fSAndrzej Pietrasiewicz fsg_lun_close(curlun);
26200a2430fSAndrzej Pietrasiewicz
26300a2430fSAndrzej Pietrasiewicz curlun->blksize = blksize;
26400a2430fSAndrzej Pietrasiewicz curlun->blkbits = blkbits;
26500a2430fSAndrzej Pietrasiewicz curlun->ro = ro;
26600a2430fSAndrzej Pietrasiewicz curlun->filp = filp;
26700a2430fSAndrzej Pietrasiewicz curlun->file_length = size;
26800a2430fSAndrzej Pietrasiewicz curlun->num_sectors = num_sectors;
26900a2430fSAndrzej Pietrasiewicz LDBG(curlun, "open backing file: %s\n", filename);
27000a2430fSAndrzej Pietrasiewicz return 0;
27100a2430fSAndrzej Pietrasiewicz
27200a2430fSAndrzej Pietrasiewicz out:
27300a2430fSAndrzej Pietrasiewicz fput(filp);
27400a2430fSAndrzej Pietrasiewicz return rc;
27500a2430fSAndrzej Pietrasiewicz }
27600a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_lun_open);
27700a2430fSAndrzej Pietrasiewicz
27800a2430fSAndrzej Pietrasiewicz
27900a2430fSAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
28000a2430fSAndrzej Pietrasiewicz
28100a2430fSAndrzej Pietrasiewicz /*
28200a2430fSAndrzej Pietrasiewicz * Sync the file data, don't bother with the metadata.
28300a2430fSAndrzej Pietrasiewicz * This code was copied from fs/buffer.c:sys_fdatasync().
28400a2430fSAndrzej Pietrasiewicz */
fsg_lun_fsync_sub(struct fsg_lun * curlun)28500a2430fSAndrzej Pietrasiewicz int fsg_lun_fsync_sub(struct fsg_lun *curlun)
28600a2430fSAndrzej Pietrasiewicz {
28700a2430fSAndrzej Pietrasiewicz struct file *filp = curlun->filp;
28800a2430fSAndrzej Pietrasiewicz
28900a2430fSAndrzej Pietrasiewicz if (curlun->ro || !filp)
29000a2430fSAndrzej Pietrasiewicz return 0;
29100a2430fSAndrzej Pietrasiewicz return vfs_fsync(filp, 1);
29200a2430fSAndrzej Pietrasiewicz }
29300a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub);
29400a2430fSAndrzej Pietrasiewicz
store_cdrom_address(u8 * dest,int msf,u32 addr)29500a2430fSAndrzej Pietrasiewicz void store_cdrom_address(u8 *dest, int msf, u32 addr)
29600a2430fSAndrzej Pietrasiewicz {
29700a2430fSAndrzej Pietrasiewicz if (msf) {
2989d4dc16eSKrishna Kurapati /*
2999d4dc16eSKrishna Kurapati * Convert to Minutes-Seconds-Frames.
3009d4dc16eSKrishna Kurapati * Sector size is already set to 2048 bytes.
3019d4dc16eSKrishna Kurapati */
30200a2430fSAndrzej Pietrasiewicz addr += 2*75; /* Lead-in occupies 2 seconds */
30300a2430fSAndrzej Pietrasiewicz dest[3] = addr % 75; /* Frames */
30400a2430fSAndrzej Pietrasiewicz addr /= 75;
30500a2430fSAndrzej Pietrasiewicz dest[2] = addr % 60; /* Seconds */
30600a2430fSAndrzej Pietrasiewicz addr /= 60;
30700a2430fSAndrzej Pietrasiewicz dest[1] = addr; /* Minutes */
30800a2430fSAndrzej Pietrasiewicz dest[0] = 0; /* Reserved */
30900a2430fSAndrzej Pietrasiewicz } else {
31000a2430fSAndrzej Pietrasiewicz /* Absolute sector */
31100a2430fSAndrzej Pietrasiewicz put_unaligned_be32(addr, dest);
31200a2430fSAndrzej Pietrasiewicz }
31300a2430fSAndrzej Pietrasiewicz }
31400a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(store_cdrom_address);
31500a2430fSAndrzej Pietrasiewicz
31600a2430fSAndrzej Pietrasiewicz /*-------------------------------------------------------------------------*/
31700a2430fSAndrzej Pietrasiewicz
31800a2430fSAndrzej Pietrasiewicz
fsg_show_ro(struct fsg_lun * curlun,char * buf)31900a2430fSAndrzej Pietrasiewicz ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf)
32000a2430fSAndrzej Pietrasiewicz {
32100a2430fSAndrzej Pietrasiewicz return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
32200a2430fSAndrzej Pietrasiewicz ? curlun->ro
32300a2430fSAndrzej Pietrasiewicz : curlun->initially_ro);
32400a2430fSAndrzej Pietrasiewicz }
32500a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_show_ro);
32600a2430fSAndrzej Pietrasiewicz
fsg_show_nofua(struct fsg_lun * curlun,char * buf)32700a2430fSAndrzej Pietrasiewicz ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf)
32800a2430fSAndrzej Pietrasiewicz {
32900a2430fSAndrzej Pietrasiewicz return sprintf(buf, "%u\n", curlun->nofua);
33000a2430fSAndrzej Pietrasiewicz }
33100a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_show_nofua);
33200a2430fSAndrzej Pietrasiewicz
fsg_show_file(struct fsg_lun * curlun,struct rw_semaphore * filesem,char * buf)33300a2430fSAndrzej Pietrasiewicz ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
33400a2430fSAndrzej Pietrasiewicz char *buf)
33500a2430fSAndrzej Pietrasiewicz {
33600a2430fSAndrzej Pietrasiewicz char *p;
33700a2430fSAndrzej Pietrasiewicz ssize_t rc;
33800a2430fSAndrzej Pietrasiewicz
33900a2430fSAndrzej Pietrasiewicz down_read(filesem);
34000a2430fSAndrzej Pietrasiewicz if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */
3419bf39ab2SMiklos Szeredi p = file_path(curlun->filp, buf, PAGE_SIZE - 1);
34200a2430fSAndrzej Pietrasiewicz if (IS_ERR(p))
34300a2430fSAndrzej Pietrasiewicz rc = PTR_ERR(p);
34400a2430fSAndrzej Pietrasiewicz else {
34500a2430fSAndrzej Pietrasiewicz rc = strlen(p);
34600a2430fSAndrzej Pietrasiewicz memmove(buf, p, rc);
34700a2430fSAndrzej Pietrasiewicz buf[rc] = '\n'; /* Add a newline */
34800a2430fSAndrzej Pietrasiewicz buf[++rc] = 0;
34900a2430fSAndrzej Pietrasiewicz }
35000a2430fSAndrzej Pietrasiewicz } else { /* No file, return 0 bytes */
35100a2430fSAndrzej Pietrasiewicz *buf = 0;
35200a2430fSAndrzej Pietrasiewicz rc = 0;
35300a2430fSAndrzej Pietrasiewicz }
35400a2430fSAndrzej Pietrasiewicz up_read(filesem);
35500a2430fSAndrzej Pietrasiewicz return rc;
35600a2430fSAndrzej Pietrasiewicz }
35700a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_show_file);
35800a2430fSAndrzej Pietrasiewicz
fsg_show_cdrom(struct fsg_lun * curlun,char * buf)35900a2430fSAndrzej Pietrasiewicz ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf)
36000a2430fSAndrzej Pietrasiewicz {
36100a2430fSAndrzej Pietrasiewicz return sprintf(buf, "%u\n", curlun->cdrom);
36200a2430fSAndrzej Pietrasiewicz }
36300a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_show_cdrom);
36400a2430fSAndrzej Pietrasiewicz
fsg_show_removable(struct fsg_lun * curlun,char * buf)36500a2430fSAndrzej Pietrasiewicz ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf)
36600a2430fSAndrzej Pietrasiewicz {
36700a2430fSAndrzej Pietrasiewicz return sprintf(buf, "%u\n", curlun->removable);
36800a2430fSAndrzej Pietrasiewicz }
36900a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_show_removable);
37000a2430fSAndrzej Pietrasiewicz
fsg_show_inquiry_string(struct fsg_lun * curlun,char * buf)3716ac47090SPhilipp Gesang ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf)
3726ac47090SPhilipp Gesang {
3736ac47090SPhilipp Gesang return sprintf(buf, "%s\n", curlun->inquiry_string);
3746ac47090SPhilipp Gesang }
3756ac47090SPhilipp Gesang EXPORT_SYMBOL_GPL(fsg_show_inquiry_string);
3766ac47090SPhilipp Gesang
37700a2430fSAndrzej Pietrasiewicz /*
37800a2430fSAndrzej Pietrasiewicz * The caller must hold fsg->filesem for reading when calling this function.
37900a2430fSAndrzej Pietrasiewicz */
_fsg_store_ro(struct fsg_lun * curlun,bool ro)38000a2430fSAndrzej Pietrasiewicz static ssize_t _fsg_store_ro(struct fsg_lun *curlun, bool ro)
38100a2430fSAndrzej Pietrasiewicz {
38200a2430fSAndrzej Pietrasiewicz if (fsg_lun_is_open(curlun)) {
38300a2430fSAndrzej Pietrasiewicz LDBG(curlun, "read-only status change prevented\n");
38400a2430fSAndrzej Pietrasiewicz return -EBUSY;
38500a2430fSAndrzej Pietrasiewicz }
38600a2430fSAndrzej Pietrasiewicz
38700a2430fSAndrzej Pietrasiewicz curlun->ro = ro;
38800a2430fSAndrzej Pietrasiewicz curlun->initially_ro = ro;
38900a2430fSAndrzej Pietrasiewicz LDBG(curlun, "read-only status set to %d\n", curlun->ro);
39000a2430fSAndrzej Pietrasiewicz
39100a2430fSAndrzej Pietrasiewicz return 0;
39200a2430fSAndrzej Pietrasiewicz }
39300a2430fSAndrzej Pietrasiewicz
fsg_store_ro(struct fsg_lun * curlun,struct rw_semaphore * filesem,const char * buf,size_t count)39400a2430fSAndrzej Pietrasiewicz ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
39500a2430fSAndrzej Pietrasiewicz const char *buf, size_t count)
39600a2430fSAndrzej Pietrasiewicz {
39700a2430fSAndrzej Pietrasiewicz ssize_t rc;
39800a2430fSAndrzej Pietrasiewicz bool ro;
39900a2430fSAndrzej Pietrasiewicz
400*a8bc8cc1SChristophe JAILLET rc = kstrtobool(buf, &ro);
40100a2430fSAndrzej Pietrasiewicz if (rc)
40200a2430fSAndrzej Pietrasiewicz return rc;
40300a2430fSAndrzej Pietrasiewicz
40400a2430fSAndrzej Pietrasiewicz /*
40500a2430fSAndrzej Pietrasiewicz * Allow the write-enable status to change only while the
40600a2430fSAndrzej Pietrasiewicz * backing file is closed.
40700a2430fSAndrzej Pietrasiewicz */
40800a2430fSAndrzej Pietrasiewicz down_read(filesem);
40900a2430fSAndrzej Pietrasiewicz rc = _fsg_store_ro(curlun, ro);
41000a2430fSAndrzej Pietrasiewicz if (!rc)
41100a2430fSAndrzej Pietrasiewicz rc = count;
41200a2430fSAndrzej Pietrasiewicz up_read(filesem);
41300a2430fSAndrzej Pietrasiewicz
41400a2430fSAndrzej Pietrasiewicz return rc;
41500a2430fSAndrzej Pietrasiewicz }
41600a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_store_ro);
41700a2430fSAndrzej Pietrasiewicz
fsg_store_nofua(struct fsg_lun * curlun,const char * buf,size_t count)41800a2430fSAndrzej Pietrasiewicz ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)
41900a2430fSAndrzej Pietrasiewicz {
42000a2430fSAndrzej Pietrasiewicz bool nofua;
42100a2430fSAndrzej Pietrasiewicz int ret;
42200a2430fSAndrzej Pietrasiewicz
423*a8bc8cc1SChristophe JAILLET ret = kstrtobool(buf, &nofua);
42400a2430fSAndrzej Pietrasiewicz if (ret)
42500a2430fSAndrzej Pietrasiewicz return ret;
42600a2430fSAndrzej Pietrasiewicz
42700a2430fSAndrzej Pietrasiewicz /* Sync data when switching from async mode to sync */
42800a2430fSAndrzej Pietrasiewicz if (!nofua && curlun->nofua)
42900a2430fSAndrzej Pietrasiewicz fsg_lun_fsync_sub(curlun);
43000a2430fSAndrzej Pietrasiewicz
43100a2430fSAndrzej Pietrasiewicz curlun->nofua = nofua;
43200a2430fSAndrzej Pietrasiewicz
43300a2430fSAndrzej Pietrasiewicz return count;
43400a2430fSAndrzej Pietrasiewicz }
43500a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_store_nofua);
43600a2430fSAndrzej Pietrasiewicz
fsg_store_file(struct fsg_lun * curlun,struct rw_semaphore * filesem,const char * buf,size_t count)43700a2430fSAndrzej Pietrasiewicz ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
43800a2430fSAndrzej Pietrasiewicz const char *buf, size_t count)
43900a2430fSAndrzej Pietrasiewicz {
44000a2430fSAndrzej Pietrasiewicz int rc = 0;
44100a2430fSAndrzej Pietrasiewicz
44200a2430fSAndrzej Pietrasiewicz if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
44300a2430fSAndrzej Pietrasiewicz LDBG(curlun, "eject attempt prevented\n");
44400a2430fSAndrzej Pietrasiewicz return -EBUSY; /* "Door is locked" */
44500a2430fSAndrzej Pietrasiewicz }
44600a2430fSAndrzej Pietrasiewicz
44700a2430fSAndrzej Pietrasiewicz /* Remove a trailing newline */
44800a2430fSAndrzej Pietrasiewicz if (count > 0 && buf[count-1] == '\n')
44900a2430fSAndrzej Pietrasiewicz ((char *) buf)[count-1] = 0; /* Ugh! */
45000a2430fSAndrzej Pietrasiewicz
45100a2430fSAndrzej Pietrasiewicz /* Load new medium */
45200a2430fSAndrzej Pietrasiewicz down_write(filesem);
45300a2430fSAndrzej Pietrasiewicz if (count > 0 && buf[0]) {
45400a2430fSAndrzej Pietrasiewicz /* fsg_lun_open() will close existing file if any. */
45500a2430fSAndrzej Pietrasiewicz rc = fsg_lun_open(curlun, buf);
45600a2430fSAndrzej Pietrasiewicz if (rc == 0)
45700a2430fSAndrzej Pietrasiewicz curlun->unit_attention_data =
45800a2430fSAndrzej Pietrasiewicz SS_NOT_READY_TO_READY_TRANSITION;
45900a2430fSAndrzej Pietrasiewicz } else if (fsg_lun_is_open(curlun)) {
46000a2430fSAndrzej Pietrasiewicz fsg_lun_close(curlun);
46100a2430fSAndrzej Pietrasiewicz curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
46200a2430fSAndrzej Pietrasiewicz }
46300a2430fSAndrzej Pietrasiewicz up_write(filesem);
46400a2430fSAndrzej Pietrasiewicz return (rc < 0 ? rc : count);
46500a2430fSAndrzej Pietrasiewicz }
46600a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_store_file);
46700a2430fSAndrzej Pietrasiewicz
fsg_store_cdrom(struct fsg_lun * curlun,struct rw_semaphore * filesem,const char * buf,size_t count)46800a2430fSAndrzej Pietrasiewicz ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem,
46900a2430fSAndrzej Pietrasiewicz const char *buf, size_t count)
47000a2430fSAndrzej Pietrasiewicz {
47100a2430fSAndrzej Pietrasiewicz bool cdrom;
47200a2430fSAndrzej Pietrasiewicz int ret;
47300a2430fSAndrzej Pietrasiewicz
474*a8bc8cc1SChristophe JAILLET ret = kstrtobool(buf, &cdrom);
47500a2430fSAndrzej Pietrasiewicz if (ret)
47600a2430fSAndrzej Pietrasiewicz return ret;
47700a2430fSAndrzej Pietrasiewicz
47800a2430fSAndrzej Pietrasiewicz down_read(filesem);
47900a2430fSAndrzej Pietrasiewicz ret = cdrom ? _fsg_store_ro(curlun, true) : 0;
48000a2430fSAndrzej Pietrasiewicz
48100a2430fSAndrzej Pietrasiewicz if (!ret) {
48200a2430fSAndrzej Pietrasiewicz curlun->cdrom = cdrom;
48300a2430fSAndrzej Pietrasiewicz ret = count;
48400a2430fSAndrzej Pietrasiewicz }
48500a2430fSAndrzej Pietrasiewicz up_read(filesem);
48600a2430fSAndrzej Pietrasiewicz
48700a2430fSAndrzej Pietrasiewicz return ret;
48800a2430fSAndrzej Pietrasiewicz }
48900a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_store_cdrom);
49000a2430fSAndrzej Pietrasiewicz
fsg_store_removable(struct fsg_lun * curlun,const char * buf,size_t count)49100a2430fSAndrzej Pietrasiewicz ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf,
49200a2430fSAndrzej Pietrasiewicz size_t count)
49300a2430fSAndrzej Pietrasiewicz {
49400a2430fSAndrzej Pietrasiewicz bool removable;
49500a2430fSAndrzej Pietrasiewicz int ret;
49600a2430fSAndrzej Pietrasiewicz
497*a8bc8cc1SChristophe JAILLET ret = kstrtobool(buf, &removable);
49800a2430fSAndrzej Pietrasiewicz if (ret)
49900a2430fSAndrzej Pietrasiewicz return ret;
50000a2430fSAndrzej Pietrasiewicz
50100a2430fSAndrzej Pietrasiewicz curlun->removable = removable;
50200a2430fSAndrzej Pietrasiewicz
50300a2430fSAndrzej Pietrasiewicz return count;
50400a2430fSAndrzej Pietrasiewicz }
50500a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(fsg_store_removable);
50600a2430fSAndrzej Pietrasiewicz
fsg_store_inquiry_string(struct fsg_lun * curlun,const char * buf,size_t count)5076ac47090SPhilipp Gesang ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf,
5086ac47090SPhilipp Gesang size_t count)
5096ac47090SPhilipp Gesang {
5106ac47090SPhilipp Gesang const size_t len = min(count, sizeof(curlun->inquiry_string));
5116ac47090SPhilipp Gesang
5126ac47090SPhilipp Gesang if (len == 0 || buf[0] == '\n') {
5136ac47090SPhilipp Gesang curlun->inquiry_string[0] = 0;
5146ac47090SPhilipp Gesang } else {
5156ac47090SPhilipp Gesang snprintf(curlun->inquiry_string,
5166ac47090SPhilipp Gesang sizeof(curlun->inquiry_string), "%-28s", buf);
5176ac47090SPhilipp Gesang if (curlun->inquiry_string[len-1] == '\n')
5186ac47090SPhilipp Gesang curlun->inquiry_string[len-1] = ' ';
5196ac47090SPhilipp Gesang }
5206ac47090SPhilipp Gesang
5216ac47090SPhilipp Gesang return count;
5226ac47090SPhilipp Gesang }
5236ac47090SPhilipp Gesang EXPORT_SYMBOL_GPL(fsg_store_inquiry_string);
5246ac47090SPhilipp Gesang
fsg_store_forced_eject(struct fsg_lun * curlun,struct rw_semaphore * filesem,const char * buf,size_t count)525421c8d9aSMaxim Devaev ssize_t fsg_store_forced_eject(struct fsg_lun *curlun, struct rw_semaphore *filesem,
526421c8d9aSMaxim Devaev const char *buf, size_t count)
527421c8d9aSMaxim Devaev {
528421c8d9aSMaxim Devaev int ret;
529421c8d9aSMaxim Devaev
530421c8d9aSMaxim Devaev /*
531421c8d9aSMaxim Devaev * Forcibly detach the backing file from the LUN
532421c8d9aSMaxim Devaev * regardless of whether the host has allowed it.
533421c8d9aSMaxim Devaev */
534421c8d9aSMaxim Devaev curlun->prevent_medium_removal = 0;
535421c8d9aSMaxim Devaev ret = fsg_store_file(curlun, filesem, "", 0);
536421c8d9aSMaxim Devaev return ret < 0 ? ret : count;
537421c8d9aSMaxim Devaev }
538421c8d9aSMaxim Devaev EXPORT_SYMBOL_GPL(fsg_store_forced_eject);
539421c8d9aSMaxim Devaev
54000a2430fSAndrzej Pietrasiewicz MODULE_LICENSE("GPL");
541