Index: uspace/drv/block/ata_bd/ata_bd.c
===================================================================
--- uspace/drv/block/ata_bd/ata_bd.c	(revision 6cef8d6a633ccd8d6545bfa8b87ae7113b8d30ed)
+++ uspace/drv/block/ata_bd/ata_bd.c	(revision 21989e5a1d36e65bebb408c0ca4bdb7b3590fe28)
@@ -115,4 +115,5 @@
     void *obuf, size_t obuf_size);
 static void disk_print_summary(disk_t *d);
+static size_t ata_disk_maxnb(disk_t *d);
 static errno_t coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
 static void coord_sc_program(ata_ctrl_t *ctrl, const block_coord_t *bc,
@@ -514,4 +515,6 @@
 {
 	disk_t *disk = bd_srv_disk(bd);
+	size_t maxnb;
+	size_t nb;
 	errno_t rc;
 
@@ -519,9 +522,12 @@
 		return EINVAL;
 
+	/* Maximum number of blocks to transfer at the same time */
+	maxnb = ata_disk_maxnb(disk);
 	while (cnt > 0) {
+		nb = min(maxnb, cnt);
 		if (disk->dev_type == ata_reg_dev) {
-			rc = ata_rcmd_read(disk, ba, 1, buf);
+			rc = ata_rcmd_read(disk, ba, nb, buf);
 		} else {
-			rc = ata_pcmd_read_12(disk, ba, 1, buf,
+			rc = ata_pcmd_read_12(disk, ba, nb, buf,
 			    disk->block_size);
 		}
@@ -530,7 +536,7 @@
 			return rc;
 
-		++ba;
-		--cnt;
-		buf += disk->block_size;
+		ba += nb;
+		cnt -= nb;
+		buf += disk->block_size * nb;
 	}
 
@@ -551,4 +557,6 @@
 {
 	disk_t *disk = bd_srv_disk(bd);
+	size_t maxnb;
+	size_t nb;
 	errno_t rc;
 
@@ -559,12 +567,15 @@
 		return EINVAL;
 
+	/* Maximum number of blocks to transfer at the same time */
+	maxnb = ata_disk_maxnb(disk);
 	while (cnt > 0) {
-		rc = ata_rcmd_write(disk, ba, 1, buf);
+		nb = min(maxnb, cnt);
+		rc = ata_rcmd_write(disk, ba, nb, buf);
 		if (rc != EOK)
 			return rc;
 
-		++ba;
-		--cnt;
-		buf += disk->block_size;
+		ba += nb;
+		cnt -= nb;
+		buf += disk->block_size * nb;
 	}
 
@@ -609,23 +620,31 @@
 	uint16_t data;
 	size_t i;
+	size_t bidx;
 	uint8_t status;
 
-	/* XXX Support multiple blocks */
-	assert(nblocks == 1);
+	assert(nblocks > 0);
 	assert(blk_size % 2 == 0);
 
-	if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
-		return EIO;
-
-	if ((status & SR_DRQ) != 0) {
+	bidx = 0;
+	while (nblocks > 0) {
+		if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
+			return EIO;
+
+		if ((status & SR_DRQ) == 0) {
+			break;
+		}
+
 		/* Read data from the device buffer. */
-
 		for (i = 0; i < blk_size / 2; i++) {
 			data = pio_read_16(&ctrl->cmd->data_port);
-			((uint16_t *) obuf)[i] = data;
-		}
+			((uint16_t *) obuf)[bidx++] = data;
+		}
+
+		--nblocks;
 	}
 
 	if ((status & SR_ERR) != 0)
+		return EIO;
+	if (nblocks > 0)
 		return EIO;
 
@@ -639,22 +658,30 @@
 	ata_ctrl_t *ctrl = disk->ctrl;
 	size_t i;
+	size_t bidx;
 	uint8_t status;
 
-	/* XXX Support multiple blocks */
-	assert(nblocks == 1);
+	assert(nblocks > 0);
 	assert(blk_size % 2 == 0);
 
-	if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
-		return EIO;
-
-	if ((status & SR_DRQ) != 0) {
+	bidx = 0;
+	while (nblocks > 0) {
+		if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
+			return EIO;
+
+		if ((status & SR_DRQ) == 0)
+			break;
+
 		/* Write data to the device buffer. */
-
 		for (i = 0; i < blk_size / 2; i++) {
-			pio_write_16(&ctrl->cmd->data_port, ((uint16_t *) buf)[i]);
-		}
+			pio_write_16(&ctrl->cmd->data_port,
+			    ((uint16_t *) buf)[bidx++]);
+		}
+
+		--nblocks;
 	}
 
 	if (status & SR_ERR)
+		return EIO;
+	if (nblocks > 0)
 		return EIO;
 
@@ -781,4 +808,6 @@
 	uint8_t drv_head;
 	size_t data_size;
+	size_t remain;
+	size_t bidx;
 	uint16_t val;
 
@@ -816,29 +845,33 @@
 		pio_write_16(&ctrl->cmd->data_port, ((uint16_t *) cpkt)[i]);
 
-	if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
-		fibril_mutex_unlock(&ctrl->lock);
-		return EIO;
-	}
-
-	if ((status & SR_DRQ) == 0) {
-		fibril_mutex_unlock(&ctrl->lock);
-		return EIO;
-	}
-
-	/* Read byte count. */
-	data_size = (uint16_t) pio_read_8(&ctrl->cmd->cylinder_low) +
-	    ((uint16_t) pio_read_8(&ctrl->cmd->cylinder_high) << 8);
-
-	/* Check whether data fits into output buffer. */
-	if (data_size > obuf_size) {
-		/* Output buffer is too small to store data. */
-		fibril_mutex_unlock(&ctrl->lock);
-		return EIO;
-	}
-
-	/* Read data from the device buffer. */
-	for (i = 0; i < (data_size + 1) / 2; i++) {
-		val = pio_read_16(&ctrl->cmd->data_port);
-		((uint16_t *) obuf)[i] = val;
+	bidx = 0;
+	remain = obuf_size;
+	while (remain > 0) {
+		if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
+			fibril_mutex_unlock(&ctrl->lock);
+			return EIO;
+		}
+
+		if ((status & SR_DRQ) == 0)
+			break;
+
+		/* Read byte count. */
+		data_size = (uint16_t) pio_read_8(&ctrl->cmd->cylinder_low) +
+		    ((uint16_t) pio_read_8(&ctrl->cmd->cylinder_high) << 8);
+
+		/* Check whether data fits into output buffer. */
+		if (data_size > obuf_size) {
+			/* Output buffer is too small to store data. */
+			fibril_mutex_unlock(&ctrl->lock);
+			return EIO;
+		}
+
+		/* Read data from the device buffer. */
+		for (i = 0; i < (data_size + 1) / 2; i++) {
+			val = pio_read_16(&ctrl->cmd->data_port);
+			((uint16_t *) obuf)[bidx++] = val;
+		}
+
+		remain -= data_size;
 	}
 
@@ -849,5 +882,5 @@
 
 	if (rcvd_size != NULL)
-		*rcvd_size = data_size;
+		*rcvd_size = obuf_size - remain;
 	return EOK;
 }
@@ -1040,5 +1073,5 @@
 
 	/* Program block coordinates into the device. */
-	coord_sc_program(ctrl, &bc, 1);
+	coord_sc_program(ctrl, &bc, blk_cnt);
 
 	pio_write_8(&ctrl->cmd->command, disk->amode == am_lba48 ?
@@ -1100,5 +1133,5 @@
 
 	/* Program block coordinates into the device. */
-	coord_sc_program(ctrl, &bc, 1);
+	coord_sc_program(ctrl, &bc, cnt);
 
 	pio_write_8(&ctrl->cmd->command, disk->amode == am_lba48 ?
@@ -1150,4 +1183,37 @@
 	fibril_mutex_unlock(&ctrl->lock);
 	return rc;
+}
+
+/** Get the maximum number of blocks to be transferred in one I/O
+ *
+ * @param d Disk
+ * @return Maximum number of blocks
+ */
+static size_t ata_disk_maxnb(disk_t *d)
+{
+	size_t maxnb;
+
+	maxnb = 0;
+
+	if (d->dev_type == ata_pkt_dev) {
+		/* Could be more depending on SCSI command support */
+		maxnb = 0x100;
+	} else {
+		switch (d->amode) {
+		case am_chs:
+		case am_lba28:
+			maxnb = 0x100;
+			break;
+		case am_lba48:
+			maxnb = 0x10000;
+			break;
+		}
+	}
+
+	/*
+	 * If using DMA, this needs to be further restricted not to
+	 * exceed DMA buffer size.
+	 */
+	return maxnb;
 }
 
