Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision 4ef117f8acd0c54154d30257a2472a276db3c765)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision a1f48f6d73bf4ec2afbde3a3ac7e9be6a34e0f78)
@@ -35,6 +35,12 @@
  * @brief ATA disk driver
  *
- * This driver currently works only with CHS addressing and uses PIO.
- * Currently based on the (now obsolete) ATA-1, ATA-2 standards.
+ * This driver supports CHS, 28-bit and 48-bit LBA addressing. It only uses
+ * PIO transfers. There is no support DMA, the PACKET feature set or any other
+ * fancy features such as S.M.A.R.T, removable devices, etc.
+ *
+ * This driver is based on the ATA-1, ATA-2, ATA-3 and ATA/ATAPI-4 through 7
+ * standards, as published by the ANSI, NCITS and INCITS standards bodies,
+ * which are freely available. This driver contains no vendor-specific
+ * code at this moment.
  *
  * The driver services a single controller which can have up to two disks
@@ -100,5 +106,5 @@
 	printf(NAME ": ATA disk driver\n");
 
-	printf("I/O address 0x%x\n", cmd_physical);
+	printf("I/O address 0x%p/0x%p\n", ctl_physical, cmd_physical);
 
 	if (ata_bd_init() != EOK)
@@ -156,9 +162,15 @@
 	printf("%s: ", d->model);
 
-	if (d->amode == am_chs) {
+	switch (d->amode) {
+	case am_chs:
 		printf("CHS %u cylinders, %u heads, %u sectors",
 		    disk->geom.cylinders, disk->geom.heads, disk->geom.sectors);
-	} else {
+		break;
+	case am_lba28:
 		printf("LBA-28");
+		break;
+	case am_lba48:
+		printf("LBA-48");
+		break;
 	}
 
@@ -288,5 +300,5 @@
 	size_t pos, len;
 	int rc;
-	int i;
+	unsigned i;
 
 	rc = drive_identify(disk_id, &idata);
@@ -305,6 +317,6 @@
 
 		d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors;
-	} else {
-		/* Device supports LBA-28. */
+	} else if ((idata.cmd_set1 & cs1_addr48) == 0) {
+		/* Device only supports LBA-28 addressing. */
 		d->amode = am_lba28;
 
@@ -314,6 +326,19 @@
 
 		d->blocks =
-		    (uint32_t) idata.total_lba_sec0 | 
-		    ((uint32_t) idata.total_lba_sec1 << 16);
+		     (uint32_t) idata.total_lba28_0 | 
+		    ((uint32_t) idata.total_lba28_1 << 16);
+	} else {
+		/* Device supports LBA-48 addressing. */
+		d->amode = am_lba48;
+
+		d->geom.cylinders = 0;
+		d->geom.heads = 0;
+		d->geom.sectors = 0;
+
+		d->blocks =
+		     (uint64_t) idata.total_lba48_0 |
+		    ((uint64_t) idata.total_lba48_1 << 16) |
+		    ((uint64_t) idata.total_lba48_2 << 32) | 
+		    ((uint64_t) idata.total_lba48_3 << 48);
 	}
 
@@ -451,5 +476,5 @@
 	uint16_t data;
 	uint8_t status;
-	uint64_t c, h, s;
+	uint64_t c, h, s, c1, s1;
 	uint64_t idx;
 	uint8_t drv_head;
@@ -462,5 +487,6 @@
 		return EINVAL;
 
-	if (d->amode == am_chs) {
+	switch (d->amode) {
+	case am_chs:
 		/* Compute CHS coordinates. */
 		c = blk_idx / (d->geom.heads * d->geom.sectors);
@@ -469,9 +495,21 @@
 		h = idx / d->geom.sectors;
 		s = 1 + (idx % d->geom.sectors);
-	} else {
+		break;
+
+	case am_lba28:
 		/* Compute LBA-28 coordinates. */
 		s = blk_idx & 0xff;		/* bits 0-7 */
 		c = (blk_idx >> 8) & 0xffff;	/* bits 8-23 */
 		h = (blk_idx >> 24) & 0x0f;	/* bits 24-27 */
+		break;
+
+	case am_lba48:
+		/* Compute LBA-48 coordinates. */
+		s = blk_idx & 0xff;		/* bits 0-7 */
+		c = (blk_idx >> 8) & 0xffff;	/* bits 8-23 */
+		s1 = (blk_idx >> 24) & 0xff;	/* bits 24-31 */
+		c1 = (blk_idx >> 32) & 0xffff;	/* bits 32-47 */
+		h = 0;
+		break;
 	}
 
@@ -498,4 +536,13 @@
 	}
 
+	if (d->amode == am_lba48) {
+		/* Write high-order bits. */
+		pio_write_8(&cmd->sector_count, 0);
+		pio_write_8(&cmd->sector_number, s1);
+		pio_write_8(&cmd->cylinder_low, c1 & 0xff);
+		pio_write_8(&cmd->cylinder_high, c1 >> 16);
+	}
+
+	/* Write low-order bits. */
 	pio_write_8(&cmd->sector_count, 1);
 	pio_write_8(&cmd->sector_number, s);
@@ -540,5 +587,5 @@
 	size_t i;
 	uint8_t status;
-	uint64_t c, h, s;
+	uint64_t c, h, s, c1, s1;
 	uint64_t idx;
 	uint8_t drv_head;
@@ -551,5 +598,6 @@
 		return EINVAL;
 
-	if (d->amode == am_chs) {
+	switch (d->amode) {
+	case am_chs:
 		/* Compute CHS coordinates. */
 		c = blk_idx / (d->geom.heads * d->geom.sectors);
@@ -558,9 +606,21 @@
 		h = idx / d->geom.sectors;
 		s = 1 + (idx % d->geom.sectors);
-	} else {
+		break;
+
+	case am_lba28:
 		/* Compute LBA-28 coordinates. */
 		s = blk_idx & 0xff;		/* bits 0-7 */
 		c = (blk_idx >> 8) & 0xffff;	/* bits 8-23 */
 		h = (blk_idx >> 24) & 0x0f;	/* bits 24-27 */
+		break;
+
+	case am_lba48:
+		/* Compute LBA-48 coordinates. */
+		s = blk_idx & 0xff;		/* bits 0-7 */
+		c = (blk_idx >> 8) & 0xffff;	/* bits 8-23 */
+		s1 = (blk_idx >> 24) & 0xff;	/* bits 24-31 */
+		c1 = (blk_idx >> 32) & 0xffff;	/* bits 32-47 */
+		h = 0;
+		break;
 	}
 
@@ -587,4 +647,13 @@
 	}
 
+	if (d->amode == am_lba48) {
+		/* Write high-order bits. */
+		pio_write_8(&cmd->sector_count, 0);
+		pio_write_8(&cmd->sector_number, s1);
+		pio_write_8(&cmd->cylinder_low, c1 & 0xff);
+		pio_write_8(&cmd->cylinder_high, c1 >> 16);
+	}
+
+	/* Write low-order bits. */
 	pio_write_8(&cmd->sector_count, 1);
 	pio_write_8(&cmd->sector_number, s);
Index: uspace/srv/bd/ata_bd/ata_bd.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.h	(revision 4ef117f8acd0c54154d30257a2472a276db3c765)
+++ uspace/srv/bd/ata_bd/ata_bd.h	(revision a1f48f6d73bf4ec2afbde3a3ac7e9be6a34e0f78)
@@ -156,4 +156,5 @@
 	uint16_t _vs8;
 	uint16_t _vs9;
+
 	uint16_t serial_number[10];
 	uint16_t _vs20;
@@ -162,4 +163,5 @@
 	uint16_t firmware_rev[4];
 	uint16_t model_name[20];
+
 	uint16_t max_rw_multiple;
 	uint16_t _res48;
@@ -168,4 +170,5 @@
 	uint16_t pio_timing;
 	uint16_t dma_timing;
+
 	uint16_t validity;
 	uint16_t cur_cyl;
@@ -175,6 +178,6 @@
 	uint16_t cur_capacity1;
 	uint16_t mss;
-	uint16_t total_lba_sec0;
-	uint16_t total_lba_sec1;
+	uint16_t total_lba28_0;
+	uint16_t total_lba28_1;
 	uint16_t sw_dma;
 	uint16_t mw_dma;
@@ -184,7 +187,34 @@
 	uint16_t min_raw_pio_cycle;
 	uint16_t min_iordy_pio_cycle;
+
 	uint16_t _res69;
 	uint16_t _res70;
-	uint16_t _res71[1 + 127 - 71];
+	uint16_t _res71;
+	uint16_t _res72;
+	uint16_t _res73;
+	uint16_t _res74;
+
+	uint16_t queue_depth;
+	uint16_t _res76[1 + 79 - 76];
+	uint16_t version_maj;
+	uint16_t version_min;
+	uint16_t cmd_set0;
+	uint16_t cmd_set1;
+	uint16_t csf_sup_ext;
+	uint16_t csf_enabled0;
+	uint16_t csf_enabled1;
+	uint16_t csf_default;
+	uint16_t udma;
+
+	uint16_t _res89[1 + 99 - 89];
+
+	/* Total number of blocks in LBA-48 addressing */
+	uint16_t total_lba48_0;
+	uint16_t total_lba48_1;
+	uint16_t total_lba48_2;
+	uint16_t total_lba48_3;
+
+	/* Note: more fields are defined in ATA/ATAPI-7 */
+	uint16_t _res104[1 + 127 - 104];
 	uint16_t _vs128[1 + 159 - 128];
 	uint16_t _res160[1 + 255 - 160];
@@ -198,8 +228,14 @@
 };
 
+/** Bits of @c identify_data_t.cmd_set1 */
+enum ata_cs1 {
+	cs1_addr48	= 0x0400	/**< 48-bit address feature set */
+};
+
 /** Block addressing mode. */
 enum addr_mode {
-	am_chs,
-	am_lba28
+	am_chs,		/**< CHS block addressing */
+	am_lba28,	/**< LBA-28 block addressing */
+	am_lba48	/**< LBA-48 block addressing */
 };
 
