Index: uspace/drv/bus/usb/usbmast/cmds.c
===================================================================
--- uspace/drv/bus/usb/usbmast/cmds.c	(revision ff65e919e94df2ad211a3d64817421d7d652ca8c)
+++ uspace/drv/bus/usb/usbmast/cmds.c	(revision 38c9505b89604cf985448cc6a31261adcb01ff59)
@@ -42,5 +42,5 @@
 void usb_massstor_cbw_prepare(usb_massstor_cbw_t *cbw,
     uint32_t tag, uint32_t transfer_length, usb_direction_t dir,
-    uint8_t lun, uint8_t cmd_len, uint8_t *cmd)
+    uint8_t lun, uint8_t cmd_len, const uint8_t *cmd)
 {
 	cbw->dCBWSignature = uint32_host2usb(0x43425355);
Index: uspace/drv/bus/usb/usbmast/cmds.h
===================================================================
--- uspace/drv/bus/usb/usbmast/cmds.h	(revision ff65e919e94df2ad211a3d64817421d7d652ca8c)
+++ uspace/drv/bus/usb/usbmast/cmds.h	(revision 38c9505b89604cf985448cc6a31261adcb01ff59)
@@ -58,5 +58,5 @@
 
 extern void usb_massstor_cbw_prepare(usb_massstor_cbw_t *, uint32_t, uint32_t,
-    usb_direction_t, uint8_t, uint8_t, uint8_t *);
+    usb_direction_t, uint8_t, uint8_t, const uint8_t *);
 
 #endif
Index: uspace/drv/bus/usb/usbmast/main.c
===================================================================
--- uspace/drv/bus/usb/usbmast/main.c	(revision ff65e919e94df2ad211a3d64817421d7d652ca8c)
+++ uspace/drv/bus/usb/usbmast/main.c	(revision 38c9505b89604cf985448cc6a31261adcb01ff59)
@@ -214,6 +214,4 @@
 	int retval;
 
-	usb_log_debug("usbmast_bd_connection()\n");
-
 	async_answer_0(iid, EOK);
 
@@ -259,10 +257,10 @@
 			break;
 		case BD_WRITE_BLOCKS:
-			usb_log_debug("usbmast_bd_connection() - BD_WRITE_BLOCKS\n");
-/*			ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
 			cnt = IPC_GET_ARG3(call);
-			retval = 0;
+			retval = usbmast_write(msfun->usb_dev, ba, cnt,
+			    msfun->block_size, comm_buf);
 			async_answer_0(callid, retval);
-			break;*/
+			break;
 		default:
 			async_answer_0(callid, EINVAL);
Index: uspace/drv/bus/usb/usbmast/mast.c
===================================================================
--- uspace/drv/bus/usb/usbmast/mast.c	(revision ff65e919e94df2ad211a3d64817421d7d652ca8c)
+++ uspace/drv/bus/usb/usbmast/mast.c	(revision 38c9505b89604cf985448cc6a31261adcb01ff59)
@@ -51,18 +51,21 @@
 	} while (false)
 
-/** Request data from mass storage device.
- *
- * @param tag Command block wrapper tag (automatically compared with answer).
- * @param lun LUN index.
- * @param cmd SCSI command buffer (in SCSI endianness).
- * @param cmd_size Length of SCSI command @p cmd in bytes.
- * @param in_buffer Buffer where to store the answer (CSW is not returned).
- * @param in_buffer_size Size of the buffer (size of the request to the device).
- * @param received_size Number of actually received bytes.
- * @return Error code.
- */
-int usb_massstor_data_in(usb_device_t *dev,
-    uint32_t tag, uint8_t lun, void *cmd, size_t cmd_size,
-    void *in_buffer, size_t in_buffer_size, size_t *received_size)
+/** Send command via bulk-only transport.
+ *
+ * @param tag		Command block wrapper tag (automatically compared
+ *			with answer)
+ * @param lun		LUN
+ * @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
+ *
+ * @return		Error code
+ */
+static int usb_massstor_cmd(usb_device_t *dev, uint32_t tag, uint8_t lun,
+    const void *cmd, size_t cmd_size, usb_direction_t ddir, void *dbuf,
+    size_t dbuf_size, size_t *xferred_size)
 {
 	int rc;
@@ -73,8 +76,8 @@
 	/* Prepare CBW - command block wrapper */
 	usb_massstor_cbw_t cbw;
-	usb_massstor_cbw_prepare(&cbw, tag, in_buffer_size,
-	    USB_DIRECTION_IN, lun, cmd_size, cmd);
-
-	/* First, send the CBW. */
+	usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, lun, cmd_size,
+	    cmd);
+
+	/* Send the CBW. */
 	rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
 	MASTLOG("CBW '%s' sent: %s.\n",
@@ -85,10 +88,18 @@
 	}
 
-	/* Try to retrieve the data from the device. */
-	act_size = 0;
-	rc = usb_pipe_read(bulk_in_pipe, in_buffer, in_buffer_size, &act_size);
-	MASTLOG("Received %zuB (%s): %s.\n", act_size,
-	    usb_debug_str_buffer((uint8_t *) in_buffer, act_size, 0),
-	    str_error(rc));
+	if (ddir == USB_DIRECTION_IN) {
+		/* Recieve data from the device. */
+		rc = usb_pipe_read(bulk_in_pipe, dbuf, dbuf_size, &act_size);
+		MASTLOG("Received %zu bytes (%s): %s.\n", act_size,
+		    usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
+		    str_error(rc));
+	} else {
+		/* Send data to the device. */
+		rc = usb_pipe_write(bulk_out_pipe, dbuf, dbuf_size);
+		MASTLOG("Sent %zu bytes (%s): %s.\n", act_size,
+		    usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
+		    str_error(rc));
+	}
+
 	if (rc != EOK) {
 		/*
@@ -103,5 +114,5 @@
 	size_t csw_size;
 	rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
-	MASTLOG("CSW '%s' received (%zuB): %s.\n",
+	MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
 	    usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
 	    str_error(rc));
@@ -132,21 +143,62 @@
 
 	size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
-	if (residue > in_buffer_size) {
-		MASTLOG("residue > in_buffer_size\n");
+	if (residue > dbuf_size) {
+		MASTLOG("residue > dbuf_size\n");
 		return ERANGE;
 	}
 
 	/*
-	 * When the device has less data to send than requested, it can
-	 * either stall the pipe or send garbage and indicate that via
-	 * the residue field in CSW. That means in_buffer_size - residue
-	 * is the authoritative size of data received.
+	 * When the device has less data to send than requested (or cannot
+	 * receive moredata), it can either stall the pipe or send garbage
+	 * (ignore data) and indicate that via the residue field in CSW.
+	 * That means dbuf_size - residue is the authoritative size of data
+	 * received (sent).
 	 */
 
-	if (received_size != NULL) {
-		*received_size = in_buffer_size - residue;
-	}
+	if (xferred_size != NULL)
+		*xferred_size = dbuf_size - residue;
 
 	return EOK;
+}
+
+/** Perform data-in command.
+ *
+ * @param tag		Command block wrapper tag (automatically compared with
+ *			answer)
+ * @param lun		LUN
+ * @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
+ *
+ * @return Error code
+ */
+int usb_massstor_data_in(usb_device_t *dev, uint32_t tag, uint8_t lun,
+    const void *cmd, size_t cmd_size, void *dbuf, size_t dbuf_size, size_t *proc_size)
+{
+	return usb_massstor_cmd(dev, tag, lun, cmd, cmd_size, USB_DIRECTION_IN,
+	    dbuf, dbuf_size, proc_size);
+}
+
+/** Perform data-out command.
+ *
+ * @param tag		Command block wrapper tag (automatically compared with
+ *			answer)
+ * @param lun		LUN
+ * @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
+ *
+ * @return Error code
+ */
+int usb_massstor_data_out(usb_device_t *dev, uint32_t tag, uint8_t lun,
+    const void *cmd, size_t cmd_size, const void *data, size_t data_size,
+    size_t *proc_size)
+{
+	return usb_massstor_cmd(dev, tag, lun, cmd, cmd_size, USB_DIRECTION_OUT,
+	    (void *) data, data_size, proc_size);
 }
 
Index: uspace/drv/bus/usb/usbmast/mast.h
===================================================================
--- uspace/drv/bus/usb/usbmast/mast.h	(revision ff65e919e94df2ad211a3d64817421d7d652ca8c)
+++ uspace/drv/bus/usb/usbmast/mast.h	(revision 38c9505b89604cf985448cc6a31261adcb01ff59)
@@ -46,10 +46,12 @@
 #define BULK_OUT_EP 1
 
-int usb_massstor_data_in(usb_device_t *dev, uint32_t, uint8_t, void *,
+extern int usb_massstor_data_in(usb_device_t *, uint32_t, uint8_t, const void *,
     size_t, void *, size_t, size_t *);
-int usb_massstor_reset(usb_device_t *);
-void usb_massstor_reset_recovery(usb_device_t *);
-int usb_massstor_get_max_lun(usb_device_t *);
-size_t usb_masstor_get_lun_count(usb_device_t *);
+extern int usb_massstor_data_out(usb_device_t *, uint32_t, uint8_t, const void *,
+    size_t, const void *, size_t, size_t *);
+extern int usb_massstor_reset(usb_device_t *);
+extern void usb_massstor_reset_recovery(usb_device_t *);
+extern int usb_massstor_get_max_lun(usb_device_t *);
+extern size_t usb_masstor_get_lun_count(usb_device_t *);
 
 #endif
Index: uspace/drv/bus/usb/usbmast/scsi_ms.c
===================================================================
--- uspace/drv/bus/usb/usbmast/scsi_ms.c	(revision ff65e919e94df2ad211a3d64817421d7d652ca8c)
+++ uspace/drv/bus/usb/usbmast/scsi_ms.c	(revision 38c9505b89604cf985448cc6a31261adcb01ff59)
@@ -239,4 +239,52 @@
 }
 
+/** Perform SCSI Write command on USB mass storage device.
+ *
+ * @param dev		USB device
+ * @param ba		Address of first block
+ * @param nblocks	Number of blocks to read
+ * @param bsize		Block size
+ * @param data		Data to write
+ *
+ * @return		Error code
+ */
+int usbmast_write(usb_device_t *dev, uint64_t ba, size_t nblocks, size_t bsize,
+    const void *data)
+{
+	scsi_cdb_write_12_t cdb;
+	size_t sent_len;
+	int rc;
+
+	/* XXX Need softstate to store block size. */
+
+	if (ba > UINT32_MAX)
+		return ELIMIT;
+
+	if ((uint64_t)nblocks * bsize > UINT32_MAX)
+		return ELIMIT;
+
+	memset(&cdb, 0, sizeof(cdb));
+	cdb.op_code = SCSI_CMD_WRITE_12;
+	cdb.lba = host2uint32_t_be(ba);
+	cdb.xfer_len = host2uint32_t_be(nblocks);
+
+	rc = usb_massstor_data_out(dev, 0xDEADBEEF, 0, (uint8_t *) &cdb,
+	    sizeof(cdb), data, nblocks * bsize, &sent_len);
+
+        if (rc != EOK) {
+		usb_log_error("Write (12) failed, device %s: %s.\n",
+		   dev->ddf_dev->name, str_error(rc));
+		return rc;
+	}
+
+	if (sent_len < nblocks * bsize) {
+		usb_log_error("SCSI Write not all bytes transferred (%zu).\n",
+		    sent_len);
+		return EIO;
+	}
+
+	return EOK;
+}
+
 /**
  * @}
Index: uspace/drv/bus/usb/usbmast/scsi_ms.h
===================================================================
--- uspace/drv/bus/usb/usbmast/scsi_ms.h	(revision ff65e919e94df2ad211a3d64817421d7d652ca8c)
+++ uspace/drv/bus/usb/usbmast/scsi_ms.h	(revision 38c9505b89604cf985448cc6a31261adcb01ff59)
@@ -63,4 +63,6 @@
 extern int usbmast_read_capacity(usb_device_t *, uint32_t *, uint32_t *);
 extern int usbmast_read(usb_device_t *, uint64_t, size_t, size_t, void *);
+extern int usbmast_write(usb_device_t *, uint64_t, size_t, size_t,
+    const void *);
 extern const char *usbmast_scsi_dev_type_str(unsigned);
 
