pci_ahci.c revision 267393
1256056Sgrehan/*-
2256056Sgrehan * Copyright (c) 2013  Zhixiang Yu <zcore@freebsd.org>
3256056Sgrehan * All rights reserved.
4256056Sgrehan *
5256056Sgrehan * Redistribution and use in source and binary forms, with or without
6256056Sgrehan * modification, are permitted provided that the following conditions
7256056Sgrehan * are met:
8256056Sgrehan * 1. Redistributions of source code must retain the above copyright
9256056Sgrehan *    notice, this list of conditions and the following disclaimer.
10256056Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
11256056Sgrehan *    notice, this list of conditions and the following disclaimer in the
12256056Sgrehan *    documentation and/or other materials provided with the distribution.
13256056Sgrehan *
14256056Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
15256056Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16256056Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17256056Sgrehan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18256056Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19256056Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20256056Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21256056Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22256056Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23256056Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24256056Sgrehan * SUCH DAMAGE.
25256056Sgrehan *
26256056Sgrehan * $FreeBSD: stable/10/usr.sbin/bhyve/pci_ahci.c 267393 2014-06-12 13:13:15Z jhb $
27256056Sgrehan */
28256056Sgrehan
29256056Sgrehan#include <sys/cdefs.h>
30256056Sgrehan__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/pci_ahci.c 267393 2014-06-12 13:13:15Z jhb $");
31256056Sgrehan
32256056Sgrehan#include <sys/param.h>
33256056Sgrehan#include <sys/linker_set.h>
34256056Sgrehan#include <sys/stat.h>
35256056Sgrehan#include <sys/uio.h>
36256056Sgrehan#include <sys/ioctl.h>
37256056Sgrehan#include <sys/disk.h>
38256056Sgrehan#include <sys/ata.h>
39256056Sgrehan#include <sys/endian.h>
40256056Sgrehan
41256056Sgrehan#include <errno.h>
42256056Sgrehan#include <fcntl.h>
43256056Sgrehan#include <stdio.h>
44256056Sgrehan#include <stdlib.h>
45256056Sgrehan#include <stdint.h>
46256056Sgrehan#include <string.h>
47256056Sgrehan#include <strings.h>
48256056Sgrehan#include <unistd.h>
49256056Sgrehan#include <assert.h>
50256056Sgrehan#include <pthread.h>
51256056Sgrehan#include <inttypes.h>
52256056Sgrehan
53256056Sgrehan#include "bhyverun.h"
54256056Sgrehan#include "pci_emul.h"
55256056Sgrehan#include "ahci.h"
56256056Sgrehan#include "block_if.h"
57256056Sgrehan
58256056Sgrehan#define	MAX_PORTS	6	/* Intel ICH8 AHCI supports 6 ports */
59256056Sgrehan
60256056Sgrehan#define	PxSIG_ATA	0x00000101 /* ATA drive */
61256056Sgrehan#define	PxSIG_ATAPI	0xeb140101 /* ATAPI drive */
62256056Sgrehan
63256056Sgrehanenum sata_fis_type {
64256056Sgrehan	FIS_TYPE_REGH2D		= 0x27,	/* Register FIS - host to device */
65256056Sgrehan	FIS_TYPE_REGD2H		= 0x34,	/* Register FIS - device to host */
66256056Sgrehan	FIS_TYPE_DMAACT		= 0x39,	/* DMA activate FIS - device to host */
67256056Sgrehan	FIS_TYPE_DMASETUP	= 0x41,	/* DMA setup FIS - bidirectional */
68256056Sgrehan	FIS_TYPE_DATA		= 0x46,	/* Data FIS - bidirectional */
69256056Sgrehan	FIS_TYPE_BIST		= 0x58,	/* BIST activate FIS - bidirectional */
70256056Sgrehan	FIS_TYPE_PIOSETUP	= 0x5F,	/* PIO setup FIS - device to host */
71256056Sgrehan	FIS_TYPE_SETDEVBITS	= 0xA1,	/* Set dev bits FIS - device to host */
72256056Sgrehan};
73256056Sgrehan
74256056Sgrehan/*
75256056Sgrehan * SCSI opcodes
76256056Sgrehan */
77256056Sgrehan#define	TEST_UNIT_READY		0x00
78256056Sgrehan#define	REQUEST_SENSE		0x03
79256056Sgrehan#define	INQUIRY			0x12
80256056Sgrehan#define	START_STOP_UNIT		0x1B
81256056Sgrehan#define	PREVENT_ALLOW		0x1E
82256056Sgrehan#define	READ_CAPACITY		0x25
83256056Sgrehan#define	READ_10			0x28
84256056Sgrehan#define	POSITION_TO_ELEMENT	0x2B
85256056Sgrehan#define	READ_TOC		0x43
86256056Sgrehan#define	GET_EVENT_STATUS_NOTIFICATION 0x4A
87256056Sgrehan#define	MODE_SENSE_10		0x5A
88256056Sgrehan#define	READ_12			0xA8
89256056Sgrehan#define	READ_CD			0xBE
90256056Sgrehan
91256056Sgrehan/*
92256056Sgrehan * SCSI mode page codes
93256056Sgrehan */
94256056Sgrehan#define	MODEPAGE_RW_ERROR_RECOVERY	0x01
95256056Sgrehan#define	MODEPAGE_CD_CAPABILITIES	0x2A
96256056Sgrehan
97256056Sgrehan/*
98267339Sjhb * ATA commands
99267339Sjhb */
100267339Sjhb#define	ATA_SF_ENAB_SATA_SF		0x10
101267339Sjhb#define		ATA_SATA_SF_AN		0x05
102267339Sjhb#define	ATA_SF_DIS_SATA_SF		0x90
103267339Sjhb
104267339Sjhb/*
105256056Sgrehan * Debug printf
106256056Sgrehan */
107256056Sgrehan#ifdef AHCI_DEBUG
108256056Sgrehanstatic FILE *dbg;
109256056Sgrehan#define DPRINTF(format, arg...)	do{fprintf(dbg, format, ##arg);fflush(dbg);}while(0)
110256056Sgrehan#else
111256056Sgrehan#define DPRINTF(format, arg...)
112256056Sgrehan#endif
113256056Sgrehan#define WPRINTF(format, arg...) printf(format, ##arg)
114256056Sgrehan
115256056Sgrehanstruct ahci_ioreq {
116256056Sgrehan	struct blockif_req io_req;
117256056Sgrehan	struct ahci_port *io_pr;
118256056Sgrehan	STAILQ_ENTRY(ahci_ioreq) io_list;
119256056Sgrehan	uint8_t *cfis;
120256056Sgrehan	uint32_t len;
121256056Sgrehan	uint32_t done;
122256056Sgrehan	int slot;
123256056Sgrehan	int prdtl;
124256056Sgrehan};
125256056Sgrehan
126256056Sgrehanstruct ahci_port {
127256056Sgrehan	struct blockif_ctxt *bctx;
128256056Sgrehan	struct pci_ahci_softc *pr_sc;
129256164Sdim	uint8_t *cmd_lst;
130256164Sdim	uint8_t *rfis;
131256056Sgrehan	int atapi;
132256056Sgrehan	int reset;
133256056Sgrehan	int mult_sectors;
134256056Sgrehan	uint8_t xfermode;
135256056Sgrehan	uint8_t sense_key;
136256056Sgrehan	uint8_t asc;
137267339Sjhb	uint32_t pending;
138256056Sgrehan
139256056Sgrehan	uint32_t clb;
140256056Sgrehan	uint32_t clbu;
141256056Sgrehan	uint32_t fb;
142256056Sgrehan	uint32_t fbu;
143256056Sgrehan	uint32_t is;
144256056Sgrehan	uint32_t ie;
145256056Sgrehan	uint32_t cmd;
146256056Sgrehan	uint32_t unused0;
147256056Sgrehan	uint32_t tfd;
148256056Sgrehan	uint32_t sig;
149256056Sgrehan	uint32_t ssts;
150256056Sgrehan	uint32_t sctl;
151256056Sgrehan	uint32_t serr;
152256056Sgrehan	uint32_t sact;
153256056Sgrehan	uint32_t ci;
154256056Sgrehan	uint32_t sntf;
155256056Sgrehan	uint32_t fbs;
156256056Sgrehan
157256056Sgrehan	/*
158256056Sgrehan	 * i/o request info
159256056Sgrehan	 */
160256056Sgrehan	struct ahci_ioreq *ioreq;
161256056Sgrehan	int ioqsz;
162256056Sgrehan	STAILQ_HEAD(ahci_fhead, ahci_ioreq) iofhd;
163256056Sgrehan};
164256056Sgrehan
165256056Sgrehanstruct ahci_cmd_hdr {
166256056Sgrehan	uint16_t flags;
167256056Sgrehan	uint16_t prdtl;
168256056Sgrehan	uint32_t prdbc;
169256056Sgrehan	uint64_t ctba;
170256056Sgrehan	uint32_t reserved[4];
171256056Sgrehan};
172256056Sgrehan
173256056Sgrehanstruct ahci_prdt_entry {
174256056Sgrehan	uint64_t dba;
175256056Sgrehan	uint32_t reserved;
176259301Sgrehan#define	DBCMASK		0x3fffff
177256056Sgrehan	uint32_t dbc;
178256056Sgrehan};
179256056Sgrehan
180256056Sgrehanstruct pci_ahci_softc {
181256056Sgrehan	struct pci_devinst *asc_pi;
182256056Sgrehan	pthread_mutex_t	mtx;
183256056Sgrehan	int ports;
184256056Sgrehan	uint32_t cap;
185256056Sgrehan	uint32_t ghc;
186256056Sgrehan	uint32_t is;
187256056Sgrehan	uint32_t pi;
188256056Sgrehan	uint32_t vs;
189256056Sgrehan	uint32_t ccc_ctl;
190256056Sgrehan	uint32_t ccc_pts;
191256056Sgrehan	uint32_t em_loc;
192256056Sgrehan	uint32_t em_ctl;
193256056Sgrehan	uint32_t cap2;
194256056Sgrehan	uint32_t bohc;
195267393Sjhb	uint32_t lintr;
196256056Sgrehan	struct ahci_port port[MAX_PORTS];
197256056Sgrehan};
198256056Sgrehan#define	ahci_ctx(sc)	((sc)->asc_pi->pi_vmctx)
199256056Sgrehan
200256056Sgrehanstatic inline void lba_to_msf(uint8_t *buf, int lba)
201256056Sgrehan{
202256056Sgrehan	lba += 150;
203256056Sgrehan	buf[0] = (lba / 75) / 60;
204256056Sgrehan	buf[1] = (lba / 75) % 60;
205256056Sgrehan	buf[2] = lba % 75;
206256056Sgrehan}
207256056Sgrehan
208256056Sgrehan/*
209256056Sgrehan * generate HBA intr depending on whether or not ports within
210256056Sgrehan * the controller have an interrupt pending.
211256056Sgrehan */
212256056Sgrehanstatic void
213256056Sgrehanahci_generate_intr(struct pci_ahci_softc *sc)
214256056Sgrehan{
215267393Sjhb	struct pci_devinst *pi;
216256056Sgrehan	int i;
217256056Sgrehan
218267393Sjhb	pi = sc->asc_pi;
219267393Sjhb
220256056Sgrehan	for (i = 0; i < sc->ports; i++) {
221256056Sgrehan		struct ahci_port *pr;
222256056Sgrehan		pr = &sc->port[i];
223256056Sgrehan		if (pr->is & pr->ie)
224256056Sgrehan			sc->is |= (1 << i);
225256056Sgrehan	}
226256056Sgrehan
227256056Sgrehan	DPRINTF("%s %x\n", __func__, sc->is);
228256056Sgrehan
229267393Sjhb	if (sc->is && (sc->ghc & AHCI_GHC_IE)) {
230267393Sjhb		if (pci_msi_enabled(pi)) {
231267393Sjhb			/*
232267393Sjhb			 * Generate an MSI interrupt on every edge
233267393Sjhb			 */
234267393Sjhb			pci_generate_msi(pi, 0);
235267393Sjhb		} else if (!sc->lintr) {
236267393Sjhb			/*
237267393Sjhb			 * Only generate a pin-based interrupt if one wasn't
238267393Sjhb			 * in progress
239267393Sjhb			 */
240267393Sjhb			sc->lintr = 1;
241267393Sjhb			pci_lintr_assert(pi);
242267393Sjhb		}
243267393Sjhb	} else if (sc->lintr) {
244267393Sjhb		/*
245267393Sjhb		 * No interrupts: deassert pin-based signal if it had
246267393Sjhb		 * been asserted
247267393Sjhb		 */
248267393Sjhb		pci_lintr_deassert(pi);
249267393Sjhb		sc->lintr = 0;
250267393Sjhb	}
251256056Sgrehan}
252256056Sgrehan
253256056Sgrehanstatic void
254256056Sgrehanahci_write_fis(struct ahci_port *p, enum sata_fis_type ft, uint8_t *fis)
255256056Sgrehan{
256256056Sgrehan	int offset, len, irq;
257256056Sgrehan
258256164Sdim	if (p->rfis == NULL || !(p->cmd & AHCI_P_CMD_FRE))
259256056Sgrehan		return;
260256056Sgrehan
261256056Sgrehan	switch (ft) {
262256056Sgrehan	case FIS_TYPE_REGD2H:
263256056Sgrehan		offset = 0x40;
264256056Sgrehan		len = 20;
265256056Sgrehan		irq = AHCI_P_IX_DHR;
266256056Sgrehan		break;
267256056Sgrehan	case FIS_TYPE_SETDEVBITS:
268256056Sgrehan		offset = 0x58;
269256056Sgrehan		len = 8;
270256056Sgrehan		irq = AHCI_P_IX_SDB;
271256056Sgrehan		break;
272256056Sgrehan	case FIS_TYPE_PIOSETUP:
273256056Sgrehan		offset = 0x20;
274256056Sgrehan		len = 20;
275256056Sgrehan		irq = 0;
276256056Sgrehan		break;
277256056Sgrehan	default:
278256056Sgrehan		WPRINTF("unsupported fis type %d\n", ft);
279256056Sgrehan		return;
280256056Sgrehan	}
281256056Sgrehan	memcpy(p->rfis + offset, fis, len);
282256056Sgrehan	if (irq) {
283256056Sgrehan		p->is |= irq;
284256056Sgrehan		ahci_generate_intr(p->pr_sc);
285256056Sgrehan	}
286256056Sgrehan}
287256056Sgrehan
288256056Sgrehanstatic void
289267339Sjhbahci_write_fis_piosetup(struct ahci_port *p)
290267339Sjhb{
291267339Sjhb	uint8_t fis[20];
292267339Sjhb
293267339Sjhb	memset(fis, 0, sizeof(fis));
294267339Sjhb	fis[0] = FIS_TYPE_PIOSETUP;
295267339Sjhb	ahci_write_fis(p, FIS_TYPE_PIOSETUP, fis);
296267339Sjhb}
297267339Sjhb
298267339Sjhbstatic void
299256056Sgrehanahci_write_fis_sdb(struct ahci_port *p, int slot, uint32_t tfd)
300256056Sgrehan{
301256056Sgrehan	uint8_t fis[8];
302256056Sgrehan	uint8_t error;
303256056Sgrehan
304256056Sgrehan	error = (tfd >> 8) & 0xff;
305256056Sgrehan	memset(fis, 0, sizeof(fis));
306256056Sgrehan	fis[0] = error;
307256056Sgrehan	fis[2] = tfd & 0x77;
308256056Sgrehan	*(uint32_t *)(fis + 4) = (1 << slot);
309256056Sgrehan	if (fis[2] & ATA_S_ERROR)
310256056Sgrehan		p->is |= AHCI_P_IX_TFE;
311256056Sgrehan	p->tfd = tfd;
312256056Sgrehan	ahci_write_fis(p, FIS_TYPE_SETDEVBITS, fis);
313256056Sgrehan}
314256056Sgrehan
315256056Sgrehanstatic void
316256056Sgrehanahci_write_fis_d2h(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd)
317256056Sgrehan{
318256056Sgrehan	uint8_t fis[20];
319256056Sgrehan	uint8_t error;
320256056Sgrehan
321256056Sgrehan	error = (tfd >> 8) & 0xff;
322256056Sgrehan	memset(fis, 0, sizeof(fis));
323256056Sgrehan	fis[0] = FIS_TYPE_REGD2H;
324256056Sgrehan	fis[1] = (1 << 6);
325256056Sgrehan	fis[2] = tfd & 0xff;
326256056Sgrehan	fis[3] = error;
327256056Sgrehan	fis[4] = cfis[4];
328256056Sgrehan	fis[5] = cfis[5];
329256056Sgrehan	fis[6] = cfis[6];
330256056Sgrehan	fis[7] = cfis[7];
331256056Sgrehan	fis[8] = cfis[8];
332256056Sgrehan	fis[9] = cfis[9];
333256056Sgrehan	fis[10] = cfis[10];
334256056Sgrehan	fis[11] = cfis[11];
335256056Sgrehan	fis[12] = cfis[12];
336256056Sgrehan	fis[13] = cfis[13];
337256056Sgrehan	if (fis[2] & ATA_S_ERROR)
338256056Sgrehan		p->is |= AHCI_P_IX_TFE;
339256056Sgrehan	p->tfd = tfd;
340256056Sgrehan	p->ci &= ~(1 << slot);
341256056Sgrehan	ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
342256056Sgrehan}
343256056Sgrehan
344256056Sgrehanstatic void
345256056Sgrehanahci_write_reset_fis_d2h(struct ahci_port *p)
346256056Sgrehan{
347256056Sgrehan	uint8_t fis[20];
348256056Sgrehan
349256056Sgrehan	memset(fis, 0, sizeof(fis));
350256056Sgrehan	fis[0] = FIS_TYPE_REGD2H;
351256056Sgrehan	fis[3] = 1;
352256056Sgrehan	fis[4] = 1;
353256056Sgrehan	if (p->atapi) {
354256056Sgrehan		fis[5] = 0x14;
355256056Sgrehan		fis[6] = 0xeb;
356256056Sgrehan	}
357256056Sgrehan	fis[12] = 1;
358256056Sgrehan	ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
359256056Sgrehan}
360256056Sgrehan
361256056Sgrehanstatic void
362256056Sgrehanahci_port_reset(struct ahci_port *pr)
363256056Sgrehan{
364256056Sgrehan	pr->sctl = 0;
365256056Sgrehan	pr->serr = 0;
366256056Sgrehan	pr->sact = 0;
367256056Sgrehan	pr->xfermode = ATA_UDMA6;
368256056Sgrehan	pr->mult_sectors = 128;
369256056Sgrehan
370256056Sgrehan	if (!pr->bctx) {
371256056Sgrehan		pr->ssts = ATA_SS_DET_NO_DEVICE;
372256056Sgrehan		pr->sig = 0xFFFFFFFF;
373256056Sgrehan		pr->tfd = 0x7F;
374256056Sgrehan		return;
375256056Sgrehan	}
376256056Sgrehan	pr->ssts = ATA_SS_DET_PHY_ONLINE | ATA_SS_SPD_GEN2 |
377256056Sgrehan		ATA_SS_IPM_ACTIVE;
378256056Sgrehan	pr->tfd = (1 << 8) | ATA_S_DSC | ATA_S_DMA;
379256056Sgrehan	if (!pr->atapi) {
380256056Sgrehan		pr->sig = PxSIG_ATA;
381256056Sgrehan		pr->tfd |= ATA_S_READY;
382256056Sgrehan	} else
383256056Sgrehan		pr->sig = PxSIG_ATAPI;
384256056Sgrehan	ahci_write_reset_fis_d2h(pr);
385256056Sgrehan}
386256056Sgrehan
387256056Sgrehanstatic void
388256056Sgrehanahci_reset(struct pci_ahci_softc *sc)
389256056Sgrehan{
390256056Sgrehan	int i;
391256056Sgrehan
392256056Sgrehan	sc->ghc = AHCI_GHC_AE;
393256056Sgrehan	sc->is = 0;
394267393Sjhb
395267393Sjhb	if (sc->lintr) {
396267393Sjhb		pci_lintr_deassert(sc->asc_pi);
397267393Sjhb		sc->lintr = 0;
398267393Sjhb	}
399267393Sjhb
400256056Sgrehan	for (i = 0; i < sc->ports; i++) {
401256056Sgrehan		sc->port[i].ie = 0;
402256056Sgrehan		sc->port[i].is = 0;
403256056Sgrehan		ahci_port_reset(&sc->port[i]);
404256056Sgrehan	}
405256056Sgrehan}
406256056Sgrehan
407256056Sgrehanstatic void
408256056Sgrehanata_string(uint8_t *dest, const char *src, int len)
409256056Sgrehan{
410256056Sgrehan	int i;
411256056Sgrehan
412256056Sgrehan	for (i = 0; i < len; i++) {
413256056Sgrehan		if (*src)
414256056Sgrehan			dest[i ^ 1] = *src++;
415256056Sgrehan		else
416256056Sgrehan			dest[i ^ 1] = ' ';
417256056Sgrehan	}
418256056Sgrehan}
419256056Sgrehan
420256056Sgrehanstatic void
421256056Sgrehanatapi_string(uint8_t *dest, const char *src, int len)
422256056Sgrehan{
423256056Sgrehan	int i;
424256056Sgrehan
425256056Sgrehan	for (i = 0; i < len; i++) {
426256056Sgrehan		if (*src)
427256056Sgrehan			dest[i] = *src++;
428256056Sgrehan		else
429256056Sgrehan			dest[i] = ' ';
430256056Sgrehan	}
431256056Sgrehan}
432256056Sgrehan
433256056Sgrehanstatic void
434256056Sgrehanahci_handle_dma(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done,
435256056Sgrehan    int seek)
436256056Sgrehan{
437256056Sgrehan	struct ahci_ioreq *aior;
438256056Sgrehan	struct blockif_req *breq;
439256056Sgrehan	struct pci_ahci_softc *sc;
440256056Sgrehan	struct ahci_prdt_entry *prdt;
441256056Sgrehan	struct ahci_cmd_hdr *hdr;
442256056Sgrehan	uint64_t lba;
443256056Sgrehan	uint32_t len;
444256056Sgrehan	int i, err, iovcnt, ncq, readop;
445256056Sgrehan
446256056Sgrehan	sc = p->pr_sc;
447256056Sgrehan	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
448256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
449256056Sgrehan	ncq = 0;
450256056Sgrehan	readop = 1;
451256056Sgrehan
452256056Sgrehan	prdt += seek;
453256056Sgrehan	if (cfis[2] == ATA_WRITE_DMA || cfis[2] == ATA_WRITE_DMA48 ||
454256056Sgrehan			cfis[2] == ATA_WRITE_FPDMA_QUEUED)
455256056Sgrehan		readop = 0;
456256056Sgrehan
457256056Sgrehan	if (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||
458256056Sgrehan			cfis[2] == ATA_READ_FPDMA_QUEUED) {
459256056Sgrehan		lba = ((uint64_t)cfis[10] << 40) |
460256056Sgrehan			((uint64_t)cfis[9] << 32) |
461256056Sgrehan			((uint64_t)cfis[8] << 24) |
462256056Sgrehan			((uint64_t)cfis[6] << 16) |
463256056Sgrehan			((uint64_t)cfis[5] << 8) |
464256056Sgrehan			cfis[4];
465256056Sgrehan		len = cfis[11] << 8 | cfis[3];
466256056Sgrehan		if (!len)
467256056Sgrehan			len = 65536;
468256056Sgrehan		ncq = 1;
469256056Sgrehan	} else if (cfis[2] == ATA_READ_DMA48 || cfis[2] == ATA_WRITE_DMA48) {
470256056Sgrehan		lba = ((uint64_t)cfis[10] << 40) |
471256056Sgrehan			((uint64_t)cfis[9] << 32) |
472256056Sgrehan			((uint64_t)cfis[8] << 24) |
473256056Sgrehan			((uint64_t)cfis[6] << 16) |
474256056Sgrehan			((uint64_t)cfis[5] << 8) |
475256056Sgrehan			cfis[4];
476256056Sgrehan		len = cfis[13] << 8 | cfis[12];
477256056Sgrehan		if (!len)
478256056Sgrehan			len = 65536;
479256056Sgrehan	} else {
480256056Sgrehan		lba = ((cfis[7] & 0xf) << 24) | (cfis[6] << 16) |
481256056Sgrehan			(cfis[5] << 8) | cfis[4];
482256056Sgrehan		len = cfis[12];
483256056Sgrehan		if (!len)
484256056Sgrehan			len = 256;
485256056Sgrehan	}
486256056Sgrehan	lba *= blockif_sectsz(p->bctx);
487256056Sgrehan	len *= blockif_sectsz(p->bctx);
488256056Sgrehan
489256056Sgrehan	/*
490256056Sgrehan	 * Pull request off free list
491256056Sgrehan	 */
492256056Sgrehan	aior = STAILQ_FIRST(&p->iofhd);
493256056Sgrehan	assert(aior != NULL);
494256056Sgrehan	STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
495256056Sgrehan	aior->cfis = cfis;
496256056Sgrehan	aior->slot = slot;
497256056Sgrehan	aior->len = len;
498256056Sgrehan	aior->done = done;
499256056Sgrehan	breq = &aior->io_req;
500256056Sgrehan	breq->br_offset = lba + done;
501256056Sgrehan	iovcnt = hdr->prdtl - seek;
502256056Sgrehan	if (iovcnt > BLOCKIF_IOV_MAX) {
503256056Sgrehan		aior->prdtl = iovcnt - BLOCKIF_IOV_MAX;
504256056Sgrehan		iovcnt = BLOCKIF_IOV_MAX;
505267339Sjhb		/*
506267339Sjhb		 * Mark this command in-flight.
507267339Sjhb		 */
508267339Sjhb		p->pending |= 1 << slot;
509256056Sgrehan	} else
510256056Sgrehan		aior->prdtl = 0;
511256056Sgrehan	breq->br_iovcnt = iovcnt;
512256056Sgrehan
513256056Sgrehan	/*
514256056Sgrehan	 * Build up the iovec based on the prdt
515256056Sgrehan	 */
516256056Sgrehan	for (i = 0; i < iovcnt; i++) {
517259301Sgrehan		uint32_t dbcsz;
518259301Sgrehan
519259301Sgrehan		dbcsz = (prdt->dbc & DBCMASK) + 1;
520256056Sgrehan		breq->br_iov[i].iov_base = paddr_guest2host(ahci_ctx(sc),
521259301Sgrehan		    prdt->dba, dbcsz);
522259301Sgrehan		breq->br_iov[i].iov_len = dbcsz;
523259301Sgrehan		aior->done += dbcsz;
524256056Sgrehan		prdt++;
525256056Sgrehan	}
526256056Sgrehan	if (readop)
527256056Sgrehan		err = blockif_read(p->bctx, breq);
528256056Sgrehan	else
529256056Sgrehan		err = blockif_write(p->bctx, breq);
530256056Sgrehan	assert(err == 0);
531256056Sgrehan
532267339Sjhb	if (ncq)
533256056Sgrehan		p->ci &= ~(1 << slot);
534256056Sgrehan}
535256056Sgrehan
536256056Sgrehanstatic void
537256056Sgrehanahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis)
538256056Sgrehan{
539256056Sgrehan	struct ahci_ioreq *aior;
540256056Sgrehan	struct blockif_req *breq;
541256056Sgrehan	int err;
542256056Sgrehan
543256056Sgrehan	/*
544256056Sgrehan	 * Pull request off free list
545256056Sgrehan	 */
546256056Sgrehan	aior = STAILQ_FIRST(&p->iofhd);
547256056Sgrehan	assert(aior != NULL);
548256056Sgrehan	STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
549256056Sgrehan	aior->cfis = cfis;
550256056Sgrehan	aior->slot = slot;
551256056Sgrehan	aior->len = 0;
552267339Sjhb	aior->done = 0;
553267339Sjhb	aior->prdtl = 0;
554256056Sgrehan	breq = &aior->io_req;
555256056Sgrehan
556256056Sgrehan	err = blockif_flush(p->bctx, breq);
557256056Sgrehan	assert(err == 0);
558256056Sgrehan}
559256056Sgrehan
560256056Sgrehanstatic inline void
561256056Sgrehanwrite_prdt(struct ahci_port *p, int slot, uint8_t *cfis,
562256056Sgrehan		void *buf, int size)
563256056Sgrehan{
564256056Sgrehan	struct ahci_cmd_hdr *hdr;
565256056Sgrehan	struct ahci_prdt_entry *prdt;
566256056Sgrehan	void *from;
567256056Sgrehan	int i, len;
568256056Sgrehan
569256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
570256056Sgrehan	len = size;
571256056Sgrehan	from = buf;
572256056Sgrehan	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
573256056Sgrehan	for (i = 0; i < hdr->prdtl && len; i++) {
574259301Sgrehan		uint8_t *ptr;
575259301Sgrehan		uint32_t dbcsz;
576267339Sjhb		int sublen;
577259301Sgrehan
578259301Sgrehan		dbcsz = (prdt->dbc & DBCMASK) + 1;
579259301Sgrehan		ptr = paddr_guest2host(ahci_ctx(p->pr_sc), prdt->dba, dbcsz);
580267339Sjhb		sublen = len < dbcsz ? len : dbcsz;
581267339Sjhb		memcpy(ptr, from, sublen);
582267339Sjhb		len -= sublen;
583267339Sjhb		from += sublen;
584256056Sgrehan		prdt++;
585256056Sgrehan	}
586256056Sgrehan	hdr->prdbc = size - len;
587256056Sgrehan}
588256056Sgrehan
589256056Sgrehanstatic void
590256056Sgrehanhandle_identify(struct ahci_port *p, int slot, uint8_t *cfis)
591256056Sgrehan{
592256056Sgrehan	struct ahci_cmd_hdr *hdr;
593256056Sgrehan
594256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
595256056Sgrehan	if (p->atapi || hdr->prdtl == 0) {
596256056Sgrehan		p->tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
597256056Sgrehan		p->is |= AHCI_P_IX_TFE;
598256056Sgrehan	} else {
599256056Sgrehan		uint16_t buf[256];
600256056Sgrehan		uint64_t sectors;
601256056Sgrehan
602256056Sgrehan		sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
603256056Sgrehan		memset(buf, 0, sizeof(buf));
604256056Sgrehan		buf[0] = 0x0040;
605256056Sgrehan		/* TODO emulate different serial? */
606256056Sgrehan		ata_string((uint8_t *)(buf+10), "123456", 20);
607256056Sgrehan		ata_string((uint8_t *)(buf+23), "001", 8);
608256056Sgrehan		ata_string((uint8_t *)(buf+27), "BHYVE SATA DISK", 40);
609256056Sgrehan		buf[47] = (0x8000 | 128);
610256056Sgrehan		buf[48] = 0x1;
611256056Sgrehan		buf[49] = (1 << 8 | 1 << 9 | 1 << 11);
612256056Sgrehan		buf[50] = (1 << 14);
613256056Sgrehan		buf[53] = (1 << 1 | 1 << 2);
614256056Sgrehan		if (p->mult_sectors)
615256056Sgrehan			buf[59] = (0x100 | p->mult_sectors);
616256056Sgrehan		buf[60] = sectors;
617256056Sgrehan		buf[61] = (sectors >> 16);
618256056Sgrehan		buf[63] = 0x7;
619256056Sgrehan		if (p->xfermode & ATA_WDMA0)
620256056Sgrehan			buf[63] |= (1 << ((p->xfermode & 7) + 8));
621256056Sgrehan		buf[64] = 0x3;
622256056Sgrehan		buf[65] = 100;
623256056Sgrehan		buf[66] = 100;
624256056Sgrehan		buf[67] = 100;
625256056Sgrehan		buf[68] = 100;
626256056Sgrehan		buf[75] = 31;
627256056Sgrehan		buf[76] = (1 << 8 | 1 << 2);
628256056Sgrehan		buf[80] = 0x1f0;
629256056Sgrehan		buf[81] = 0x28;
630256056Sgrehan		buf[82] = (1 << 5 | 1 << 14);
631256056Sgrehan		buf[83] = (1 << 10 | 1 << 12 | 1 << 13 | 1 << 14);
632256056Sgrehan		buf[84] = (1 << 14);
633256056Sgrehan		buf[85] = (1 << 5 | 1 << 14);
634256056Sgrehan		buf[86] = (1 << 10 | 1 << 12 | 1 << 13);
635256056Sgrehan		buf[87] = (1 << 14);
636256056Sgrehan		buf[88] = 0x7f;
637256056Sgrehan		if (p->xfermode & ATA_UDMA0)
638256056Sgrehan			buf[88] |= (1 << ((p->xfermode & 7) + 8));
639256056Sgrehan		buf[93] = (1 | 1 <<14);
640256056Sgrehan		buf[100] = sectors;
641256056Sgrehan		buf[101] = (sectors >> 16);
642256056Sgrehan		buf[102] = (sectors >> 32);
643256056Sgrehan		buf[103] = (sectors >> 48);
644267339Sjhb		ahci_write_fis_piosetup(p);
645256056Sgrehan		write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
646256056Sgrehan		p->tfd = ATA_S_DSC | ATA_S_READY;
647256056Sgrehan		p->is |= AHCI_P_IX_DP;
648256056Sgrehan	}
649256056Sgrehan	p->ci &= ~(1 << slot);
650256056Sgrehan	ahci_generate_intr(p->pr_sc);
651256056Sgrehan}
652256056Sgrehan
653256056Sgrehanstatic void
654256056Sgrehanhandle_atapi_identify(struct ahci_port *p, int slot, uint8_t *cfis)
655256056Sgrehan{
656256056Sgrehan	if (!p->atapi) {
657256056Sgrehan		p->tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
658256056Sgrehan		p->is |= AHCI_P_IX_TFE;
659256056Sgrehan	} else {
660256056Sgrehan		uint16_t buf[256];
661256056Sgrehan
662256056Sgrehan		memset(buf, 0, sizeof(buf));
663256056Sgrehan		buf[0] = (2 << 14 | 5 << 8 | 1 << 7 | 2 << 5);
664256056Sgrehan		/* TODO emulate different serial? */
665256056Sgrehan		ata_string((uint8_t *)(buf+10), "123456", 20);
666256056Sgrehan		ata_string((uint8_t *)(buf+23), "001", 8);
667256056Sgrehan		ata_string((uint8_t *)(buf+27), "BHYVE SATA DVD ROM", 40);
668256056Sgrehan		buf[49] = (1 << 9 | 1 << 8);
669256056Sgrehan		buf[50] = (1 << 14 | 1);
670256056Sgrehan		buf[53] = (1 << 2 | 1 << 1);
671256056Sgrehan		buf[62] = 0x3f;
672256056Sgrehan		buf[63] = 7;
673256056Sgrehan		buf[64] = 3;
674256056Sgrehan		buf[65] = 100;
675256056Sgrehan		buf[66] = 100;
676256056Sgrehan		buf[67] = 100;
677256056Sgrehan		buf[68] = 100;
678256056Sgrehan		buf[76] = (1 << 2 | 1 << 1);
679256056Sgrehan		buf[78] = (1 << 5);
680256056Sgrehan		buf[80] = (0x1f << 4);
681256056Sgrehan		buf[82] = (1 << 4);
682256056Sgrehan		buf[83] = (1 << 14);
683256056Sgrehan		buf[84] = (1 << 14);
684256056Sgrehan		buf[85] = (1 << 4);
685256056Sgrehan		buf[87] = (1 << 14);
686256056Sgrehan		buf[88] = (1 << 14 | 0x7f);
687267339Sjhb		ahci_write_fis_piosetup(p);
688256056Sgrehan		write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
689256056Sgrehan		p->tfd = ATA_S_DSC | ATA_S_READY;
690256056Sgrehan		p->is |= AHCI_P_IX_DHR;
691256056Sgrehan	}
692256056Sgrehan	p->ci &= ~(1 << slot);
693256056Sgrehan	ahci_generate_intr(p->pr_sc);
694256056Sgrehan}
695256056Sgrehan
696256056Sgrehanstatic void
697256056Sgrehanatapi_inquiry(struct ahci_port *p, int slot, uint8_t *cfis)
698256056Sgrehan{
699256056Sgrehan	uint8_t buf[36];
700256056Sgrehan	uint8_t *acmd;
701256056Sgrehan	int len;
702256056Sgrehan
703256056Sgrehan	acmd = cfis + 0x40;
704256056Sgrehan
705256056Sgrehan	buf[0] = 0x05;
706256056Sgrehan	buf[1] = 0x80;
707256056Sgrehan	buf[2] = 0x00;
708256056Sgrehan	buf[3] = 0x21;
709256056Sgrehan	buf[4] = 31;
710256056Sgrehan	buf[5] = 0;
711256056Sgrehan	buf[6] = 0;
712256056Sgrehan	buf[7] = 0;
713256056Sgrehan	atapi_string(buf + 8, "BHYVE", 8);
714256056Sgrehan	atapi_string(buf + 16, "BHYVE DVD-ROM", 16);
715256056Sgrehan	atapi_string(buf + 32, "001", 4);
716256056Sgrehan
717256056Sgrehan	len = sizeof(buf);
718256056Sgrehan	if (len > acmd[4])
719256056Sgrehan		len = acmd[4];
720256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
721256056Sgrehan	write_prdt(p, slot, cfis, buf, len);
722256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
723256056Sgrehan}
724256056Sgrehan
725256056Sgrehanstatic void
726256056Sgrehanatapi_read_capacity(struct ahci_port *p, int slot, uint8_t *cfis)
727256056Sgrehan{
728256056Sgrehan	uint8_t buf[8];
729256056Sgrehan	uint64_t sectors;
730256056Sgrehan
731257128Sgrehan	sectors = blockif_size(p->bctx) / 2048;
732256056Sgrehan	be32enc(buf, sectors - 1);
733256056Sgrehan	be32enc(buf + 4, 2048);
734256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
735256056Sgrehan	write_prdt(p, slot, cfis, buf, sizeof(buf));
736256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
737256056Sgrehan}
738256056Sgrehan
739256056Sgrehanstatic void
740256056Sgrehanatapi_read_toc(struct ahci_port *p, int slot, uint8_t *cfis)
741256056Sgrehan{
742256056Sgrehan	uint8_t *acmd;
743256056Sgrehan	uint8_t format;
744256056Sgrehan	int len;
745256056Sgrehan
746256056Sgrehan	acmd = cfis + 0x40;
747256056Sgrehan
748256056Sgrehan	len = be16dec(acmd + 7);
749256056Sgrehan	format = acmd[9] >> 6;
750256056Sgrehan	switch (format) {
751256056Sgrehan	case 0:
752256056Sgrehan	{
753256056Sgrehan		int msf, size;
754256056Sgrehan		uint64_t sectors;
755256056Sgrehan		uint8_t start_track, buf[20], *bp;
756256056Sgrehan
757256056Sgrehan		msf = (acmd[1] >> 1) & 1;
758256056Sgrehan		start_track = acmd[6];
759256056Sgrehan		if (start_track > 1 && start_track != 0xaa) {
760256056Sgrehan			uint32_t tfd;
761256056Sgrehan			p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
762256056Sgrehan			p->asc = 0x24;
763256056Sgrehan			tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
764256056Sgrehan			cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
765256056Sgrehan			ahci_write_fis_d2h(p, slot, cfis, tfd);
766256056Sgrehan			return;
767256056Sgrehan		}
768256056Sgrehan		bp = buf + 2;
769256056Sgrehan		*bp++ = 1;
770256056Sgrehan		*bp++ = 1;
771256056Sgrehan		if (start_track <= 1) {
772256056Sgrehan			*bp++ = 0;
773256056Sgrehan			*bp++ = 0x14;
774256056Sgrehan			*bp++ = 1;
775256056Sgrehan			*bp++ = 0;
776256056Sgrehan			if (msf) {
777256056Sgrehan				*bp++ = 0;
778256056Sgrehan				lba_to_msf(bp, 0);
779256056Sgrehan				bp += 3;
780256056Sgrehan			} else {
781256056Sgrehan				*bp++ = 0;
782256056Sgrehan				*bp++ = 0;
783256056Sgrehan				*bp++ = 0;
784256056Sgrehan				*bp++ = 0;
785256056Sgrehan			}
786256056Sgrehan		}
787256056Sgrehan		*bp++ = 0;
788256056Sgrehan		*bp++ = 0x14;
789256056Sgrehan		*bp++ = 0xaa;
790256056Sgrehan		*bp++ = 0;
791256056Sgrehan		sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
792256056Sgrehan		sectors >>= 2;
793256056Sgrehan		if (msf) {
794256056Sgrehan			*bp++ = 0;
795256056Sgrehan			lba_to_msf(bp, sectors);
796256056Sgrehan			bp += 3;
797256056Sgrehan		} else {
798256056Sgrehan			be32enc(bp, sectors);
799256056Sgrehan			bp += 4;
800256056Sgrehan		}
801256056Sgrehan		size = bp - buf;
802256056Sgrehan		be16enc(buf, size - 2);
803256056Sgrehan		if (len > size)
804256056Sgrehan			len = size;
805256056Sgrehan		write_prdt(p, slot, cfis, buf, len);
806256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
807256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
808256056Sgrehan		break;
809256056Sgrehan	}
810256056Sgrehan	case 1:
811256056Sgrehan	{
812256056Sgrehan		uint8_t buf[12];
813256056Sgrehan
814256056Sgrehan		memset(buf, 0, sizeof(buf));
815256056Sgrehan		buf[1] = 0xa;
816256056Sgrehan		buf[2] = 0x1;
817256056Sgrehan		buf[3] = 0x1;
818256056Sgrehan		if (len > sizeof(buf))
819256056Sgrehan			len = sizeof(buf);
820256056Sgrehan		write_prdt(p, slot, cfis, buf, len);
821256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
822256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
823256056Sgrehan		break;
824256056Sgrehan	}
825256056Sgrehan	case 2:
826256056Sgrehan	{
827256056Sgrehan		int msf, size;
828256056Sgrehan		uint64_t sectors;
829256056Sgrehan		uint8_t start_track, *bp, buf[50];
830256056Sgrehan
831256056Sgrehan		msf = (acmd[1] >> 1) & 1;
832256056Sgrehan		start_track = acmd[6];
833256056Sgrehan		bp = buf + 2;
834256056Sgrehan		*bp++ = 1;
835256056Sgrehan		*bp++ = 1;
836256056Sgrehan
837256056Sgrehan		*bp++ = 1;
838256056Sgrehan		*bp++ = 0x14;
839256056Sgrehan		*bp++ = 0;
840256056Sgrehan		*bp++ = 0xa0;
841256056Sgrehan		*bp++ = 0;
842256056Sgrehan		*bp++ = 0;
843256056Sgrehan		*bp++ = 0;
844256056Sgrehan		*bp++ = 0;
845256056Sgrehan		*bp++ = 1;
846256056Sgrehan		*bp++ = 0;
847256056Sgrehan		*bp++ = 0;
848256056Sgrehan
849256056Sgrehan		*bp++ = 1;
850256056Sgrehan		*bp++ = 0x14;
851256056Sgrehan		*bp++ = 0;
852256056Sgrehan		*bp++ = 0xa1;
853256056Sgrehan		*bp++ = 0;
854256056Sgrehan		*bp++ = 0;
855256056Sgrehan		*bp++ = 0;
856256056Sgrehan		*bp++ = 0;
857256056Sgrehan		*bp++ = 1;
858256056Sgrehan		*bp++ = 0;
859256056Sgrehan		*bp++ = 0;
860256056Sgrehan
861256056Sgrehan		*bp++ = 1;
862256056Sgrehan		*bp++ = 0x14;
863256056Sgrehan		*bp++ = 0;
864256056Sgrehan		*bp++ = 0xa2;
865256056Sgrehan		*bp++ = 0;
866256056Sgrehan		*bp++ = 0;
867256056Sgrehan		*bp++ = 0;
868256056Sgrehan		sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
869256056Sgrehan		sectors >>= 2;
870256056Sgrehan		if (msf) {
871256056Sgrehan			*bp++ = 0;
872256056Sgrehan			lba_to_msf(bp, sectors);
873256056Sgrehan			bp += 3;
874256056Sgrehan		} else {
875256056Sgrehan			be32enc(bp, sectors);
876256056Sgrehan			bp += 4;
877256056Sgrehan		}
878256056Sgrehan
879256056Sgrehan		*bp++ = 1;
880256056Sgrehan		*bp++ = 0x14;
881256056Sgrehan		*bp++ = 0;
882256056Sgrehan		*bp++ = 1;
883256056Sgrehan		*bp++ = 0;
884256056Sgrehan		*bp++ = 0;
885256056Sgrehan		*bp++ = 0;
886256056Sgrehan		if (msf) {
887256056Sgrehan			*bp++ = 0;
888256056Sgrehan			lba_to_msf(bp, 0);
889256056Sgrehan			bp += 3;
890256056Sgrehan		} else {
891256056Sgrehan			*bp++ = 0;
892256056Sgrehan			*bp++ = 0;
893256056Sgrehan			*bp++ = 0;
894256056Sgrehan			*bp++ = 0;
895256056Sgrehan		}
896256056Sgrehan
897256056Sgrehan		size = bp - buf;
898256056Sgrehan		be16enc(buf, size - 2);
899256056Sgrehan		if (len > size)
900256056Sgrehan			len = size;
901256056Sgrehan		write_prdt(p, slot, cfis, buf, len);
902256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
903256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
904256056Sgrehan		break;
905256056Sgrehan	}
906256056Sgrehan	default:
907256056Sgrehan	{
908256056Sgrehan		uint32_t tfd;
909256056Sgrehan
910256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
911256056Sgrehan		p->asc = 0x24;
912256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
913256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
914256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, tfd);
915256056Sgrehan		break;
916256056Sgrehan	}
917256056Sgrehan	}
918256056Sgrehan}
919256056Sgrehan
920256056Sgrehanstatic void
921256056Sgrehanatapi_read(struct ahci_port *p, int slot, uint8_t *cfis,
922256056Sgrehan		uint32_t done, int seek)
923256056Sgrehan{
924256056Sgrehan	struct ahci_ioreq *aior;
925256056Sgrehan	struct ahci_cmd_hdr *hdr;
926256056Sgrehan	struct ahci_prdt_entry *prdt;
927256056Sgrehan	struct blockif_req *breq;
928256056Sgrehan	struct pci_ahci_softc *sc;
929256056Sgrehan	uint8_t *acmd;
930256056Sgrehan	uint64_t lba;
931256056Sgrehan	uint32_t len;
932256056Sgrehan	int i, err, iovcnt;
933256056Sgrehan
934256056Sgrehan	sc = p->pr_sc;
935256056Sgrehan	acmd = cfis + 0x40;
936256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
937256056Sgrehan	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
938256056Sgrehan
939256056Sgrehan	prdt += seek;
940256056Sgrehan	lba = be32dec(acmd + 2);
941256056Sgrehan	if (acmd[0] == READ_10)
942256056Sgrehan		len = be16dec(acmd + 7);
943256056Sgrehan	else
944256056Sgrehan		len = be32dec(acmd + 6);
945256056Sgrehan	if (len == 0) {
946256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
947256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
948256056Sgrehan	}
949256056Sgrehan	lba *= 2048;
950256056Sgrehan	len *= 2048;
951256056Sgrehan
952256056Sgrehan	/*
953256056Sgrehan	 * Pull request off free list
954256056Sgrehan	 */
955256056Sgrehan	aior = STAILQ_FIRST(&p->iofhd);
956256056Sgrehan	assert(aior != NULL);
957256056Sgrehan	STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
958256056Sgrehan	aior->cfis = cfis;
959256056Sgrehan	aior->slot = slot;
960256056Sgrehan	aior->len = len;
961256056Sgrehan	aior->done = done;
962256056Sgrehan	breq = &aior->io_req;
963256056Sgrehan	breq->br_offset = lba + done;
964256056Sgrehan	iovcnt = hdr->prdtl - seek;
965256056Sgrehan	if (iovcnt > BLOCKIF_IOV_MAX) {
966256056Sgrehan		aior->prdtl = iovcnt - BLOCKIF_IOV_MAX;
967256056Sgrehan		iovcnt = BLOCKIF_IOV_MAX;
968256056Sgrehan	} else
969256056Sgrehan		aior->prdtl = 0;
970256056Sgrehan	breq->br_iovcnt = iovcnt;
971256056Sgrehan
972256056Sgrehan	/*
973256056Sgrehan	 * Build up the iovec based on the prdt
974256056Sgrehan	 */
975257128Sgrehan	for (i = 0; i < iovcnt; i++) {
976259301Sgrehan		uint32_t dbcsz;
977259301Sgrehan
978259301Sgrehan		dbcsz = (prdt->dbc & DBCMASK) + 1;
979256056Sgrehan		breq->br_iov[i].iov_base = paddr_guest2host(ahci_ctx(sc),
980259301Sgrehan		    prdt->dba, dbcsz);
981259301Sgrehan		breq->br_iov[i].iov_len = dbcsz;
982259301Sgrehan		aior->done += dbcsz;
983256056Sgrehan		prdt++;
984256056Sgrehan	}
985256056Sgrehan	err = blockif_read(p->bctx, breq);
986256056Sgrehan	assert(err == 0);
987256056Sgrehan}
988256056Sgrehan
989256056Sgrehanstatic void
990256056Sgrehanatapi_request_sense(struct ahci_port *p, int slot, uint8_t *cfis)
991256056Sgrehan{
992256056Sgrehan	uint8_t buf[64];
993256056Sgrehan	uint8_t *acmd;
994256056Sgrehan	int len;
995256056Sgrehan
996256056Sgrehan	acmd = cfis + 0x40;
997256056Sgrehan	len = acmd[4];
998256056Sgrehan	if (len > sizeof(buf))
999256056Sgrehan		len = sizeof(buf);
1000256056Sgrehan	memset(buf, 0, len);
1001256056Sgrehan	buf[0] = 0x70 | (1 << 7);
1002256056Sgrehan	buf[2] = p->sense_key;
1003256056Sgrehan	buf[7] = 10;
1004256056Sgrehan	buf[12] = p->asc;
1005256056Sgrehan	write_prdt(p, slot, cfis, buf, len);
1006256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1007256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1008256056Sgrehan}
1009256056Sgrehan
1010256056Sgrehanstatic void
1011256056Sgrehanatapi_start_stop_unit(struct ahci_port *p, int slot, uint8_t *cfis)
1012256056Sgrehan{
1013256056Sgrehan	uint8_t *acmd = cfis + 0x40;
1014256056Sgrehan	uint32_t tfd;
1015256056Sgrehan
1016256056Sgrehan	switch (acmd[4] & 3) {
1017256056Sgrehan	case 0:
1018256056Sgrehan	case 1:
1019256056Sgrehan	case 3:
1020256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1021256056Sgrehan		tfd = ATA_S_READY | ATA_S_DSC;
1022256056Sgrehan		break;
1023256056Sgrehan	case 2:
1024256056Sgrehan		/* TODO eject media */
1025256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1026256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1027256056Sgrehan		p->asc = 0x53;
1028256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1029256056Sgrehan		break;
1030256056Sgrehan	}
1031256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, tfd);
1032256056Sgrehan}
1033256056Sgrehan
1034256056Sgrehanstatic void
1035256056Sgrehanatapi_mode_sense(struct ahci_port *p, int slot, uint8_t *cfis)
1036256056Sgrehan{
1037256056Sgrehan	uint8_t *acmd;
1038256056Sgrehan	uint32_t tfd;
1039256056Sgrehan	uint8_t pc, code;
1040256056Sgrehan	int len;
1041256056Sgrehan
1042256056Sgrehan	acmd = cfis + 0x40;
1043256056Sgrehan	len = be16dec(acmd + 7);
1044256056Sgrehan	pc = acmd[2] >> 6;
1045256056Sgrehan	code = acmd[2] & 0x3f;
1046256056Sgrehan
1047256056Sgrehan	switch (pc) {
1048256056Sgrehan	case 0:
1049256056Sgrehan		switch (code) {
1050256056Sgrehan		case MODEPAGE_RW_ERROR_RECOVERY:
1051256056Sgrehan		{
1052256056Sgrehan			uint8_t buf[16];
1053256056Sgrehan
1054256056Sgrehan			if (len > sizeof(buf))
1055256056Sgrehan				len = sizeof(buf);
1056256056Sgrehan
1057256056Sgrehan			memset(buf, 0, sizeof(buf));
1058256056Sgrehan			be16enc(buf, 16 - 2);
1059256056Sgrehan			buf[2] = 0x70;
1060256056Sgrehan			buf[8] = 0x01;
1061256056Sgrehan			buf[9] = 16 - 10;
1062256056Sgrehan			buf[11] = 0x05;
1063256056Sgrehan			write_prdt(p, slot, cfis, buf, len);
1064256056Sgrehan			tfd = ATA_S_READY | ATA_S_DSC;
1065256056Sgrehan			break;
1066256056Sgrehan		}
1067256056Sgrehan		case MODEPAGE_CD_CAPABILITIES:
1068256056Sgrehan		{
1069256056Sgrehan			uint8_t buf[30];
1070256056Sgrehan
1071256056Sgrehan			if (len > sizeof(buf))
1072256056Sgrehan				len = sizeof(buf);
1073256056Sgrehan
1074256056Sgrehan			memset(buf, 0, sizeof(buf));
1075256056Sgrehan			be16enc(buf, 30 - 2);
1076256056Sgrehan			buf[2] = 0x70;
1077256056Sgrehan			buf[8] = 0x2A;
1078256056Sgrehan			buf[9] = 30 - 10;
1079256056Sgrehan			buf[10] = 0x08;
1080256056Sgrehan			buf[12] = 0x71;
1081256056Sgrehan			be16enc(&buf[18], 2);
1082256056Sgrehan			be16enc(&buf[20], 512);
1083256056Sgrehan			write_prdt(p, slot, cfis, buf, len);
1084256056Sgrehan			tfd = ATA_S_READY | ATA_S_DSC;
1085256056Sgrehan			break;
1086256056Sgrehan		}
1087256056Sgrehan		default:
1088256056Sgrehan			goto error;
1089256056Sgrehan			break;
1090256056Sgrehan		}
1091256056Sgrehan		break;
1092256056Sgrehan	case 3:
1093256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1094256056Sgrehan		p->asc = 0x39;
1095256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1096256056Sgrehan		break;
1097256056Sgrehanerror:
1098256056Sgrehan	case 1:
1099256056Sgrehan	case 2:
1100256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1101256056Sgrehan		p->asc = 0x24;
1102256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1103256056Sgrehan		break;
1104256056Sgrehan	}
1105256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1106256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, tfd);
1107256056Sgrehan}
1108256056Sgrehan
1109256056Sgrehanstatic void
1110256056Sgrehanatapi_get_event_status_notification(struct ahci_port *p, int slot,
1111256056Sgrehan    uint8_t *cfis)
1112256056Sgrehan{
1113256056Sgrehan	uint8_t *acmd;
1114256056Sgrehan	uint32_t tfd;
1115256056Sgrehan
1116256056Sgrehan	acmd = cfis + 0x40;
1117256056Sgrehan
1118256056Sgrehan	/* we don't support asynchronous operation */
1119256056Sgrehan	if (!(acmd[1] & 1)) {
1120256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1121256056Sgrehan		p->asc = 0x24;
1122256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1123256056Sgrehan	} else {
1124256056Sgrehan		uint8_t buf[8];
1125256056Sgrehan		int len;
1126256056Sgrehan
1127256056Sgrehan		len = be16dec(acmd + 7);
1128256056Sgrehan		if (len > sizeof(buf))
1129256056Sgrehan			len = sizeof(buf);
1130256056Sgrehan
1131256056Sgrehan		memset(buf, 0, sizeof(buf));
1132256056Sgrehan		be16enc(buf, 8 - 2);
1133256056Sgrehan		buf[2] = 0x04;
1134256056Sgrehan		buf[3] = 0x10;
1135256056Sgrehan		buf[5] = 0x02;
1136256056Sgrehan		write_prdt(p, slot, cfis, buf, len);
1137256056Sgrehan		tfd = ATA_S_READY | ATA_S_DSC;
1138256056Sgrehan	}
1139256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1140256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, tfd);
1141256056Sgrehan}
1142256056Sgrehan
1143256056Sgrehanstatic void
1144256056Sgrehanhandle_packet_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
1145256056Sgrehan{
1146256056Sgrehan	uint8_t *acmd;
1147256056Sgrehan
1148256056Sgrehan	acmd = cfis + 0x40;
1149256056Sgrehan
1150256056Sgrehan#ifdef AHCI_DEBUG
1151256056Sgrehan	{
1152256056Sgrehan		int i;
1153256056Sgrehan		DPRINTF("ACMD:");
1154256056Sgrehan		for (i = 0; i < 16; i++)
1155256056Sgrehan			DPRINTF("%02x ", acmd[i]);
1156256056Sgrehan		DPRINTF("\n");
1157256056Sgrehan	}
1158256056Sgrehan#endif
1159256056Sgrehan
1160256056Sgrehan	switch (acmd[0]) {
1161256056Sgrehan	case TEST_UNIT_READY:
1162256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1163256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1164256056Sgrehan		break;
1165256056Sgrehan	case INQUIRY:
1166256056Sgrehan		atapi_inquiry(p, slot, cfis);
1167256056Sgrehan		break;
1168256056Sgrehan	case READ_CAPACITY:
1169256056Sgrehan		atapi_read_capacity(p, slot, cfis);
1170256056Sgrehan		break;
1171256056Sgrehan	case PREVENT_ALLOW:
1172256056Sgrehan		/* TODO */
1173256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1174256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1175256056Sgrehan		break;
1176256056Sgrehan	case READ_TOC:
1177256056Sgrehan		atapi_read_toc(p, slot, cfis);
1178256056Sgrehan		break;
1179256056Sgrehan	case READ_10:
1180256056Sgrehan	case READ_12:
1181256056Sgrehan		atapi_read(p, slot, cfis, 0, 0);
1182256056Sgrehan		break;
1183256056Sgrehan	case REQUEST_SENSE:
1184256056Sgrehan		atapi_request_sense(p, slot, cfis);
1185256056Sgrehan		break;
1186256056Sgrehan	case START_STOP_UNIT:
1187256056Sgrehan		atapi_start_stop_unit(p, slot, cfis);
1188256056Sgrehan		break;
1189256056Sgrehan	case MODE_SENSE_10:
1190256056Sgrehan		atapi_mode_sense(p, slot, cfis);
1191256056Sgrehan		break;
1192256056Sgrehan	case GET_EVENT_STATUS_NOTIFICATION:
1193256056Sgrehan		atapi_get_event_status_notification(p, slot, cfis);
1194256056Sgrehan		break;
1195256056Sgrehan	default:
1196256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1197256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1198256056Sgrehan		p->asc = 0x20;
1199256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, (p->sense_key << 12) |
1200256056Sgrehan				ATA_S_READY | ATA_S_ERROR);
1201256056Sgrehan		break;
1202256056Sgrehan	}
1203256056Sgrehan}
1204256056Sgrehan
1205256056Sgrehanstatic void
1206256056Sgrehanahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
1207256056Sgrehan{
1208256056Sgrehan
1209256056Sgrehan	switch (cfis[2]) {
1210256056Sgrehan	case ATA_ATA_IDENTIFY:
1211256056Sgrehan		handle_identify(p, slot, cfis);
1212256056Sgrehan		break;
1213256056Sgrehan	case ATA_SETFEATURES:
1214256056Sgrehan	{
1215256056Sgrehan		switch (cfis[3]) {
1216267339Sjhb		case ATA_SF_ENAB_SATA_SF:
1217267339Sjhb			switch (cfis[12]) {
1218267339Sjhb			case ATA_SATA_SF_AN:
1219267339Sjhb				p->tfd = ATA_S_DSC | ATA_S_READY;
1220267339Sjhb				break;
1221267339Sjhb			default:
1222267339Sjhb				p->tfd = ATA_S_ERROR | ATA_S_READY;
1223267339Sjhb				p->tfd |= (ATA_ERROR_ABORT << 8);
1224267339Sjhb				break;
1225267339Sjhb			}
1226267339Sjhb			break;
1227256056Sgrehan		case ATA_SF_ENAB_WCACHE:
1228256056Sgrehan		case ATA_SF_DIS_WCACHE:
1229256056Sgrehan		case ATA_SF_ENAB_RCACHE:
1230256056Sgrehan		case ATA_SF_DIS_RCACHE:
1231256056Sgrehan			p->tfd = ATA_S_DSC | ATA_S_READY;
1232256056Sgrehan			break;
1233256056Sgrehan		case ATA_SF_SETXFER:
1234256056Sgrehan		{
1235256056Sgrehan			switch (cfis[12] & 0xf8) {
1236256056Sgrehan			case ATA_PIO:
1237256056Sgrehan			case ATA_PIO0:
1238256056Sgrehan				break;
1239256056Sgrehan			case ATA_WDMA0:
1240256056Sgrehan			case ATA_UDMA0:
1241256056Sgrehan				p->xfermode = (cfis[12] & 0x7);
1242256056Sgrehan				break;
1243256056Sgrehan			}
1244256056Sgrehan			p->tfd = ATA_S_DSC | ATA_S_READY;
1245256056Sgrehan			break;
1246256056Sgrehan		}
1247256056Sgrehan		default:
1248256056Sgrehan			p->tfd = ATA_S_ERROR | ATA_S_READY;
1249256056Sgrehan			p->tfd |= (ATA_ERROR_ABORT << 8);
1250256056Sgrehan			break;
1251256056Sgrehan		}
1252267339Sjhb		ahci_write_fis_d2h(p, slot, cfis, p->tfd);
1253256056Sgrehan		break;
1254256056Sgrehan	}
1255256056Sgrehan	case ATA_SET_MULTI:
1256256056Sgrehan		if (cfis[12] != 0 &&
1257256164Sdim			(cfis[12] > 128 || (cfis[12] & (cfis[12] - 1)))) {
1258256056Sgrehan			p->tfd = ATA_S_ERROR | ATA_S_READY;
1259256056Sgrehan			p->tfd |= (ATA_ERROR_ABORT << 8);
1260256056Sgrehan		} else {
1261256056Sgrehan			p->mult_sectors = cfis[12];
1262256056Sgrehan			p->tfd = ATA_S_DSC | ATA_S_READY;
1263256056Sgrehan		}
1264256056Sgrehan		p->is |= AHCI_P_IX_DP;
1265256056Sgrehan		p->ci &= ~(1 << slot);
1266256056Sgrehan		ahci_generate_intr(p->pr_sc);
1267256056Sgrehan		break;
1268256056Sgrehan	case ATA_READ_DMA:
1269256056Sgrehan	case ATA_WRITE_DMA:
1270256056Sgrehan	case ATA_READ_DMA48:
1271256056Sgrehan	case ATA_WRITE_DMA48:
1272256056Sgrehan	case ATA_READ_FPDMA_QUEUED:
1273256056Sgrehan	case ATA_WRITE_FPDMA_QUEUED:
1274256056Sgrehan		ahci_handle_dma(p, slot, cfis, 0, 0);
1275256056Sgrehan		break;
1276256056Sgrehan	case ATA_FLUSHCACHE:
1277256056Sgrehan	case ATA_FLUSHCACHE48:
1278256056Sgrehan		ahci_handle_flush(p, slot, cfis);
1279256056Sgrehan		break;
1280256056Sgrehan	case ATA_STANDBY_CMD:
1281256056Sgrehan		break;
1282256056Sgrehan	case ATA_NOP:
1283256056Sgrehan	case ATA_STANDBY_IMMEDIATE:
1284256056Sgrehan	case ATA_IDLE_IMMEDIATE:
1285256056Sgrehan	case ATA_SLEEP:
1286256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1287256056Sgrehan		break;
1288256056Sgrehan	case ATA_ATAPI_IDENTIFY:
1289256056Sgrehan		handle_atapi_identify(p, slot, cfis);
1290256056Sgrehan		break;
1291256056Sgrehan	case ATA_PACKET_CMD:
1292256056Sgrehan		if (!p->atapi) {
1293256056Sgrehan			p->tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
1294256056Sgrehan			p->is |= AHCI_P_IX_TFE;
1295256056Sgrehan			p->ci &= ~(1 << slot);
1296256056Sgrehan			ahci_generate_intr(p->pr_sc);
1297256056Sgrehan		} else
1298256056Sgrehan			handle_packet_cmd(p, slot, cfis);
1299256056Sgrehan		break;
1300256056Sgrehan	default:
1301256056Sgrehan		WPRINTF("Unsupported cmd:%02x\n", cfis[2]);
1302256056Sgrehan		p->tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
1303256056Sgrehan		p->is |= AHCI_P_IX_TFE;
1304256056Sgrehan		p->ci &= ~(1 << slot);
1305256056Sgrehan		ahci_generate_intr(p->pr_sc);
1306256056Sgrehan		break;
1307256056Sgrehan	}
1308256056Sgrehan}
1309256056Sgrehan
1310256056Sgrehanstatic void
1311256056Sgrehanahci_handle_slot(struct ahci_port *p, int slot)
1312256056Sgrehan{
1313256056Sgrehan	struct ahci_cmd_hdr *hdr;
1314256056Sgrehan	struct ahci_prdt_entry *prdt;
1315256056Sgrehan	struct pci_ahci_softc *sc;
1316256056Sgrehan	uint8_t *cfis;
1317256056Sgrehan	int cfl;
1318256056Sgrehan
1319256056Sgrehan	sc = p->pr_sc;
1320256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
1321256056Sgrehan	cfl = (hdr->flags & 0x1f) * 4;
1322256056Sgrehan	cfis = paddr_guest2host(ahci_ctx(sc), hdr->ctba,
1323256056Sgrehan			0x80 + hdr->prdtl * sizeof(struct ahci_prdt_entry));
1324256056Sgrehan	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
1325256056Sgrehan
1326256056Sgrehan#ifdef AHCI_DEBUG
1327256056Sgrehan	DPRINTF("\ncfis:");
1328256056Sgrehan	for (i = 0; i < cfl; i++) {
1329256056Sgrehan		if (i % 10 == 0)
1330256056Sgrehan			DPRINTF("\n");
1331256056Sgrehan		DPRINTF("%02x ", cfis[i]);
1332256056Sgrehan	}
1333256056Sgrehan	DPRINTF("\n");
1334256056Sgrehan
1335256056Sgrehan	for (i = 0; i < hdr->prdtl; i++) {
1336256056Sgrehan		DPRINTF("%d@%08"PRIx64"\n", prdt->dbc & 0x3fffff, prdt->dba);
1337256056Sgrehan		prdt++;
1338256056Sgrehan	}
1339256056Sgrehan#endif
1340256056Sgrehan
1341256056Sgrehan	if (cfis[0] != FIS_TYPE_REGH2D) {
1342256056Sgrehan		WPRINTF("Not a H2D FIS:%02x\n", cfis[0]);
1343256056Sgrehan		return;
1344256056Sgrehan	}
1345256056Sgrehan
1346256056Sgrehan	if (cfis[1] & 0x80) {
1347256056Sgrehan		ahci_handle_cmd(p, slot, cfis);
1348256056Sgrehan	} else {
1349256056Sgrehan		if (cfis[15] & (1 << 2))
1350256056Sgrehan			p->reset = 1;
1351256056Sgrehan		else if (p->reset) {
1352256056Sgrehan			p->reset = 0;
1353256056Sgrehan			ahci_port_reset(p);
1354256056Sgrehan		}
1355256056Sgrehan		p->ci &= ~(1 << slot);
1356256056Sgrehan	}
1357256056Sgrehan}
1358256056Sgrehan
1359256056Sgrehanstatic void
1360256056Sgrehanahci_handle_port(struct ahci_port *p)
1361256056Sgrehan{
1362256056Sgrehan	int i;
1363256056Sgrehan
1364256056Sgrehan	if (!(p->cmd & AHCI_P_CMD_ST))
1365256056Sgrehan		return;
1366256056Sgrehan
1367267339Sjhb	/*
1368267339Sjhb	 * Search for any new commands to issue ignoring those that
1369267339Sjhb	 * are already in-flight.
1370267339Sjhb	 */
1371256056Sgrehan	for (i = 0; (i < 32) && p->ci; i++) {
1372267339Sjhb		if ((p->ci & (1 << i)) && !(p->pending & (1 << i)))
1373256056Sgrehan			ahci_handle_slot(p, i);
1374256056Sgrehan	}
1375256056Sgrehan}
1376256056Sgrehan
1377256056Sgrehan/*
1378256056Sgrehan * blockif callback routine - this runs in the context of the blockif
1379256056Sgrehan * i/o thread, so the mutex needs to be acquired.
1380256056Sgrehan */
1381256056Sgrehanstatic void
1382256056Sgrehanata_ioreq_cb(struct blockif_req *br, int err)
1383256056Sgrehan{
1384256056Sgrehan	struct ahci_cmd_hdr *hdr;
1385256056Sgrehan	struct ahci_ioreq *aior;
1386256056Sgrehan	struct ahci_port *p;
1387256056Sgrehan	struct pci_ahci_softc *sc;
1388256056Sgrehan	uint32_t tfd;
1389256056Sgrehan	uint8_t *cfis;
1390256056Sgrehan	int pending, slot, ncq;
1391256056Sgrehan
1392256056Sgrehan	DPRINTF("%s %d\n", __func__, err);
1393256056Sgrehan
1394256056Sgrehan	ncq = 0;
1395256056Sgrehan	aior = br->br_param;
1396256056Sgrehan	p = aior->io_pr;
1397256056Sgrehan	cfis = aior->cfis;
1398256056Sgrehan	slot = aior->slot;
1399256056Sgrehan	pending = aior->prdtl;
1400256056Sgrehan	sc = p->pr_sc;
1401256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
1402256056Sgrehan
1403256056Sgrehan	if (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||
1404256056Sgrehan			cfis[2] == ATA_READ_FPDMA_QUEUED)
1405256056Sgrehan		ncq = 1;
1406256056Sgrehan
1407256056Sgrehan	pthread_mutex_lock(&sc->mtx);
1408256056Sgrehan
1409256056Sgrehan	/*
1410256056Sgrehan	 * Move the blockif request back to the free list
1411256056Sgrehan	 */
1412256056Sgrehan	STAILQ_INSERT_TAIL(&p->iofhd, aior, io_list);
1413256056Sgrehan
1414256056Sgrehan	if (pending && !err) {
1415256056Sgrehan		ahci_handle_dma(p, slot, cfis, aior->done,
1416256056Sgrehan		    hdr->prdtl - pending);
1417256056Sgrehan		goto out;
1418256056Sgrehan	}
1419256056Sgrehan
1420256056Sgrehan	if (!err && aior->done == aior->len) {
1421256056Sgrehan		tfd = ATA_S_READY | ATA_S_DSC;
1422256056Sgrehan		if (ncq)
1423256056Sgrehan			hdr->prdbc = 0;
1424256056Sgrehan		else
1425256056Sgrehan			hdr->prdbc = aior->len;
1426256056Sgrehan	} else {
1427256056Sgrehan		tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
1428256056Sgrehan		hdr->prdbc = 0;
1429256056Sgrehan		if (ncq)
1430256056Sgrehan			p->serr |= (1 << slot);
1431256056Sgrehan	}
1432256056Sgrehan
1433267339Sjhb	/*
1434267339Sjhb	 * This command is now complete.
1435267339Sjhb	 */
1436267339Sjhb	p->pending &= ~(1 << slot);
1437267339Sjhb
1438256056Sgrehan	if (ncq) {
1439256056Sgrehan		p->sact &= ~(1 << slot);
1440256056Sgrehan		ahci_write_fis_sdb(p, slot, tfd);
1441256056Sgrehan	} else
1442256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, tfd);
1443256056Sgrehan
1444256056Sgrehanout:
1445256056Sgrehan	pthread_mutex_unlock(&sc->mtx);
1446256056Sgrehan	DPRINTF("%s exit\n", __func__);
1447256056Sgrehan}
1448256056Sgrehan
1449256056Sgrehanstatic void
1450256056Sgrehanatapi_ioreq_cb(struct blockif_req *br, int err)
1451256056Sgrehan{
1452256056Sgrehan	struct ahci_cmd_hdr *hdr;
1453256056Sgrehan	struct ahci_ioreq *aior;
1454256056Sgrehan	struct ahci_port *p;
1455256056Sgrehan	struct pci_ahci_softc *sc;
1456256056Sgrehan	uint8_t *cfis;
1457256056Sgrehan	uint32_t tfd;
1458256056Sgrehan	int pending, slot;
1459256056Sgrehan
1460256056Sgrehan	DPRINTF("%s %d\n", __func__, err);
1461256056Sgrehan
1462256056Sgrehan	aior = br->br_param;
1463256056Sgrehan	p = aior->io_pr;
1464256056Sgrehan	cfis = aior->cfis;
1465256056Sgrehan	slot = aior->slot;
1466256056Sgrehan	pending = aior->prdtl;
1467256056Sgrehan	sc = p->pr_sc;
1468256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + aior->slot * AHCI_CL_SIZE);
1469256056Sgrehan
1470256056Sgrehan	pthread_mutex_lock(&sc->mtx);
1471256056Sgrehan
1472256056Sgrehan	/*
1473256056Sgrehan	 * Move the blockif request back to the free list
1474256056Sgrehan	 */
1475256056Sgrehan	STAILQ_INSERT_TAIL(&p->iofhd, aior, io_list);
1476256056Sgrehan
1477256056Sgrehan	if (pending && !err) {
1478256056Sgrehan		atapi_read(p, slot, cfis, aior->done, hdr->prdtl - pending);
1479256056Sgrehan		goto out;
1480256056Sgrehan	}
1481256056Sgrehan
1482256056Sgrehan	if (!err && aior->done == aior->len) {
1483256056Sgrehan		tfd = ATA_S_READY | ATA_S_DSC;
1484256056Sgrehan		hdr->prdbc = aior->len;
1485256056Sgrehan	} else {
1486256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1487256056Sgrehan		p->asc = 0x21;
1488256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1489256056Sgrehan		hdr->prdbc = 0;
1490256056Sgrehan	}
1491256056Sgrehan
1492256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1493256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, tfd);
1494256056Sgrehan
1495256056Sgrehanout:
1496256056Sgrehan	pthread_mutex_unlock(&sc->mtx);
1497256056Sgrehan	DPRINTF("%s exit\n", __func__);
1498256056Sgrehan}
1499256056Sgrehan
1500256056Sgrehanstatic void
1501256056Sgrehanpci_ahci_ioreq_init(struct ahci_port *pr)
1502256056Sgrehan{
1503256056Sgrehan	struct ahci_ioreq *vr;
1504256056Sgrehan	int i;
1505256056Sgrehan
1506256056Sgrehan	pr->ioqsz = blockif_queuesz(pr->bctx);
1507256056Sgrehan	pr->ioreq = calloc(pr->ioqsz, sizeof(struct ahci_ioreq));
1508256056Sgrehan	STAILQ_INIT(&pr->iofhd);
1509256056Sgrehan
1510256056Sgrehan	/*
1511256056Sgrehan	 * Add all i/o request entries to the free queue
1512256056Sgrehan	 */
1513256056Sgrehan	for (i = 0; i < pr->ioqsz; i++) {
1514256056Sgrehan		vr = &pr->ioreq[i];
1515256056Sgrehan		vr->io_pr = pr;
1516256056Sgrehan		if (!pr->atapi)
1517256056Sgrehan			vr->io_req.br_callback = ata_ioreq_cb;
1518256056Sgrehan		else
1519256056Sgrehan			vr->io_req.br_callback = atapi_ioreq_cb;
1520256056Sgrehan		vr->io_req.br_param = vr;
1521256056Sgrehan		STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_list);
1522256056Sgrehan	}
1523256056Sgrehan}
1524256056Sgrehan
1525256056Sgrehanstatic void
1526256056Sgrehanpci_ahci_port_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)
1527256056Sgrehan{
1528256056Sgrehan	int port = (offset - AHCI_OFFSET) / AHCI_STEP;
1529256056Sgrehan	offset = (offset - AHCI_OFFSET) % AHCI_STEP;
1530256056Sgrehan	struct ahci_port *p = &sc->port[port];
1531256056Sgrehan
1532256056Sgrehan	DPRINTF("pci_ahci_port %d: write offset 0x%"PRIx64" value 0x%"PRIx64"\n",
1533256056Sgrehan		port, offset, value);
1534256056Sgrehan
1535256056Sgrehan	switch (offset) {
1536256056Sgrehan	case AHCI_P_CLB:
1537256056Sgrehan		p->clb = value;
1538256056Sgrehan		break;
1539256056Sgrehan	case AHCI_P_CLBU:
1540256056Sgrehan		p->clbu = value;
1541256056Sgrehan		break;
1542256056Sgrehan	case AHCI_P_FB:
1543256056Sgrehan		p->fb = value;
1544256056Sgrehan		break;
1545256056Sgrehan	case AHCI_P_FBU:
1546256056Sgrehan		p->fbu = value;
1547256056Sgrehan		break;
1548256056Sgrehan	case AHCI_P_IS:
1549256056Sgrehan		p->is &= ~value;
1550256056Sgrehan		break;
1551256056Sgrehan	case AHCI_P_IE:
1552256056Sgrehan		p->ie = value & 0xFDC000FF;
1553256056Sgrehan		ahci_generate_intr(sc);
1554256056Sgrehan		break;
1555256056Sgrehan	case AHCI_P_CMD:
1556256056Sgrehan	{
1557256056Sgrehan		p->cmd = value;
1558256056Sgrehan
1559256056Sgrehan		if (!(value & AHCI_P_CMD_ST)) {
1560256056Sgrehan			p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK);
1561256056Sgrehan			p->ci = 0;
1562256056Sgrehan			p->sact = 0;
1563256056Sgrehan		} else {
1564256056Sgrehan			uint64_t clb;
1565256056Sgrehan
1566256056Sgrehan			p->cmd |= AHCI_P_CMD_CR;
1567256056Sgrehan			clb = (uint64_t)p->clbu << 32 | p->clb;
1568256056Sgrehan			p->cmd_lst = paddr_guest2host(ahci_ctx(sc), clb,
1569256056Sgrehan					AHCI_CL_SIZE * AHCI_MAX_SLOTS);
1570256056Sgrehan		}
1571256056Sgrehan
1572256056Sgrehan		if (value & AHCI_P_CMD_FRE) {
1573256056Sgrehan			uint64_t fb;
1574256056Sgrehan
1575256056Sgrehan			p->cmd |= AHCI_P_CMD_FR;
1576256056Sgrehan			fb = (uint64_t)p->fbu << 32 | p->fb;
1577256056Sgrehan			/* we don't support FBSCP, so rfis size is 256Bytes */
1578256056Sgrehan			p->rfis = paddr_guest2host(ahci_ctx(sc), fb, 256);
1579256056Sgrehan		} else {
1580256056Sgrehan			p->cmd &= ~AHCI_P_CMD_FR;
1581256056Sgrehan		}
1582256056Sgrehan
1583256056Sgrehan		if (value & AHCI_P_CMD_CLO) {
1584256056Sgrehan			p->tfd = 0;
1585256056Sgrehan			p->cmd &= ~AHCI_P_CMD_CLO;
1586256056Sgrehan		}
1587256056Sgrehan
1588256056Sgrehan		ahci_handle_port(p);
1589256056Sgrehan		break;
1590256056Sgrehan	}
1591256056Sgrehan	case AHCI_P_TFD:
1592256056Sgrehan	case AHCI_P_SIG:
1593256056Sgrehan	case AHCI_P_SSTS:
1594256056Sgrehan		WPRINTF("pci_ahci_port: read only registers 0x%"PRIx64"\n", offset);
1595256056Sgrehan		break;
1596256056Sgrehan	case AHCI_P_SCTL:
1597256056Sgrehan		if (!(p->cmd & AHCI_P_CMD_ST)) {
1598256056Sgrehan			if (value & ATA_SC_DET_RESET)
1599256056Sgrehan				ahci_port_reset(p);
1600256056Sgrehan			p->sctl = value;
1601256056Sgrehan		}
1602256056Sgrehan		break;
1603256056Sgrehan	case AHCI_P_SERR:
1604256056Sgrehan		p->serr &= ~value;
1605256056Sgrehan		break;
1606256056Sgrehan	case AHCI_P_SACT:
1607256056Sgrehan		p->sact |= value;
1608256056Sgrehan		break;
1609256056Sgrehan	case AHCI_P_CI:
1610256056Sgrehan		p->ci |= value;
1611256056Sgrehan		ahci_handle_port(p);
1612256056Sgrehan		break;
1613256056Sgrehan	case AHCI_P_SNTF:
1614256056Sgrehan	case AHCI_P_FBS:
1615256056Sgrehan	default:
1616256056Sgrehan		break;
1617256056Sgrehan	}
1618256056Sgrehan}
1619256056Sgrehan
1620256056Sgrehanstatic void
1621256056Sgrehanpci_ahci_host_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)
1622256056Sgrehan{
1623256056Sgrehan	DPRINTF("pci_ahci_host: write offset 0x%"PRIx64" value 0x%"PRIx64"\n",
1624256056Sgrehan		offset, value);
1625256056Sgrehan
1626256056Sgrehan	switch (offset) {
1627256056Sgrehan	case AHCI_CAP:
1628256056Sgrehan	case AHCI_PI:
1629256056Sgrehan	case AHCI_VS:
1630256056Sgrehan	case AHCI_CAP2:
1631256754Sgrehan		DPRINTF("pci_ahci_host: read only registers 0x%"PRIx64"\n", offset);
1632256056Sgrehan		break;
1633256056Sgrehan	case AHCI_GHC:
1634256056Sgrehan		if (value & AHCI_GHC_HR)
1635256056Sgrehan			ahci_reset(sc);
1636256056Sgrehan		else if (value & AHCI_GHC_IE) {
1637256056Sgrehan			sc->ghc |= AHCI_GHC_IE;
1638256056Sgrehan			ahci_generate_intr(sc);
1639256056Sgrehan		}
1640256056Sgrehan		break;
1641256056Sgrehan	case AHCI_IS:
1642256056Sgrehan		sc->is &= ~value;
1643256056Sgrehan		ahci_generate_intr(sc);
1644256056Sgrehan		break;
1645256056Sgrehan	default:
1646256056Sgrehan		break;
1647256056Sgrehan	}
1648256056Sgrehan}
1649256056Sgrehan
1650256056Sgrehanstatic void
1651256056Sgrehanpci_ahci_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
1652256056Sgrehan		int baridx, uint64_t offset, int size, uint64_t value)
1653256056Sgrehan{
1654256056Sgrehan	struct pci_ahci_softc *sc = pi->pi_arg;
1655256056Sgrehan
1656256056Sgrehan	assert(baridx == 5);
1657256056Sgrehan	assert(size == 4);
1658256056Sgrehan
1659256056Sgrehan	pthread_mutex_lock(&sc->mtx);
1660256056Sgrehan
1661256056Sgrehan	if (offset < AHCI_OFFSET)
1662256056Sgrehan		pci_ahci_host_write(sc, offset, value);
1663256056Sgrehan	else if (offset < AHCI_OFFSET + sc->ports * AHCI_STEP)
1664256056Sgrehan		pci_ahci_port_write(sc, offset, value);
1665256056Sgrehan	else
1666256056Sgrehan		WPRINTF("pci_ahci: unknown i/o write offset 0x%"PRIx64"\n", offset);
1667256056Sgrehan
1668256056Sgrehan	pthread_mutex_unlock(&sc->mtx);
1669256056Sgrehan}
1670256056Sgrehan
1671256056Sgrehanstatic uint64_t
1672256056Sgrehanpci_ahci_host_read(struct pci_ahci_softc *sc, uint64_t offset)
1673256056Sgrehan{
1674256056Sgrehan	uint32_t value;
1675256056Sgrehan
1676256056Sgrehan	switch (offset) {
1677256056Sgrehan	case AHCI_CAP:
1678256056Sgrehan	case AHCI_GHC:
1679256056Sgrehan	case AHCI_IS:
1680256056Sgrehan	case AHCI_PI:
1681256056Sgrehan	case AHCI_VS:
1682256056Sgrehan	case AHCI_CCCC:
1683256056Sgrehan	case AHCI_CCCP:
1684256056Sgrehan	case AHCI_EM_LOC:
1685256056Sgrehan	case AHCI_EM_CTL:
1686256056Sgrehan	case AHCI_CAP2:
1687256056Sgrehan	{
1688256056Sgrehan		uint32_t *p = &sc->cap;
1689256056Sgrehan		p += (offset - AHCI_CAP) / sizeof(uint32_t);
1690256056Sgrehan		value = *p;
1691256056Sgrehan		break;
1692256056Sgrehan	}
1693256056Sgrehan	default:
1694256056Sgrehan		value = 0;
1695256056Sgrehan		break;
1696256056Sgrehan	}
1697256056Sgrehan	DPRINTF("pci_ahci_host: read offset 0x%"PRIx64" value 0x%x\n",
1698256056Sgrehan		offset, value);
1699256056Sgrehan
1700256056Sgrehan	return (value);
1701256056Sgrehan}
1702256056Sgrehan
1703256056Sgrehanstatic uint64_t
1704256056Sgrehanpci_ahci_port_read(struct pci_ahci_softc *sc, uint64_t offset)
1705256056Sgrehan{
1706256056Sgrehan	uint32_t value;
1707256056Sgrehan	int port = (offset - AHCI_OFFSET) / AHCI_STEP;
1708256056Sgrehan	offset = (offset - AHCI_OFFSET) % AHCI_STEP;
1709256056Sgrehan
1710256056Sgrehan	switch (offset) {
1711256056Sgrehan	case AHCI_P_CLB:
1712256056Sgrehan	case AHCI_P_CLBU:
1713256056Sgrehan	case AHCI_P_FB:
1714256056Sgrehan	case AHCI_P_FBU:
1715256056Sgrehan	case AHCI_P_IS:
1716256056Sgrehan	case AHCI_P_IE:
1717256056Sgrehan	case AHCI_P_CMD:
1718256056Sgrehan	case AHCI_P_TFD:
1719256056Sgrehan	case AHCI_P_SIG:
1720256056Sgrehan	case AHCI_P_SSTS:
1721256056Sgrehan	case AHCI_P_SCTL:
1722256056Sgrehan	case AHCI_P_SERR:
1723256056Sgrehan	case AHCI_P_SACT:
1724256056Sgrehan	case AHCI_P_CI:
1725256056Sgrehan	case AHCI_P_SNTF:
1726256056Sgrehan	case AHCI_P_FBS:
1727256056Sgrehan	{
1728256056Sgrehan		uint32_t *p= &sc->port[port].clb;
1729256056Sgrehan		p += (offset - AHCI_P_CLB) / sizeof(uint32_t);
1730256056Sgrehan		value = *p;
1731256056Sgrehan		break;
1732256056Sgrehan	}
1733256056Sgrehan	default:
1734256056Sgrehan		value = 0;
1735256056Sgrehan		break;
1736256056Sgrehan	}
1737256056Sgrehan
1738256056Sgrehan	DPRINTF("pci_ahci_port %d: read offset 0x%"PRIx64" value 0x%x\n",
1739256056Sgrehan		port, offset, value);
1740256056Sgrehan
1741256056Sgrehan	return value;
1742256056Sgrehan}
1743256056Sgrehan
1744256056Sgrehanstatic uint64_t
1745256056Sgrehanpci_ahci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
1746256056Sgrehan    uint64_t offset, int size)
1747256056Sgrehan{
1748256056Sgrehan	struct pci_ahci_softc *sc = pi->pi_arg;
1749256056Sgrehan	uint32_t value;
1750256056Sgrehan
1751256056Sgrehan	assert(baridx == 5);
1752256056Sgrehan	assert(size == 4);
1753256056Sgrehan
1754256056Sgrehan	pthread_mutex_lock(&sc->mtx);
1755256056Sgrehan
1756256056Sgrehan	if (offset < AHCI_OFFSET)
1757256056Sgrehan		value = pci_ahci_host_read(sc, offset);
1758256056Sgrehan	else if (offset < AHCI_OFFSET + sc->ports * AHCI_STEP)
1759256056Sgrehan		value = pci_ahci_port_read(sc, offset);
1760256056Sgrehan	else {
1761256056Sgrehan		value = 0;
1762256056Sgrehan		WPRINTF("pci_ahci: unknown i/o read offset 0x%"PRIx64"\n", offset);
1763256056Sgrehan	}
1764256056Sgrehan
1765256056Sgrehan	pthread_mutex_unlock(&sc->mtx);
1766256056Sgrehan
1767256056Sgrehan	return (value);
1768256056Sgrehan}
1769256056Sgrehan
1770256056Sgrehanstatic int
1771256056Sgrehanpci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi)
1772256056Sgrehan{
1773256056Sgrehan	char bident[sizeof("XX:X:X")];
1774256056Sgrehan	struct blockif_ctxt *bctxt;
1775256056Sgrehan	struct pci_ahci_softc *sc;
1776256056Sgrehan	int ret, slots;
1777256056Sgrehan
1778256056Sgrehan	ret = 0;
1779256056Sgrehan
1780256056Sgrehan	if (opts == NULL) {
1781256056Sgrehan		fprintf(stderr, "pci_ahci: backing device required\n");
1782256056Sgrehan		return (1);
1783256056Sgrehan	}
1784256056Sgrehan
1785256056Sgrehan#ifdef AHCI_DEBUG
1786256056Sgrehan	dbg = fopen("/tmp/log", "w+");
1787256056Sgrehan#endif
1788256056Sgrehan
1789256056Sgrehan       	sc = malloc(sizeof(struct pci_ahci_softc));
1790256056Sgrehan	memset(sc, 0, sizeof(struct pci_ahci_softc));
1791256056Sgrehan	pi->pi_arg = sc;
1792256056Sgrehan	sc->asc_pi = pi;
1793256056Sgrehan	sc->ports = MAX_PORTS;
1794256056Sgrehan
1795256056Sgrehan	/*
1796256056Sgrehan	 * Only use port 0 for a backing device. All other ports will be
1797256056Sgrehan	 * marked as unused
1798256056Sgrehan	 */
1799256056Sgrehan	sc->port[0].atapi = atapi;
1800256056Sgrehan
1801256056Sgrehan	/*
1802256056Sgrehan	 * Attempt to open the backing image. Use the PCI
1803259301Sgrehan	 * slot/func for the identifier string.
1804256056Sgrehan	 */
1805259301Sgrehan	snprintf(bident, sizeof(bident), "%d:%d", pi->pi_slot, pi->pi_func);
1806256056Sgrehan	bctxt = blockif_open(opts, bident);
1807256056Sgrehan	if (bctxt == NULL) {
1808256056Sgrehan		ret = 1;
1809256056Sgrehan		goto open_fail;
1810256056Sgrehan	}
1811256056Sgrehan	sc->port[0].bctx = bctxt;
1812256056Sgrehan	sc->port[0].pr_sc = sc;
1813256056Sgrehan
1814256056Sgrehan	/*
1815256056Sgrehan	 * Allocate blockif request structures and add them
1816256056Sgrehan	 * to the free list
1817256056Sgrehan	 */
1818256056Sgrehan	pci_ahci_ioreq_init(&sc->port[0]);
1819256056Sgrehan
1820256056Sgrehan	pthread_mutex_init(&sc->mtx, NULL);
1821256056Sgrehan
1822256056Sgrehan	/* Intel ICH8 AHCI */
1823256056Sgrehan	slots = sc->port[0].ioqsz;
1824256056Sgrehan	if (slots > 32)
1825256056Sgrehan		slots = 32;
1826256056Sgrehan	--slots;
1827256056Sgrehan	sc->cap = AHCI_CAP_64BIT | AHCI_CAP_SNCQ | AHCI_CAP_SSNTF |
1828256056Sgrehan	    AHCI_CAP_SMPS | AHCI_CAP_SSS | AHCI_CAP_SALP |
1829256056Sgrehan	    AHCI_CAP_SAL | AHCI_CAP_SCLO | (0x3 << AHCI_CAP_ISS_SHIFT)|
1830256056Sgrehan	    AHCI_CAP_PMD | AHCI_CAP_SSC | AHCI_CAP_PSC |
1831256056Sgrehan	    (slots << AHCI_CAP_NCS_SHIFT) | AHCI_CAP_SXS | (sc->ports - 1);
1832256056Sgrehan
1833256056Sgrehan	/* Only port 0 implemented */
1834256056Sgrehan	sc->pi = 1;
1835256056Sgrehan	sc->vs = 0x10300;
1836256056Sgrehan	sc->cap2 = AHCI_CAP2_APST;
1837256056Sgrehan	ahci_reset(sc);
1838256056Sgrehan
1839256056Sgrehan	pci_set_cfgdata16(pi, PCIR_DEVICE, 0x2821);
1840256056Sgrehan	pci_set_cfgdata16(pi, PCIR_VENDOR, 0x8086);
1841256056Sgrehan	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE);
1842256056Sgrehan	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_STORAGE_SATA);
1843256056Sgrehan	pci_set_cfgdata8(pi, PCIR_PROGIF, PCIP_STORAGE_SATA_AHCI_1_0);
1844256056Sgrehan	pci_emul_add_msicap(pi, 1);
1845256056Sgrehan	pci_emul_alloc_bar(pi, 5, PCIBAR_MEM32,
1846256056Sgrehan	    AHCI_OFFSET + sc->ports * AHCI_STEP);
1847256056Sgrehan
1848267393Sjhb	pci_lintr_request(pi);
1849267393Sjhb
1850256056Sgrehanopen_fail:
1851256056Sgrehan	if (ret) {
1852256056Sgrehan		blockif_close(sc->port[0].bctx);
1853256056Sgrehan		free(sc);
1854256056Sgrehan	}
1855256056Sgrehan
1856256056Sgrehan	return (ret);
1857256056Sgrehan}
1858256056Sgrehan
1859256056Sgrehanstatic int
1860256056Sgrehanpci_ahci_hd_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
1861256056Sgrehan{
1862256056Sgrehan
1863256056Sgrehan	return (pci_ahci_init(ctx, pi, opts, 0));
1864256056Sgrehan}
1865256056Sgrehan
1866256056Sgrehanstatic int
1867256056Sgrehanpci_ahci_atapi_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
1868256056Sgrehan{
1869256056Sgrehan
1870256056Sgrehan	return (pci_ahci_init(ctx, pi, opts, 1));
1871256056Sgrehan}
1872256056Sgrehan
1873256056Sgrehan/*
1874256056Sgrehan * Use separate emulation names to distinguish drive and atapi devices
1875256056Sgrehan */
1876256056Sgrehanstruct pci_devemu pci_de_ahci_hd = {
1877256056Sgrehan	.pe_emu =	"ahci-hd",
1878256056Sgrehan	.pe_init =	pci_ahci_hd_init,
1879256056Sgrehan	.pe_barwrite =	pci_ahci_write,
1880256056Sgrehan	.pe_barread =	pci_ahci_read
1881256056Sgrehan};
1882256056SgrehanPCI_EMUL_SET(pci_de_ahci_hd);
1883256056Sgrehan
1884256056Sgrehanstruct pci_devemu pci_de_ahci_cd = {
1885256056Sgrehan	.pe_emu =	"ahci-cd",
1886256056Sgrehan	.pe_init =	pci_ahci_atapi_init,
1887256056Sgrehan	.pe_barwrite =	pci_ahci_write,
1888256056Sgrehan	.pe_barread =	pci_ahci_read
1889256056Sgrehan};
1890256056SgrehanPCI_EMUL_SET(pci_de_ahci_cd);
1891