2009-10-28 18:57:14 +03:00
/*
* storage_common . c - - Common definitions for mass storage functionality
*
* Copyright ( C ) 2003 - 2008 Alan Stern
* Copyeight ( C ) 2009 Samsung Electronics
2012-01-13 18:05:16 +04:00
* Author : Michal Nazarewicz ( mina86 @ mina86 . com )
2009-10-28 18:57:15 +03:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
/*
* This file requires the following identifiers used in USB strings to
* be defined ( each of type pointer to char ) :
* - fsg_string_interface - - name of the interface
2009-10-28 18:57:19 +03:00
*/
usb: gadget: storage: make FSG_NUM_BUFFERS variable size
FSG_NUM_BUFFERS is set to 2 as default.
Usually 2 buffers are enough to establish a good buffering pipeline.
The number may be increased in order to compensate a for bursty VFS
behaviour.
Here follows a description of system that may require more than
2 buffers.
* CPU ondemand governor active
* latency cost for wake up and/or frequency change
* DMA for IO
Use case description.
* Data transfer from MMC via VFS to USB.
* DMA shuffles data from MMC and to USB.
* The CPU wakes up every now and then to pass data in and out from VFS,
which cause the bursty VFS behaviour.
Test set up
* Running dd on the host reading from the mass storage device
* cmdline: dd if=/dev/sdb of=/dev/null bs=4k count=$((256*100))
* Caches are dropped on the host and on the device before each run
Measurements on a Snowball board with ondemand_governor active.
FSG_NUM_BUFFERS 2
104857600 bytes (105 MB) copied, 5.62173 s, 18.7 MB/s
104857600 bytes (105 MB) copied, 5.61811 s, 18.7 MB/s
104857600 bytes (105 MB) copied, 5.57817 s, 18.8 MB/s
FSG_NUM_BUFFERS 4
104857600 bytes (105 MB) copied, 5.26839 s, 19.9 MB/s
104857600 bytes (105 MB) copied, 5.2691 s, 19.9 MB/s
104857600 bytes (105 MB) copied, 5.2711 s, 19.9 MB/s
There may not be one optimal number for all boards. This is why
the number is added to Kconfig. If selecting USB_GADGET_DEBUG_FILES
this value may be set by a module parameter as well.
Signed-off-by: Per Forlin <per.forlin@linaro.org>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Felipe Balbi <balbi@ti.com>
2011-08-19 23:21:27 +04:00
/*
* When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
* sets the number of pipeline buffers ( length of the fsg_buffhd array ) .
* The valid range of num_buffers is : num > = 2 & & num < = 4.
*/
2009-10-28 18:57:14 +03:00
2010-10-07 15:05:24 +04:00
# include <linux/usb/storage.h>
2010-10-07 16:46:15 +04:00
# include <scsi/scsi.h>
# include <asm/unaligned.h>
2009-10-28 18:57:15 +03:00
2009-10-28 18:57:14 +03:00
2010-07-05 18:38:04 +04:00
/*
* Thanks to NetChip Technologies for donating this product ID .
2009-10-28 18:57:17 +03:00
*
* DO NOT REUSE THESE IDs with any other driver ! ! Ever ! !
2010-07-05 18:38:04 +04:00
* Instead : allocate your own , using normal USB - IF procedures .
*/
2009-11-09 16:15:23 +03:00
# define FSG_VENDOR_ID 0x0525 /* NetChip */
# define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
2009-10-28 18:57:17 +03:00
2009-10-28 18:57:14 +03:00
/*-------------------------------------------------------------------------*/
# ifndef DEBUG
# undef VERBOSE_DEBUG
# undef DUMP_MSGS
# endif /* !DEBUG */
# ifdef VERBOSE_DEBUG
# define VLDBG LDBG
# else
# define VLDBG(lun, fmt, args...) do { } while (0)
# endif /* VERBOSE_DEBUG */
# define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args)
# define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
# define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args)
# define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args)
# ifdef DUMP_MSGS
# define dump_msg(fsg, /* const char * */ label, \
2009-11-09 16:15:23 +03:00
/* const u8 * */ buf , /* unsigned */ length ) do { \
2009-10-28 18:57:14 +03:00
if ( length < 512 ) { \
DBG ( fsg , " %s, length %u: \n " , label , length ) ; \
print_hex_dump ( KERN_DEBUG , " " , DUMP_PREFIX_OFFSET , \
16 , 1 , buf , length , 0 ) ; \
} \
} while ( 0 )
# define dump_cdb(fsg) do { } while (0)
# else
# define dump_msg(fsg, /* const char * */ label, \
2009-11-09 16:15:23 +03:00
/* const u8 * */ buf , /* unsigned */ length ) do { } while ( 0 )
2009-10-28 18:57:14 +03:00
# ifdef VERBOSE_DEBUG
2009-11-09 16:15:23 +03:00
# define dump_cdb(fsg) \
2009-10-28 18:57:14 +03:00
print_hex_dump ( KERN_DEBUG , " SCSI CDB: " , DUMP_PREFIX_NONE , \
16 , 1 , ( fsg ) - > cmnd , ( fsg ) - > cmnd_size , 0 ) \
# else
# define dump_cdb(fsg) do { } while (0)
# endif /* VERBOSE_DEBUG */
# endif /* DUMP_MSGS */
/*-------------------------------------------------------------------------*/
2009-11-09 16:15:23 +03:00
/* Length of a SCSI Command Data Block */
# define MAX_COMMAND_SIZE 16
2009-10-28 18:57:14 +03:00
/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
# define SS_NO_SENSE 0
# define SS_COMMUNICATION_FAILURE 0x040800
# define SS_INVALID_COMMAND 0x052000
# define SS_INVALID_FIELD_IN_CDB 0x052400
# define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100
# define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500
# define SS_MEDIUM_NOT_PRESENT 0x023a00
# define SS_MEDIUM_REMOVAL_PREVENTED 0x055302
# define SS_NOT_READY_TO_READY_TRANSITION 0x062800
# define SS_RESET_OCCURRED 0x062900
# define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900
# define SS_UNRECOVERED_READ_ERROR 0x031100
# define SS_WRITE_ERROR 0x030c02
# define SS_WRITE_PROTECTED 0x072700
2009-11-09 16:15:23 +03:00
# define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */
2009-10-28 18:57:14 +03:00
# define ASC(x) ((u8) ((x) >> 8))
# define ASCQ(x) ((u8) (x))
/*-------------------------------------------------------------------------*/
2009-10-28 18:57:15 +03:00
struct fsg_lun {
2009-10-28 18:57:14 +03:00
struct file * filp ;
loff_t file_length ;
loff_t num_sectors ;
2009-11-09 16:15:23 +03:00
unsigned int initially_ro : 1 ;
unsigned int ro : 1 ;
unsigned int removable : 1 ;
unsigned int cdrom : 1 ;
unsigned int prevent_medium_removal : 1 ;
unsigned int registered : 1 ;
unsigned int info_valid : 1 ;
2010-07-22 18:53:56 +04:00
unsigned int nofua : 1 ;
2009-10-28 18:57:14 +03:00
u32 sense_data ;
u32 sense_data_info ;
u32 unit_attention_data ;
2011-08-18 09:52:59 +04:00
unsigned int blkbits ; /* Bits of logical block size of bound block device */
unsigned int blksize ; /* logical block size of bound block device */
2009-10-28 18:57:14 +03:00
struct device dev ;
} ;
2012-11-07 01:52:39 +04:00
static inline bool fsg_lun_is_open ( struct fsg_lun * curlun )
{
return curlun - > filp ! = NULL ;
}
2009-10-28 18:57:14 +03:00
2012-11-07 01:52:39 +04:00
static inline struct fsg_lun * fsg_lun_from_dev ( struct device * dev )
2009-10-28 18:57:14 +03:00
{
2009-10-28 18:57:15 +03:00
return container_of ( dev , struct fsg_lun , dev ) ;
2009-10-28 18:57:14 +03:00
}
/* Big enough to hold our biggest descriptor */
# define EP0_BUFSIZE 256
2009-11-09 16:15:23 +03:00
# define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
2009-10-28 18:57:14 +03:00
usb: gadget: storage: make FSG_NUM_BUFFERS variable size
FSG_NUM_BUFFERS is set to 2 as default.
Usually 2 buffers are enough to establish a good buffering pipeline.
The number may be increased in order to compensate a for bursty VFS
behaviour.
Here follows a description of system that may require more than
2 buffers.
* CPU ondemand governor active
* latency cost for wake up and/or frequency change
* DMA for IO
Use case description.
* Data transfer from MMC via VFS to USB.
* DMA shuffles data from MMC and to USB.
* The CPU wakes up every now and then to pass data in and out from VFS,
which cause the bursty VFS behaviour.
Test set up
* Running dd on the host reading from the mass storage device
* cmdline: dd if=/dev/sdb of=/dev/null bs=4k count=$((256*100))
* Caches are dropped on the host and on the device before each run
Measurements on a Snowball board with ondemand_governor active.
FSG_NUM_BUFFERS 2
104857600 bytes (105 MB) copied, 5.62173 s, 18.7 MB/s
104857600 bytes (105 MB) copied, 5.61811 s, 18.7 MB/s
104857600 bytes (105 MB) copied, 5.57817 s, 18.8 MB/s
FSG_NUM_BUFFERS 4
104857600 bytes (105 MB) copied, 5.26839 s, 19.9 MB/s
104857600 bytes (105 MB) copied, 5.2691 s, 19.9 MB/s
104857600 bytes (105 MB) copied, 5.2711 s, 19.9 MB/s
There may not be one optimal number for all boards. This is why
the number is added to Kconfig. If selecting USB_GADGET_DEBUG_FILES
this value may be set by a module parameter as well.
Signed-off-by: Per Forlin <per.forlin@linaro.org>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Felipe Balbi <balbi@ti.com>
2011-08-19 23:21:27 +04:00
# ifdef CONFIG_USB_GADGET_DEBUG_FILES
static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS ;
module_param_named ( num_buffers , fsg_num_buffers , uint , S_IRUGO ) ;
MODULE_PARM_DESC ( num_buffers , " Number of pipeline buffers " ) ;
# else
/*
* Number of buffers we will use .
* 2 is usually enough for good buffering pipeline
*/
# define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
# endif /* CONFIG_USB_DEBUG */
/* check if fsg_num_buffers is within a valid range */
static inline int fsg_num_buffers_validate ( void )
{
if ( fsg_num_buffers > = 2 & & fsg_num_buffers < = 4 )
return 0 ;
pr_err ( " fsg_num_buffers %u is out of range (%d to %d) \n " ,
fsg_num_buffers , 2 , 4 ) ;
return - EINVAL ;
}
2009-10-28 18:57:14 +03:00
2009-10-28 18:57:17 +03:00
/* Default size of buffer length. */
# define FSG_BUFLEN ((u32)16384)
/* Maximal number of LUNs supported in mass storage function */
# define FSG_MAX_LUNS 8
2009-10-28 18:57:14 +03:00
enum fsg_buffer_state {
BUF_STATE_EMPTY = 0 ,
BUF_STATE_FULL ,
BUF_STATE_BUSY
} ;
struct fsg_buffhd {
void * buf ;
enum fsg_buffer_state state ;
struct fsg_buffhd * next ;
2011-04-15 00:42:46 +04:00
/*
* The NetChip 2280 is faster , and handles some protocol faults
* better , if we don ' t submit any short bulk - out read requests .
* So we will record the intended request length here .
*/
unsigned int bulk_out_intended_length ;
2009-10-28 18:57:14 +03:00
struct usb_request * inreq ;
int inreq_busy ;
struct usb_request * outreq ;
int outreq_busy ;
} ;
enum fsg_state {
2009-11-09 16:15:23 +03:00
/* This one isn't used anywhere */
FSG_STATE_COMMAND_PHASE = - 10 ,
2009-10-28 18:57:14 +03:00
FSG_STATE_DATA_PHASE ,
FSG_STATE_STATUS_PHASE ,
FSG_STATE_IDLE = 0 ,
FSG_STATE_ABORT_BULK_OUT ,
FSG_STATE_RESET ,
FSG_STATE_INTERFACE_CHANGE ,
FSG_STATE_CONFIG_CHANGE ,
FSG_STATE_DISCONNECT ,
FSG_STATE_EXIT ,
FSG_STATE_TERMINATED
} ;
enum data_direction {
DATA_DIR_UNKNOWN = 0 ,
DATA_DIR_FROM_HOST ,
DATA_DIR_TO_HOST ,
DATA_DIR_NONE
} ;
/*-------------------------------------------------------------------------*/
static inline u32 get_unaligned_be24 ( u8 * buf )
{
return 0xffffff & ( u32 ) get_unaligned_be32 ( buf - 1 ) ;
}
/*-------------------------------------------------------------------------*/
2009-10-28 18:57:15 +03:00
enum {
FSG_STRING_INTERFACE
} ;
2009-10-28 18:57:14 +03:00
/* There is only one interface. */
static struct usb_interface_descriptor
2009-10-28 18:57:15 +03:00
fsg_intf_desc = {
. bLength = sizeof fsg_intf_desc ,
2009-10-28 18:57:14 +03:00
. bDescriptorType = USB_DT_INTERFACE ,
2009-11-09 16:15:23 +03:00
. bNumEndpoints = 2 , /* Adjusted during fsg_bind() */
2009-10-28 18:57:14 +03:00
. bInterfaceClass = USB_CLASS_MASS_STORAGE ,
2009-11-09 16:15:23 +03:00
. bInterfaceSubClass = USB_SC_SCSI , /* Adjusted during fsg_bind() */
. bInterfaceProtocol = USB_PR_BULK , /* Adjusted during fsg_bind() */
2009-10-28 18:57:15 +03:00
. iInterface = FSG_STRING_INTERFACE ,
2009-10-28 18:57:14 +03:00
} ;
2010-07-05 18:38:04 +04:00
/*
* Three full - speed endpoint descriptors : bulk - in , bulk - out , and
* interrupt - in .
*/
2009-10-28 18:57:14 +03:00
static struct usb_endpoint_descriptor
2009-10-28 18:57:15 +03:00
fsg_fs_bulk_in_desc = {
2009-10-28 18:57:14 +03:00
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
. bEndpointAddress = USB_DIR_IN ,
. bmAttributes = USB_ENDPOINT_XFER_BULK ,
/* wMaxPacketSize set by autoconfiguration */
} ;
static struct usb_endpoint_descriptor
2009-10-28 18:57:15 +03:00
fsg_fs_bulk_out_desc = {
2009-10-28 18:57:14 +03:00
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
. bEndpointAddress = USB_DIR_OUT ,
. bmAttributes = USB_ENDPOINT_XFER_BULK ,
/* wMaxPacketSize set by autoconfiguration */
} ;
2009-11-09 16:15:20 +03:00
static struct usb_descriptor_header * fsg_fs_function [ ] = {
2009-10-28 18:57:15 +03:00
( struct usb_descriptor_header * ) & fsg_intf_desc ,
( struct usb_descriptor_header * ) & fsg_fs_bulk_in_desc ,
( struct usb_descriptor_header * ) & fsg_fs_bulk_out_desc ,
2009-10-28 18:57:14 +03:00
NULL ,
} ;
/*
* USB 2.0 devices need to expose both high speed and full speed
* descriptors , unless they only run at full speed .
*
* That means alternate endpoint descriptors ( bigger packets )
* and a " device qualifier " . . . plus more construction options
2010-07-05 18:38:04 +04:00
* for the configuration descriptor .
2009-10-28 18:57:14 +03:00
*/
static struct usb_endpoint_descriptor
2009-10-28 18:57:15 +03:00
fsg_hs_bulk_in_desc = {
2009-10-28 18:57:14 +03:00
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
. bmAttributes = USB_ENDPOINT_XFER_BULK ,
. wMaxPacketSize = cpu_to_le16 ( 512 ) ,
} ;
static struct usb_endpoint_descriptor
2009-10-28 18:57:15 +03:00
fsg_hs_bulk_out_desc = {
2009-10-28 18:57:14 +03:00
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
. bmAttributes = USB_ENDPOINT_XFER_BULK ,
. wMaxPacketSize = cpu_to_le16 ( 512 ) ,
2009-11-09 16:15:23 +03:00
. bInterval = 1 , /* NAK every 1 uframe */
2009-10-28 18:57:14 +03:00
} ;
2009-10-28 18:57:19 +03:00
2009-11-09 16:15:20 +03:00
static struct usb_descriptor_header * fsg_hs_function [ ] = {
2009-10-28 18:57:15 +03:00
( struct usb_descriptor_header * ) & fsg_intf_desc ,
( struct usb_descriptor_header * ) & fsg_hs_bulk_in_desc ,
( struct usb_descriptor_header * ) & fsg_hs_bulk_out_desc ,
2009-10-28 18:57:14 +03:00
NULL ,
} ;
2011-08-03 15:33:27 +04:00
static struct usb_endpoint_descriptor
fsg_ss_bulk_in_desc = {
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
. bmAttributes = USB_ENDPOINT_XFER_BULK ,
. wMaxPacketSize = cpu_to_le16 ( 1024 ) ,
} ;
static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
. bLength = sizeof ( fsg_ss_bulk_in_comp_desc ) ,
. bDescriptorType = USB_DT_SS_ENDPOINT_COMP ,
/*.bMaxBurst = DYNAMIC, */
} ;
static struct usb_endpoint_descriptor
fsg_ss_bulk_out_desc = {
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
. bmAttributes = USB_ENDPOINT_XFER_BULK ,
. wMaxPacketSize = cpu_to_le16 ( 1024 ) ,
} ;
static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
. bLength = sizeof ( fsg_ss_bulk_in_comp_desc ) ,
. bDescriptorType = USB_DT_SS_ENDPOINT_COMP ,
/*.bMaxBurst = DYNAMIC, */
} ;
static struct usb_descriptor_header * fsg_ss_function [ ] = {
( struct usb_descriptor_header * ) & fsg_intf_desc ,
( struct usb_descriptor_header * ) & fsg_ss_bulk_in_desc ,
( struct usb_descriptor_header * ) & fsg_ss_bulk_in_comp_desc ,
( struct usb_descriptor_header * ) & fsg_ss_bulk_out_desc ,
( struct usb_descriptor_header * ) & fsg_ss_bulk_out_comp_desc ,
NULL ,
} ;
2009-10-28 18:57:14 +03:00
/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
2009-10-28 18:57:15 +03:00
static struct usb_string fsg_strings [ ] = {
{ FSG_STRING_INTERFACE , fsg_string_interface } ,
2009-10-28 18:57:14 +03:00
{ }
} ;
2009-10-28 18:57:15 +03:00
static struct usb_gadget_strings fsg_stringtab = {
2009-11-09 16:15:23 +03:00
. language = 0x0409 , /* en-us */
2009-10-28 18:57:15 +03:00
. strings = fsg_strings ,
2009-10-28 18:57:14 +03:00
} ;
/*-------------------------------------------------------------------------*/
2010-07-05 18:38:04 +04:00
/*
* If the next two routines are called while the gadget is registered ,
* the caller must own fsg - > filesem for writing .
*/
2009-10-28 18:57:14 +03:00
2012-06-18 16:37:20 +04:00
static void fsg_lun_close ( struct fsg_lun * curlun )
{
if ( curlun - > filp ) {
LDBG ( curlun , " close backing file \n " ) ;
fput ( curlun - > filp ) ;
curlun - > filp = NULL ;
}
}
2009-10-28 18:57:15 +03:00
static int fsg_lun_open ( struct fsg_lun * curlun , const char * filename )
2009-10-28 18:57:14 +03:00
{
int ro ;
struct file * filp = NULL ;
int rc = - EINVAL ;
struct inode * inode = NULL ;
loff_t size ;
loff_t num_sectors ;
loff_t min_sectors ;
2012-06-18 16:37:20 +04:00
unsigned int blkbits ;
unsigned int blksize ;
2009-10-28 18:57:14 +03:00
/* R/W if we can, R/O if we must */
2009-10-28 18:57:16 +03:00
ro = curlun - > initially_ro ;
2009-10-28 18:57:14 +03:00
if ( ! ro ) {
filp = filp_open ( filename , O_RDWR | O_LARGEFILE , 0 ) ;
2010-11-13 13:55:17 +03:00
if ( PTR_ERR ( filp ) = = - EROFS | | PTR_ERR ( filp ) = = - EACCES )
2009-10-28 18:57:14 +03:00
ro = 1 ;
}
if ( ro )
filp = filp_open ( filename , O_RDONLY | O_LARGEFILE , 0 ) ;
if ( IS_ERR ( filp ) ) {
LINFO ( curlun , " unable to open backing file: %s \n " , filename ) ;
return PTR_ERR ( filp ) ;
}
if ( ! ( filp - > f_mode & FMODE_WRITE ) )
ro = 1 ;
2013-01-24 02:07:38 +04:00
inode = file_inode ( filp ) ;
2012-07-22 21:23:33 +04:00
if ( ( ! S_ISREG ( inode - > i_mode ) & & ! S_ISBLK ( inode - > i_mode ) ) ) {
2009-10-28 18:57:14 +03:00
LINFO ( curlun , " invalid file type: %s \n " , filename ) ;
goto out ;
}
2010-07-05 18:38:04 +04:00
/*
* If we can ' t read the file , it ' s no good .
* If we can ' t write the file , use it read - only .
*/
2012-07-22 21:23:33 +04:00
if ( ! ( filp - > f_op - > read | | filp - > f_op - > aio_read ) ) {
2009-10-28 18:57:14 +03:00
LINFO ( curlun , " file not readable: %s \n " , filename ) ;
goto out ;
}
if ( ! ( filp - > f_op - > write | | filp - > f_op - > aio_write ) )
ro = 1 ;
size = i_size_read ( inode - > i_mapping - > host ) ;
if ( size < 0 ) {
LINFO ( curlun , " unable to find file size: %s \n " , filename ) ;
rc = ( int ) size ;
goto out ;
}
2011-08-18 09:52:59 +04:00
if ( curlun - > cdrom ) {
2012-06-18 16:37:20 +04:00
blksize = 2048 ;
blkbits = 11 ;
2011-08-18 09:52:59 +04:00
} else if ( inode - > i_bdev ) {
2012-06-18 16:37:20 +04:00
blksize = bdev_logical_block_size ( inode - > i_bdev ) ;
blkbits = blksize_bits ( blksize ) ;
2011-08-18 09:52:59 +04:00
} else {
2012-06-18 16:37:20 +04:00
blksize = 512 ;
blkbits = 9 ;
2011-08-18 09:52:59 +04:00
}
2012-06-18 16:37:20 +04:00
num_sectors = size > > blkbits ; /* File size in logic-block-size blocks */
2009-10-28 18:57:14 +03:00
min_sectors = 1 ;
2009-10-28 18:57:16 +03:00
if ( curlun - > cdrom ) {
2011-08-18 09:52:59 +04:00
min_sectors = 300 ; /* Smallest track is 300 frames */
if ( num_sectors > = 256 * 60 * 75 ) {
num_sectors = 256 * 60 * 75 - 1 ;
2009-10-28 18:57:14 +03:00
LINFO ( curlun , " file too big: %s \n " , filename ) ;
LINFO ( curlun , " using only first %d blocks \n " ,
( int ) num_sectors ) ;
}
}
if ( num_sectors < min_sectors ) {
LINFO ( curlun , " file too small: %s \n " , filename ) ;
rc = - ETOOSMALL ;
goto out ;
}
2012-06-18 16:37:20 +04:00
if ( fsg_lun_is_open ( curlun ) )
fsg_lun_close ( curlun ) ;
curlun - > blksize = blksize ;
curlun - > blkbits = blkbits ;
2009-10-28 18:57:14 +03:00
curlun - > ro = ro ;
curlun - > filp = filp ;
curlun - > file_length = size ;
curlun - > num_sectors = num_sectors ;
LDBG ( curlun , " open backing file: %s \n " , filename ) ;
2012-07-22 21:23:33 +04:00
return 0 ;
2009-10-28 18:57:14 +03:00
out :
2012-07-22 21:23:33 +04:00
fput ( filp ) ;
2009-10-28 18:57:14 +03:00
return rc ;
}
/*-------------------------------------------------------------------------*/
2010-07-05 18:38:04 +04:00
/*
* Sync the file data , don ' t bother with the metadata .
* This code was copied from fs / buffer . c : sys_fdatasync ( ) .
*/
2009-10-28 18:57:15 +03:00
static int fsg_lun_fsync_sub ( struct fsg_lun * curlun )
2009-10-28 18:57:14 +03:00
{
struct file * filp = curlun - > filp ;
if ( curlun - > ro | | ! filp )
return 0 ;
2010-03-22 19:32:25 +03:00
return vfs_fsync ( filp , 1 ) ;
2009-10-28 18:57:14 +03:00
}
static void store_cdrom_address ( u8 * dest , int msf , u32 addr )
{
if ( msf ) {
/* Convert to Minutes-Seconds-Frames */
addr > > = 2 ; /* Convert to 2048-byte frames */
addr + = 2 * 75 ; /* Lead-in occupies 2 seconds */
dest [ 3 ] = addr % 75 ; /* Frames */
addr / = 75 ;
dest [ 2 ] = addr % 60 ; /* Seconds */
addr / = 60 ;
dest [ 1 ] = addr ; /* Minutes */
dest [ 0 ] = 0 ; /* Reserved */
} else {
/* Absolute sector */
put_unaligned_be32 ( addr , dest ) ;
}
}
2009-10-28 18:57:17 +03:00
/*-------------------------------------------------------------------------*/
static ssize_t fsg_show_ro ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
return sprintf ( buf , " %d \n " , fsg_lun_is_open ( curlun )
? curlun - > ro
: curlun - > initially_ro ) ;
}
2010-07-22 18:53:56 +04:00
static ssize_t fsg_show_nofua ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
return sprintf ( buf , " %u \n " , curlun - > nofua ) ;
}
2009-10-28 18:57:17 +03:00
static ssize_t fsg_show_file ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
struct rw_semaphore * filesem = dev_get_drvdata ( dev ) ;
char * p ;
ssize_t rc ;
down_read ( filesem ) ;
2009-11-09 16:15:23 +03:00
if ( fsg_lun_is_open ( curlun ) ) { /* Get the complete pathname */
2009-10-28 18:57:17 +03:00
p = d_path ( & curlun - > filp - > f_path , buf , PAGE_SIZE - 1 ) ;
if ( IS_ERR ( p ) )
rc = PTR_ERR ( p ) ;
else {
rc = strlen ( p ) ;
memmove ( buf , p , rc ) ;
2009-11-09 16:15:23 +03:00
buf [ rc ] = ' \n ' ; /* Add a newline */
2009-10-28 18:57:17 +03:00
buf [ + + rc ] = 0 ;
}
2009-11-09 16:15:23 +03:00
} else { /* No file, return 0 bytes */
2009-10-28 18:57:17 +03:00
* buf = 0 ;
rc = 0 ;
}
up_read ( filesem ) ;
return rc ;
}
static ssize_t fsg_store_ro ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
2011-04-14 13:55:43 +04:00
ssize_t rc ;
2009-10-28 18:57:17 +03:00
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
struct rw_semaphore * filesem = dev_get_drvdata ( dev ) ;
2011-04-14 02:37:00 +04:00
unsigned ro ;
2009-10-28 18:57:17 +03:00
2011-04-14 02:37:00 +04:00
rc = kstrtouint ( buf , 2 , & ro ) ;
if ( rc )
return rc ;
2009-10-28 18:57:17 +03:00
2010-07-05 18:38:04 +04:00
/*
* Allow the write - enable status to change only while the
* backing file is closed .
*/
2009-10-28 18:57:17 +03:00
down_read ( filesem ) ;
if ( fsg_lun_is_open ( curlun ) ) {
LDBG ( curlun , " read-only status change prevented \n " ) ;
rc = - EBUSY ;
} else {
2010-07-22 12:58:47 +04:00
curlun - > ro = ro ;
curlun - > initially_ro = ro ;
2009-10-28 18:57:17 +03:00
LDBG ( curlun , " read-only status set to %d \n " , curlun - > ro ) ;
2011-04-14 13:55:43 +04:00
rc = count ;
2009-10-28 18:57:17 +03:00
}
up_read ( filesem ) ;
return rc ;
}
2010-07-22 18:53:56 +04:00
static ssize_t fsg_store_nofua ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
2011-04-14 02:37:00 +04:00
unsigned nofua ;
int ret ;
2010-07-22 18:53:56 +04:00
2011-04-14 02:37:00 +04:00
ret = kstrtouint ( buf , 2 , & nofua ) ;
if ( ret )
return ret ;
2010-07-22 18:53:56 +04:00
/* Sync data when switching from async mode to sync */
if ( ! nofua & & curlun - > nofua )
fsg_lun_fsync_sub ( curlun ) ;
curlun - > nofua = nofua ;
return count ;
}
2009-10-28 18:57:17 +03:00
static ssize_t fsg_store_file ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
struct rw_semaphore * filesem = dev_get_drvdata ( dev ) ;
int rc = 0 ;
if ( curlun - > prevent_medium_removal & & fsg_lun_is_open ( curlun ) ) {
LDBG ( curlun , " eject attempt prevented \n " ) ;
2009-11-09 16:15:23 +03:00
return - EBUSY ; /* "Door is locked" */
2009-10-28 18:57:17 +03:00
}
/* Remove a trailing newline */
if ( count > 0 & & buf [ count - 1 ] = = ' \n ' )
2009-11-09 16:15:23 +03:00
( ( char * ) buf ) [ count - 1 ] = 0 ; /* Ugh! */
2009-10-28 18:57:17 +03:00
/* Load new medium */
2012-06-18 16:37:20 +04:00
down_write ( filesem ) ;
2009-10-28 18:57:17 +03:00
if ( count > 0 & & buf [ 0 ] ) {
2012-06-18 16:37:20 +04:00
/* fsg_lun_open() will close existing file if any. */
2009-10-28 18:57:17 +03:00
rc = fsg_lun_open ( curlun , buf ) ;
if ( rc = = 0 )
curlun - > unit_attention_data =
SS_NOT_READY_TO_READY_TRANSITION ;
2012-06-18 16:37:20 +04:00
} else if ( fsg_lun_is_open ( curlun ) ) {
fsg_lun_close ( curlun ) ;
curlun - > unit_attention_data = SS_MEDIUM_NOT_PRESENT ;
2009-10-28 18:57:17 +03:00
}
up_write ( filesem ) ;
return ( rc < 0 ? rc : count ) ;
}