socsvn commit: r257336 - soc2013/zcore/head/usr.sbin/bhyve

zcore at FreeBSD.org zcore at FreeBSD.org
Sat Sep 14 16:02:39 UTC 2013


Author: zcore
Date: Sat Sep 14 16:02:39 2013
New Revision: 257336
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=257336

Log:
  support ATAPI_READ_TOC

Modified:
  soc2013/zcore/head/usr.sbin/bhyve/pci_ahci.c

Modified: soc2013/zcore/head/usr.sbin/bhyve/pci_ahci.c
==============================================================================
--- soc2013/zcore/head/usr.sbin/bhyve/pci_ahci.c	Sat Sep 14 16:01:40 2013	(r257335)
+++ soc2013/zcore/head/usr.sbin/bhyve/pci_ahci.c	Sat Sep 14 16:02:39 2013	(r257336)
@@ -171,6 +171,25 @@
 		((val & 0xff000000) >> 24);
 }
 
+static inline uint32_t cpu_to_be16(uint16_t val)
+{
+	return ((val & 0xff) << 8) |
+		((val & 0xff00) >> 8);
+}
+
+static inline uint16_t be16_to_cpu(uint8_t *val)
+{
+	return (val[0] << 8) | val[1];
+}
+
+static inline void lba_to_msf(uint8_t *buf, int lba)
+{
+	lba += 150;
+	buf[0] = (lba / 75) / 60;
+	buf[1] = (lba / 75) % 60;
+	buf[2] = lba % 75;
+}
+
 /*
  * generate HBA intr depending on whether or not ports within
  * the controller have an interrupt pending.
@@ -605,6 +624,7 @@
 	len = sizeof(buf);
 	if (len > acmd[4])
 		len = acmd[4];
+	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
 	write_prdt(p, slot, cfis, buf, len);
 	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
 }
@@ -619,11 +639,187 @@
 	sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
 	ptr[0] = cpu_to_be32(sectors - 1);
 	ptr[1] = cpu_to_be32(2048);
+	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
 	write_prdt(p, slot, cfis, buf, sizeof(buf));
 	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
 }
 
 static void
+atapi_read_toc(struct ahci_port *p, int slot, uint8_t *cfis)
+{
+	int len;
+	uint8_t format, *acmd = cfis + 0x40;
+
+	len = be16_to_cpu(acmd + 7);
+	format = acmd[9] >> 6;
+	switch (format) {
+	case 0:
+	{
+		int msf, size;
+		uint64_t sectors;
+		uint8_t start_track, buf[20], *bp;
+
+		msf = (acmd[1] >> 1) & 1;
+		start_track = acmd[6];
+		if (start_track > 1 && start_track != 0xaa) {
+			uint32_t tfd;
+			p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
+			p->asc = 0x24;
+			tfd = (p->sense_key << 4) | ATA_S_READY | ATA_S_ERROR;
+			cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
+			ahci_write_fis_d2h(p, slot, cfis, tfd);
+			return;
+		}
+		bp = buf + 2;
+		*bp++ = 1;
+		*bp++ = 1;
+		if (start_track <= 1) {
+			*bp++ = 0;
+			*bp++ = 0x14;
+			*bp++ = 1;
+			*bp++ = 0;
+			if (msf) {
+				*bp++ = 0;
+				lba_to_msf(bp, 0);
+				bp += 3;
+			} else {
+				*bp++ = 0;
+				*bp++ = 0;
+				*bp++ = 0;
+				*bp++ = 0;
+			}
+		}
+		*bp++ = 0;
+		*bp++ = 0x14;
+		*bp++ = 0xaa;
+		*bp++ = 0;
+		sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
+		if (msf) {
+			*bp++ = 0;
+			lba_to_msf(bp, sectors);
+			bp += 3;
+		} else {
+			*(uint32_t *)bp = cpu_to_be32(sectors);
+			bp += 4;
+		}
+		size = bp - buf;
+		*(uint16_t*)buf = cpu_to_be16(size - 2);
+		if (len > size)
+			len = size;
+		write_prdt(p, slot, cfis, buf, len);
+		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
+		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
+		break;
+	}
+	case 1:
+	{
+		uint8_t buf[12];
+
+		memset(buf, 0, sizeof(buf));
+		buf[1] = 0xa;
+		buf[2] = 0x1;
+		buf[3] = 0x1;
+		if (len > sizeof(buf))
+			len = sizeof(buf);
+		write_prdt(p, slot, cfis, buf, len);
+		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
+		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
+		break;
+	}
+	case 2:
+	{
+		int msf, size;
+		uint64_t sectors;
+		uint8_t start_track, *bp, buf[50];
+
+		msf = (acmd[1] >> 1) & 1;
+		start_track = acmd[6];
+		bp = buf + 2;
+		*bp++ = 1;
+		*bp++ = 1;
+
+		*bp++ = 1;
+		*bp++ = 0x14;
+		*bp++ = 0;
+		*bp++ = 0xa0;
+		*bp++ = 0;
+		*bp++ = 0;
+		*bp++ = 0;
+		*bp++ = 0;
+		*bp++ = 1;
+		*bp++ = 0;
+		*bp++ = 0;
+
+		*bp++ = 1;
+		*bp++ = 0x14;
+		*bp++ = 0;
+		*bp++ = 0xa1;
+		*bp++ = 0;
+		*bp++ = 0;
+		*bp++ = 0;
+		*bp++ = 0;
+		*bp++ = 1;
+		*bp++ = 0;
+		*bp++ = 0;
+
+		*bp++ = 1;
+		*bp++ = 0x14;
+		*bp++ = 0;
+		*bp++ = 0xa2;
+		*bp++ = 0;
+		*bp++ = 0;
+		*bp++ = 0;
+		sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
+		if (msf) {
+			*bp++ = 0;
+			lba_to_msf(bp, sectors);
+			bp += 3;
+		} else {
+			*(uint32_t *)bp = cpu_to_be32(sectors);
+			bp += 4;
+		}
+
+		*bp++ = 1;
+		*bp++ = 0x14;
+		*bp++ = 0;
+		*bp++ = 1;
+		*bp++ = 0;
+		*bp++ = 0;
+		*bp++ = 0;
+		if (msf) {
+			*bp++ = 0;
+			lba_to_msf(bp, 0);
+			bp += 3;
+		} else {
+			*bp++ = 0;
+			*bp++ = 0;
+			*bp++ = 0;
+			*bp++ = 0;
+		}
+
+		size = bp - buf;
+		*(uint16_t*)buf = cpu_to_be16(size - 2);
+		if (len > size)
+			len = size;
+		write_prdt(p, slot, cfis, buf, len);
+		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
+		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
+		break;
+	}
+	default:
+	{
+		uint32_t tfd;
+		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
+		p->asc = 0x24;
+		tfd = (p->sense_key << 4) | ATA_S_READY | ATA_S_ERROR;
+		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
+		ahci_write_fis_d2h(p, slot, cfis, tfd);
+		break;
+	}
+	}
+}
+
+static void
 handle_packet_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
 {
 	uint8_t *acmd = cfis + 0x40;
@@ -641,11 +837,9 @@
 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
 		break;
 	case ATAPI_INQUIRY:
-		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
 		atapi_inquiry(p, slot, cfis);
 		break;
 	case ATAPI_READ_CAPACITY:
-		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
 		atapi_read_capacity(p, slot, cfis);
 		break;
 	case ATAPI_PREVENT_ALLOW:
@@ -653,6 +847,9 @@
 		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
 		break;
+	case ATAPI_READ_TOC:
+		atapi_read_toc(p, slot, cfis);
+		break;
 	default:
 		break;
 	}


More information about the svn-soc-all mailing list