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$
27256056Sgrehan */
28256056Sgrehan
29256056Sgrehan#include <sys/cdefs.h>
30256056Sgrehan__FBSDID("$FreeBSD$");
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;
339270159Sgrehan	else
340270159Sgrehan		p->ci &= ~(1 << slot);
341256056Sgrehan	p->tfd = tfd;
342256056Sgrehan	ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
343256056Sgrehan}
344256056Sgrehan
345256056Sgrehanstatic void
346256056Sgrehanahci_write_reset_fis_d2h(struct ahci_port *p)
347256056Sgrehan{
348256056Sgrehan	uint8_t fis[20];
349256056Sgrehan
350256056Sgrehan	memset(fis, 0, sizeof(fis));
351256056Sgrehan	fis[0] = FIS_TYPE_REGD2H;
352256056Sgrehan	fis[3] = 1;
353256056Sgrehan	fis[4] = 1;
354256056Sgrehan	if (p->atapi) {
355256056Sgrehan		fis[5] = 0x14;
356256056Sgrehan		fis[6] = 0xeb;
357256056Sgrehan	}
358256056Sgrehan	fis[12] = 1;
359256056Sgrehan	ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
360256056Sgrehan}
361256056Sgrehan
362256056Sgrehanstatic void
363256056Sgrehanahci_port_reset(struct ahci_port *pr)
364256056Sgrehan{
365256056Sgrehan	pr->sctl = 0;
366256056Sgrehan	pr->serr = 0;
367256056Sgrehan	pr->sact = 0;
368256056Sgrehan	pr->xfermode = ATA_UDMA6;
369256056Sgrehan	pr->mult_sectors = 128;
370256056Sgrehan
371256056Sgrehan	if (!pr->bctx) {
372256056Sgrehan		pr->ssts = ATA_SS_DET_NO_DEVICE;
373256056Sgrehan		pr->sig = 0xFFFFFFFF;
374256056Sgrehan		pr->tfd = 0x7F;
375256056Sgrehan		return;
376256056Sgrehan	}
377256056Sgrehan	pr->ssts = ATA_SS_DET_PHY_ONLINE | ATA_SS_SPD_GEN2 |
378256056Sgrehan		ATA_SS_IPM_ACTIVE;
379256056Sgrehan	pr->tfd = (1 << 8) | ATA_S_DSC | ATA_S_DMA;
380256056Sgrehan	if (!pr->atapi) {
381256056Sgrehan		pr->sig = PxSIG_ATA;
382256056Sgrehan		pr->tfd |= ATA_S_READY;
383256056Sgrehan	} else
384256056Sgrehan		pr->sig = PxSIG_ATAPI;
385256056Sgrehan	ahci_write_reset_fis_d2h(pr);
386256056Sgrehan}
387256056Sgrehan
388256056Sgrehanstatic void
389256056Sgrehanahci_reset(struct pci_ahci_softc *sc)
390256056Sgrehan{
391256056Sgrehan	int i;
392256056Sgrehan
393256056Sgrehan	sc->ghc = AHCI_GHC_AE;
394256056Sgrehan	sc->is = 0;
395267393Sjhb
396267393Sjhb	if (sc->lintr) {
397267393Sjhb		pci_lintr_deassert(sc->asc_pi);
398267393Sjhb		sc->lintr = 0;
399267393Sjhb	}
400267393Sjhb
401256056Sgrehan	for (i = 0; i < sc->ports; i++) {
402256056Sgrehan		sc->port[i].ie = 0;
403256056Sgrehan		sc->port[i].is = 0;
404256056Sgrehan		ahci_port_reset(&sc->port[i]);
405256056Sgrehan	}
406256056Sgrehan}
407256056Sgrehan
408256056Sgrehanstatic void
409256056Sgrehanata_string(uint8_t *dest, const char *src, int len)
410256056Sgrehan{
411256056Sgrehan	int i;
412256056Sgrehan
413256056Sgrehan	for (i = 0; i < len; i++) {
414256056Sgrehan		if (*src)
415256056Sgrehan			dest[i ^ 1] = *src++;
416256056Sgrehan		else
417256056Sgrehan			dest[i ^ 1] = ' ';
418256056Sgrehan	}
419256056Sgrehan}
420256056Sgrehan
421256056Sgrehanstatic void
422256056Sgrehanatapi_string(uint8_t *dest, const char *src, int len)
423256056Sgrehan{
424256056Sgrehan	int i;
425256056Sgrehan
426256056Sgrehan	for (i = 0; i < len; i++) {
427256056Sgrehan		if (*src)
428256056Sgrehan			dest[i] = *src++;
429256056Sgrehan		else
430256056Sgrehan			dest[i] = ' ';
431256056Sgrehan	}
432256056Sgrehan}
433256056Sgrehan
434256056Sgrehanstatic void
435256056Sgrehanahci_handle_dma(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done,
436256056Sgrehan    int seek)
437256056Sgrehan{
438256056Sgrehan	struct ahci_ioreq *aior;
439256056Sgrehan	struct blockif_req *breq;
440256056Sgrehan	struct pci_ahci_softc *sc;
441256056Sgrehan	struct ahci_prdt_entry *prdt;
442256056Sgrehan	struct ahci_cmd_hdr *hdr;
443256056Sgrehan	uint64_t lba;
444256056Sgrehan	uint32_t len;
445256056Sgrehan	int i, err, iovcnt, ncq, readop;
446256056Sgrehan
447256056Sgrehan	sc = p->pr_sc;
448256056Sgrehan	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
449256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
450256056Sgrehan	ncq = 0;
451256056Sgrehan	readop = 1;
452256056Sgrehan
453256056Sgrehan	prdt += seek;
454256056Sgrehan	if (cfis[2] == ATA_WRITE_DMA || cfis[2] == ATA_WRITE_DMA48 ||
455256056Sgrehan			cfis[2] == ATA_WRITE_FPDMA_QUEUED)
456256056Sgrehan		readop = 0;
457256056Sgrehan
458256056Sgrehan	if (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||
459256056Sgrehan			cfis[2] == ATA_READ_FPDMA_QUEUED) {
460256056Sgrehan		lba = ((uint64_t)cfis[10] << 40) |
461256056Sgrehan			((uint64_t)cfis[9] << 32) |
462256056Sgrehan			((uint64_t)cfis[8] << 24) |
463256056Sgrehan			((uint64_t)cfis[6] << 16) |
464256056Sgrehan			((uint64_t)cfis[5] << 8) |
465256056Sgrehan			cfis[4];
466256056Sgrehan		len = cfis[11] << 8 | cfis[3];
467256056Sgrehan		if (!len)
468256056Sgrehan			len = 65536;
469256056Sgrehan		ncq = 1;
470256056Sgrehan	} else if (cfis[2] == ATA_READ_DMA48 || cfis[2] == ATA_WRITE_DMA48) {
471256056Sgrehan		lba = ((uint64_t)cfis[10] << 40) |
472256056Sgrehan			((uint64_t)cfis[9] << 32) |
473256056Sgrehan			((uint64_t)cfis[8] << 24) |
474256056Sgrehan			((uint64_t)cfis[6] << 16) |
475256056Sgrehan			((uint64_t)cfis[5] << 8) |
476256056Sgrehan			cfis[4];
477256056Sgrehan		len = cfis[13] << 8 | cfis[12];
478256056Sgrehan		if (!len)
479256056Sgrehan			len = 65536;
480256056Sgrehan	} else {
481256056Sgrehan		lba = ((cfis[7] & 0xf) << 24) | (cfis[6] << 16) |
482256056Sgrehan			(cfis[5] << 8) | cfis[4];
483256056Sgrehan		len = cfis[12];
484256056Sgrehan		if (!len)
485256056Sgrehan			len = 256;
486256056Sgrehan	}
487256056Sgrehan	lba *= blockif_sectsz(p->bctx);
488256056Sgrehan	len *= blockif_sectsz(p->bctx);
489256056Sgrehan
490256056Sgrehan	/*
491256056Sgrehan	 * Pull request off free list
492256056Sgrehan	 */
493256056Sgrehan	aior = STAILQ_FIRST(&p->iofhd);
494256056Sgrehan	assert(aior != NULL);
495256056Sgrehan	STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
496256056Sgrehan	aior->cfis = cfis;
497256056Sgrehan	aior->slot = slot;
498256056Sgrehan	aior->len = len;
499256056Sgrehan	aior->done = done;
500256056Sgrehan	breq = &aior->io_req;
501256056Sgrehan	breq->br_offset = lba + done;
502256056Sgrehan	iovcnt = hdr->prdtl - seek;
503256056Sgrehan	if (iovcnt > BLOCKIF_IOV_MAX) {
504256056Sgrehan		aior->prdtl = iovcnt - BLOCKIF_IOV_MAX;
505256056Sgrehan		iovcnt = BLOCKIF_IOV_MAX;
506267339Sjhb		/*
507267339Sjhb		 * Mark this command in-flight.
508267339Sjhb		 */
509267339Sjhb		p->pending |= 1 << slot;
510256056Sgrehan	} else
511256056Sgrehan		aior->prdtl = 0;
512256056Sgrehan	breq->br_iovcnt = iovcnt;
513256056Sgrehan
514256056Sgrehan	/*
515256056Sgrehan	 * Build up the iovec based on the prdt
516256056Sgrehan	 */
517256056Sgrehan	for (i = 0; i < iovcnt; i++) {
518259301Sgrehan		uint32_t dbcsz;
519259301Sgrehan
520259301Sgrehan		dbcsz = (prdt->dbc & DBCMASK) + 1;
521256056Sgrehan		breq->br_iov[i].iov_base = paddr_guest2host(ahci_ctx(sc),
522259301Sgrehan		    prdt->dba, dbcsz);
523259301Sgrehan		breq->br_iov[i].iov_len = dbcsz;
524259301Sgrehan		aior->done += dbcsz;
525256056Sgrehan		prdt++;
526256056Sgrehan	}
527256056Sgrehan	if (readop)
528256056Sgrehan		err = blockif_read(p->bctx, breq);
529256056Sgrehan	else
530256056Sgrehan		err = blockif_write(p->bctx, breq);
531256056Sgrehan	assert(err == 0);
532256056Sgrehan
533267339Sjhb	if (ncq)
534256056Sgrehan		p->ci &= ~(1 << slot);
535256056Sgrehan}
536256056Sgrehan
537256056Sgrehanstatic void
538256056Sgrehanahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis)
539256056Sgrehan{
540256056Sgrehan	struct ahci_ioreq *aior;
541256056Sgrehan	struct blockif_req *breq;
542256056Sgrehan	int err;
543256056Sgrehan
544256056Sgrehan	/*
545256056Sgrehan	 * Pull request off free list
546256056Sgrehan	 */
547256056Sgrehan	aior = STAILQ_FIRST(&p->iofhd);
548256056Sgrehan	assert(aior != NULL);
549256056Sgrehan	STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
550256056Sgrehan	aior->cfis = cfis;
551256056Sgrehan	aior->slot = slot;
552256056Sgrehan	aior->len = 0;
553267339Sjhb	aior->done = 0;
554267339Sjhb	aior->prdtl = 0;
555256056Sgrehan	breq = &aior->io_req;
556256056Sgrehan
557256056Sgrehan	err = blockif_flush(p->bctx, breq);
558256056Sgrehan	assert(err == 0);
559256056Sgrehan}
560256056Sgrehan
561256056Sgrehanstatic inline void
562256056Sgrehanwrite_prdt(struct ahci_port *p, int slot, uint8_t *cfis,
563256056Sgrehan		void *buf, int size)
564256056Sgrehan{
565256056Sgrehan	struct ahci_cmd_hdr *hdr;
566256056Sgrehan	struct ahci_prdt_entry *prdt;
567256056Sgrehan	void *from;
568256056Sgrehan	int i, len;
569256056Sgrehan
570256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
571256056Sgrehan	len = size;
572256056Sgrehan	from = buf;
573256056Sgrehan	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
574256056Sgrehan	for (i = 0; i < hdr->prdtl && len; i++) {
575259301Sgrehan		uint8_t *ptr;
576259301Sgrehan		uint32_t dbcsz;
577267339Sjhb		int sublen;
578259301Sgrehan
579259301Sgrehan		dbcsz = (prdt->dbc & DBCMASK) + 1;
580259301Sgrehan		ptr = paddr_guest2host(ahci_ctx(p->pr_sc), prdt->dba, dbcsz);
581267339Sjhb		sublen = len < dbcsz ? len : dbcsz;
582267339Sjhb		memcpy(ptr, from, sublen);
583267339Sjhb		len -= sublen;
584267339Sjhb		from += sublen;
585256056Sgrehan		prdt++;
586256056Sgrehan	}
587256056Sgrehan	hdr->prdbc = size - len;
588256056Sgrehan}
589256056Sgrehan
590256056Sgrehanstatic void
591256056Sgrehanhandle_identify(struct ahci_port *p, int slot, uint8_t *cfis)
592256056Sgrehan{
593256056Sgrehan	struct ahci_cmd_hdr *hdr;
594256056Sgrehan
595256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
596256056Sgrehan	if (p->atapi || hdr->prdtl == 0) {
597256056Sgrehan		p->tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
598256056Sgrehan		p->is |= AHCI_P_IX_TFE;
599256056Sgrehan	} else {
600256056Sgrehan		uint16_t buf[256];
601256056Sgrehan		uint64_t sectors;
602270159Sgrehan		uint16_t cyl;
603270159Sgrehan		uint8_t sech, heads;
604256056Sgrehan
605256056Sgrehan		sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
606270159Sgrehan		blockif_chs(p->bctx, &cyl, &heads, &sech);
607256056Sgrehan		memset(buf, 0, sizeof(buf));
608256056Sgrehan		buf[0] = 0x0040;
609270159Sgrehan		buf[1] = cyl;
610270159Sgrehan		buf[3] = heads;
611270159Sgrehan		buf[6] = sech;
612256056Sgrehan		/* TODO emulate different serial? */
613256056Sgrehan		ata_string((uint8_t *)(buf+10), "123456", 20);
614256056Sgrehan		ata_string((uint8_t *)(buf+23), "001", 8);
615256056Sgrehan		ata_string((uint8_t *)(buf+27), "BHYVE SATA DISK", 40);
616256056Sgrehan		buf[47] = (0x8000 | 128);
617256056Sgrehan		buf[48] = 0x1;
618256056Sgrehan		buf[49] = (1 << 8 | 1 << 9 | 1 << 11);
619256056Sgrehan		buf[50] = (1 << 14);
620256056Sgrehan		buf[53] = (1 << 1 | 1 << 2);
621256056Sgrehan		if (p->mult_sectors)
622256056Sgrehan			buf[59] = (0x100 | p->mult_sectors);
623256056Sgrehan		buf[60] = sectors;
624256056Sgrehan		buf[61] = (sectors >> 16);
625256056Sgrehan		buf[63] = 0x7;
626256056Sgrehan		if (p->xfermode & ATA_WDMA0)
627256056Sgrehan			buf[63] |= (1 << ((p->xfermode & 7) + 8));
628256056Sgrehan		buf[64] = 0x3;
629256056Sgrehan		buf[65] = 100;
630256056Sgrehan		buf[66] = 100;
631256056Sgrehan		buf[67] = 100;
632256056Sgrehan		buf[68] = 100;
633256056Sgrehan		buf[75] = 31;
634256056Sgrehan		buf[76] = (1 << 8 | 1 << 2);
635256056Sgrehan		buf[80] = 0x1f0;
636256056Sgrehan		buf[81] = 0x28;
637256056Sgrehan		buf[82] = (1 << 5 | 1 << 14);
638256056Sgrehan		buf[83] = (1 << 10 | 1 << 12 | 1 << 13 | 1 << 14);
639256056Sgrehan		buf[84] = (1 << 14);
640256056Sgrehan		buf[85] = (1 << 5 | 1 << 14);
641256056Sgrehan		buf[86] = (1 << 10 | 1 << 12 | 1 << 13);
642256056Sgrehan		buf[87] = (1 << 14);
643256056Sgrehan		buf[88] = 0x7f;
644256056Sgrehan		if (p->xfermode & ATA_UDMA0)
645256056Sgrehan			buf[88] |= (1 << ((p->xfermode & 7) + 8));
646256056Sgrehan		buf[93] = (1 | 1 <<14);
647256056Sgrehan		buf[100] = sectors;
648256056Sgrehan		buf[101] = (sectors >> 16);
649256056Sgrehan		buf[102] = (sectors >> 32);
650256056Sgrehan		buf[103] = (sectors >> 48);
651267339Sjhb		ahci_write_fis_piosetup(p);
652256056Sgrehan		write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
653256056Sgrehan		p->tfd = ATA_S_DSC | ATA_S_READY;
654256056Sgrehan		p->is |= AHCI_P_IX_DP;
655270159Sgrehan		p->ci &= ~(1 << slot);
656256056Sgrehan	}
657256056Sgrehan	ahci_generate_intr(p->pr_sc);
658256056Sgrehan}
659256056Sgrehan
660256056Sgrehanstatic void
661256056Sgrehanhandle_atapi_identify(struct ahci_port *p, int slot, uint8_t *cfis)
662256056Sgrehan{
663256056Sgrehan	if (!p->atapi) {
664256056Sgrehan		p->tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
665256056Sgrehan		p->is |= AHCI_P_IX_TFE;
666256056Sgrehan	} else {
667256056Sgrehan		uint16_t buf[256];
668256056Sgrehan
669256056Sgrehan		memset(buf, 0, sizeof(buf));
670256056Sgrehan		buf[0] = (2 << 14 | 5 << 8 | 1 << 7 | 2 << 5);
671256056Sgrehan		/* TODO emulate different serial? */
672256056Sgrehan		ata_string((uint8_t *)(buf+10), "123456", 20);
673256056Sgrehan		ata_string((uint8_t *)(buf+23), "001", 8);
674256056Sgrehan		ata_string((uint8_t *)(buf+27), "BHYVE SATA DVD ROM", 40);
675256056Sgrehan		buf[49] = (1 << 9 | 1 << 8);
676256056Sgrehan		buf[50] = (1 << 14 | 1);
677256056Sgrehan		buf[53] = (1 << 2 | 1 << 1);
678256056Sgrehan		buf[62] = 0x3f;
679256056Sgrehan		buf[63] = 7;
680256056Sgrehan		buf[64] = 3;
681256056Sgrehan		buf[65] = 100;
682256056Sgrehan		buf[66] = 100;
683256056Sgrehan		buf[67] = 100;
684256056Sgrehan		buf[68] = 100;
685256056Sgrehan		buf[76] = (1 << 2 | 1 << 1);
686256056Sgrehan		buf[78] = (1 << 5);
687256056Sgrehan		buf[80] = (0x1f << 4);
688256056Sgrehan		buf[82] = (1 << 4);
689256056Sgrehan		buf[83] = (1 << 14);
690256056Sgrehan		buf[84] = (1 << 14);
691256056Sgrehan		buf[85] = (1 << 4);
692256056Sgrehan		buf[87] = (1 << 14);
693256056Sgrehan		buf[88] = (1 << 14 | 0x7f);
694267339Sjhb		ahci_write_fis_piosetup(p);
695256056Sgrehan		write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
696256056Sgrehan		p->tfd = ATA_S_DSC | ATA_S_READY;
697256056Sgrehan		p->is |= AHCI_P_IX_DHR;
698270159Sgrehan		p->ci &= ~(1 << slot);
699256056Sgrehan	}
700256056Sgrehan	ahci_generate_intr(p->pr_sc);
701256056Sgrehan}
702256056Sgrehan
703256056Sgrehanstatic void
704256056Sgrehanatapi_inquiry(struct ahci_port *p, int slot, uint8_t *cfis)
705256056Sgrehan{
706256056Sgrehan	uint8_t buf[36];
707256056Sgrehan	uint8_t *acmd;
708256056Sgrehan	int len;
709256056Sgrehan
710256056Sgrehan	acmd = cfis + 0x40;
711256056Sgrehan
712256056Sgrehan	buf[0] = 0x05;
713256056Sgrehan	buf[1] = 0x80;
714256056Sgrehan	buf[2] = 0x00;
715256056Sgrehan	buf[3] = 0x21;
716256056Sgrehan	buf[4] = 31;
717256056Sgrehan	buf[5] = 0;
718256056Sgrehan	buf[6] = 0;
719256056Sgrehan	buf[7] = 0;
720256056Sgrehan	atapi_string(buf + 8, "BHYVE", 8);
721256056Sgrehan	atapi_string(buf + 16, "BHYVE DVD-ROM", 16);
722256056Sgrehan	atapi_string(buf + 32, "001", 4);
723256056Sgrehan
724256056Sgrehan	len = sizeof(buf);
725256056Sgrehan	if (len > acmd[4])
726256056Sgrehan		len = acmd[4];
727256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
728256056Sgrehan	write_prdt(p, slot, cfis, buf, len);
729256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
730256056Sgrehan}
731256056Sgrehan
732256056Sgrehanstatic void
733256056Sgrehanatapi_read_capacity(struct ahci_port *p, int slot, uint8_t *cfis)
734256056Sgrehan{
735256056Sgrehan	uint8_t buf[8];
736256056Sgrehan	uint64_t sectors;
737256056Sgrehan
738257128Sgrehan	sectors = blockif_size(p->bctx) / 2048;
739256056Sgrehan	be32enc(buf, sectors - 1);
740256056Sgrehan	be32enc(buf + 4, 2048);
741256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
742256056Sgrehan	write_prdt(p, slot, cfis, buf, sizeof(buf));
743256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
744256056Sgrehan}
745256056Sgrehan
746256056Sgrehanstatic void
747256056Sgrehanatapi_read_toc(struct ahci_port *p, int slot, uint8_t *cfis)
748256056Sgrehan{
749256056Sgrehan	uint8_t *acmd;
750256056Sgrehan	uint8_t format;
751256056Sgrehan	int len;
752256056Sgrehan
753256056Sgrehan	acmd = cfis + 0x40;
754256056Sgrehan
755256056Sgrehan	len = be16dec(acmd + 7);
756256056Sgrehan	format = acmd[9] >> 6;
757256056Sgrehan	switch (format) {
758256056Sgrehan	case 0:
759256056Sgrehan	{
760256056Sgrehan		int msf, size;
761256056Sgrehan		uint64_t sectors;
762256056Sgrehan		uint8_t start_track, buf[20], *bp;
763256056Sgrehan
764256056Sgrehan		msf = (acmd[1] >> 1) & 1;
765256056Sgrehan		start_track = acmd[6];
766256056Sgrehan		if (start_track > 1 && start_track != 0xaa) {
767256056Sgrehan			uint32_t tfd;
768256056Sgrehan			p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
769256056Sgrehan			p->asc = 0x24;
770256056Sgrehan			tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
771256056Sgrehan			cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
772256056Sgrehan			ahci_write_fis_d2h(p, slot, cfis, tfd);
773256056Sgrehan			return;
774256056Sgrehan		}
775256056Sgrehan		bp = buf + 2;
776256056Sgrehan		*bp++ = 1;
777256056Sgrehan		*bp++ = 1;
778256056Sgrehan		if (start_track <= 1) {
779256056Sgrehan			*bp++ = 0;
780256056Sgrehan			*bp++ = 0x14;
781256056Sgrehan			*bp++ = 1;
782256056Sgrehan			*bp++ = 0;
783256056Sgrehan			if (msf) {
784256056Sgrehan				*bp++ = 0;
785256056Sgrehan				lba_to_msf(bp, 0);
786256056Sgrehan				bp += 3;
787256056Sgrehan			} else {
788256056Sgrehan				*bp++ = 0;
789256056Sgrehan				*bp++ = 0;
790256056Sgrehan				*bp++ = 0;
791256056Sgrehan				*bp++ = 0;
792256056Sgrehan			}
793256056Sgrehan		}
794256056Sgrehan		*bp++ = 0;
795256056Sgrehan		*bp++ = 0x14;
796256056Sgrehan		*bp++ = 0xaa;
797256056Sgrehan		*bp++ = 0;
798256056Sgrehan		sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
799256056Sgrehan		sectors >>= 2;
800256056Sgrehan		if (msf) {
801256056Sgrehan			*bp++ = 0;
802256056Sgrehan			lba_to_msf(bp, sectors);
803256056Sgrehan			bp += 3;
804256056Sgrehan		} else {
805256056Sgrehan			be32enc(bp, sectors);
806256056Sgrehan			bp += 4;
807256056Sgrehan		}
808256056Sgrehan		size = bp - buf;
809256056Sgrehan		be16enc(buf, size - 2);
810256056Sgrehan		if (len > size)
811256056Sgrehan			len = size;
812256056Sgrehan		write_prdt(p, slot, cfis, buf, len);
813256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
814256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
815256056Sgrehan		break;
816256056Sgrehan	}
817256056Sgrehan	case 1:
818256056Sgrehan	{
819256056Sgrehan		uint8_t buf[12];
820256056Sgrehan
821256056Sgrehan		memset(buf, 0, sizeof(buf));
822256056Sgrehan		buf[1] = 0xa;
823256056Sgrehan		buf[2] = 0x1;
824256056Sgrehan		buf[3] = 0x1;
825256056Sgrehan		if (len > sizeof(buf))
826256056Sgrehan			len = sizeof(buf);
827256056Sgrehan		write_prdt(p, slot, cfis, buf, len);
828256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
829256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
830256056Sgrehan		break;
831256056Sgrehan	}
832256056Sgrehan	case 2:
833256056Sgrehan	{
834256056Sgrehan		int msf, size;
835256056Sgrehan		uint64_t sectors;
836256056Sgrehan		uint8_t start_track, *bp, buf[50];
837256056Sgrehan
838256056Sgrehan		msf = (acmd[1] >> 1) & 1;
839256056Sgrehan		start_track = acmd[6];
840256056Sgrehan		bp = buf + 2;
841256056Sgrehan		*bp++ = 1;
842256056Sgrehan		*bp++ = 1;
843256056Sgrehan
844256056Sgrehan		*bp++ = 1;
845256056Sgrehan		*bp++ = 0x14;
846256056Sgrehan		*bp++ = 0;
847256056Sgrehan		*bp++ = 0xa0;
848256056Sgrehan		*bp++ = 0;
849256056Sgrehan		*bp++ = 0;
850256056Sgrehan		*bp++ = 0;
851256056Sgrehan		*bp++ = 0;
852256056Sgrehan		*bp++ = 1;
853256056Sgrehan		*bp++ = 0;
854256056Sgrehan		*bp++ = 0;
855256056Sgrehan
856256056Sgrehan		*bp++ = 1;
857256056Sgrehan		*bp++ = 0x14;
858256056Sgrehan		*bp++ = 0;
859256056Sgrehan		*bp++ = 0xa1;
860256056Sgrehan		*bp++ = 0;
861256056Sgrehan		*bp++ = 0;
862256056Sgrehan		*bp++ = 0;
863256056Sgrehan		*bp++ = 0;
864256056Sgrehan		*bp++ = 1;
865256056Sgrehan		*bp++ = 0;
866256056Sgrehan		*bp++ = 0;
867256056Sgrehan
868256056Sgrehan		*bp++ = 1;
869256056Sgrehan		*bp++ = 0x14;
870256056Sgrehan		*bp++ = 0;
871256056Sgrehan		*bp++ = 0xa2;
872256056Sgrehan		*bp++ = 0;
873256056Sgrehan		*bp++ = 0;
874256056Sgrehan		*bp++ = 0;
875256056Sgrehan		sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
876256056Sgrehan		sectors >>= 2;
877256056Sgrehan		if (msf) {
878256056Sgrehan			*bp++ = 0;
879256056Sgrehan			lba_to_msf(bp, sectors);
880256056Sgrehan			bp += 3;
881256056Sgrehan		} else {
882256056Sgrehan			be32enc(bp, sectors);
883256056Sgrehan			bp += 4;
884256056Sgrehan		}
885256056Sgrehan
886256056Sgrehan		*bp++ = 1;
887256056Sgrehan		*bp++ = 0x14;
888256056Sgrehan		*bp++ = 0;
889256056Sgrehan		*bp++ = 1;
890256056Sgrehan		*bp++ = 0;
891256056Sgrehan		*bp++ = 0;
892256056Sgrehan		*bp++ = 0;
893256056Sgrehan		if (msf) {
894256056Sgrehan			*bp++ = 0;
895256056Sgrehan			lba_to_msf(bp, 0);
896256056Sgrehan			bp += 3;
897256056Sgrehan		} else {
898256056Sgrehan			*bp++ = 0;
899256056Sgrehan			*bp++ = 0;
900256056Sgrehan			*bp++ = 0;
901256056Sgrehan			*bp++ = 0;
902256056Sgrehan		}
903256056Sgrehan
904256056Sgrehan		size = bp - buf;
905256056Sgrehan		be16enc(buf, size - 2);
906256056Sgrehan		if (len > size)
907256056Sgrehan			len = size;
908256056Sgrehan		write_prdt(p, slot, cfis, buf, len);
909256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
910256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
911256056Sgrehan		break;
912256056Sgrehan	}
913256056Sgrehan	default:
914256056Sgrehan	{
915256056Sgrehan		uint32_t tfd;
916256056Sgrehan
917256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
918256056Sgrehan		p->asc = 0x24;
919256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
920256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
921256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, tfd);
922256056Sgrehan		break;
923256056Sgrehan	}
924256056Sgrehan	}
925256056Sgrehan}
926256056Sgrehan
927256056Sgrehanstatic void
928256056Sgrehanatapi_read(struct ahci_port *p, int slot, uint8_t *cfis,
929256056Sgrehan		uint32_t done, int seek)
930256056Sgrehan{
931256056Sgrehan	struct ahci_ioreq *aior;
932256056Sgrehan	struct ahci_cmd_hdr *hdr;
933256056Sgrehan	struct ahci_prdt_entry *prdt;
934256056Sgrehan	struct blockif_req *breq;
935256056Sgrehan	struct pci_ahci_softc *sc;
936256056Sgrehan	uint8_t *acmd;
937256056Sgrehan	uint64_t lba;
938256056Sgrehan	uint32_t len;
939256056Sgrehan	int i, err, iovcnt;
940256056Sgrehan
941256056Sgrehan	sc = p->pr_sc;
942256056Sgrehan	acmd = cfis + 0x40;
943256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
944256056Sgrehan	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
945256056Sgrehan
946256056Sgrehan	prdt += seek;
947256056Sgrehan	lba = be32dec(acmd + 2);
948256056Sgrehan	if (acmd[0] == READ_10)
949256056Sgrehan		len = be16dec(acmd + 7);
950256056Sgrehan	else
951256056Sgrehan		len = be32dec(acmd + 6);
952256056Sgrehan	if (len == 0) {
953256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
954256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
955256056Sgrehan	}
956256056Sgrehan	lba *= 2048;
957256056Sgrehan	len *= 2048;
958256056Sgrehan
959256056Sgrehan	/*
960256056Sgrehan	 * Pull request off free list
961256056Sgrehan	 */
962256056Sgrehan	aior = STAILQ_FIRST(&p->iofhd);
963256056Sgrehan	assert(aior != NULL);
964256056Sgrehan	STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
965256056Sgrehan	aior->cfis = cfis;
966256056Sgrehan	aior->slot = slot;
967256056Sgrehan	aior->len = len;
968256056Sgrehan	aior->done = done;
969256056Sgrehan	breq = &aior->io_req;
970256056Sgrehan	breq->br_offset = lba + done;
971256056Sgrehan	iovcnt = hdr->prdtl - seek;
972256056Sgrehan	if (iovcnt > BLOCKIF_IOV_MAX) {
973256056Sgrehan		aior->prdtl = iovcnt - BLOCKIF_IOV_MAX;
974256056Sgrehan		iovcnt = BLOCKIF_IOV_MAX;
975256056Sgrehan	} else
976256056Sgrehan		aior->prdtl = 0;
977256056Sgrehan	breq->br_iovcnt = iovcnt;
978256056Sgrehan
979256056Sgrehan	/*
980256056Sgrehan	 * Build up the iovec based on the prdt
981256056Sgrehan	 */
982257128Sgrehan	for (i = 0; i < iovcnt; i++) {
983259301Sgrehan		uint32_t dbcsz;
984259301Sgrehan
985259301Sgrehan		dbcsz = (prdt->dbc & DBCMASK) + 1;
986256056Sgrehan		breq->br_iov[i].iov_base = paddr_guest2host(ahci_ctx(sc),
987259301Sgrehan		    prdt->dba, dbcsz);
988259301Sgrehan		breq->br_iov[i].iov_len = dbcsz;
989259301Sgrehan		aior->done += dbcsz;
990256056Sgrehan		prdt++;
991256056Sgrehan	}
992256056Sgrehan	err = blockif_read(p->bctx, breq);
993256056Sgrehan	assert(err == 0);
994256056Sgrehan}
995256056Sgrehan
996256056Sgrehanstatic void
997256056Sgrehanatapi_request_sense(struct ahci_port *p, int slot, uint8_t *cfis)
998256056Sgrehan{
999256056Sgrehan	uint8_t buf[64];
1000256056Sgrehan	uint8_t *acmd;
1001256056Sgrehan	int len;
1002256056Sgrehan
1003256056Sgrehan	acmd = cfis + 0x40;
1004256056Sgrehan	len = acmd[4];
1005256056Sgrehan	if (len > sizeof(buf))
1006256056Sgrehan		len = sizeof(buf);
1007256056Sgrehan	memset(buf, 0, len);
1008256056Sgrehan	buf[0] = 0x70 | (1 << 7);
1009256056Sgrehan	buf[2] = p->sense_key;
1010256056Sgrehan	buf[7] = 10;
1011256056Sgrehan	buf[12] = p->asc;
1012256056Sgrehan	write_prdt(p, slot, cfis, buf, len);
1013256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1014256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1015256056Sgrehan}
1016256056Sgrehan
1017256056Sgrehanstatic void
1018256056Sgrehanatapi_start_stop_unit(struct ahci_port *p, int slot, uint8_t *cfis)
1019256056Sgrehan{
1020256056Sgrehan	uint8_t *acmd = cfis + 0x40;
1021256056Sgrehan	uint32_t tfd;
1022256056Sgrehan
1023256056Sgrehan	switch (acmd[4] & 3) {
1024256056Sgrehan	case 0:
1025256056Sgrehan	case 1:
1026256056Sgrehan	case 3:
1027256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1028256056Sgrehan		tfd = ATA_S_READY | ATA_S_DSC;
1029256056Sgrehan		break;
1030256056Sgrehan	case 2:
1031256056Sgrehan		/* TODO eject media */
1032256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1033256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1034256056Sgrehan		p->asc = 0x53;
1035256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1036256056Sgrehan		break;
1037256056Sgrehan	}
1038256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, tfd);
1039256056Sgrehan}
1040256056Sgrehan
1041256056Sgrehanstatic void
1042256056Sgrehanatapi_mode_sense(struct ahci_port *p, int slot, uint8_t *cfis)
1043256056Sgrehan{
1044256056Sgrehan	uint8_t *acmd;
1045256056Sgrehan	uint32_t tfd;
1046256056Sgrehan	uint8_t pc, code;
1047256056Sgrehan	int len;
1048256056Sgrehan
1049256056Sgrehan	acmd = cfis + 0x40;
1050256056Sgrehan	len = be16dec(acmd + 7);
1051256056Sgrehan	pc = acmd[2] >> 6;
1052256056Sgrehan	code = acmd[2] & 0x3f;
1053256056Sgrehan
1054256056Sgrehan	switch (pc) {
1055256056Sgrehan	case 0:
1056256056Sgrehan		switch (code) {
1057256056Sgrehan		case MODEPAGE_RW_ERROR_RECOVERY:
1058256056Sgrehan		{
1059256056Sgrehan			uint8_t buf[16];
1060256056Sgrehan
1061256056Sgrehan			if (len > sizeof(buf))
1062256056Sgrehan				len = sizeof(buf);
1063256056Sgrehan
1064256056Sgrehan			memset(buf, 0, sizeof(buf));
1065256056Sgrehan			be16enc(buf, 16 - 2);
1066256056Sgrehan			buf[2] = 0x70;
1067256056Sgrehan			buf[8] = 0x01;
1068256056Sgrehan			buf[9] = 16 - 10;
1069256056Sgrehan			buf[11] = 0x05;
1070256056Sgrehan			write_prdt(p, slot, cfis, buf, len);
1071256056Sgrehan			tfd = ATA_S_READY | ATA_S_DSC;
1072256056Sgrehan			break;
1073256056Sgrehan		}
1074256056Sgrehan		case MODEPAGE_CD_CAPABILITIES:
1075256056Sgrehan		{
1076256056Sgrehan			uint8_t buf[30];
1077256056Sgrehan
1078256056Sgrehan			if (len > sizeof(buf))
1079256056Sgrehan				len = sizeof(buf);
1080256056Sgrehan
1081256056Sgrehan			memset(buf, 0, sizeof(buf));
1082256056Sgrehan			be16enc(buf, 30 - 2);
1083256056Sgrehan			buf[2] = 0x70;
1084256056Sgrehan			buf[8] = 0x2A;
1085256056Sgrehan			buf[9] = 30 - 10;
1086256056Sgrehan			buf[10] = 0x08;
1087256056Sgrehan			buf[12] = 0x71;
1088256056Sgrehan			be16enc(&buf[18], 2);
1089256056Sgrehan			be16enc(&buf[20], 512);
1090256056Sgrehan			write_prdt(p, slot, cfis, buf, len);
1091256056Sgrehan			tfd = ATA_S_READY | ATA_S_DSC;
1092256056Sgrehan			break;
1093256056Sgrehan		}
1094256056Sgrehan		default:
1095256056Sgrehan			goto error;
1096256056Sgrehan			break;
1097256056Sgrehan		}
1098256056Sgrehan		break;
1099256056Sgrehan	case 3:
1100256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1101256056Sgrehan		p->asc = 0x39;
1102256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1103256056Sgrehan		break;
1104256056Sgrehanerror:
1105256056Sgrehan	case 1:
1106256056Sgrehan	case 2:
1107256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1108256056Sgrehan		p->asc = 0x24;
1109256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1110256056Sgrehan		break;
1111256056Sgrehan	}
1112256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1113256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, tfd);
1114256056Sgrehan}
1115256056Sgrehan
1116256056Sgrehanstatic void
1117256056Sgrehanatapi_get_event_status_notification(struct ahci_port *p, int slot,
1118256056Sgrehan    uint8_t *cfis)
1119256056Sgrehan{
1120256056Sgrehan	uint8_t *acmd;
1121256056Sgrehan	uint32_t tfd;
1122256056Sgrehan
1123256056Sgrehan	acmd = cfis + 0x40;
1124256056Sgrehan
1125256056Sgrehan	/* we don't support asynchronous operation */
1126256056Sgrehan	if (!(acmd[1] & 1)) {
1127256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1128256056Sgrehan		p->asc = 0x24;
1129256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1130256056Sgrehan	} else {
1131256056Sgrehan		uint8_t buf[8];
1132256056Sgrehan		int len;
1133256056Sgrehan
1134256056Sgrehan		len = be16dec(acmd + 7);
1135256056Sgrehan		if (len > sizeof(buf))
1136256056Sgrehan			len = sizeof(buf);
1137256056Sgrehan
1138256056Sgrehan		memset(buf, 0, sizeof(buf));
1139256056Sgrehan		be16enc(buf, 8 - 2);
1140256056Sgrehan		buf[2] = 0x04;
1141256056Sgrehan		buf[3] = 0x10;
1142256056Sgrehan		buf[5] = 0x02;
1143256056Sgrehan		write_prdt(p, slot, cfis, buf, len);
1144256056Sgrehan		tfd = ATA_S_READY | ATA_S_DSC;
1145256056Sgrehan	}
1146256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1147256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, tfd);
1148256056Sgrehan}
1149256056Sgrehan
1150256056Sgrehanstatic void
1151256056Sgrehanhandle_packet_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
1152256056Sgrehan{
1153256056Sgrehan	uint8_t *acmd;
1154256056Sgrehan
1155256056Sgrehan	acmd = cfis + 0x40;
1156256056Sgrehan
1157256056Sgrehan#ifdef AHCI_DEBUG
1158256056Sgrehan	{
1159256056Sgrehan		int i;
1160256056Sgrehan		DPRINTF("ACMD:");
1161256056Sgrehan		for (i = 0; i < 16; i++)
1162256056Sgrehan			DPRINTF("%02x ", acmd[i]);
1163256056Sgrehan		DPRINTF("\n");
1164256056Sgrehan	}
1165256056Sgrehan#endif
1166256056Sgrehan
1167256056Sgrehan	switch (acmd[0]) {
1168256056Sgrehan	case TEST_UNIT_READY:
1169256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1170256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1171256056Sgrehan		break;
1172256056Sgrehan	case INQUIRY:
1173256056Sgrehan		atapi_inquiry(p, slot, cfis);
1174256056Sgrehan		break;
1175256056Sgrehan	case READ_CAPACITY:
1176256056Sgrehan		atapi_read_capacity(p, slot, cfis);
1177256056Sgrehan		break;
1178256056Sgrehan	case PREVENT_ALLOW:
1179256056Sgrehan		/* TODO */
1180256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1181256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1182256056Sgrehan		break;
1183256056Sgrehan	case READ_TOC:
1184256056Sgrehan		atapi_read_toc(p, slot, cfis);
1185256056Sgrehan		break;
1186256056Sgrehan	case READ_10:
1187256056Sgrehan	case READ_12:
1188256056Sgrehan		atapi_read(p, slot, cfis, 0, 0);
1189256056Sgrehan		break;
1190256056Sgrehan	case REQUEST_SENSE:
1191256056Sgrehan		atapi_request_sense(p, slot, cfis);
1192256056Sgrehan		break;
1193256056Sgrehan	case START_STOP_UNIT:
1194256056Sgrehan		atapi_start_stop_unit(p, slot, cfis);
1195256056Sgrehan		break;
1196256056Sgrehan	case MODE_SENSE_10:
1197256056Sgrehan		atapi_mode_sense(p, slot, cfis);
1198256056Sgrehan		break;
1199256056Sgrehan	case GET_EVENT_STATUS_NOTIFICATION:
1200256056Sgrehan		atapi_get_event_status_notification(p, slot, cfis);
1201256056Sgrehan		break;
1202256056Sgrehan	default:
1203256056Sgrehan		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1204256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1205256056Sgrehan		p->asc = 0x20;
1206256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, (p->sense_key << 12) |
1207256056Sgrehan				ATA_S_READY | ATA_S_ERROR);
1208256056Sgrehan		break;
1209256056Sgrehan	}
1210256056Sgrehan}
1211256056Sgrehan
1212256056Sgrehanstatic void
1213256056Sgrehanahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
1214256056Sgrehan{
1215256056Sgrehan
1216256056Sgrehan	switch (cfis[2]) {
1217256056Sgrehan	case ATA_ATA_IDENTIFY:
1218256056Sgrehan		handle_identify(p, slot, cfis);
1219256056Sgrehan		break;
1220256056Sgrehan	case ATA_SETFEATURES:
1221256056Sgrehan	{
1222256056Sgrehan		switch (cfis[3]) {
1223267339Sjhb		case ATA_SF_ENAB_SATA_SF:
1224267339Sjhb			switch (cfis[12]) {
1225267339Sjhb			case ATA_SATA_SF_AN:
1226267339Sjhb				p->tfd = ATA_S_DSC | ATA_S_READY;
1227267339Sjhb				break;
1228267339Sjhb			default:
1229267339Sjhb				p->tfd = ATA_S_ERROR | ATA_S_READY;
1230267339Sjhb				p->tfd |= (ATA_ERROR_ABORT << 8);
1231267339Sjhb				break;
1232267339Sjhb			}
1233267339Sjhb			break;
1234256056Sgrehan		case ATA_SF_ENAB_WCACHE:
1235256056Sgrehan		case ATA_SF_DIS_WCACHE:
1236256056Sgrehan		case ATA_SF_ENAB_RCACHE:
1237256056Sgrehan		case ATA_SF_DIS_RCACHE:
1238256056Sgrehan			p->tfd = ATA_S_DSC | ATA_S_READY;
1239256056Sgrehan			break;
1240256056Sgrehan		case ATA_SF_SETXFER:
1241256056Sgrehan		{
1242256056Sgrehan			switch (cfis[12] & 0xf8) {
1243256056Sgrehan			case ATA_PIO:
1244256056Sgrehan			case ATA_PIO0:
1245256056Sgrehan				break;
1246256056Sgrehan			case ATA_WDMA0:
1247256056Sgrehan			case ATA_UDMA0:
1248256056Sgrehan				p->xfermode = (cfis[12] & 0x7);
1249256056Sgrehan				break;
1250256056Sgrehan			}
1251256056Sgrehan			p->tfd = ATA_S_DSC | ATA_S_READY;
1252256056Sgrehan			break;
1253256056Sgrehan		}
1254256056Sgrehan		default:
1255256056Sgrehan			p->tfd = ATA_S_ERROR | ATA_S_READY;
1256256056Sgrehan			p->tfd |= (ATA_ERROR_ABORT << 8);
1257256056Sgrehan			break;
1258256056Sgrehan		}
1259267339Sjhb		ahci_write_fis_d2h(p, slot, cfis, p->tfd);
1260256056Sgrehan		break;
1261256056Sgrehan	}
1262256056Sgrehan	case ATA_SET_MULTI:
1263256056Sgrehan		if (cfis[12] != 0 &&
1264256164Sdim			(cfis[12] > 128 || (cfis[12] & (cfis[12] - 1)))) {
1265256056Sgrehan			p->tfd = ATA_S_ERROR | ATA_S_READY;
1266256056Sgrehan			p->tfd |= (ATA_ERROR_ABORT << 8);
1267256056Sgrehan		} else {
1268256056Sgrehan			p->mult_sectors = cfis[12];
1269256056Sgrehan			p->tfd = ATA_S_DSC | ATA_S_READY;
1270256056Sgrehan		}
1271256056Sgrehan		p->is |= AHCI_P_IX_DP;
1272256056Sgrehan		p->ci &= ~(1 << slot);
1273256056Sgrehan		ahci_generate_intr(p->pr_sc);
1274256056Sgrehan		break;
1275256056Sgrehan	case ATA_READ_DMA:
1276256056Sgrehan	case ATA_WRITE_DMA:
1277256056Sgrehan	case ATA_READ_DMA48:
1278256056Sgrehan	case ATA_WRITE_DMA48:
1279256056Sgrehan	case ATA_READ_FPDMA_QUEUED:
1280256056Sgrehan	case ATA_WRITE_FPDMA_QUEUED:
1281256056Sgrehan		ahci_handle_dma(p, slot, cfis, 0, 0);
1282256056Sgrehan		break;
1283256056Sgrehan	case ATA_FLUSHCACHE:
1284256056Sgrehan	case ATA_FLUSHCACHE48:
1285256056Sgrehan		ahci_handle_flush(p, slot, cfis);
1286256056Sgrehan		break;
1287256056Sgrehan	case ATA_STANDBY_CMD:
1288256056Sgrehan		break;
1289256056Sgrehan	case ATA_NOP:
1290256056Sgrehan	case ATA_STANDBY_IMMEDIATE:
1291256056Sgrehan	case ATA_IDLE_IMMEDIATE:
1292256056Sgrehan	case ATA_SLEEP:
1293256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1294256056Sgrehan		break;
1295256056Sgrehan	case ATA_ATAPI_IDENTIFY:
1296256056Sgrehan		handle_atapi_identify(p, slot, cfis);
1297256056Sgrehan		break;
1298256056Sgrehan	case ATA_PACKET_CMD:
1299256056Sgrehan		if (!p->atapi) {
1300256056Sgrehan			p->tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
1301256056Sgrehan			p->is |= AHCI_P_IX_TFE;
1302256056Sgrehan			ahci_generate_intr(p->pr_sc);
1303256056Sgrehan		} else
1304256056Sgrehan			handle_packet_cmd(p, slot, cfis);
1305256056Sgrehan		break;
1306256056Sgrehan	default:
1307256056Sgrehan		WPRINTF("Unsupported cmd:%02x\n", cfis[2]);
1308256056Sgrehan		p->tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
1309256056Sgrehan		p->is |= AHCI_P_IX_TFE;
1310256056Sgrehan		ahci_generate_intr(p->pr_sc);
1311256056Sgrehan		break;
1312256056Sgrehan	}
1313256056Sgrehan}
1314256056Sgrehan
1315256056Sgrehanstatic void
1316256056Sgrehanahci_handle_slot(struct ahci_port *p, int slot)
1317256056Sgrehan{
1318256056Sgrehan	struct ahci_cmd_hdr *hdr;
1319256056Sgrehan	struct ahci_prdt_entry *prdt;
1320256056Sgrehan	struct pci_ahci_softc *sc;
1321256056Sgrehan	uint8_t *cfis;
1322256056Sgrehan	int cfl;
1323256056Sgrehan
1324256056Sgrehan	sc = p->pr_sc;
1325256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
1326256056Sgrehan	cfl = (hdr->flags & 0x1f) * 4;
1327256056Sgrehan	cfis = paddr_guest2host(ahci_ctx(sc), hdr->ctba,
1328256056Sgrehan			0x80 + hdr->prdtl * sizeof(struct ahci_prdt_entry));
1329256056Sgrehan	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
1330256056Sgrehan
1331256056Sgrehan#ifdef AHCI_DEBUG
1332256056Sgrehan	DPRINTF("\ncfis:");
1333256056Sgrehan	for (i = 0; i < cfl; i++) {
1334256056Sgrehan		if (i % 10 == 0)
1335256056Sgrehan			DPRINTF("\n");
1336256056Sgrehan		DPRINTF("%02x ", cfis[i]);
1337256056Sgrehan	}
1338256056Sgrehan	DPRINTF("\n");
1339256056Sgrehan
1340256056Sgrehan	for (i = 0; i < hdr->prdtl; i++) {
1341256056Sgrehan		DPRINTF("%d@%08"PRIx64"\n", prdt->dbc & 0x3fffff, prdt->dba);
1342256056Sgrehan		prdt++;
1343256056Sgrehan	}
1344256056Sgrehan#endif
1345256056Sgrehan
1346256056Sgrehan	if (cfis[0] != FIS_TYPE_REGH2D) {
1347256056Sgrehan		WPRINTF("Not a H2D FIS:%02x\n", cfis[0]);
1348256056Sgrehan		return;
1349256056Sgrehan	}
1350256056Sgrehan
1351256056Sgrehan	if (cfis[1] & 0x80) {
1352256056Sgrehan		ahci_handle_cmd(p, slot, cfis);
1353256056Sgrehan	} else {
1354256056Sgrehan		if (cfis[15] & (1 << 2))
1355256056Sgrehan			p->reset = 1;
1356256056Sgrehan		else if (p->reset) {
1357256056Sgrehan			p->reset = 0;
1358256056Sgrehan			ahci_port_reset(p);
1359256056Sgrehan		}
1360256056Sgrehan		p->ci &= ~(1 << slot);
1361256056Sgrehan	}
1362256056Sgrehan}
1363256056Sgrehan
1364256056Sgrehanstatic void
1365256056Sgrehanahci_handle_port(struct ahci_port *p)
1366256056Sgrehan{
1367256056Sgrehan	int i;
1368256056Sgrehan
1369256056Sgrehan	if (!(p->cmd & AHCI_P_CMD_ST))
1370256056Sgrehan		return;
1371256056Sgrehan
1372267339Sjhb	/*
1373267339Sjhb	 * Search for any new commands to issue ignoring those that
1374267339Sjhb	 * are already in-flight.
1375267339Sjhb	 */
1376256056Sgrehan	for (i = 0; (i < 32) && p->ci; i++) {
1377270159Sgrehan		if ((p->ci & (1 << i)) && !(p->pending & (1 << i))) {
1378270159Sgrehan			p->cmd &= ~AHCI_P_CMD_CCS_MASK;
1379270159Sgrehan			p->cmd |= i << AHCI_P_CMD_CCS_SHIFT;
1380256056Sgrehan			ahci_handle_slot(p, i);
1381270159Sgrehan		}
1382256056Sgrehan	}
1383256056Sgrehan}
1384256056Sgrehan
1385256056Sgrehan/*
1386256056Sgrehan * blockif callback routine - this runs in the context of the blockif
1387256056Sgrehan * i/o thread, so the mutex needs to be acquired.
1388256056Sgrehan */
1389256056Sgrehanstatic void
1390256056Sgrehanata_ioreq_cb(struct blockif_req *br, int err)
1391256056Sgrehan{
1392256056Sgrehan	struct ahci_cmd_hdr *hdr;
1393256056Sgrehan	struct ahci_ioreq *aior;
1394256056Sgrehan	struct ahci_port *p;
1395256056Sgrehan	struct pci_ahci_softc *sc;
1396256056Sgrehan	uint32_t tfd;
1397256056Sgrehan	uint8_t *cfis;
1398256056Sgrehan	int pending, slot, ncq;
1399256056Sgrehan
1400256056Sgrehan	DPRINTF("%s %d\n", __func__, err);
1401256056Sgrehan
1402256056Sgrehan	ncq = 0;
1403256056Sgrehan	aior = br->br_param;
1404256056Sgrehan	p = aior->io_pr;
1405256056Sgrehan	cfis = aior->cfis;
1406256056Sgrehan	slot = aior->slot;
1407256056Sgrehan	pending = aior->prdtl;
1408256056Sgrehan	sc = p->pr_sc;
1409256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
1410256056Sgrehan
1411256056Sgrehan	if (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||
1412256056Sgrehan			cfis[2] == ATA_READ_FPDMA_QUEUED)
1413256056Sgrehan		ncq = 1;
1414256056Sgrehan
1415256056Sgrehan	pthread_mutex_lock(&sc->mtx);
1416256056Sgrehan
1417256056Sgrehan	/*
1418256056Sgrehan	 * Move the blockif request back to the free list
1419256056Sgrehan	 */
1420256056Sgrehan	STAILQ_INSERT_TAIL(&p->iofhd, aior, io_list);
1421256056Sgrehan
1422256056Sgrehan	if (pending && !err) {
1423256056Sgrehan		ahci_handle_dma(p, slot, cfis, aior->done,
1424256056Sgrehan		    hdr->prdtl - pending);
1425256056Sgrehan		goto out;
1426256056Sgrehan	}
1427256056Sgrehan
1428256056Sgrehan	if (!err && aior->done == aior->len) {
1429256056Sgrehan		tfd = ATA_S_READY | ATA_S_DSC;
1430256056Sgrehan		if (ncq)
1431256056Sgrehan			hdr->prdbc = 0;
1432256056Sgrehan		else
1433256056Sgrehan			hdr->prdbc = aior->len;
1434256056Sgrehan	} else {
1435256056Sgrehan		tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
1436256056Sgrehan		hdr->prdbc = 0;
1437256056Sgrehan		if (ncq)
1438256056Sgrehan			p->serr |= (1 << slot);
1439256056Sgrehan	}
1440256056Sgrehan
1441267339Sjhb	/*
1442267339Sjhb	 * This command is now complete.
1443267339Sjhb	 */
1444267339Sjhb	p->pending &= ~(1 << slot);
1445267339Sjhb
1446256056Sgrehan	if (ncq) {
1447256056Sgrehan		p->sact &= ~(1 << slot);
1448256056Sgrehan		ahci_write_fis_sdb(p, slot, tfd);
1449256056Sgrehan	} else
1450256056Sgrehan		ahci_write_fis_d2h(p, slot, cfis, tfd);
1451256056Sgrehan
1452256056Sgrehanout:
1453256056Sgrehan	pthread_mutex_unlock(&sc->mtx);
1454256056Sgrehan	DPRINTF("%s exit\n", __func__);
1455256056Sgrehan}
1456256056Sgrehan
1457256056Sgrehanstatic void
1458256056Sgrehanatapi_ioreq_cb(struct blockif_req *br, int err)
1459256056Sgrehan{
1460256056Sgrehan	struct ahci_cmd_hdr *hdr;
1461256056Sgrehan	struct ahci_ioreq *aior;
1462256056Sgrehan	struct ahci_port *p;
1463256056Sgrehan	struct pci_ahci_softc *sc;
1464256056Sgrehan	uint8_t *cfis;
1465256056Sgrehan	uint32_t tfd;
1466256056Sgrehan	int pending, slot;
1467256056Sgrehan
1468256056Sgrehan	DPRINTF("%s %d\n", __func__, err);
1469256056Sgrehan
1470256056Sgrehan	aior = br->br_param;
1471256056Sgrehan	p = aior->io_pr;
1472256056Sgrehan	cfis = aior->cfis;
1473256056Sgrehan	slot = aior->slot;
1474256056Sgrehan	pending = aior->prdtl;
1475256056Sgrehan	sc = p->pr_sc;
1476256164Sdim	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + aior->slot * AHCI_CL_SIZE);
1477256056Sgrehan
1478256056Sgrehan	pthread_mutex_lock(&sc->mtx);
1479256056Sgrehan
1480256056Sgrehan	/*
1481256056Sgrehan	 * Move the blockif request back to the free list
1482256056Sgrehan	 */
1483256056Sgrehan	STAILQ_INSERT_TAIL(&p->iofhd, aior, io_list);
1484256056Sgrehan
1485256056Sgrehan	if (pending && !err) {
1486256056Sgrehan		atapi_read(p, slot, cfis, aior->done, hdr->prdtl - pending);
1487256056Sgrehan		goto out;
1488256056Sgrehan	}
1489256056Sgrehan
1490256056Sgrehan	if (!err && aior->done == aior->len) {
1491256056Sgrehan		tfd = ATA_S_READY | ATA_S_DSC;
1492256056Sgrehan		hdr->prdbc = aior->len;
1493256056Sgrehan	} else {
1494256056Sgrehan		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1495256056Sgrehan		p->asc = 0x21;
1496256056Sgrehan		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1497256056Sgrehan		hdr->prdbc = 0;
1498256056Sgrehan	}
1499256056Sgrehan
1500256056Sgrehan	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1501256056Sgrehan	ahci_write_fis_d2h(p, slot, cfis, tfd);
1502256056Sgrehan
1503256056Sgrehanout:
1504256056Sgrehan	pthread_mutex_unlock(&sc->mtx);
1505256056Sgrehan	DPRINTF("%s exit\n", __func__);
1506256056Sgrehan}
1507256056Sgrehan
1508256056Sgrehanstatic void
1509256056Sgrehanpci_ahci_ioreq_init(struct ahci_port *pr)
1510256056Sgrehan{
1511256056Sgrehan	struct ahci_ioreq *vr;
1512256056Sgrehan	int i;
1513256056Sgrehan
1514256056Sgrehan	pr->ioqsz = blockif_queuesz(pr->bctx);
1515256056Sgrehan	pr->ioreq = calloc(pr->ioqsz, sizeof(struct ahci_ioreq));
1516256056Sgrehan	STAILQ_INIT(&pr->iofhd);
1517256056Sgrehan
1518256056Sgrehan	/*
1519256056Sgrehan	 * Add all i/o request entries to the free queue
1520256056Sgrehan	 */
1521256056Sgrehan	for (i = 0; i < pr->ioqsz; i++) {
1522256056Sgrehan		vr = &pr->ioreq[i];
1523256056Sgrehan		vr->io_pr = pr;
1524256056Sgrehan		if (!pr->atapi)
1525256056Sgrehan			vr->io_req.br_callback = ata_ioreq_cb;
1526256056Sgrehan		else
1527256056Sgrehan			vr->io_req.br_callback = atapi_ioreq_cb;
1528256056Sgrehan		vr->io_req.br_param = vr;
1529256056Sgrehan		STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_list);
1530256056Sgrehan	}
1531256056Sgrehan}
1532256056Sgrehan
1533256056Sgrehanstatic void
1534256056Sgrehanpci_ahci_port_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)
1535256056Sgrehan{
1536256056Sgrehan	int port = (offset - AHCI_OFFSET) / AHCI_STEP;
1537256056Sgrehan	offset = (offset - AHCI_OFFSET) % AHCI_STEP;
1538256056Sgrehan	struct ahci_port *p = &sc->port[port];
1539256056Sgrehan
1540256056Sgrehan	DPRINTF("pci_ahci_port %d: write offset 0x%"PRIx64" value 0x%"PRIx64"\n",
1541256056Sgrehan		port, offset, value);
1542256056Sgrehan
1543256056Sgrehan	switch (offset) {
1544256056Sgrehan	case AHCI_P_CLB:
1545256056Sgrehan		p->clb = value;
1546256056Sgrehan		break;
1547256056Sgrehan	case AHCI_P_CLBU:
1548256056Sgrehan		p->clbu = value;
1549256056Sgrehan		break;
1550256056Sgrehan	case AHCI_P_FB:
1551256056Sgrehan		p->fb = value;
1552256056Sgrehan		break;
1553256056Sgrehan	case AHCI_P_FBU:
1554256056Sgrehan		p->fbu = value;
1555256056Sgrehan		break;
1556256056Sgrehan	case AHCI_P_IS:
1557256056Sgrehan		p->is &= ~value;
1558256056Sgrehan		break;
1559256056Sgrehan	case AHCI_P_IE:
1560256056Sgrehan		p->ie = value & 0xFDC000FF;
1561256056Sgrehan		ahci_generate_intr(sc);
1562256056Sgrehan		break;
1563256056Sgrehan	case AHCI_P_CMD:
1564256056Sgrehan	{
1565256056Sgrehan		p->cmd = value;
1566256056Sgrehan
1567256056Sgrehan		if (!(value & AHCI_P_CMD_ST)) {
1568256056Sgrehan			p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK);
1569256056Sgrehan			p->ci = 0;
1570256056Sgrehan			p->sact = 0;
1571256056Sgrehan		} else {
1572256056Sgrehan			uint64_t clb;
1573256056Sgrehan
1574256056Sgrehan			p->cmd |= AHCI_P_CMD_CR;
1575256056Sgrehan			clb = (uint64_t)p->clbu << 32 | p->clb;
1576256056Sgrehan			p->cmd_lst = paddr_guest2host(ahci_ctx(sc), clb,
1577256056Sgrehan					AHCI_CL_SIZE * AHCI_MAX_SLOTS);
1578256056Sgrehan		}
1579256056Sgrehan
1580256056Sgrehan		if (value & AHCI_P_CMD_FRE) {
1581256056Sgrehan			uint64_t fb;
1582256056Sgrehan
1583256056Sgrehan			p->cmd |= AHCI_P_CMD_FR;
1584256056Sgrehan			fb = (uint64_t)p->fbu << 32 | p->fb;
1585256056Sgrehan			/* we don't support FBSCP, so rfis size is 256Bytes */
1586256056Sgrehan			p->rfis = paddr_guest2host(ahci_ctx(sc), fb, 256);
1587256056Sgrehan		} else {
1588256056Sgrehan			p->cmd &= ~AHCI_P_CMD_FR;
1589256056Sgrehan		}
1590256056Sgrehan
1591256056Sgrehan		if (value & AHCI_P_CMD_CLO) {
1592256056Sgrehan			p->tfd = 0;
1593256056Sgrehan			p->cmd &= ~AHCI_P_CMD_CLO;
1594256056Sgrehan		}
1595256056Sgrehan
1596256056Sgrehan		ahci_handle_port(p);
1597256056Sgrehan		break;
1598256056Sgrehan	}
1599256056Sgrehan	case AHCI_P_TFD:
1600256056Sgrehan	case AHCI_P_SIG:
1601256056Sgrehan	case AHCI_P_SSTS:
1602256056Sgrehan		WPRINTF("pci_ahci_port: read only registers 0x%"PRIx64"\n", offset);
1603256056Sgrehan		break;
1604256056Sgrehan	case AHCI_P_SCTL:
1605256056Sgrehan		if (!(p->cmd & AHCI_P_CMD_ST)) {
1606256056Sgrehan			if (value & ATA_SC_DET_RESET)
1607256056Sgrehan				ahci_port_reset(p);
1608256056Sgrehan			p->sctl = value;
1609256056Sgrehan		}
1610256056Sgrehan		break;
1611256056Sgrehan	case AHCI_P_SERR:
1612256056Sgrehan		p->serr &= ~value;
1613256056Sgrehan		break;
1614256056Sgrehan	case AHCI_P_SACT:
1615256056Sgrehan		p->sact |= value;
1616256056Sgrehan		break;
1617256056Sgrehan	case AHCI_P_CI:
1618256056Sgrehan		p->ci |= value;
1619256056Sgrehan		ahci_handle_port(p);
1620256056Sgrehan		break;
1621256056Sgrehan	case AHCI_P_SNTF:
1622256056Sgrehan	case AHCI_P_FBS:
1623256056Sgrehan	default:
1624256056Sgrehan		break;
1625256056Sgrehan	}
1626256056Sgrehan}
1627256056Sgrehan
1628256056Sgrehanstatic void
1629256056Sgrehanpci_ahci_host_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)
1630256056Sgrehan{
1631256056Sgrehan	DPRINTF("pci_ahci_host: write offset 0x%"PRIx64" value 0x%"PRIx64"\n",
1632256056Sgrehan		offset, value);
1633256056Sgrehan
1634256056Sgrehan	switch (offset) {
1635256056Sgrehan	case AHCI_CAP:
1636256056Sgrehan	case AHCI_PI:
1637256056Sgrehan	case AHCI_VS:
1638256056Sgrehan	case AHCI_CAP2:
1639256754Sgrehan		DPRINTF("pci_ahci_host: read only registers 0x%"PRIx64"\n", offset);
1640256056Sgrehan		break;
1641256056Sgrehan	case AHCI_GHC:
1642256056Sgrehan		if (value & AHCI_GHC_HR)
1643256056Sgrehan			ahci_reset(sc);
1644256056Sgrehan		else if (value & AHCI_GHC_IE) {
1645256056Sgrehan			sc->ghc |= AHCI_GHC_IE;
1646256056Sgrehan			ahci_generate_intr(sc);
1647256056Sgrehan		}
1648256056Sgrehan		break;
1649256056Sgrehan	case AHCI_IS:
1650256056Sgrehan		sc->is &= ~value;
1651256056Sgrehan		ahci_generate_intr(sc);
1652256056Sgrehan		break;
1653256056Sgrehan	default:
1654256056Sgrehan		break;
1655256056Sgrehan	}
1656256056Sgrehan}
1657256056Sgrehan
1658256056Sgrehanstatic void
1659256056Sgrehanpci_ahci_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
1660256056Sgrehan		int baridx, uint64_t offset, int size, uint64_t value)
1661256056Sgrehan{
1662256056Sgrehan	struct pci_ahci_softc *sc = pi->pi_arg;
1663256056Sgrehan
1664256056Sgrehan	assert(baridx == 5);
1665256056Sgrehan	assert(size == 4);
1666256056Sgrehan
1667256056Sgrehan	pthread_mutex_lock(&sc->mtx);
1668256056Sgrehan
1669256056Sgrehan	if (offset < AHCI_OFFSET)
1670256056Sgrehan		pci_ahci_host_write(sc, offset, value);
1671256056Sgrehan	else if (offset < AHCI_OFFSET + sc->ports * AHCI_STEP)
1672256056Sgrehan		pci_ahci_port_write(sc, offset, value);
1673256056Sgrehan	else
1674256056Sgrehan		WPRINTF("pci_ahci: unknown i/o write offset 0x%"PRIx64"\n", offset);
1675256056Sgrehan
1676256056Sgrehan	pthread_mutex_unlock(&sc->mtx);
1677256056Sgrehan}
1678256056Sgrehan
1679256056Sgrehanstatic uint64_t
1680256056Sgrehanpci_ahci_host_read(struct pci_ahci_softc *sc, uint64_t offset)
1681256056Sgrehan{
1682256056Sgrehan	uint32_t value;
1683256056Sgrehan
1684256056Sgrehan	switch (offset) {
1685256056Sgrehan	case AHCI_CAP:
1686256056Sgrehan	case AHCI_GHC:
1687256056Sgrehan	case AHCI_IS:
1688256056Sgrehan	case AHCI_PI:
1689256056Sgrehan	case AHCI_VS:
1690256056Sgrehan	case AHCI_CCCC:
1691256056Sgrehan	case AHCI_CCCP:
1692256056Sgrehan	case AHCI_EM_LOC:
1693256056Sgrehan	case AHCI_EM_CTL:
1694256056Sgrehan	case AHCI_CAP2:
1695256056Sgrehan	{
1696256056Sgrehan		uint32_t *p = &sc->cap;
1697256056Sgrehan		p += (offset - AHCI_CAP) / sizeof(uint32_t);
1698256056Sgrehan		value = *p;
1699256056Sgrehan		break;
1700256056Sgrehan	}
1701256056Sgrehan	default:
1702256056Sgrehan		value = 0;
1703256056Sgrehan		break;
1704256056Sgrehan	}
1705256056Sgrehan	DPRINTF("pci_ahci_host: read offset 0x%"PRIx64" value 0x%x\n",
1706256056Sgrehan		offset, value);
1707256056Sgrehan
1708256056Sgrehan	return (value);
1709256056Sgrehan}
1710256056Sgrehan
1711256056Sgrehanstatic uint64_t
1712256056Sgrehanpci_ahci_port_read(struct pci_ahci_softc *sc, uint64_t offset)
1713256056Sgrehan{
1714256056Sgrehan	uint32_t value;
1715256056Sgrehan	int port = (offset - AHCI_OFFSET) / AHCI_STEP;
1716256056Sgrehan	offset = (offset - AHCI_OFFSET) % AHCI_STEP;
1717256056Sgrehan
1718256056Sgrehan	switch (offset) {
1719256056Sgrehan	case AHCI_P_CLB:
1720256056Sgrehan	case AHCI_P_CLBU:
1721256056Sgrehan	case AHCI_P_FB:
1722256056Sgrehan	case AHCI_P_FBU:
1723256056Sgrehan	case AHCI_P_IS:
1724256056Sgrehan	case AHCI_P_IE:
1725256056Sgrehan	case AHCI_P_CMD:
1726256056Sgrehan	case AHCI_P_TFD:
1727256056Sgrehan	case AHCI_P_SIG:
1728256056Sgrehan	case AHCI_P_SSTS:
1729256056Sgrehan	case AHCI_P_SCTL:
1730256056Sgrehan	case AHCI_P_SERR:
1731256056Sgrehan	case AHCI_P_SACT:
1732256056Sgrehan	case AHCI_P_CI:
1733256056Sgrehan	case AHCI_P_SNTF:
1734256056Sgrehan	case AHCI_P_FBS:
1735256056Sgrehan	{
1736256056Sgrehan		uint32_t *p= &sc->port[port].clb;
1737256056Sgrehan		p += (offset - AHCI_P_CLB) / sizeof(uint32_t);
1738256056Sgrehan		value = *p;
1739256056Sgrehan		break;
1740256056Sgrehan	}
1741256056Sgrehan	default:
1742256056Sgrehan		value = 0;
1743256056Sgrehan		break;
1744256056Sgrehan	}
1745256056Sgrehan
1746256056Sgrehan	DPRINTF("pci_ahci_port %d: read offset 0x%"PRIx64" value 0x%x\n",
1747256056Sgrehan		port, offset, value);
1748256056Sgrehan
1749256056Sgrehan	return value;
1750256056Sgrehan}
1751256056Sgrehan
1752256056Sgrehanstatic uint64_t
1753256056Sgrehanpci_ahci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
1754256056Sgrehan    uint64_t offset, int size)
1755256056Sgrehan{
1756256056Sgrehan	struct pci_ahci_softc *sc = pi->pi_arg;
1757256056Sgrehan	uint32_t value;
1758256056Sgrehan
1759256056Sgrehan	assert(baridx == 5);
1760256056Sgrehan	assert(size == 4);
1761256056Sgrehan
1762256056Sgrehan	pthread_mutex_lock(&sc->mtx);
1763256056Sgrehan
1764256056Sgrehan	if (offset < AHCI_OFFSET)
1765256056Sgrehan		value = pci_ahci_host_read(sc, offset);
1766256056Sgrehan	else if (offset < AHCI_OFFSET + sc->ports * AHCI_STEP)
1767256056Sgrehan		value = pci_ahci_port_read(sc, offset);
1768256056Sgrehan	else {
1769256056Sgrehan		value = 0;
1770256056Sgrehan		WPRINTF("pci_ahci: unknown i/o read offset 0x%"PRIx64"\n", offset);
1771256056Sgrehan	}
1772256056Sgrehan
1773256056Sgrehan	pthread_mutex_unlock(&sc->mtx);
1774256056Sgrehan
1775256056Sgrehan	return (value);
1776256056Sgrehan}
1777256056Sgrehan
1778256056Sgrehanstatic int
1779256056Sgrehanpci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi)
1780256056Sgrehan{
1781256056Sgrehan	char bident[sizeof("XX:X:X")];
1782256056Sgrehan	struct blockif_ctxt *bctxt;
1783256056Sgrehan	struct pci_ahci_softc *sc;
1784256056Sgrehan	int ret, slots;
1785256056Sgrehan
1786256056Sgrehan	ret = 0;
1787256056Sgrehan
1788256056Sgrehan	if (opts == NULL) {
1789256056Sgrehan		fprintf(stderr, "pci_ahci: backing device required\n");
1790256056Sgrehan		return (1);
1791256056Sgrehan	}
1792256056Sgrehan
1793256056Sgrehan#ifdef AHCI_DEBUG
1794256056Sgrehan	dbg = fopen("/tmp/log", "w+");
1795256056Sgrehan#endif
1796256056Sgrehan
1797268953Sjhb	sc = calloc(1, sizeof(struct pci_ahci_softc));
1798256056Sgrehan	pi->pi_arg = sc;
1799256056Sgrehan	sc->asc_pi = pi;
1800256056Sgrehan	sc->ports = MAX_PORTS;
1801256056Sgrehan
1802256056Sgrehan	/*
1803256056Sgrehan	 * Only use port 0 for a backing device. All other ports will be
1804256056Sgrehan	 * marked as unused
1805256056Sgrehan	 */
1806256056Sgrehan	sc->port[0].atapi = atapi;
1807256056Sgrehan
1808256056Sgrehan	/*
1809256056Sgrehan	 * Attempt to open the backing image. Use the PCI
1810259301Sgrehan	 * slot/func for the identifier string.
1811256056Sgrehan	 */
1812259301Sgrehan	snprintf(bident, sizeof(bident), "%d:%d", pi->pi_slot, pi->pi_func);
1813256056Sgrehan	bctxt = blockif_open(opts, bident);
1814256056Sgrehan	if (bctxt == NULL) {
1815256056Sgrehan		ret = 1;
1816256056Sgrehan		goto open_fail;
1817256056Sgrehan	}
1818256056Sgrehan	sc->port[0].bctx = bctxt;
1819256056Sgrehan	sc->port[0].pr_sc = sc;
1820256056Sgrehan
1821256056Sgrehan	/*
1822256056Sgrehan	 * Allocate blockif request structures and add them
1823256056Sgrehan	 * to the free list
1824256056Sgrehan	 */
1825256056Sgrehan	pci_ahci_ioreq_init(&sc->port[0]);
1826256056Sgrehan
1827256056Sgrehan	pthread_mutex_init(&sc->mtx, NULL);
1828256056Sgrehan
1829256056Sgrehan	/* Intel ICH8 AHCI */
1830256056Sgrehan	slots = sc->port[0].ioqsz;
1831256056Sgrehan	if (slots > 32)
1832256056Sgrehan		slots = 32;
1833256056Sgrehan	--slots;
1834256056Sgrehan	sc->cap = AHCI_CAP_64BIT | AHCI_CAP_SNCQ | AHCI_CAP_SSNTF |
1835256056Sgrehan	    AHCI_CAP_SMPS | AHCI_CAP_SSS | AHCI_CAP_SALP |
1836256056Sgrehan	    AHCI_CAP_SAL | AHCI_CAP_SCLO | (0x3 << AHCI_CAP_ISS_SHIFT)|
1837256056Sgrehan	    AHCI_CAP_PMD | AHCI_CAP_SSC | AHCI_CAP_PSC |
1838256056Sgrehan	    (slots << AHCI_CAP_NCS_SHIFT) | AHCI_CAP_SXS | (sc->ports - 1);
1839256056Sgrehan
1840256056Sgrehan	/* Only port 0 implemented */
1841256056Sgrehan	sc->pi = 1;
1842256056Sgrehan	sc->vs = 0x10300;
1843256056Sgrehan	sc->cap2 = AHCI_CAP2_APST;
1844256056Sgrehan	ahci_reset(sc);
1845256056Sgrehan
1846256056Sgrehan	pci_set_cfgdata16(pi, PCIR_DEVICE, 0x2821);
1847256056Sgrehan	pci_set_cfgdata16(pi, PCIR_VENDOR, 0x8086);
1848256056Sgrehan	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE);
1849256056Sgrehan	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_STORAGE_SATA);
1850256056Sgrehan	pci_set_cfgdata8(pi, PCIR_PROGIF, PCIP_STORAGE_SATA_AHCI_1_0);
1851256056Sgrehan	pci_emul_add_msicap(pi, 1);
1852256056Sgrehan	pci_emul_alloc_bar(pi, 5, PCIBAR_MEM32,
1853256056Sgrehan	    AHCI_OFFSET + sc->ports * AHCI_STEP);
1854256056Sgrehan
1855267393Sjhb	pci_lintr_request(pi);
1856267393Sjhb
1857256056Sgrehanopen_fail:
1858256056Sgrehan	if (ret) {
1859256056Sgrehan		blockif_close(sc->port[0].bctx);
1860256056Sgrehan		free(sc);
1861256056Sgrehan	}
1862256056Sgrehan
1863256056Sgrehan	return (ret);
1864256056Sgrehan}
1865256056Sgrehan
1866256056Sgrehanstatic int
1867256056Sgrehanpci_ahci_hd_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
1868256056Sgrehan{
1869256056Sgrehan
1870256056Sgrehan	return (pci_ahci_init(ctx, pi, opts, 0));
1871256056Sgrehan}
1872256056Sgrehan
1873256056Sgrehanstatic int
1874256056Sgrehanpci_ahci_atapi_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
1875256056Sgrehan{
1876256056Sgrehan
1877256056Sgrehan	return (pci_ahci_init(ctx, pi, opts, 1));
1878256056Sgrehan}
1879256056Sgrehan
1880256056Sgrehan/*
1881256056Sgrehan * Use separate emulation names to distinguish drive and atapi devices
1882256056Sgrehan */
1883256056Sgrehanstruct pci_devemu pci_de_ahci_hd = {
1884256056Sgrehan	.pe_emu =	"ahci-hd",
1885256056Sgrehan	.pe_init =	pci_ahci_hd_init,
1886256056Sgrehan	.pe_barwrite =	pci_ahci_write,
1887256056Sgrehan	.pe_barread =	pci_ahci_read
1888256056Sgrehan};
1889256056SgrehanPCI_EMUL_SET(pci_de_ahci_hd);
1890256056Sgrehan
1891256056Sgrehanstruct pci_devemu pci_de_ahci_cd = {
1892256056Sgrehan	.pe_emu =	"ahci-cd",
1893256056Sgrehan	.pe_init =	pci_ahci_atapi_init,
1894256056Sgrehan	.pe_barwrite =	pci_ahci_write,
1895256056Sgrehan	.pe_barread =	pci_ahci_read
1896256056Sgrehan};
1897256056SgrehanPCI_EMUL_SET(pci_de_ahci_cd);
1898