1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * storage_common.c -- Common definitions for mass storage functionality
4 *
5 * Copyright (C) 2003-2008 Alan Stern
6 * Copyeight (C) 2009 Samsung Electronics
7 * Author: Michal Nazarewicz (mina86@mina86.com)
8 */
9
10/*
11 * This file requires the following identifiers used in USB strings to
12 * be defined (each of type pointer to char):
13 *  - fsg_string_interface    -- name of the interface
14 */
15
16/*
17 * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
18 * sets the number of pipeline buffers (length of the fsg_buffhd array).
19 * The valid range of num_buffers is: num >= 2 && num <= 4.
20 */
21
22#include <linux/module.h>
23#include <linux/blkdev.h>
24#include <linux/file.h>
25#include <linux/fs.h>
26#include <linux/usb/composite.h>
27
28#include "storage_common.h"
29
30/* There is only one interface. */
31
32struct usb_interface_descriptor fsg_intf_desc = {
33	.bLength =		sizeof fsg_intf_desc,
34	.bDescriptorType =	USB_DT_INTERFACE,
35
36	.bNumEndpoints =	2,		/* Adjusted during fsg_bind() */
37	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
38	.bInterfaceSubClass =	USB_SC_SCSI,	/* Adjusted during fsg_bind() */
39	.bInterfaceProtocol =	USB_PR_BULK,	/* Adjusted during fsg_bind() */
40	.iInterface =		FSG_STRING_INTERFACE,
41};
42EXPORT_SYMBOL_GPL(fsg_intf_desc);
43
44/*
45 * Three full-speed endpoint descriptors: bulk-in, bulk-out, and
46 * interrupt-in.
47 */
48
49struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = {
50	.bLength =		USB_DT_ENDPOINT_SIZE,
51	.bDescriptorType =	USB_DT_ENDPOINT,
52
53	.bEndpointAddress =	USB_DIR_IN,
54	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
55	/* wMaxPacketSize set by autoconfiguration */
56};
57EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc);
58
59struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = {
60	.bLength =		USB_DT_ENDPOINT_SIZE,
61	.bDescriptorType =	USB_DT_ENDPOINT,
62
63	.bEndpointAddress =	USB_DIR_OUT,
64	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
65	/* wMaxPacketSize set by autoconfiguration */
66};
67EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc);
68
69struct usb_descriptor_header *fsg_fs_function[] = {
70	(struct usb_descriptor_header *) &fsg_intf_desc,
71	(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
72	(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
73	NULL,
74};
75EXPORT_SYMBOL_GPL(fsg_fs_function);
76
77
78/*
79 * USB 2.0 devices need to expose both high speed and full speed
80 * descriptors, unless they only run at full speed.
81 *
82 * That means alternate endpoint descriptors (bigger packets).
83 */
84struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = {
85	.bLength =		USB_DT_ENDPOINT_SIZE,
86	.bDescriptorType =	USB_DT_ENDPOINT,
87
88	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
89	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
90	.wMaxPacketSize =	cpu_to_le16(512),
91};
92EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc);
93
94struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = {
95	.bLength =		USB_DT_ENDPOINT_SIZE,
96	.bDescriptorType =	USB_DT_ENDPOINT,
97
98	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
99	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
100	.wMaxPacketSize =	cpu_to_le16(512),
101	.bInterval =		1,	/* NAK every 1 uframe */
102};
103EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc);
104
105
106struct usb_descriptor_header *fsg_hs_function[] = {
107	(struct usb_descriptor_header *) &fsg_intf_desc,
108	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
109	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
110	NULL,
111};
112EXPORT_SYMBOL_GPL(fsg_hs_function);
113
114struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = {
115	.bLength =		USB_DT_ENDPOINT_SIZE,
116	.bDescriptorType =	USB_DT_ENDPOINT,
117
118	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
119	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
120	.wMaxPacketSize =	cpu_to_le16(1024),
121};
122EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc);
123
124struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
125	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
126	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
127
128	/*.bMaxBurst =		DYNAMIC, */
129};
130EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc);
131
132struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = {
133	.bLength =		USB_DT_ENDPOINT_SIZE,
134	.bDescriptorType =	USB_DT_ENDPOINT,
135
136	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
137	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
138	.wMaxPacketSize =	cpu_to_le16(1024),
139};
140EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc);
141
142struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
143	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
144	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
145
146	/*.bMaxBurst =		DYNAMIC, */
147};
148EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc);
149
150struct usb_descriptor_header *fsg_ss_function[] = {
151	(struct usb_descriptor_header *) &fsg_intf_desc,
152	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
153	(struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
154	(struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
155	(struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
156	NULL,
157};
158EXPORT_SYMBOL_GPL(fsg_ss_function);
159
160
161 /*-------------------------------------------------------------------------*/
162
163/*
164 * If the next two routines are called while the gadget is registered,
165 * the caller must own fsg->filesem for writing.
166 */
167
168void fsg_lun_close(struct fsg_lun *curlun)
169{
170	if (curlun->filp) {
171		LDBG(curlun, "close backing file\n");
172		fput(curlun->filp);
173		curlun->filp = NULL;
174	}
175}
176EXPORT_SYMBOL_GPL(fsg_lun_close);
177
178int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
179{
180	int				ro;
181	struct file			*filp = NULL;
182	int				rc = -EINVAL;
183	struct inode			*inode = NULL;
184	loff_t				size;
185	loff_t				num_sectors;
186	loff_t				min_sectors;
187	unsigned int			blkbits;
188	unsigned int			blksize;
189
190	/* R/W if we can, R/O if we must */
191	ro = curlun->initially_ro;
192	if (!ro) {
193		filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
194		if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
195			ro = 1;
196	}
197	if (ro)
198		filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
199	if (IS_ERR(filp)) {
200		LINFO(curlun, "unable to open backing file: %s\n", filename);
201		return PTR_ERR(filp);
202	}
203
204	if (!(filp->f_mode & FMODE_WRITE))
205		ro = 1;
206
207	inode = file_inode(filp);
208	if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
209		LINFO(curlun, "invalid file type: %s\n", filename);
210		goto out;
211	}
212
213	/*
214	 * If we can't read the file, it's no good.
215	 * If we can't write the file, use it read-only.
216	 */
217	if (!(filp->f_mode & FMODE_CAN_READ)) {
218		LINFO(curlun, "file not readable: %s\n", filename);
219		goto out;
220	}
221	if (!(filp->f_mode & FMODE_CAN_WRITE))
222		ro = 1;
223
224	size = i_size_read(inode->i_mapping->host);
225	if (size < 0) {
226		LINFO(curlun, "unable to find file size: %s\n", filename);
227		rc = (int) size;
228		goto out;
229	}
230
231	if (curlun->cdrom) {
232		blksize = 2048;
233		blkbits = 11;
234	} else if (inode->i_bdev) {
235		blksize = bdev_logical_block_size(inode->i_bdev);
236		blkbits = blksize_bits(blksize);
237	} else {
238		blksize = 512;
239		blkbits = 9;
240	}
241
242	num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
243	min_sectors = 1;
244	if (curlun->cdrom) {
245		min_sectors = 300;	/* Smallest track is 300 frames */
246		if (num_sectors >= 256*60*75) {
247			num_sectors = 256*60*75 - 1;
248			LINFO(curlun, "file too big: %s\n", filename);
249			LINFO(curlun, "using only first %d blocks\n",
250					(int) num_sectors);
251		}
252	}
253	if (num_sectors < min_sectors) {
254		LINFO(curlun, "file too small: %s\n", filename);
255		rc = -ETOOSMALL;
256		goto out;
257	}
258
259	if (fsg_lun_is_open(curlun))
260		fsg_lun_close(curlun);
261
262	curlun->blksize = blksize;
263	curlun->blkbits = blkbits;
264	curlun->ro = ro;
265	curlun->filp = filp;
266	curlun->file_length = size;
267	curlun->num_sectors = num_sectors;
268	LDBG(curlun, "open backing file: %s\n", filename);
269	return 0;
270
271out:
272	fput(filp);
273	return rc;
274}
275EXPORT_SYMBOL_GPL(fsg_lun_open);
276
277
278/*-------------------------------------------------------------------------*/
279
280/*
281 * Sync the file data, don't bother with the metadata.
282 * This code was copied from fs/buffer.c:sys_fdatasync().
283 */
284int fsg_lun_fsync_sub(struct fsg_lun *curlun)
285{
286	struct file	*filp = curlun->filp;
287
288	if (curlun->ro || !filp)
289		return 0;
290	return vfs_fsync(filp, 1);
291}
292EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub);
293
294void store_cdrom_address(u8 *dest, int msf, u32 addr)
295{
296	if (msf) {
297		/*
298		 * Convert to Minutes-Seconds-Frames.
299		 * Sector size is already set to 2048 bytes.
300		 */
301		addr += 2*75;		/* Lead-in occupies 2 seconds */
302		dest[3] = addr % 75;	/* Frames */
303		addr /= 75;
304		dest[2] = addr % 60;	/* Seconds */
305		addr /= 60;
306		dest[1] = addr;		/* Minutes */
307		dest[0] = 0;		/* Reserved */
308	} else {
309		/* Absolute sector */
310		put_unaligned_be32(addr, dest);
311	}
312}
313EXPORT_SYMBOL_GPL(store_cdrom_address);
314
315/*-------------------------------------------------------------------------*/
316
317
318ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf)
319{
320	return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
321				  ? curlun->ro
322				  : curlun->initially_ro);
323}
324EXPORT_SYMBOL_GPL(fsg_show_ro);
325
326ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf)
327{
328	return sprintf(buf, "%u\n", curlun->nofua);
329}
330EXPORT_SYMBOL_GPL(fsg_show_nofua);
331
332ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
333		      char *buf)
334{
335	char		*p;
336	ssize_t		rc;
337
338	down_read(filesem);
339	if (fsg_lun_is_open(curlun)) {	/* Get the complete pathname */
340		p = file_path(curlun->filp, buf, PAGE_SIZE - 1);
341		if (IS_ERR(p))
342			rc = PTR_ERR(p);
343		else {
344			rc = strlen(p);
345			memmove(buf, p, rc);
346			buf[rc] = '\n';		/* Add a newline */
347			buf[++rc] = 0;
348		}
349	} else {				/* No file, return 0 bytes */
350		*buf = 0;
351		rc = 0;
352	}
353	up_read(filesem);
354	return rc;
355}
356EXPORT_SYMBOL_GPL(fsg_show_file);
357
358ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf)
359{
360	return sprintf(buf, "%u\n", curlun->cdrom);
361}
362EXPORT_SYMBOL_GPL(fsg_show_cdrom);
363
364ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf)
365{
366	return sprintf(buf, "%u\n", curlun->removable);
367}
368EXPORT_SYMBOL_GPL(fsg_show_removable);
369
370ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf)
371{
372	return sprintf(buf, "%s\n", curlun->inquiry_string);
373}
374EXPORT_SYMBOL_GPL(fsg_show_inquiry_string);
375
376/*
377 * The caller must hold fsg->filesem for reading when calling this function.
378 */
379static ssize_t _fsg_store_ro(struct fsg_lun *curlun, bool ro)
380{
381	if (fsg_lun_is_open(curlun)) {
382		LDBG(curlun, "read-only status change prevented\n");
383		return -EBUSY;
384	}
385
386	curlun->ro = ro;
387	curlun->initially_ro = ro;
388	LDBG(curlun, "read-only status set to %d\n", curlun->ro);
389
390	return 0;
391}
392
393ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
394		     const char *buf, size_t count)
395{
396	ssize_t		rc;
397	bool		ro;
398
399	rc = strtobool(buf, &ro);
400	if (rc)
401		return rc;
402
403	/*
404	 * Allow the write-enable status to change only while the
405	 * backing file is closed.
406	 */
407	down_read(filesem);
408	rc = _fsg_store_ro(curlun, ro);
409	if (!rc)
410		rc = count;
411	up_read(filesem);
412
413	return rc;
414}
415EXPORT_SYMBOL_GPL(fsg_store_ro);
416
417ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)
418{
419	bool		nofua;
420	int		ret;
421
422	ret = strtobool(buf, &nofua);
423	if (ret)
424		return ret;
425
426	/* Sync data when switching from async mode to sync */
427	if (!nofua && curlun->nofua)
428		fsg_lun_fsync_sub(curlun);
429
430	curlun->nofua = nofua;
431
432	return count;
433}
434EXPORT_SYMBOL_GPL(fsg_store_nofua);
435
436ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
437		       const char *buf, size_t count)
438{
439	int		rc = 0;
440
441	if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
442		LDBG(curlun, "eject attempt prevented\n");
443		return -EBUSY;				/* "Door is locked" */
444	}
445
446	/* Remove a trailing newline */
447	if (count > 0 && buf[count-1] == '\n')
448		((char *) buf)[count-1] = 0;		/* Ugh! */
449
450	/* Load new medium */
451	down_write(filesem);
452	if (count > 0 && buf[0]) {
453		/* fsg_lun_open() will close existing file if any. */
454		rc = fsg_lun_open(curlun, buf);
455		if (rc == 0)
456			curlun->unit_attention_data =
457					SS_NOT_READY_TO_READY_TRANSITION;
458	} else if (fsg_lun_is_open(curlun)) {
459		fsg_lun_close(curlun);
460		curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
461	}
462	up_write(filesem);
463	return (rc < 0 ? rc : count);
464}
465EXPORT_SYMBOL_GPL(fsg_store_file);
466
467ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem,
468			const char *buf, size_t count)
469{
470	bool		cdrom;
471	int		ret;
472
473	ret = strtobool(buf, &cdrom);
474	if (ret)
475		return ret;
476
477	down_read(filesem);
478	ret = cdrom ? _fsg_store_ro(curlun, true) : 0;
479
480	if (!ret) {
481		curlun->cdrom = cdrom;
482		ret = count;
483	}
484	up_read(filesem);
485
486	return ret;
487}
488EXPORT_SYMBOL_GPL(fsg_store_cdrom);
489
490ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf,
491			    size_t count)
492{
493	bool		removable;
494	int		ret;
495
496	ret = strtobool(buf, &removable);
497	if (ret)
498		return ret;
499
500	curlun->removable = removable;
501
502	return count;
503}
504EXPORT_SYMBOL_GPL(fsg_store_removable);
505
506ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf,
507				 size_t count)
508{
509	const size_t len = min(count, sizeof(curlun->inquiry_string));
510
511	if (len == 0 || buf[0] == '\n') {
512		curlun->inquiry_string[0] = 0;
513	} else {
514		snprintf(curlun->inquiry_string,
515			 sizeof(curlun->inquiry_string), "%-28s", buf);
516		if (curlun->inquiry_string[len-1] == '\n')
517			curlun->inquiry_string[len-1] = ' ';
518	}
519
520	return count;
521}
522EXPORT_SYMBOL_GPL(fsg_store_inquiry_string);
523
524MODULE_LICENSE("GPL");
525