Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e449dc59 authored by Azhar Shaikh's avatar Azhar Shaikh
Browse files

USB: android gadget: mass_storage: read/write performance enhancement



As per the mass storage protocol, csw is sent from the device
after successfully writing the data on to storage media, where
there is a time factor involved. With this csw hack, csw is sent
just after receiving the data & before writing the data on the
storage media. By, any chance, if the write fails, the corresponding
lun is removed to indicate the user of write failure.

Buffers has been increased to 4, so that there is enough space for
the incoming data, which is usually 64KB per CBW.

Change-Id: I59dd9add13d1224f09d94e951ad9190c44c4d1b7
Signed-off-by: default avatarChiranjeevi Velempati <cvelempa@codeaurora.org>
Signed-off-by: default avatarAzhar Shaikh <azhars@codeaurora.org>
parent 125aa701
Loading
Loading
Loading
Loading
+54 −4
Original line number Diff line number Diff line
@@ -261,6 +261,9 @@ static int msc_vfs_timer_period_ms = MSC_VFS_TIMER_PERIOD_MS;
module_param(msc_vfs_timer_period_ms, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(msc_vfs_timer_period_ms, "Set period for MSC VFS timer");

static int write_error_after_csw_sent;
static int csw_sent;

struct fsg_dev;
struct fsg_common;

@@ -285,7 +288,6 @@ struct fsg_common {
	struct fsg_buffhd	*next_buffhd_to_drain;
	struct fsg_buffhd	*buffhds;
	unsigned int		fsg_num_buffers;

	int			cmnd_size;
	u8			cmnd[MAX_COMMAND_SIZE];

@@ -384,6 +386,7 @@ static inline struct fsg_dev *fsg_from_func(struct usb_function *f)
}

typedef void (*fsg_routine_t)(struct fsg_dev *);
static int send_status(struct fsg_common *common);

static int exception_in_progress(struct fsg_common *common)
{
@@ -804,8 +807,8 @@ static int do_write(struct fsg_common *common)
	loff_t			usb_offset, file_offset, file_offset_tmp;
	unsigned int		amount;
	ssize_t			nwritten;
	int			rc;
	ktime_t			start, diff;
	int			rc, i;

	if (curlun->ro) {
		curlun->sense_data = SS_WRITE_PROTECTED;
@@ -899,7 +902,13 @@ static int do_write(struct fsg_common *common)
		bh = common->next_buffhd_to_drain;
		if (bh->state == BUF_STATE_EMPTY && !get_some_more)
			break;			/* We stopped early */
		if (bh->state == BUF_STATE_FULL) {
		/*
		 * If the csw packet is already submmitted to the hardware,
		 * by marking the state of buffer as full, then by checking
		 * the residue, we make sure that this csw packet is not
		 * written on to the storage media.
		 */
		if (bh->state == BUF_STATE_FULL && common->residue) {
			smp_rmb();
			common->next_buffhd_to_drain = bh->next;
			bh->state = BUF_STATE_EMPTY;
@@ -969,9 +978,32 @@ static int do_write(struct fsg_common *common)
				curlun->sense_data_info =
					file_offset >> curlun->blkbits;
				curlun->info_valid = 1;
				write_error_after_csw_sent = 1;
				goto write_error;
				break;
			}

write_error:
			if ((nwritten == amount) && !csw_sent) {
				if (write_error_after_csw_sent)
					break;
				/*
				 * Check if any of the buffer is in the
				 * busy state, if any buffer is in busy state,
				 * means the complete data is not received
				 * yet from the host. So there is no point in
				 * csw right away without the complete data.
				 */
				for (i = 0; i < common->fsg_num_buffers; i++) {
					if (common->buffhds[i].state ==
							BUF_STATE_BUSY)
						break;
				}
				if (!amount_left_to_req &&
						i == common->fsg_num_buffers) {
					csw_sent = 1;
					send_status(common);
				}
			}
 empty_write:
			/* Did the host decide to stop early? */
			if (bh->outreq->actual < bh->bulk_out_intended_length) {
@@ -1714,6 +1746,15 @@ static int send_status(struct fsg_common *common)
	csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
	csw->Tag = common->tag;
	csw->Residue = cpu_to_le32(common->residue);
	/*
	 * Since csw is being sent early, before
	 * writing on to storage media, need to set
	 * residue to zero,assuming that write will succeed.
	 */
	if (write_error_after_csw_sent)
		write_error_after_csw_sent = 0;
	else
		csw->Residue = 0;
	csw->Status = status;

	bh->inreq->length = US_BULK_CS_WRAP_LEN;
@@ -2611,6 +2652,15 @@ static int fsg_main_thread(void *common_)
			common->state = FSG_STATE_STATUS_PHASE;
		spin_unlock_irq(&common->lock);

		/*
		 * Since status is already sent for write scsi command,
		 * need to skip sending status once again if it is a
		 * write scsi command.
		 */
		if (csw_sent) {
			csw_sent = 0;
			continue;
		}
		if (send_status(common))
			continue;