Index: uspace/drv/bus/usb/usbmast/bo_trans.c
===================================================================
--- uspace/drv/bus/usb/usbmast/bo_trans.c	(revision 582fe3883b8f9c711df6bea212070d0290a92558)
+++ uspace/drv/bus/usb/usbmast/bo_trans.c	(revision de3432be3bd5cf920867c570f84e50d62887f870)
@@ -58,17 +58,9 @@
  * @param tag		Command block wrapper tag (automatically compared
  *			with answer)
- * @param cmd		Command block
- * @param cmd_size	Command block size in bytes
- * @param ddir		Direction in which data will be transferred
- * @param dbuf		Data send/receive buffer
- * @param dbuf_size	Size of the data buffer
- * @param xferred_size	Number of bytes actually transferred
- * @param cmd_status	Command status
+ * @param cmd		SCSI command
  *
  * @return		Error code
  */
-static int usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, const void *cmd,
-    size_t cmd_size, usb_direction_t ddir, void *dbuf, size_t dbuf_size,
-    size_t *xferred_size, cmd_status_t *cmd_status)
+int usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, scsi_cmd_t *cmd)
 {
 	int rc;
@@ -77,9 +69,24 @@
 	usb_pipe_t *bulk_in_pipe = mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe;
 	usb_pipe_t *bulk_out_pipe = mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe;
+	usb_direction_t ddir;
+	void *dbuf;
+	size_t dbuf_size;
+
+	if (cmd->data_out != NULL && cmd->data_in == NULL) {
+		ddir = USB_DIRECTION_OUT;
+		dbuf = (void *)cmd->data_out;
+		dbuf_size = cmd->data_out_size;
+	} else if (cmd->data_out == NULL && cmd->data_in != NULL) {
+		ddir = USB_DIRECTION_IN;
+		dbuf = cmd->data_in;
+		dbuf_size = cmd->data_in_size;
+	} else {
+		assert(false);
+	}
 
 	/* Prepare CBW - command block wrapper */
 	usb_massstor_cbw_t cbw;
 	usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, mfun->lun,
-	    cmd_size, cmd);
+	    cmd->cdb_size, cmd->cdb);
 
 	/* Send the CBW. */
@@ -148,9 +155,9 @@
 	switch (csw.dCSWStatus) {
 	case cbs_passed:
-		*cmd_status = CMDS_GOOD;
+		cmd->status = CMDS_GOOD;
 		break;
 	case cbs_failed:
 		MASTLOG("Command failed\n");
-		*cmd_status = CMDS_FAILED;
+		cmd->status = CMDS_FAILED;
 		break;
 	case cbs_phase_error:
@@ -177,52 +184,8 @@
 	 */
 
-	if (xferred_size != NULL)
-		*xferred_size = dbuf_size - residue;
+	if (ddir == USB_DIRECTION_IN)
+		cmd->rcvd_size = dbuf_size - residue;
 
 	return retval;
-}
-
-/** Perform data-in command.
- *
- * @param mfun		Mass storage function
- * @param tag		Command block wrapper tag (automatically compared with
- *			answer)
- * @param cmd		CDB (Command Descriptor)
- * @param cmd_size	CDB length in bytes
- * @param dbuf		Data receive buffer
- * @param dbuf_size	Data receive buffer size in bytes
- * @param proc_size	Number of bytes actually processed by device
- * @param cmd_status	Command status
- *
- * @return Error code
- */
-int usb_massstor_data_in(usbmast_fun_t *mfun, uint32_t tag, const void *cmd,
-    size_t cmd_size, void *dbuf, size_t dbuf_size, size_t *proc_size,
-    cmd_status_t *cmd_status)
-{
-	return usb_massstor_cmd(mfun, tag, cmd, cmd_size, USB_DIRECTION_IN,
-	    dbuf, dbuf_size, proc_size, cmd_status);
-}
-
-/** Perform data-out command.
- *
- * @param mfun		Mass storage function
- * @param tag		Command block wrapper tag (automatically compared with
- *			answer)
- * @param cmd		CDB (Command Descriptor)
- * @param cmd_size	CDB length in bytes
- * @param data		Command data
- * @param data_size	Size of @a data in bytes
- * @param proc_size	Number of bytes actually processed by device
- * @param cmd_status	Command status
- *
- * @return Error code
- */
-int usb_massstor_data_out(usbmast_fun_t *mfun, uint32_t tag, const void *cmd,
-    size_t cmd_size, const void *data, size_t data_size, size_t *proc_size,
-    cmd_status_t *cmd_status)
-{
-	return usb_massstor_cmd(mfun, tag, cmd, cmd_size, USB_DIRECTION_OUT,
-	    (void *) data, data_size, proc_size, cmd_status);
 }
 
Index: uspace/drv/bus/usb/usbmast/bo_trans.h
===================================================================
--- uspace/drv/bus/usb/usbmast/bo_trans.h	(revision 582fe3883b8f9c711df6bea212070d0290a92558)
+++ uspace/drv/bus/usb/usbmast/bo_trans.h	(revision de3432be3bd5cf920867c570f84e50d62887f870)
@@ -52,8 +52,41 @@
 } cmd_status_t;
 
-extern int usb_massstor_data_in(usbmast_fun_t *, uint32_t, const void *,
-    size_t, void *, size_t, size_t *, cmd_status_t *);
-extern int usb_massstor_data_out(usbmast_fun_t *, uint32_t, const void *,
-    size_t, const void *, size_t, size_t *, cmd_status_t *);
+/** SCSI command.
+ *
+ * Contains (a subset of) the input and output arguments of SCSI
+ * Execute Command procedure call (see SAM-4 chapter 5.1)
+ */
+typedef struct {
+	/*
+	 * Related to IN fields
+	 */
+
+	/** Command Descriptor Block */
+	void *cdb;
+	/** CDB size in bytes */
+	size_t cdb_size;
+
+	/** Outgoing data */
+	const void *data_out;
+	/** Size of outgoing data in bytes */
+	size_t data_out_size;
+
+	/*
+	 * Related to OUT fields
+	 */
+
+	/** Buffer for incoming data */
+	void *data_in;
+	/** Size of input buffer in bytes */
+	size_t data_in_size;
+
+	/** Number of bytes actually received */
+	size_t rcvd_size;
+
+	/** Status */
+	cmd_status_t status;
+} scsi_cmd_t;
+
+extern int usb_massstor_cmd(usbmast_fun_t *, uint32_t, scsi_cmd_t *);
 extern int usb_massstor_reset(usbmast_dev_t *);
 extern void usb_massstor_reset_recovery(usbmast_dev_t *);
Index: uspace/drv/bus/usb/usbmast/scsi_ms.c
===================================================================
--- uspace/drv/bus/usb/usbmast/scsi_ms.c	(revision 582fe3883b8f9c711df6bea212070d0290a92558)
+++ uspace/drv/bus/usb/usbmast/scsi_ms.c	(revision de3432be3bd5cf920867c570f84e50d62887f870)
@@ -89,7 +89,6 @@
 {
 	scsi_std_inquiry_data_t inq_data;
-	size_t response_len;
+	scsi_cmd_t cmd;
 	scsi_cdb_inquiry_t cdb;
-	cmd_status_t status;
 	int rc;
 
@@ -98,6 +97,11 @@
 	cdb.alloc_len = host2uint16_t_be(sizeof(inq_data));
 
-	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
-	    sizeof(cdb), &inq_data, sizeof(inq_data), &response_len, &status);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = &inq_data;
+	cmd.data_in_size = sizeof(inq_data);
+
+	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
 
 	if (rc != EOK) {
@@ -107,5 +111,5 @@
 	}
 
-	if (status != CMDS_GOOD) {
+	if (cmd.status != CMDS_GOOD) {
 		usb_log_error("Inquiry command failed, device %s.\n",
 		   mfun->mdev->ddf_dev->name);
@@ -114,7 +118,7 @@
 	}
 
-	if (response_len < SCSI_STD_INQUIRY_DATA_MIN_SIZE) {
+	if (cmd.rcvd_size < SCSI_STD_INQUIRY_DATA_MIN_SIZE) {
 		usb_log_error("SCSI Inquiry response too short (%zu).\n",
-		    response_len);
+		    cmd.rcvd_size);
 		return EIO;
 	}
@@ -154,7 +158,6 @@
 int usbmast_request_sense(usbmast_fun_t *mfun, void *buf, size_t size)
 {
+	scsi_cmd_t cmd;
 	scsi_cdb_request_sense_t cdb;
-	size_t data_len;
-	cmd_status_t status;
 	int rc;
 
@@ -163,8 +166,13 @@
 	cdb.alloc_len = min(size, SCSI_SENSE_DATA_MAX_SIZE);
 
-	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
-	    sizeof(cdb), buf, size, &data_len, &status);
-
-        if (rc != EOK || status != CMDS_GOOD) {
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = buf;
+	cmd.data_in_size = size;
+
+	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
+
+        if (rc != EOK || cmd.status != CMDS_GOOD) {
 		usb_log_error("Request Sense failed, device %s: %s.\n",
 		   mfun->mdev->ddf_dev->name, str_error(rc));
@@ -172,8 +180,8 @@
 	}
 
-	if (data_len < SCSI_SENSE_DATA_MIN_SIZE) {
+	if (cmd.rcvd_size < SCSI_SENSE_DATA_MIN_SIZE) {
 		/* The missing bytes should be considered to be zeroes. */
-		memset((uint8_t *)buf + data_len, 0,
-		    SCSI_SENSE_DATA_MIN_SIZE - data_len);
+		memset((uint8_t *)buf + cmd.rcvd_size, 0,
+		    SCSI_SENSE_DATA_MIN_SIZE - cmd.rcvd_size);
 	}
 
@@ -192,8 +200,7 @@
     uint32_t *block_size)
 {
+	scsi_cmd_t cmd;
 	scsi_cdb_read_capacity_10_t cdb;
 	scsi_read_capacity_10_data_t data;
-	size_t data_len;
-	cmd_status_t status;
 	int rc;
 
@@ -201,6 +208,11 @@
 	cdb.op_code = SCSI_CMD_READ_CAPACITY_10;
 
-	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
-	    sizeof(cdb), &data, sizeof(data), &data_len, &status);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = &data;
+	cmd.data_in_size = sizeof(data);
+
+	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
 
         if (rc != EOK) {
@@ -210,5 +222,5 @@
 	}
 
-	if (status != CMDS_GOOD) {
+	if (cmd.status != CMDS_GOOD) {
 		usb_log_error("Read Capacity (10) command failed, device %s.\n",
 		   mfun->mdev->ddf_dev->name);
@@ -217,7 +229,7 @@
 	}
 
-	if (data_len < sizeof(data)) {
+	if (cmd.rcvd_size < sizeof(data)) {
 		usb_log_error("SCSI Read Capacity response too short (%zu).\n",
-		    data_len);
+		    cmd.rcvd_size);
 		return EIO;
 	}
@@ -239,10 +251,7 @@
 int usbmast_read(usbmast_fun_t *mfun, uint64_t ba, size_t nblocks, void *buf)
 {
+	scsi_cmd_t cmd;
 	scsi_cdb_read_12_t cdb;
-	size_t data_len;
-	cmd_status_t status;
-	int rc;
-
-	/* XXX Need softstate to store block size. */
+	int rc;
 
 	if (ba > UINT32_MAX)
@@ -257,6 +266,11 @@
 	cdb.xfer_len = host2uint32_t_be(nblocks);
 
-	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
-	    sizeof(cdb), buf, nblocks * mfun->block_size, &data_len, &status);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = buf;
+	cmd.data_in_size = nblocks * mfun->block_size;
+
+	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
 
         if (rc != EOK) {
@@ -266,5 +280,5 @@
 	}
 
-	if (status != CMDS_GOOD) {
+	if (cmd.status != CMDS_GOOD) {
 		usb_log_error("Read (12) command failed, device %s.\n",
 		   mfun->mdev->ddf_dev->name);
@@ -273,7 +287,7 @@
 	}
 
-	if (data_len < nblocks * mfun->block_size) {
+	if (cmd.rcvd_size < nblocks * mfun->block_size) {
 		usb_log_error("SCSI Read response too short (%zu).\n",
-		    data_len);
+		    cmd.rcvd_size);
 		return EIO;
 	}
@@ -294,7 +308,6 @@
     const void *data)
 {
+	scsi_cmd_t cmd;
 	scsi_cdb_write_12_t cdb;
-	size_t sent_len;
-	cmd_status_t status;
 	int rc;
 
@@ -310,6 +323,11 @@
 	cdb.xfer_len = host2uint32_t_be(nblocks);
 
-	rc = usb_massstor_data_out(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
-	    sizeof(cdb), data, nblocks * mfun->block_size, &sent_len, &status);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_out = data;
+	cmd.data_out_size = nblocks * mfun->block_size;
+
+	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
 
         if (rc != EOK) {
@@ -319,5 +337,5 @@
 	}
 
-	if (status != CMDS_GOOD) {
+	if (cmd.status != CMDS_GOOD) {
 		usb_log_error("Write (12) command failed, device %s.\n",
 		   mfun->mdev->ddf_dev->name);
@@ -326,10 +344,4 @@
 	}
 
-	if (sent_len < nblocks * mfun->block_size) {
-		usb_log_error("SCSI Write not all bytes transferred (%zu).\n",
-		    sent_len);
-		return EIO;
-	}
-
 	return EOK;
 }
