Index: uspace/lib/block/libblock.c
===================================================================
--- uspace/lib/block/libblock.c	(revision 5b68e0ca93e8b5310f537cf69218025800ed6aab)
+++ uspace/lib/block/libblock.c	(revision f480d7e1f5cf4ba7a6678d2d63060e7f8756330d)
@@ -93,4 +93,5 @@
 static int get_block_size(async_sess_t *, size_t *);
 static int get_num_blocks(async_sess_t *, aoff64_t *);
+static int read_toc(async_sess_t *, uint8_t);
 static aoff64_t ba_ltop(devcon_t *, aoff64_t);
 
@@ -891,4 +892,30 @@
 }
 
+/** Get TOC from device.
+ *
+ * @param service_id Service ID of the block device.
+ * @param session    Starting session.
+ * @param data       Buffer to read TOC into.
+ *
+ * @return EOK on success.
+ * @return Error code on failure.
+ *
+ */
+int block_get_toc(service_id_t service_id, uint8_t session, void *data)
+{
+	devcon_t *devcon = devcon_search(service_id);
+	assert(devcon);
+	
+	fibril_mutex_lock(&devcon->comm_area_lock);
+	
+	int rc = read_toc(devcon->sess, session);
+	if (rc == EOK)
+		memcpy(data, devcon->comm_area, devcon->pblock_size);
+	
+	fibril_mutex_unlock(&devcon->comm_area_lock);
+	
+	return rc;
+}
+
 /** Read blocks from block device.
  *
@@ -981,4 +1008,14 @@
 }
 
+/** Get TOC from block device. */
+static int read_toc(async_sess_t *sess, uint8_t session)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_1_0(exch, BD_READ_TOC, session);
+	async_exchange_end(exch);
+
+	return rc;
+}
+
 /** Convert logical block address to physical block address. */
 static aoff64_t ba_ltop(devcon_t *devcon, aoff64_t lba)
Index: uspace/lib/block/libblock.h
===================================================================
--- uspace/lib/block/libblock.h	(revision 5b68e0ca93e8b5310f537cf69218025800ed6aab)
+++ uspace/lib/block/libblock.h	(revision f480d7e1f5cf4ba7a6678d2d63060e7f8756330d)
@@ -114,4 +114,5 @@
 extern int block_get_bsize(service_id_t, size_t *);
 extern int block_get_nblocks(service_id_t, aoff64_t *);
+extern int block_get_toc(service_id_t, uint8_t, void *);
 extern int block_read_direct(service_id_t, aoff64_t, size_t, void *);
 extern int block_read_bytes_direct(service_id_t, aoff64_t, size_t, void *);
Index: uspace/lib/c/generic/str.c
===================================================================
--- uspace/lib/c/generic/str.c	(revision 5b68e0ca93e8b5310f537cf69218025800ed6aab)
+++ uspace/lib/c/generic/str.c	(revision f480d7e1f5cf4ba7a6678d2d63060e7f8756330d)
@@ -551,5 +551,5 @@
  *
  * Common legacy text encoding in hardware is 7-bit ASCII fitted into
- * a fixed-with byte buffer (bit 7 always zero), right-padded with spaces
+ * a fixed-width byte buffer (bit 7 always zero), right-padded with spaces
  * (ASCII 0x20). Convert space-padded ascii to string representation.
  *
Index: uspace/lib/c/include/ipc/bd.h
===================================================================
--- uspace/lib/c/include/ipc/bd.h	(revision 5b68e0ca93e8b5310f537cf69218025800ed6aab)
+++ uspace/lib/c/include/ipc/bd.h	(revision f480d7e1f5cf4ba7a6678d2d63060e7f8756330d)
@@ -42,5 +42,6 @@
 	BD_GET_NUM_BLOCKS,
 	BD_READ_BLOCKS,
-	BD_WRITE_BLOCKS
+	BD_WRITE_BLOCKS,
+	BD_READ_TOC
 } bd_request_t;
 
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision 5b68e0ca93e8b5310f537cf69218025800ed6aab)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision f480d7e1f5cf4ba7a6678d2d63060e7f8756330d)
@@ -118,4 +118,6 @@
 static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size);
 static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
+    void *obuf, size_t obuf_size);
+static int ata_pcmd_read_toc(int dev_idx, uint8_t ses,
     void *obuf, size_t obuf_size);
 static void disk_print_summary(disk_t *d);
@@ -353,4 +355,12 @@
 			    UPPER32(disk[disk_id].blocks));
 			continue;
+		case BD_READ_TOC:
+			cnt = IPC_GET_ARG1(call);
+			if (disk[disk_id].dev_type == ata_pkt_dev)
+				retval = ata_pcmd_read_toc(disk_id, cnt, fs_va,
+				    disk[disk_id].block_size);
+			else
+				retval = EINVAL;
+			break;
 		default:
 			retval = EINVAL;
@@ -810,4 +820,43 @@
 }
 
+/** Issue ATAPI read TOC command.
+ *
+ * Read TOC in 'multi-session' format (first and last session number
+ * with last session LBA).
+ *
+ * http://suif.stanford.edu/~csapuntz/specs/INF-8020.PDF page 171
+ *
+ * Output buffer must be large enough to hold the data, otherwise the
+ * function will fail.
+ *
+ * @param dev_idx	Device index (0 or 1)
+ * @param session	Starting session
+ * @param obuf		Buffer for storing inquiry data read from device
+ * @param obuf_size	Size of obuf in bytes
+ *
+ * @return EOK on success, EIO on error.
+ */
+static int ata_pcmd_read_toc(int dev_idx, uint8_t session, void *obuf,
+    size_t obuf_size)
+{
+	ata_pcmd_read_toc_t cp;
+	int rc;
+
+	memset(&cp, 0, sizeof(cp));
+
+	cp.opcode = PCMD_READ_TOC;
+	cp.msf = 0;
+	cp.format = 0x01; /* 0x01 = multi-session mode */
+	cp.start = session;
+	cp.size = host2uint16_t_be(obuf_size);
+	cp.oldformat = 0x40; /* 0x01 = multi-session mode (shifted to MSB) */
+	
+	rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
+	if (rc != EOK)
+		return rc;
+	
+	return EOK;
+}
+
 /** Read a physical from the device.
  *
Index: uspace/srv/bd/ata_bd/ata_hw.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_hw.h	(revision 5b68e0ca93e8b5310f537cf69218025800ed6aab)
+++ uspace/srv/bd/ata_bd/ata_hw.h	(revision f480d7e1f5cf4ba7a6678d2d63060e7f8756330d)
@@ -244,5 +244,6 @@
 enum ata_pkt_command {
 	PCMD_INQUIRY		= 0x12,
-	PCMD_READ_12		= 0xa8
+	PCMD_READ_12		= 0xa8,
+	PCMD_READ_TOC		= 0x43
 };
 
@@ -269,4 +270,19 @@
 	uint8_t _res2;
 } __attribute__ ((packed)) ata_pcmd_read_12_t;
+
+/** ATAPI Read TOC command */
+typedef struct {
+	uint8_t opcode;		/**< Operation code (PCMD_READ_TOC) */
+	uint8_t msf;            /**< 0x2 = MSF bit set */
+	uint8_t format;         /**< low 3 bits */
+	uint8_t _res0;
+	uint8_t _res1;
+	uint8_t _res2;
+	uint8_t start;          /**< starting track/session number */
+	uint16_t size;		/**< Allocation length */
+	uint8_t oldformat;         /**< high 2 bits */
+	uint8_t _res3;
+	uint8_t _res4;
+} __attribute__ ((packed)) ata_pcmd_read_toc_t;
 
 /** Data returned from Inquiry command (mandatory part) */
