xref: /illumos-gate/usr/src/cmd/bhyve/pci_ahci.c (revision 154972aff898a787b38af3bab5b8d754b5a42447)
1bf21cd93STycho Nightingale /*-
24c87aefeSPatrick Mooney  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
34c87aefeSPatrick Mooney  *
4bf21cd93STycho Nightingale  * Copyright (c) 2013  Zhixiang Yu <zcore@freebsd.org>
54c87aefeSPatrick Mooney  * Copyright (c) 2015-2016 Alexander Motin <mav@FreeBSD.org>
6bf21cd93STycho Nightingale  * All rights reserved.
7bf21cd93STycho Nightingale  *
8bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
9bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
10bf21cd93STycho Nightingale  * are met:
11bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
12bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
13bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
14bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
15bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
16bf21cd93STycho Nightingale  *
17bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
18bf21cd93STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19bf21cd93STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20bf21cd93STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21bf21cd93STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22bf21cd93STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23bf21cd93STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24bf21cd93STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25bf21cd93STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26bf21cd93STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27bf21cd93STycho Nightingale  * SUCH DAMAGE.
28bf21cd93STycho Nightingale  *
294c87aefeSPatrick Mooney  * $FreeBSD$
30bf21cd93STycho Nightingale  */
31bf21cd93STycho Nightingale 
32bf21cd93STycho Nightingale #include <sys/cdefs.h>
334c87aefeSPatrick Mooney __FBSDID("$FreeBSD$");
34bf21cd93STycho Nightingale 
35bf21cd93STycho Nightingale #include <sys/param.h>
36bf21cd93STycho Nightingale #include <sys/linker_set.h>
37bf21cd93STycho Nightingale #include <sys/stat.h>
38bf21cd93STycho Nightingale #include <sys/uio.h>
39bf21cd93STycho Nightingale #include <sys/ioctl.h>
40bf21cd93STycho Nightingale #include <sys/disk.h>
41bf21cd93STycho Nightingale #include <sys/ata.h>
42bf21cd93STycho Nightingale #include <sys/endian.h>
43bf21cd93STycho Nightingale 
44bf21cd93STycho Nightingale #include <errno.h>
45bf21cd93STycho Nightingale #include <fcntl.h>
46bf21cd93STycho Nightingale #include <stdio.h>
47bf21cd93STycho Nightingale #include <stdlib.h>
48bf21cd93STycho Nightingale #include <stdint.h>
49bf21cd93STycho Nightingale #include <string.h>
50bf21cd93STycho Nightingale #include <strings.h>
51bf21cd93STycho Nightingale #include <unistd.h>
52bf21cd93STycho Nightingale #include <assert.h>
53bf21cd93STycho Nightingale #include <pthread.h>
54bf21cd93STycho Nightingale #include <pthread_np.h>
55bf21cd93STycho Nightingale #include <inttypes.h>
564c87aefeSPatrick Mooney #include <md5.h>
57bf21cd93STycho Nightingale 
58bf21cd93STycho Nightingale #include "bhyverun.h"
59bf21cd93STycho Nightingale #include "pci_emul.h"
60bf21cd93STycho Nightingale #include "ahci.h"
61bf21cd93STycho Nightingale #include "block_if.h"
62bf21cd93STycho Nightingale 
634c87aefeSPatrick Mooney #define	DEF_PORTS	6	/* Intel ICH8 AHCI supports 6 ports */
644c87aefeSPatrick Mooney #define	MAX_PORTS	32	/* AHCI supports 32 ports */
65bf21cd93STycho Nightingale 
66bf21cd93STycho Nightingale #define	PxSIG_ATA	0x00000101 /* ATA drive */
67bf21cd93STycho Nightingale #define	PxSIG_ATAPI	0xeb140101 /* ATAPI drive */
68bf21cd93STycho Nightingale 
69bf21cd93STycho Nightingale enum sata_fis_type {
70bf21cd93STycho Nightingale 	FIS_TYPE_REGH2D		= 0x27,	/* Register FIS - host to device */
71bf21cd93STycho Nightingale 	FIS_TYPE_REGD2H		= 0x34,	/* Register FIS - device to host */
72bf21cd93STycho Nightingale 	FIS_TYPE_DMAACT		= 0x39,	/* DMA activate FIS - device to host */
73bf21cd93STycho Nightingale 	FIS_TYPE_DMASETUP	= 0x41,	/* DMA setup FIS - bidirectional */
74bf21cd93STycho Nightingale 	FIS_TYPE_DATA		= 0x46,	/* Data FIS - bidirectional */
75bf21cd93STycho Nightingale 	FIS_TYPE_BIST		= 0x58,	/* BIST activate FIS - bidirectional */
76bf21cd93STycho Nightingale 	FIS_TYPE_PIOSETUP	= 0x5F,	/* PIO setup FIS - device to host */
77bf21cd93STycho Nightingale 	FIS_TYPE_SETDEVBITS	= 0xA1,	/* Set dev bits FIS - device to host */
78bf21cd93STycho Nightingale };
79bf21cd93STycho Nightingale 
80bf21cd93STycho Nightingale /*
81bf21cd93STycho Nightingale  * SCSI opcodes
82bf21cd93STycho Nightingale  */
83bf21cd93STycho Nightingale #define	TEST_UNIT_READY		0x00
84bf21cd93STycho Nightingale #define	REQUEST_SENSE		0x03
85bf21cd93STycho Nightingale #define	INQUIRY			0x12
86bf21cd93STycho Nightingale #define	START_STOP_UNIT		0x1B
87bf21cd93STycho Nightingale #define	PREVENT_ALLOW		0x1E
88bf21cd93STycho Nightingale #define	READ_CAPACITY		0x25
89bf21cd93STycho Nightingale #define	READ_10			0x28
90bf21cd93STycho Nightingale #define	POSITION_TO_ELEMENT	0x2B
91bf21cd93STycho Nightingale #define	READ_TOC		0x43
92bf21cd93STycho Nightingale #define	GET_EVENT_STATUS_NOTIFICATION 0x4A
93bf21cd93STycho Nightingale #define	MODE_SENSE_10		0x5A
944c87aefeSPatrick Mooney #define	REPORT_LUNS		0xA0
95bf21cd93STycho Nightingale #define	READ_12			0xA8
96bf21cd93STycho Nightingale #define	READ_CD			0xBE
97bf21cd93STycho Nightingale 
98bf21cd93STycho Nightingale /*
99bf21cd93STycho Nightingale  * SCSI mode page codes
100bf21cd93STycho Nightingale  */
101bf21cd93STycho Nightingale #define	MODEPAGE_RW_ERROR_RECOVERY	0x01
102bf21cd93STycho Nightingale #define	MODEPAGE_CD_CAPABILITIES	0x2A
103bf21cd93STycho Nightingale 
104bf21cd93STycho Nightingale /*
105bf21cd93STycho Nightingale  * ATA commands
106bf21cd93STycho Nightingale  */
107bf21cd93STycho Nightingale #define	ATA_SF_ENAB_SATA_SF		0x10
108bf21cd93STycho Nightingale #define	ATA_SATA_SF_AN			0x05
109bf21cd93STycho Nightingale #define	ATA_SF_DIS_SATA_SF		0x90
110bf21cd93STycho Nightingale 
111bf21cd93STycho Nightingale /*
112bf21cd93STycho Nightingale  * Debug printf
113bf21cd93STycho Nightingale  */
114bf21cd93STycho Nightingale #ifdef AHCI_DEBUG
115bf21cd93STycho Nightingale static FILE *dbg;
116bf21cd93STycho Nightingale #define DPRINTF(format, arg...)	do{fprintf(dbg, format, ##arg);fflush(dbg);}while(0)
117bf21cd93STycho Nightingale #else
118bf21cd93STycho Nightingale #define DPRINTF(format, arg...)
119bf21cd93STycho Nightingale #endif
120bf21cd93STycho Nightingale #define WPRINTF(format, arg...) printf(format, ##arg)
121bf21cd93STycho Nightingale 
1224c87aefeSPatrick Mooney #define AHCI_PORT_IDENT 20 + 1
1234c87aefeSPatrick Mooney 
124bf21cd93STycho Nightingale struct ahci_ioreq {
125bf21cd93STycho Nightingale 	struct blockif_req io_req;
126bf21cd93STycho Nightingale 	struct ahci_port *io_pr;
127bf21cd93STycho Nightingale 	STAILQ_ENTRY(ahci_ioreq) io_flist;
128bf21cd93STycho Nightingale 	TAILQ_ENTRY(ahci_ioreq) io_blist;
129bf21cd93STycho Nightingale 	uint8_t *cfis;
130bf21cd93STycho Nightingale 	uint32_t len;
131bf21cd93STycho Nightingale 	uint32_t done;
132bf21cd93STycho Nightingale 	int slot;
1334c87aefeSPatrick Mooney 	int more;
134bf21cd93STycho Nightingale };
135bf21cd93STycho Nightingale 
136bf21cd93STycho Nightingale struct ahci_port {
137bf21cd93STycho Nightingale 	struct blockif_ctxt *bctx;
138bf21cd93STycho Nightingale 	struct pci_ahci_softc *pr_sc;
139bf21cd93STycho Nightingale 	uint8_t *cmd_lst;
140bf21cd93STycho Nightingale 	uint8_t *rfis;
1414c87aefeSPatrick Mooney 	char ident[AHCI_PORT_IDENT];
1424c87aefeSPatrick Mooney 	int port;
143bf21cd93STycho Nightingale 	int atapi;
144bf21cd93STycho Nightingale 	int reset;
1454c87aefeSPatrick Mooney 	int waitforclear;
146bf21cd93STycho Nightingale 	int mult_sectors;
147bf21cd93STycho Nightingale 	uint8_t xfermode;
1484c87aefeSPatrick Mooney 	uint8_t err_cfis[20];
149bf21cd93STycho Nightingale 	uint8_t sense_key;
150bf21cd93STycho Nightingale 	uint8_t asc;
1514c87aefeSPatrick Mooney 	u_int ccs;
152bf21cd93STycho Nightingale 	uint32_t pending;
153bf21cd93STycho Nightingale 
154bf21cd93STycho Nightingale 	uint32_t clb;
155bf21cd93STycho Nightingale 	uint32_t clbu;
156bf21cd93STycho Nightingale 	uint32_t fb;
157bf21cd93STycho Nightingale 	uint32_t fbu;
158bf21cd93STycho Nightingale 	uint32_t is;
159bf21cd93STycho Nightingale 	uint32_t ie;
160bf21cd93STycho Nightingale 	uint32_t cmd;
161bf21cd93STycho Nightingale 	uint32_t unused0;
162bf21cd93STycho Nightingale 	uint32_t tfd;
163bf21cd93STycho Nightingale 	uint32_t sig;
164bf21cd93STycho Nightingale 	uint32_t ssts;
165bf21cd93STycho Nightingale 	uint32_t sctl;
166bf21cd93STycho Nightingale 	uint32_t serr;
167bf21cd93STycho Nightingale 	uint32_t sact;
168bf21cd93STycho Nightingale 	uint32_t ci;
169bf21cd93STycho Nightingale 	uint32_t sntf;
170bf21cd93STycho Nightingale 	uint32_t fbs;
171bf21cd93STycho Nightingale 
172bf21cd93STycho Nightingale 	/*
173bf21cd93STycho Nightingale 	 * i/o request info
174bf21cd93STycho Nightingale 	 */
175bf21cd93STycho Nightingale 	struct ahci_ioreq *ioreq;
176bf21cd93STycho Nightingale 	int ioqsz;
177bf21cd93STycho Nightingale 	STAILQ_HEAD(ahci_fhead, ahci_ioreq) iofhd;
178bf21cd93STycho Nightingale 	TAILQ_HEAD(ahci_bhead, ahci_ioreq) iobhd;
179bf21cd93STycho Nightingale };
180bf21cd93STycho Nightingale 
181bf21cd93STycho Nightingale struct ahci_cmd_hdr {
182bf21cd93STycho Nightingale 	uint16_t flags;
183bf21cd93STycho Nightingale 	uint16_t prdtl;
184bf21cd93STycho Nightingale 	uint32_t prdbc;
185bf21cd93STycho Nightingale 	uint64_t ctba;
186bf21cd93STycho Nightingale 	uint32_t reserved[4];
187bf21cd93STycho Nightingale };
188bf21cd93STycho Nightingale 
189bf21cd93STycho Nightingale struct ahci_prdt_entry {
190bf21cd93STycho Nightingale 	uint64_t dba;
191bf21cd93STycho Nightingale 	uint32_t reserved;
192bf21cd93STycho Nightingale #define	DBCMASK		0x3fffff
193bf21cd93STycho Nightingale 	uint32_t dbc;
194bf21cd93STycho Nightingale };
195bf21cd93STycho Nightingale 
196bf21cd93STycho Nightingale struct pci_ahci_softc {
197bf21cd93STycho Nightingale 	struct pci_devinst *asc_pi;
198bf21cd93STycho Nightingale 	pthread_mutex_t	mtx;
199bf21cd93STycho Nightingale 	int ports;
200bf21cd93STycho Nightingale 	uint32_t cap;
201bf21cd93STycho Nightingale 	uint32_t ghc;
202bf21cd93STycho Nightingale 	uint32_t is;
203bf21cd93STycho Nightingale 	uint32_t pi;
204bf21cd93STycho Nightingale 	uint32_t vs;
205bf21cd93STycho Nightingale 	uint32_t ccc_ctl;
206bf21cd93STycho Nightingale 	uint32_t ccc_pts;
207bf21cd93STycho Nightingale 	uint32_t em_loc;
208bf21cd93STycho Nightingale 	uint32_t em_ctl;
209bf21cd93STycho Nightingale 	uint32_t cap2;
210bf21cd93STycho Nightingale 	uint32_t bohc;
211bf21cd93STycho Nightingale 	uint32_t lintr;
212bf21cd93STycho Nightingale 	struct ahci_port port[MAX_PORTS];
213bf21cd93STycho Nightingale };
214bf21cd93STycho Nightingale #define	ahci_ctx(sc)	((sc)->asc_pi->pi_vmctx)
215bf21cd93STycho Nightingale 
2164c87aefeSPatrick Mooney static void ahci_handle_port(struct ahci_port *p);
2174c87aefeSPatrick Mooney 
218bf21cd93STycho Nightingale static inline void lba_to_msf(uint8_t *buf, int lba)
219bf21cd93STycho Nightingale {
220bf21cd93STycho Nightingale 	lba += 150;
221bf21cd93STycho Nightingale 	buf[0] = (lba / 75) / 60;
222bf21cd93STycho Nightingale 	buf[1] = (lba / 75) % 60;
223bf21cd93STycho Nightingale 	buf[2] = lba % 75;
224bf21cd93STycho Nightingale }
225bf21cd93STycho Nightingale 
226bf21cd93STycho Nightingale /*
2274c87aefeSPatrick Mooney  * Generate HBA interrupts on global IS register write.
228bf21cd93STycho Nightingale  */
229bf21cd93STycho Nightingale static void
2304c87aefeSPatrick Mooney ahci_generate_intr(struct pci_ahci_softc *sc, uint32_t mask)
231bf21cd93STycho Nightingale {
2324c87aefeSPatrick Mooney 	struct pci_devinst *pi = sc->asc_pi;
2334c87aefeSPatrick Mooney 	struct ahci_port *p;
2344c87aefeSPatrick Mooney 	int i, nmsg;
2354c87aefeSPatrick Mooney 	uint32_t mmask;
236bf21cd93STycho Nightingale 
2374c87aefeSPatrick Mooney 	/* Update global IS from PxIS/PxIE. */
238bf21cd93STycho Nightingale 	for (i = 0; i < sc->ports; i++) {
2394c87aefeSPatrick Mooney 		p = &sc->port[i];
2404c87aefeSPatrick Mooney 		if (p->is & p->ie)
241bf21cd93STycho Nightingale 			sc->is |= (1 << i);
242bf21cd93STycho Nightingale 	}
243*154972afSPatrick Mooney 	DPRINTF("%s(%08x) %08x", __func__, mask, sc->is);
244bf21cd93STycho Nightingale 
2454c87aefeSPatrick Mooney 	/* If there is nothing enabled -- clear legacy interrupt and exit. */
2464c87aefeSPatrick Mooney 	if (sc->is == 0 || (sc->ghc & AHCI_GHC_IE) == 0) {
2474c87aefeSPatrick Mooney 		if (sc->lintr) {
2484c87aefeSPatrick Mooney 			pci_lintr_deassert(pi);
2494c87aefeSPatrick Mooney 			sc->lintr = 0;
2504c87aefeSPatrick Mooney 		}
2514c87aefeSPatrick Mooney 		return;
2524c87aefeSPatrick Mooney 	}
253bf21cd93STycho Nightingale 
2544c87aefeSPatrick Mooney 	/* If there is anything and no MSI -- assert legacy interrupt. */
2554c87aefeSPatrick Mooney 	nmsg = pci_msi_maxmsgnum(pi);
2564c87aefeSPatrick Mooney 	if (nmsg == 0) {
2574c87aefeSPatrick Mooney 		if (!sc->lintr) {
258bf21cd93STycho Nightingale 			sc->lintr = 1;
259bf21cd93STycho Nightingale 			pci_lintr_assert(pi);
260bf21cd93STycho Nightingale 		}
2614c87aefeSPatrick Mooney 		return;
2624c87aefeSPatrick Mooney 	}
2634c87aefeSPatrick Mooney 
2644c87aefeSPatrick Mooney 	/* Assert respective MSIs for ports that were touched. */
2654c87aefeSPatrick Mooney 	for (i = 0; i < nmsg; i++) {
2664c87aefeSPatrick Mooney 		if (sc->ports <= nmsg || i < nmsg - 1)
2674c87aefeSPatrick Mooney 			mmask = 1 << i;
2684c87aefeSPatrick Mooney 		else
2694c87aefeSPatrick Mooney 			mmask = 0xffffffff << i;
2704c87aefeSPatrick Mooney 		if (sc->is & mask && mmask & mask)
2714c87aefeSPatrick Mooney 			pci_generate_msi(pi, i);
2724c87aefeSPatrick Mooney 	}
2734c87aefeSPatrick Mooney }
2744c87aefeSPatrick Mooney 
275bf21cd93STycho Nightingale /*
2764c87aefeSPatrick Mooney  * Generate HBA interrupt on specific port event.
277bf21cd93STycho Nightingale  */
2784c87aefeSPatrick Mooney static void
2794c87aefeSPatrick Mooney ahci_port_intr(struct ahci_port *p)
2804c87aefeSPatrick Mooney {
2814c87aefeSPatrick Mooney 	struct pci_ahci_softc *sc = p->pr_sc;
2824c87aefeSPatrick Mooney 	struct pci_devinst *pi = sc->asc_pi;
2834c87aefeSPatrick Mooney 	int nmsg;
2844c87aefeSPatrick Mooney 
285*154972afSPatrick Mooney 	DPRINTF("%s(%d) %08x/%08x %08x", __func__,
2864c87aefeSPatrick Mooney 	    p->port, p->is, p->ie, sc->is);
2874c87aefeSPatrick Mooney 
2884c87aefeSPatrick Mooney 	/* If there is nothing enabled -- we are done. */
2894c87aefeSPatrick Mooney 	if ((p->is & p->ie) == 0)
2904c87aefeSPatrick Mooney 		return;
2914c87aefeSPatrick Mooney 
2924c87aefeSPatrick Mooney 	/* In case of non-shared MSI always generate interrupt. */
2934c87aefeSPatrick Mooney 	nmsg = pci_msi_maxmsgnum(pi);
2944c87aefeSPatrick Mooney 	if (sc->ports <= nmsg || p->port < nmsg - 1) {
2954c87aefeSPatrick Mooney 		sc->is |= (1 << p->port);
2964c87aefeSPatrick Mooney 		if ((sc->ghc & AHCI_GHC_IE) == 0)
2974c87aefeSPatrick Mooney 			return;
2984c87aefeSPatrick Mooney 		pci_generate_msi(pi, p->port);
2994c87aefeSPatrick Mooney 		return;
3004c87aefeSPatrick Mooney 	}
3014c87aefeSPatrick Mooney 
3024c87aefeSPatrick Mooney 	/* If IS for this port is already set -- do nothing. */
3034c87aefeSPatrick Mooney 	if (sc->is & (1 << p->port))
3044c87aefeSPatrick Mooney 		return;
3054c87aefeSPatrick Mooney 
3064c87aefeSPatrick Mooney 	sc->is |= (1 << p->port);
3074c87aefeSPatrick Mooney 
3084c87aefeSPatrick Mooney 	/* If interrupts are enabled -- generate one. */
3094c87aefeSPatrick Mooney 	if ((sc->ghc & AHCI_GHC_IE) == 0)
3104c87aefeSPatrick Mooney 		return;
3114c87aefeSPatrick Mooney 	if (nmsg > 0) {
3124c87aefeSPatrick Mooney 		pci_generate_msi(pi, nmsg - 1);
3134c87aefeSPatrick Mooney 	} else if (!sc->lintr) {
3144c87aefeSPatrick Mooney 		sc->lintr = 1;
3154c87aefeSPatrick Mooney 		pci_lintr_assert(pi);
316bf21cd93STycho Nightingale 	}
317bf21cd93STycho Nightingale }
318bf21cd93STycho Nightingale 
319bf21cd93STycho Nightingale static void
320bf21cd93STycho Nightingale ahci_write_fis(struct ahci_port *p, enum sata_fis_type ft, uint8_t *fis)
321bf21cd93STycho Nightingale {
322bf21cd93STycho Nightingale 	int offset, len, irq;
323bf21cd93STycho Nightingale 
324bf21cd93STycho Nightingale 	if (p->rfis == NULL || !(p->cmd & AHCI_P_CMD_FRE))
325bf21cd93STycho Nightingale 		return;
326bf21cd93STycho Nightingale 
327bf21cd93STycho Nightingale 	switch (ft) {
328bf21cd93STycho Nightingale 	case FIS_TYPE_REGD2H:
329bf21cd93STycho Nightingale 		offset = 0x40;
330bf21cd93STycho Nightingale 		len = 20;
3314c87aefeSPatrick Mooney 		irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_DHR : 0;
332bf21cd93STycho Nightingale 		break;
333bf21cd93STycho Nightingale 	case FIS_TYPE_SETDEVBITS:
334bf21cd93STycho Nightingale 		offset = 0x58;
335bf21cd93STycho Nightingale 		len = 8;
3364c87aefeSPatrick Mooney 		irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_SDB : 0;
337bf21cd93STycho Nightingale 		break;
338bf21cd93STycho Nightingale 	case FIS_TYPE_PIOSETUP:
339bf21cd93STycho Nightingale 		offset = 0x20;
340bf21cd93STycho Nightingale 		len = 20;
3414c87aefeSPatrick Mooney 		irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_PS : 0;
342bf21cd93STycho Nightingale 		break;
343bf21cd93STycho Nightingale 	default:
344*154972afSPatrick Mooney 		WPRINTF("unsupported fis type %d", ft);
345bf21cd93STycho Nightingale 		return;
346bf21cd93STycho Nightingale 	}
3474c87aefeSPatrick Mooney 	if (fis[2] & ATA_S_ERROR) {
3484c87aefeSPatrick Mooney 		p->waitforclear = 1;
3494c87aefeSPatrick Mooney 		irq |= AHCI_P_IX_TFE;
3504c87aefeSPatrick Mooney 	}
351bf21cd93STycho Nightingale 	memcpy(p->rfis + offset, fis, len);
352bf21cd93STycho Nightingale 	if (irq) {
3534c87aefeSPatrick Mooney 		if (~p->is & irq) {
354bf21cd93STycho Nightingale 			p->is |= irq;
3554c87aefeSPatrick Mooney 			ahci_port_intr(p);
3564c87aefeSPatrick Mooney 		}
357bf21cd93STycho Nightingale 	}
358bf21cd93STycho Nightingale }
359bf21cd93STycho Nightingale 
360bf21cd93STycho Nightingale static void
361bf21cd93STycho Nightingale ahci_write_fis_piosetup(struct ahci_port *p)
362bf21cd93STycho Nightingale {
363bf21cd93STycho Nightingale 	uint8_t fis[20];
364bf21cd93STycho Nightingale 
365bf21cd93STycho Nightingale 	memset(fis, 0, sizeof(fis));
366bf21cd93STycho Nightingale 	fis[0] = FIS_TYPE_PIOSETUP;
367bf21cd93STycho Nightingale 	ahci_write_fis(p, FIS_TYPE_PIOSETUP, fis);
368bf21cd93STycho Nightingale }
369bf21cd93STycho Nightingale 
370bf21cd93STycho Nightingale static void
3714c87aefeSPatrick Mooney ahci_write_fis_sdb(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd)
372bf21cd93STycho Nightingale {
373bf21cd93STycho Nightingale 	uint8_t fis[8];
374bf21cd93STycho Nightingale 	uint8_t error;
375bf21cd93STycho Nightingale 
376bf21cd93STycho Nightingale 	error = (tfd >> 8) & 0xff;
3774c87aefeSPatrick Mooney 	tfd &= 0x77;
378bf21cd93STycho Nightingale 	memset(fis, 0, sizeof(fis));
3794c87aefeSPatrick Mooney 	fis[0] = FIS_TYPE_SETDEVBITS;
3804c87aefeSPatrick Mooney 	fis[1] = (1 << 6);
3814c87aefeSPatrick Mooney 	fis[2] = tfd;
3824c87aefeSPatrick Mooney 	fis[3] = error;
3834c87aefeSPatrick Mooney 	if (fis[2] & ATA_S_ERROR) {
3844c87aefeSPatrick Mooney 		p->err_cfis[0] = slot;
3854c87aefeSPatrick Mooney 		p->err_cfis[2] = tfd;
3864c87aefeSPatrick Mooney 		p->err_cfis[3] = error;
3874c87aefeSPatrick Mooney 		memcpy(&p->err_cfis[4], cfis + 4, 16);
3884c87aefeSPatrick Mooney 	} else {
389bf21cd93STycho Nightingale 		*(uint32_t *)(fis + 4) = (1 << slot);
3904c87aefeSPatrick Mooney 		p->sact &= ~(1 << slot);
3914c87aefeSPatrick Mooney 	}
3924c87aefeSPatrick Mooney 	p->tfd &= ~0x77;
3934c87aefeSPatrick Mooney 	p->tfd |= tfd;
394bf21cd93STycho Nightingale 	ahci_write_fis(p, FIS_TYPE_SETDEVBITS, fis);
395bf21cd93STycho Nightingale }
396bf21cd93STycho Nightingale 
397bf21cd93STycho Nightingale static void
398bf21cd93STycho Nightingale ahci_write_fis_d2h(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd)
399bf21cd93STycho Nightingale {
400bf21cd93STycho Nightingale 	uint8_t fis[20];
401bf21cd93STycho Nightingale 	uint8_t error;
402bf21cd93STycho Nightingale 
403bf21cd93STycho Nightingale 	error = (tfd >> 8) & 0xff;
404bf21cd93STycho Nightingale 	memset(fis, 0, sizeof(fis));
405bf21cd93STycho Nightingale 	fis[0] = FIS_TYPE_REGD2H;
406bf21cd93STycho Nightingale 	fis[1] = (1 << 6);
407bf21cd93STycho Nightingale 	fis[2] = tfd & 0xff;
408bf21cd93STycho Nightingale 	fis[3] = error;
409bf21cd93STycho Nightingale 	fis[4] = cfis[4];
410bf21cd93STycho Nightingale 	fis[5] = cfis[5];
411bf21cd93STycho Nightingale 	fis[6] = cfis[6];
412bf21cd93STycho Nightingale 	fis[7] = cfis[7];
413bf21cd93STycho Nightingale 	fis[8] = cfis[8];
414bf21cd93STycho Nightingale 	fis[9] = cfis[9];
415bf21cd93STycho Nightingale 	fis[10] = cfis[10];
416bf21cd93STycho Nightingale 	fis[11] = cfis[11];
417bf21cd93STycho Nightingale 	fis[12] = cfis[12];
418bf21cd93STycho Nightingale 	fis[13] = cfis[13];
4194c87aefeSPatrick Mooney 	if (fis[2] & ATA_S_ERROR) {
4204c87aefeSPatrick Mooney 		p->err_cfis[0] = 0x80;
4214c87aefeSPatrick Mooney 		p->err_cfis[2] = tfd & 0xff;
4224c87aefeSPatrick Mooney 		p->err_cfis[3] = error;
4234c87aefeSPatrick Mooney 		memcpy(&p->err_cfis[4], cfis + 4, 16);
4244c87aefeSPatrick Mooney 	} else
425bf21cd93STycho Nightingale 		p->ci &= ~(1 << slot);
426bf21cd93STycho Nightingale 	p->tfd = tfd;
427bf21cd93STycho Nightingale 	ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
428bf21cd93STycho Nightingale }
429bf21cd93STycho Nightingale 
430bf21cd93STycho Nightingale static void
4314c87aefeSPatrick Mooney ahci_write_fis_d2h_ncq(struct ahci_port *p, int slot)
4324c87aefeSPatrick Mooney {
4334c87aefeSPatrick Mooney 	uint8_t fis[20];
4344c87aefeSPatrick Mooney 
4354c87aefeSPatrick Mooney 	p->tfd = ATA_S_READY | ATA_S_DSC;
4364c87aefeSPatrick Mooney 	memset(fis, 0, sizeof(fis));
4374c87aefeSPatrick Mooney 	fis[0] = FIS_TYPE_REGD2H;
4384c87aefeSPatrick Mooney 	fis[1] = 0;			/* No interrupt */
4394c87aefeSPatrick Mooney 	fis[2] = p->tfd;		/* Status */
4404c87aefeSPatrick Mooney 	fis[3] = 0;			/* No error */
4414c87aefeSPatrick Mooney 	p->ci &= ~(1 << slot);
4424c87aefeSPatrick Mooney 	ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
4434c87aefeSPatrick Mooney }
4444c87aefeSPatrick Mooney 
4454c87aefeSPatrick Mooney static void
446bf21cd93STycho Nightingale ahci_write_reset_fis_d2h(struct ahci_port *p)
447bf21cd93STycho Nightingale {
448bf21cd93STycho Nightingale 	uint8_t fis[20];
449bf21cd93STycho Nightingale 
450bf21cd93STycho Nightingale 	memset(fis, 0, sizeof(fis));
451bf21cd93STycho Nightingale 	fis[0] = FIS_TYPE_REGD2H;
452bf21cd93STycho Nightingale 	fis[3] = 1;
453bf21cd93STycho Nightingale 	fis[4] = 1;
454bf21cd93STycho Nightingale 	if (p->atapi) {
455bf21cd93STycho Nightingale 		fis[5] = 0x14;
456bf21cd93STycho Nightingale 		fis[6] = 0xeb;
457bf21cd93STycho Nightingale 	}
458bf21cd93STycho Nightingale 	fis[12] = 1;
459bf21cd93STycho Nightingale 	ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
460bf21cd93STycho Nightingale }
461bf21cd93STycho Nightingale 
462bf21cd93STycho Nightingale static void
463bf21cd93STycho Nightingale ahci_check_stopped(struct ahci_port *p)
464bf21cd93STycho Nightingale {
465bf21cd93STycho Nightingale 	/*
466bf21cd93STycho Nightingale 	 * If we are no longer processing the command list and nothing
467bf21cd93STycho Nightingale 	 * is in-flight, clear the running bit, the current command
468bf21cd93STycho Nightingale 	 * slot, the command issue and active bits.
469bf21cd93STycho Nightingale 	 */
470bf21cd93STycho Nightingale 	if (!(p->cmd & AHCI_P_CMD_ST)) {
471bf21cd93STycho Nightingale 		if (p->pending == 0) {
4724c87aefeSPatrick Mooney 			p->ccs = 0;
473bf21cd93STycho Nightingale 			p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK);
474bf21cd93STycho Nightingale 			p->ci = 0;
475bf21cd93STycho Nightingale 			p->sact = 0;
4764c87aefeSPatrick Mooney 			p->waitforclear = 0;
477bf21cd93STycho Nightingale 		}
478bf21cd93STycho Nightingale 	}
479bf21cd93STycho Nightingale }
480bf21cd93STycho Nightingale 
481bf21cd93STycho Nightingale static void
482bf21cd93STycho Nightingale ahci_port_stop(struct ahci_port *p)
483bf21cd93STycho Nightingale {
484bf21cd93STycho Nightingale 	struct ahci_ioreq *aior;
485bf21cd93STycho Nightingale 	uint8_t *cfis;
486bf21cd93STycho Nightingale 	int slot;
487bf21cd93STycho Nightingale 	int error;
488bf21cd93STycho Nightingale 
489bf21cd93STycho Nightingale 	assert(pthread_mutex_isowned_np(&p->pr_sc->mtx));
490bf21cd93STycho Nightingale 
491bf21cd93STycho Nightingale 	TAILQ_FOREACH(aior, &p->iobhd, io_blist) {
492bf21cd93STycho Nightingale 		/*
493bf21cd93STycho Nightingale 		 * Try to cancel the outstanding blockif request.
494bf21cd93STycho Nightingale 		 */
495bf21cd93STycho Nightingale 		error = blockif_cancel(p->bctx, &aior->io_req);
496bf21cd93STycho Nightingale 		if (error != 0)
497bf21cd93STycho Nightingale 			continue;
498bf21cd93STycho Nightingale 
499bf21cd93STycho Nightingale 		slot = aior->slot;
500bf21cd93STycho Nightingale 		cfis = aior->cfis;
501bf21cd93STycho Nightingale 		if (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||
5024c87aefeSPatrick Mooney 		    cfis[2] == ATA_READ_FPDMA_QUEUED ||
5034c87aefeSPatrick Mooney 		    cfis[2] == ATA_SEND_FPDMA_QUEUED)
5044c87aefeSPatrick Mooney 			p->sact &= ~(1 << slot);	/* NCQ */
505bf21cd93STycho Nightingale 		else
506bf21cd93STycho Nightingale 			p->ci &= ~(1 << slot);
507bf21cd93STycho Nightingale 
508bf21cd93STycho Nightingale 		/*
509bf21cd93STycho Nightingale 		 * This command is now done.
510bf21cd93STycho Nightingale 		 */
511bf21cd93STycho Nightingale 		p->pending &= ~(1 << slot);
512bf21cd93STycho Nightingale 
513bf21cd93STycho Nightingale 		/*
514bf21cd93STycho Nightingale 		 * Delete the blockif request from the busy list
515bf21cd93STycho Nightingale 		 */
516bf21cd93STycho Nightingale 		TAILQ_REMOVE(&p->iobhd, aior, io_blist);
517bf21cd93STycho Nightingale 
518bf21cd93STycho Nightingale 		/*
519bf21cd93STycho Nightingale 		 * Move the blockif request back to the free list
520bf21cd93STycho Nightingale 		 */
521bf21cd93STycho Nightingale 		STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
522bf21cd93STycho Nightingale 	}
523bf21cd93STycho Nightingale 
524bf21cd93STycho Nightingale 	ahci_check_stopped(p);
525bf21cd93STycho Nightingale }
526bf21cd93STycho Nightingale 
527bf21cd93STycho Nightingale static void
528bf21cd93STycho Nightingale ahci_port_reset(struct ahci_port *pr)
529bf21cd93STycho Nightingale {
530bf21cd93STycho Nightingale 	pr->serr = 0;
531bf21cd93STycho Nightingale 	pr->sact = 0;
532bf21cd93STycho Nightingale 	pr->xfermode = ATA_UDMA6;
533bf21cd93STycho Nightingale 	pr->mult_sectors = 128;
534bf21cd93STycho Nightingale 
535bf21cd93STycho Nightingale 	if (!pr->bctx) {
536bf21cd93STycho Nightingale 		pr->ssts = ATA_SS_DET_NO_DEVICE;
537bf21cd93STycho Nightingale 		pr->sig = 0xFFFFFFFF;
538bf21cd93STycho Nightingale 		pr->tfd = 0x7F;
539bf21cd93STycho Nightingale 		return;
540bf21cd93STycho Nightingale 	}
5414c87aefeSPatrick Mooney 	pr->ssts = ATA_SS_DET_PHY_ONLINE | ATA_SS_IPM_ACTIVE;
5424c87aefeSPatrick Mooney 	if (pr->sctl & ATA_SC_SPD_MASK)
5434c87aefeSPatrick Mooney 		pr->ssts |= (pr->sctl & ATA_SC_SPD_MASK);
5444c87aefeSPatrick Mooney 	else
5454c87aefeSPatrick Mooney 		pr->ssts |= ATA_SS_SPD_GEN3;
546bf21cd93STycho Nightingale 	pr->tfd = (1 << 8) | ATA_S_DSC | ATA_S_DMA;
547bf21cd93STycho Nightingale 	if (!pr->atapi) {
548bf21cd93STycho Nightingale 		pr->sig = PxSIG_ATA;
549bf21cd93STycho Nightingale 		pr->tfd |= ATA_S_READY;
550bf21cd93STycho Nightingale 	} else
551bf21cd93STycho Nightingale 		pr->sig = PxSIG_ATAPI;
552bf21cd93STycho Nightingale 	ahci_write_reset_fis_d2h(pr);
553bf21cd93STycho Nightingale }
554bf21cd93STycho Nightingale 
555bf21cd93STycho Nightingale static void
556bf21cd93STycho Nightingale ahci_reset(struct pci_ahci_softc *sc)
557bf21cd93STycho Nightingale {
558bf21cd93STycho Nightingale 	int i;
559bf21cd93STycho Nightingale 
560bf21cd93STycho Nightingale 	sc->ghc = AHCI_GHC_AE;
561bf21cd93STycho Nightingale 	sc->is = 0;
562bf21cd93STycho Nightingale 
563bf21cd93STycho Nightingale 	if (sc->lintr) {
564bf21cd93STycho Nightingale 		pci_lintr_deassert(sc->asc_pi);
565bf21cd93STycho Nightingale 		sc->lintr = 0;
566bf21cd93STycho Nightingale 	}
567bf21cd93STycho Nightingale 
568bf21cd93STycho Nightingale 	for (i = 0; i < sc->ports; i++) {
569bf21cd93STycho Nightingale 		sc->port[i].ie = 0;
570bf21cd93STycho Nightingale 		sc->port[i].is = 0;
5714c87aefeSPatrick Mooney 		sc->port[i].cmd = (AHCI_P_CMD_SUD | AHCI_P_CMD_POD);
5724c87aefeSPatrick Mooney 		if (sc->port[i].bctx)
5734c87aefeSPatrick Mooney 			sc->port[i].cmd |= AHCI_P_CMD_CPS;
5744c87aefeSPatrick Mooney 		sc->port[i].sctl = 0;
575bf21cd93STycho Nightingale 		ahci_port_reset(&sc->port[i]);
576bf21cd93STycho Nightingale 	}
577bf21cd93STycho Nightingale }
578bf21cd93STycho Nightingale 
579bf21cd93STycho Nightingale static void
580bf21cd93STycho Nightingale ata_string(uint8_t *dest, const char *src, int len)
581bf21cd93STycho Nightingale {
582bf21cd93STycho Nightingale 	int i;
583bf21cd93STycho Nightingale 
584bf21cd93STycho Nightingale 	for (i = 0; i < len; i++) {
585bf21cd93STycho Nightingale 		if (*src)
586bf21cd93STycho Nightingale 			dest[i ^ 1] = *src++;
587bf21cd93STycho Nightingale 		else
588bf21cd93STycho Nightingale 			dest[i ^ 1] = ' ';
589bf21cd93STycho Nightingale 	}
590bf21cd93STycho Nightingale }
591bf21cd93STycho Nightingale 
592bf21cd93STycho Nightingale static void
593bf21cd93STycho Nightingale atapi_string(uint8_t *dest, const char *src, int len)
594bf21cd93STycho Nightingale {
595bf21cd93STycho Nightingale 	int i;
596bf21cd93STycho Nightingale 
597bf21cd93STycho Nightingale 	for (i = 0; i < len; i++) {
598bf21cd93STycho Nightingale 		if (*src)
599bf21cd93STycho Nightingale 			dest[i] = *src++;
600bf21cd93STycho Nightingale 		else
601bf21cd93STycho Nightingale 			dest[i] = ' ';
602bf21cd93STycho Nightingale 	}
603bf21cd93STycho Nightingale }
604bf21cd93STycho Nightingale 
6054c87aefeSPatrick Mooney /*
6064c87aefeSPatrick Mooney  * Build up the iovec based on the PRDT, 'done' and 'len'.
6074c87aefeSPatrick Mooney  */
608bf21cd93STycho Nightingale static void
6094c87aefeSPatrick Mooney ahci_build_iov(struct ahci_port *p, struct ahci_ioreq *aior,
6104c87aefeSPatrick Mooney     struct ahci_prdt_entry *prdt, uint16_t prdtl)
6114c87aefeSPatrick Mooney {
6124c87aefeSPatrick Mooney 	struct blockif_req *breq = &aior->io_req;
6134c87aefeSPatrick Mooney 	int i, j, skip, todo, left, extra;
6144c87aefeSPatrick Mooney 	uint32_t dbcsz;
6154c87aefeSPatrick Mooney 
6164c87aefeSPatrick Mooney 	/* Copy part of PRDT between 'done' and 'len' bytes into the iov. */
6174c87aefeSPatrick Mooney 	skip = aior->done;
6184c87aefeSPatrick Mooney 	left = aior->len - aior->done;
6194c87aefeSPatrick Mooney 	todo = 0;
6204c87aefeSPatrick Mooney 	for (i = 0, j = 0; i < prdtl && j < BLOCKIF_IOV_MAX && left > 0;
6214c87aefeSPatrick Mooney 	    i++, prdt++) {
6224c87aefeSPatrick Mooney 		dbcsz = (prdt->dbc & DBCMASK) + 1;
6234c87aefeSPatrick Mooney 		/* Skip already done part of the PRDT */
6244c87aefeSPatrick Mooney 		if (dbcsz <= skip) {
6254c87aefeSPatrick Mooney 			skip -= dbcsz;
6264c87aefeSPatrick Mooney 			continue;
6274c87aefeSPatrick Mooney 		}
6284c87aefeSPatrick Mooney 		dbcsz -= skip;
6294c87aefeSPatrick Mooney 		if (dbcsz > left)
6304c87aefeSPatrick Mooney 			dbcsz = left;
6314c87aefeSPatrick Mooney 		breq->br_iov[j].iov_base = paddr_guest2host(ahci_ctx(p->pr_sc),
6324c87aefeSPatrick Mooney 		    prdt->dba + skip, dbcsz);
6334c87aefeSPatrick Mooney 		breq->br_iov[j].iov_len = dbcsz;
6344c87aefeSPatrick Mooney 		todo += dbcsz;
6354c87aefeSPatrick Mooney 		left -= dbcsz;
6364c87aefeSPatrick Mooney 		skip = 0;
6374c87aefeSPatrick Mooney 		j++;
6384c87aefeSPatrick Mooney 	}
6394c87aefeSPatrick Mooney 
6404c87aefeSPatrick Mooney 	/* If we got limited by IOV length, round I/O down to sector size. */
6414c87aefeSPatrick Mooney 	if (j == BLOCKIF_IOV_MAX) {
6424c87aefeSPatrick Mooney 		extra = todo % blockif_sectsz(p->bctx);
6434c87aefeSPatrick Mooney 		todo -= extra;
6444c87aefeSPatrick Mooney 		assert(todo > 0);
6454c87aefeSPatrick Mooney 		while (extra > 0) {
6464c87aefeSPatrick Mooney 			if (breq->br_iov[j - 1].iov_len > extra) {
6474c87aefeSPatrick Mooney 				breq->br_iov[j - 1].iov_len -= extra;
6484c87aefeSPatrick Mooney 				break;
6494c87aefeSPatrick Mooney 			}
6504c87aefeSPatrick Mooney 			extra -= breq->br_iov[j - 1].iov_len;
6514c87aefeSPatrick Mooney 			j--;
6524c87aefeSPatrick Mooney 		}
6534c87aefeSPatrick Mooney 	}
6544c87aefeSPatrick Mooney 
6554c87aefeSPatrick Mooney 	breq->br_iovcnt = j;
6564c87aefeSPatrick Mooney 	breq->br_resid = todo;
6574c87aefeSPatrick Mooney 	aior->done += todo;
6584c87aefeSPatrick Mooney 	aior->more = (aior->done < aior->len && i < prdtl);
6594c87aefeSPatrick Mooney }
6604c87aefeSPatrick Mooney 
6614c87aefeSPatrick Mooney static void
6624c87aefeSPatrick Mooney ahci_handle_rw(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done)
663bf21cd93STycho Nightingale {
664bf21cd93STycho Nightingale 	struct ahci_ioreq *aior;
665bf21cd93STycho Nightingale 	struct blockif_req *breq;
666bf21cd93STycho Nightingale 	struct ahci_prdt_entry *prdt;
667bf21cd93STycho Nightingale 	struct ahci_cmd_hdr *hdr;
668bf21cd93STycho Nightingale 	uint64_t lba;
669bf21cd93STycho Nightingale 	uint32_t len;
6704c87aefeSPatrick Mooney 	int err, first, ncq, readop;
671bf21cd93STycho Nightingale 
672bf21cd93STycho Nightingale 	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
673bf21cd93STycho Nightingale 	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
674bf21cd93STycho Nightingale 	ncq = 0;
675bf21cd93STycho Nightingale 	readop = 1;
6764c87aefeSPatrick Mooney 	first = (done == 0);
677bf21cd93STycho Nightingale 
6784c87aefeSPatrick Mooney 	if (cfis[2] == ATA_WRITE || cfis[2] == ATA_WRITE48 ||
6794c87aefeSPatrick Mooney 	    cfis[2] == ATA_WRITE_MUL || cfis[2] == ATA_WRITE_MUL48 ||
6804c87aefeSPatrick Mooney 	    cfis[2] == ATA_WRITE_DMA || cfis[2] == ATA_WRITE_DMA48 ||
681bf21cd93STycho Nightingale 	    cfis[2] == ATA_WRITE_FPDMA_QUEUED)
682bf21cd93STycho Nightingale 		readop = 0;
683bf21cd93STycho Nightingale 
684bf21cd93STycho Nightingale 	if (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||
685bf21cd93STycho Nightingale 	    cfis[2] == ATA_READ_FPDMA_QUEUED) {
686bf21cd93STycho Nightingale 		lba = ((uint64_t)cfis[10] << 40) |
687bf21cd93STycho Nightingale 			((uint64_t)cfis[9] << 32) |
688bf21cd93STycho Nightingale 			((uint64_t)cfis[8] << 24) |
689bf21cd93STycho Nightingale 			((uint64_t)cfis[6] << 16) |
690bf21cd93STycho Nightingale 			((uint64_t)cfis[5] << 8) |
691bf21cd93STycho Nightingale 			cfis[4];
692bf21cd93STycho Nightingale 		len = cfis[11] << 8 | cfis[3];
693bf21cd93STycho Nightingale 		if (!len)
694bf21cd93STycho Nightingale 			len = 65536;
695bf21cd93STycho Nightingale 		ncq = 1;
6964c87aefeSPatrick Mooney 	} else if (cfis[2] == ATA_READ48 || cfis[2] == ATA_WRITE48 ||
6974c87aefeSPatrick Mooney 	    cfis[2] == ATA_READ_MUL48 || cfis[2] == ATA_WRITE_MUL48 ||
6984c87aefeSPatrick Mooney 	    cfis[2] == ATA_READ_DMA48 || cfis[2] == ATA_WRITE_DMA48) {
699bf21cd93STycho Nightingale 		lba = ((uint64_t)cfis[10] << 40) |
700bf21cd93STycho Nightingale 			((uint64_t)cfis[9] << 32) |
701bf21cd93STycho Nightingale 			((uint64_t)cfis[8] << 24) |
702bf21cd93STycho Nightingale 			((uint64_t)cfis[6] << 16) |
703bf21cd93STycho Nightingale 			((uint64_t)cfis[5] << 8) |
704bf21cd93STycho Nightingale 			cfis[4];
705bf21cd93STycho Nightingale 		len = cfis[13] << 8 | cfis[12];
706bf21cd93STycho Nightingale 		if (!len)
707bf21cd93STycho Nightingale 			len = 65536;
708bf21cd93STycho Nightingale 	} else {
709bf21cd93STycho Nightingale 		lba = ((cfis[7] & 0xf) << 24) | (cfis[6] << 16) |
710bf21cd93STycho Nightingale 			(cfis[5] << 8) | cfis[4];
711bf21cd93STycho Nightingale 		len = cfis[12];
712bf21cd93STycho Nightingale 		if (!len)
713bf21cd93STycho Nightingale 			len = 256;
714bf21cd93STycho Nightingale 	}
715bf21cd93STycho Nightingale 	lba *= blockif_sectsz(p->bctx);
716bf21cd93STycho Nightingale 	len *= blockif_sectsz(p->bctx);
717bf21cd93STycho Nightingale 
7184c87aefeSPatrick Mooney 	/* Pull request off free list */
719bf21cd93STycho Nightingale 	aior = STAILQ_FIRST(&p->iofhd);
720bf21cd93STycho Nightingale 	assert(aior != NULL);
721bf21cd93STycho Nightingale 	STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
7224c87aefeSPatrick Mooney 
723bf21cd93STycho Nightingale 	aior->cfis = cfis;
724bf21cd93STycho Nightingale 	aior->slot = slot;
725bf21cd93STycho Nightingale 	aior->len = len;
726bf21cd93STycho Nightingale 	aior->done = done;
727bf21cd93STycho Nightingale 	breq = &aior->io_req;
728bf21cd93STycho Nightingale 	breq->br_offset = lba + done;
7294c87aefeSPatrick Mooney 	ahci_build_iov(p, aior, prdt, hdr->prdtl);
730bf21cd93STycho Nightingale 
7314c87aefeSPatrick Mooney 	/* Mark this command in-flight. */
732bf21cd93STycho Nightingale 	p->pending |= 1 << slot;
733bf21cd93STycho Nightingale 
7344c87aefeSPatrick Mooney 	/* Stuff request onto busy list. */
735bf21cd93STycho Nightingale 	TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
736bf21cd93STycho Nightingale 
7374c87aefeSPatrick Mooney 	if (ncq && first)
7384c87aefeSPatrick Mooney 		ahci_write_fis_d2h_ncq(p, slot);
739bf21cd93STycho Nightingale 
740bf21cd93STycho Nightingale 	if (readop)
741bf21cd93STycho Nightingale 		err = blockif_read(p->bctx, breq);
742bf21cd93STycho Nightingale 	else
743bf21cd93STycho Nightingale 		err = blockif_write(p->bctx, breq);
744bf21cd93STycho Nightingale 	assert(err == 0);
745bf21cd93STycho Nightingale }
746bf21cd93STycho Nightingale 
747bf21cd93STycho Nightingale static void
748bf21cd93STycho Nightingale ahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis)
749bf21cd93STycho Nightingale {
750bf21cd93STycho Nightingale 	struct ahci_ioreq *aior;
751bf21cd93STycho Nightingale 	struct blockif_req *breq;
752bf21cd93STycho Nightingale 	int err;
753bf21cd93STycho Nightingale 
754bf21cd93STycho Nightingale 	/*
755bf21cd93STycho Nightingale 	 * Pull request off free list
756bf21cd93STycho Nightingale 	 */
757bf21cd93STycho Nightingale 	aior = STAILQ_FIRST(&p->iofhd);
758bf21cd93STycho Nightingale 	assert(aior != NULL);
759bf21cd93STycho Nightingale 	STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
760bf21cd93STycho Nightingale 	aior->cfis = cfis;
761bf21cd93STycho Nightingale 	aior->slot = slot;
762bf21cd93STycho Nightingale 	aior->len = 0;
763bf21cd93STycho Nightingale 	aior->done = 0;
7644c87aefeSPatrick Mooney 	aior->more = 0;
765bf21cd93STycho Nightingale 	breq = &aior->io_req;
766bf21cd93STycho Nightingale 
767bf21cd93STycho Nightingale 	/*
768bf21cd93STycho Nightingale 	 * Mark this command in-flight.
769bf21cd93STycho Nightingale 	 */
770bf21cd93STycho Nightingale 	p->pending |= 1 << slot;
771bf21cd93STycho Nightingale 
772bf21cd93STycho Nightingale 	/*
773bf21cd93STycho Nightingale 	 * Stuff request onto busy list
774bf21cd93STycho Nightingale 	 */
775bf21cd93STycho Nightingale 	TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
776bf21cd93STycho Nightingale 
777bf21cd93STycho Nightingale 	err = blockif_flush(p->bctx, breq);
778bf21cd93STycho Nightingale 	assert(err == 0);
779bf21cd93STycho Nightingale }
780bf21cd93STycho Nightingale 
781bf21cd93STycho Nightingale static inline void
7824c87aefeSPatrick Mooney read_prdt(struct ahci_port *p, int slot, uint8_t *cfis,
7834c87aefeSPatrick Mooney 		void *buf, int size)
7844c87aefeSPatrick Mooney {
7854c87aefeSPatrick Mooney 	struct ahci_cmd_hdr *hdr;
7864c87aefeSPatrick Mooney 	struct ahci_prdt_entry *prdt;
7874c87aefeSPatrick Mooney 	void *to;
7884c87aefeSPatrick Mooney 	int i, len;
7894c87aefeSPatrick Mooney 
7904c87aefeSPatrick Mooney 	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
7914c87aefeSPatrick Mooney 	len = size;
7924c87aefeSPatrick Mooney 	to = buf;
7934c87aefeSPatrick Mooney 	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
7944c87aefeSPatrick Mooney 	for (i = 0; i < hdr->prdtl && len; i++) {
7954c87aefeSPatrick Mooney 		uint8_t *ptr;
7964c87aefeSPatrick Mooney 		uint32_t dbcsz;
7974c87aefeSPatrick Mooney 		int sublen;
7984c87aefeSPatrick Mooney 
7994c87aefeSPatrick Mooney 		dbcsz = (prdt->dbc & DBCMASK) + 1;
8004c87aefeSPatrick Mooney 		ptr = paddr_guest2host(ahci_ctx(p->pr_sc), prdt->dba, dbcsz);
8014c87aefeSPatrick Mooney 		sublen = MIN(len, dbcsz);
8024c87aefeSPatrick Mooney 		memcpy(to, ptr, sublen);
8034c87aefeSPatrick Mooney 		len -= sublen;
8044c87aefeSPatrick Mooney 		to += sublen;
8054c87aefeSPatrick Mooney 		prdt++;
8064c87aefeSPatrick Mooney 	}
8074c87aefeSPatrick Mooney }
8084c87aefeSPatrick Mooney 
8094c87aefeSPatrick Mooney static void
8104c87aefeSPatrick Mooney ahci_handle_dsm_trim(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done)
8114c87aefeSPatrick Mooney {
8124c87aefeSPatrick Mooney 	struct ahci_ioreq *aior;
8134c87aefeSPatrick Mooney 	struct blockif_req *breq;
8144c87aefeSPatrick Mooney 	uint8_t *entry;
8154c87aefeSPatrick Mooney 	uint64_t elba;
8164c87aefeSPatrick Mooney 	uint32_t len, elen;
8174c87aefeSPatrick Mooney 	int err, first, ncq;
8184c87aefeSPatrick Mooney 	uint8_t buf[512];
8194c87aefeSPatrick Mooney 
8204c87aefeSPatrick Mooney 	first = (done == 0);
8214c87aefeSPatrick Mooney 	if (cfis[2] == ATA_DATA_SET_MANAGEMENT) {
8224c87aefeSPatrick Mooney 		len = (uint16_t)cfis[13] << 8 | cfis[12];
8234c87aefeSPatrick Mooney 		len *= 512;
8244c87aefeSPatrick Mooney 		ncq = 0;
8254c87aefeSPatrick Mooney 	} else { /* ATA_SEND_FPDMA_QUEUED */
8264c87aefeSPatrick Mooney 		len = (uint16_t)cfis[11] << 8 | cfis[3];
8274c87aefeSPatrick Mooney 		len *= 512;
8284c87aefeSPatrick Mooney 		ncq = 1;
8294c87aefeSPatrick Mooney 	}
8304c87aefeSPatrick Mooney 	read_prdt(p, slot, cfis, buf, sizeof(buf));
8314c87aefeSPatrick Mooney 
8324c87aefeSPatrick Mooney next:
8334c87aefeSPatrick Mooney 	entry = &buf[done];
8344c87aefeSPatrick Mooney 	elba = ((uint64_t)entry[5] << 40) |
8354c87aefeSPatrick Mooney 		((uint64_t)entry[4] << 32) |
8364c87aefeSPatrick Mooney 		((uint64_t)entry[3] << 24) |
8374c87aefeSPatrick Mooney 		((uint64_t)entry[2] << 16) |
8384c87aefeSPatrick Mooney 		((uint64_t)entry[1] << 8) |
8394c87aefeSPatrick Mooney 		entry[0];
8404c87aefeSPatrick Mooney 	elen = (uint16_t)entry[7] << 8 | entry[6];
8414c87aefeSPatrick Mooney 	done += 8;
8424c87aefeSPatrick Mooney 	if (elen == 0) {
8434c87aefeSPatrick Mooney 		if (done >= len) {
8444c87aefeSPatrick Mooney 			if (ncq) {
8454c87aefeSPatrick Mooney 				if (first)
8464c87aefeSPatrick Mooney 					ahci_write_fis_d2h_ncq(p, slot);
8474c87aefeSPatrick Mooney 				ahci_write_fis_sdb(p, slot, cfis,
8484c87aefeSPatrick Mooney 				    ATA_S_READY | ATA_S_DSC);
8494c87aefeSPatrick Mooney 			} else {
8504c87aefeSPatrick Mooney 				ahci_write_fis_d2h(p, slot, cfis,
8514c87aefeSPatrick Mooney 				    ATA_S_READY | ATA_S_DSC);
8524c87aefeSPatrick Mooney 			}
8534c87aefeSPatrick Mooney 			p->pending &= ~(1 << slot);
8544c87aefeSPatrick Mooney 			ahci_check_stopped(p);
8554c87aefeSPatrick Mooney 			if (!first)
8564c87aefeSPatrick Mooney 				ahci_handle_port(p);
8574c87aefeSPatrick Mooney 			return;
8584c87aefeSPatrick Mooney 		}
8594c87aefeSPatrick Mooney 		goto next;
8604c87aefeSPatrick Mooney 	}
8614c87aefeSPatrick Mooney 
8624c87aefeSPatrick Mooney 	/*
8634c87aefeSPatrick Mooney 	 * Pull request off free list
8644c87aefeSPatrick Mooney 	 */
8654c87aefeSPatrick Mooney 	aior = STAILQ_FIRST(&p->iofhd);
8664c87aefeSPatrick Mooney 	assert(aior != NULL);
8674c87aefeSPatrick Mooney 	STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
8684c87aefeSPatrick Mooney 	aior->cfis = cfis;
8694c87aefeSPatrick Mooney 	aior->slot = slot;
8704c87aefeSPatrick Mooney 	aior->len = len;
8714c87aefeSPatrick Mooney 	aior->done = done;
8724c87aefeSPatrick Mooney 	aior->more = (len != done);
8734c87aefeSPatrick Mooney 
8744c87aefeSPatrick Mooney 	breq = &aior->io_req;
8754c87aefeSPatrick Mooney 	breq->br_offset = elba * blockif_sectsz(p->bctx);
8764c87aefeSPatrick Mooney 	breq->br_resid = elen * blockif_sectsz(p->bctx);
8774c87aefeSPatrick Mooney 
8784c87aefeSPatrick Mooney 	/*
8794c87aefeSPatrick Mooney 	 * Mark this command in-flight.
8804c87aefeSPatrick Mooney 	 */
8814c87aefeSPatrick Mooney 	p->pending |= 1 << slot;
8824c87aefeSPatrick Mooney 
8834c87aefeSPatrick Mooney 	/*
8844c87aefeSPatrick Mooney 	 * Stuff request onto busy list
8854c87aefeSPatrick Mooney 	 */
8864c87aefeSPatrick Mooney 	TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
8874c87aefeSPatrick Mooney 
8884c87aefeSPatrick Mooney 	if (ncq && first)
8894c87aefeSPatrick Mooney 		ahci_write_fis_d2h_ncq(p, slot);
8904c87aefeSPatrick Mooney 
8914c87aefeSPatrick Mooney 	err = blockif_delete(p->bctx, breq);
8924c87aefeSPatrick Mooney 	assert(err == 0);
8934c87aefeSPatrick Mooney }
8944c87aefeSPatrick Mooney 
8954c87aefeSPatrick Mooney static inline void
896bf21cd93STycho Nightingale write_prdt(struct ahci_port *p, int slot, uint8_t *cfis,
897bf21cd93STycho Nightingale 		void *buf, int size)
898bf21cd93STycho Nightingale {
899bf21cd93STycho Nightingale 	struct ahci_cmd_hdr *hdr;
900bf21cd93STycho Nightingale 	struct ahci_prdt_entry *prdt;
901bf21cd93STycho Nightingale 	void *from;
902bf21cd93STycho Nightingale 	int i, len;
903bf21cd93STycho Nightingale 
904bf21cd93STycho Nightingale 	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
905bf21cd93STycho Nightingale 	len = size;
906bf21cd93STycho Nightingale 	from = buf;
907bf21cd93STycho Nightingale 	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
908bf21cd93STycho Nightingale 	for (i = 0; i < hdr->prdtl && len; i++) {
909bf21cd93STycho Nightingale 		uint8_t *ptr;
910bf21cd93STycho Nightingale 		uint32_t dbcsz;
911bf21cd93STycho Nightingale 		int sublen;
912bf21cd93STycho Nightingale 
913bf21cd93STycho Nightingale 		dbcsz = (prdt->dbc & DBCMASK) + 1;
914bf21cd93STycho Nightingale 		ptr = paddr_guest2host(ahci_ctx(p->pr_sc), prdt->dba, dbcsz);
9154c87aefeSPatrick Mooney 		sublen = MIN(len, dbcsz);
916bf21cd93STycho Nightingale 		memcpy(ptr, from, sublen);
917bf21cd93STycho Nightingale 		len -= sublen;
918bf21cd93STycho Nightingale 		from += sublen;
919bf21cd93STycho Nightingale 		prdt++;
920bf21cd93STycho Nightingale 	}
921bf21cd93STycho Nightingale 	hdr->prdbc = size - len;
922bf21cd93STycho Nightingale }
923bf21cd93STycho Nightingale 
924bf21cd93STycho Nightingale static void
9254c87aefeSPatrick Mooney ahci_checksum(uint8_t *buf, int size)
9264c87aefeSPatrick Mooney {
9274c87aefeSPatrick Mooney 	int i;
9284c87aefeSPatrick Mooney 	uint8_t sum = 0;
9294c87aefeSPatrick Mooney 
9304c87aefeSPatrick Mooney 	for (i = 0; i < size - 1; i++)
9314c87aefeSPatrick Mooney 		sum += buf[i];
9324c87aefeSPatrick Mooney 	buf[size - 1] = 0x100 - sum;
9334c87aefeSPatrick Mooney }
9344c87aefeSPatrick Mooney 
9354c87aefeSPatrick Mooney static void
9364c87aefeSPatrick Mooney ahci_handle_read_log(struct ahci_port *p, int slot, uint8_t *cfis)
9374c87aefeSPatrick Mooney {
9384c87aefeSPatrick Mooney 	struct ahci_cmd_hdr *hdr;
9394c87aefeSPatrick Mooney 	uint32_t buf[128];
9404c87aefeSPatrick Mooney 	uint8_t *buf8 = (uint8_t *)buf;
9414c87aefeSPatrick Mooney 	uint16_t *buf16 = (uint16_t *)buf;
9424c87aefeSPatrick Mooney 
9434c87aefeSPatrick Mooney 	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
9444c87aefeSPatrick Mooney 	if (p->atapi || hdr->prdtl == 0 || cfis[5] != 0 ||
9454c87aefeSPatrick Mooney 	    cfis[9] != 0 || cfis[12] != 1 || cfis[13] != 0) {
9464c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis,
9474c87aefeSPatrick Mooney 		    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
9484c87aefeSPatrick Mooney 		return;
9494c87aefeSPatrick Mooney 	}
9504c87aefeSPatrick Mooney 
9514c87aefeSPatrick Mooney 	memset(buf, 0, sizeof(buf));
9524c87aefeSPatrick Mooney 	if (cfis[4] == 0x00) {	/* Log directory */
9534c87aefeSPatrick Mooney 		buf16[0x00] = 1; /* Version -- 1 */
9544c87aefeSPatrick Mooney 		buf16[0x10] = 1; /* NCQ Command Error Log -- 1 page */
9554c87aefeSPatrick Mooney 		buf16[0x13] = 1; /* SATA NCQ Send and Receive Log -- 1 page */
9564c87aefeSPatrick Mooney 	} else if (cfis[4] == 0x10) {	/* NCQ Command Error Log */
9574c87aefeSPatrick Mooney 		memcpy(buf8, p->err_cfis, sizeof(p->err_cfis));
9584c87aefeSPatrick Mooney 		ahci_checksum(buf8, sizeof(buf));
9594c87aefeSPatrick Mooney 	} else if (cfis[4] == 0x13) {	/* SATA NCQ Send and Receive Log */
9604c87aefeSPatrick Mooney 		if (blockif_candelete(p->bctx) && !blockif_is_ro(p->bctx)) {
9614c87aefeSPatrick Mooney 			buf[0x00] = 1;	/* SFQ DSM supported */
9624c87aefeSPatrick Mooney 			buf[0x01] = 1;	/* SFQ DSM TRIM supported */
9634c87aefeSPatrick Mooney 		}
9644c87aefeSPatrick Mooney 	} else {
9654c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis,
9664c87aefeSPatrick Mooney 		    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
9674c87aefeSPatrick Mooney 		return;
9684c87aefeSPatrick Mooney 	}
9694c87aefeSPatrick Mooney 
9704c87aefeSPatrick Mooney 	if (cfis[2] == ATA_READ_LOG_EXT)
9714c87aefeSPatrick Mooney 		ahci_write_fis_piosetup(p);
9724c87aefeSPatrick Mooney 	write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
9734c87aefeSPatrick Mooney 	ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY);
9744c87aefeSPatrick Mooney }
9754c87aefeSPatrick Mooney 
9764c87aefeSPatrick Mooney static void
977bf21cd93STycho Nightingale handle_identify(struct ahci_port *p, int slot, uint8_t *cfis)
978bf21cd93STycho Nightingale {
979bf21cd93STycho Nightingale 	struct ahci_cmd_hdr *hdr;
980bf21cd93STycho Nightingale 
981bf21cd93STycho Nightingale 	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
982bf21cd93STycho Nightingale 	if (p->atapi || hdr->prdtl == 0) {
9834c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis,
9844c87aefeSPatrick Mooney 		    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
985bf21cd93STycho Nightingale 	} else {
986bf21cd93STycho Nightingale 		uint16_t buf[256];
987bf21cd93STycho Nightingale 		uint64_t sectors;
9884c87aefeSPatrick Mooney 		int sectsz, psectsz, psectoff, candelete, ro;
989bf21cd93STycho Nightingale 		uint16_t cyl;
990bf21cd93STycho Nightingale 		uint8_t sech, heads;
991bf21cd93STycho Nightingale 
9924c87aefeSPatrick Mooney 		ro = blockif_is_ro(p->bctx);
9934c87aefeSPatrick Mooney 		candelete = blockif_candelete(p->bctx);
9944c87aefeSPatrick Mooney 		sectsz = blockif_sectsz(p->bctx);
9954c87aefeSPatrick Mooney 		sectors = blockif_size(p->bctx) / sectsz;
996bf21cd93STycho Nightingale 		blockif_chs(p->bctx, &cyl, &heads, &sech);
9974c87aefeSPatrick Mooney 		blockif_psectsz(p->bctx, &psectsz, &psectoff);
998bf21cd93STycho Nightingale 		memset(buf, 0, sizeof(buf));
999bf21cd93STycho Nightingale 		buf[0] = 0x0040;
1000bf21cd93STycho Nightingale 		buf[1] = cyl;
1001bf21cd93STycho Nightingale 		buf[3] = heads;
1002bf21cd93STycho Nightingale 		buf[6] = sech;
10034c87aefeSPatrick Mooney 		ata_string((uint8_t *)(buf+10), p->ident, 20);
1004bf21cd93STycho Nightingale 		ata_string((uint8_t *)(buf+23), "001", 8);
1005bf21cd93STycho Nightingale 		ata_string((uint8_t *)(buf+27), "BHYVE SATA DISK", 40);
1006bf21cd93STycho Nightingale 		buf[47] = (0x8000 | 128);
10074c87aefeSPatrick Mooney 		buf[48] = 0;
1008bf21cd93STycho Nightingale 		buf[49] = (1 << 8 | 1 << 9 | 1 << 11);
1009bf21cd93STycho Nightingale 		buf[50] = (1 << 14);
1010bf21cd93STycho Nightingale 		buf[53] = (1 << 1 | 1 << 2);
1011bf21cd93STycho Nightingale 		if (p->mult_sectors)
1012bf21cd93STycho Nightingale 			buf[59] = (0x100 | p->mult_sectors);
10134c87aefeSPatrick Mooney 		if (sectors <= 0x0fffffff) {
1014bf21cd93STycho Nightingale 			buf[60] = sectors;
1015bf21cd93STycho Nightingale 			buf[61] = (sectors >> 16);
10164c87aefeSPatrick Mooney 		} else {
10174c87aefeSPatrick Mooney 			buf[60] = 0xffff;
10184c87aefeSPatrick Mooney 			buf[61] = 0x0fff;
10194c87aefeSPatrick Mooney 		}
1020bf21cd93STycho Nightingale 		buf[63] = 0x7;
1021bf21cd93STycho Nightingale 		if (p->xfermode & ATA_WDMA0)
1022bf21cd93STycho Nightingale 			buf[63] |= (1 << ((p->xfermode & 7) + 8));
1023bf21cd93STycho Nightingale 		buf[64] = 0x3;
10244c87aefeSPatrick Mooney 		buf[65] = 120;
10254c87aefeSPatrick Mooney 		buf[66] = 120;
10264c87aefeSPatrick Mooney 		buf[67] = 120;
10274c87aefeSPatrick Mooney 		buf[68] = 120;
10284c87aefeSPatrick Mooney 		buf[69] = 0;
1029bf21cd93STycho Nightingale 		buf[75] = 31;
10304c87aefeSPatrick Mooney 		buf[76] = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3 |
10314c87aefeSPatrick Mooney 			   ATA_SUPPORT_NCQ);
10324c87aefeSPatrick Mooney 		buf[77] = (ATA_SUPPORT_RCVSND_FPDMA_QUEUED |
10334c87aefeSPatrick Mooney 			   (p->ssts & ATA_SS_SPD_MASK) >> 3);
10344c87aefeSPatrick Mooney 		buf[80] = 0x3f0;
1035bf21cd93STycho Nightingale 		buf[81] = 0x28;
10364c87aefeSPatrick Mooney 		buf[82] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE|
10374c87aefeSPatrick Mooney 			   ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP);
10384c87aefeSPatrick Mooney 		buf[83] = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE |
10394c87aefeSPatrick Mooney 			   ATA_SUPPORT_FLUSHCACHE48 | 1 << 14);
1040bf21cd93STycho Nightingale 		buf[84] = (1 << 14);
10414c87aefeSPatrick Mooney 		buf[85] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE|
10424c87aefeSPatrick Mooney 			   ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP);
10434c87aefeSPatrick Mooney 		buf[86] = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE |
10444c87aefeSPatrick Mooney 			   ATA_SUPPORT_FLUSHCACHE48 | 1 << 15);
1045bf21cd93STycho Nightingale 		buf[87] = (1 << 14);
1046bf21cd93STycho Nightingale 		buf[88] = 0x7f;
1047bf21cd93STycho Nightingale 		if (p->xfermode & ATA_UDMA0)
1048bf21cd93STycho Nightingale 			buf[88] |= (1 << ((p->xfermode & 7) + 8));
1049bf21cd93STycho Nightingale 		buf[100] = sectors;
1050bf21cd93STycho Nightingale 		buf[101] = (sectors >> 16);
1051bf21cd93STycho Nightingale 		buf[102] = (sectors >> 32);
1052bf21cd93STycho Nightingale 		buf[103] = (sectors >> 48);
10534c87aefeSPatrick Mooney 		if (candelete && !ro) {
10544c87aefeSPatrick Mooney 			buf[69] |= ATA_SUPPORT_RZAT | ATA_SUPPORT_DRAT;
10554c87aefeSPatrick Mooney 			buf[105] = 1;
10564c87aefeSPatrick Mooney 			buf[169] = ATA_SUPPORT_DSM_TRIM;
10574c87aefeSPatrick Mooney 		}
10584c87aefeSPatrick Mooney 		buf[106] = 0x4000;
10594c87aefeSPatrick Mooney 		buf[209] = 0x4000;
10604c87aefeSPatrick Mooney 		if (psectsz > sectsz) {
10614c87aefeSPatrick Mooney 			buf[106] |= 0x2000;
10624c87aefeSPatrick Mooney 			buf[106] |= ffsl(psectsz / sectsz) - 1;
10634c87aefeSPatrick Mooney 			buf[209] |= (psectoff / sectsz);
10644c87aefeSPatrick Mooney 		}
10654c87aefeSPatrick Mooney 		if (sectsz > 512) {
10664c87aefeSPatrick Mooney 			buf[106] |= 0x1000;
10674c87aefeSPatrick Mooney 			buf[117] = sectsz / 2;
10684c87aefeSPatrick Mooney 			buf[118] = ((sectsz / 2) >> 16);
10694c87aefeSPatrick Mooney 		}
10704c87aefeSPatrick Mooney 		buf[119] = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14);
10714c87aefeSPatrick Mooney 		buf[120] = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14);
10724c87aefeSPatrick Mooney 		buf[222] = 0x1020;
10734c87aefeSPatrick Mooney 		buf[255] = 0x00a5;
10744c87aefeSPatrick Mooney 		ahci_checksum((uint8_t *)buf, sizeof(buf));
1075bf21cd93STycho Nightingale 		ahci_write_fis_piosetup(p);
1076bf21cd93STycho Nightingale 		write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
10774c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY);
1078bf21cd93STycho Nightingale 	}
1079bf21cd93STycho Nightingale }
1080bf21cd93STycho Nightingale 
1081bf21cd93STycho Nightingale static void
1082bf21cd93STycho Nightingale handle_atapi_identify(struct ahci_port *p, int slot, uint8_t *cfis)
1083bf21cd93STycho Nightingale {
1084bf21cd93STycho Nightingale 	if (!p->atapi) {
10854c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis,
10864c87aefeSPatrick Mooney 		    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
1087bf21cd93STycho Nightingale 	} else {
1088bf21cd93STycho Nightingale 		uint16_t buf[256];
1089bf21cd93STycho Nightingale 
1090bf21cd93STycho Nightingale 		memset(buf, 0, sizeof(buf));
1091bf21cd93STycho Nightingale 		buf[0] = (2 << 14 | 5 << 8 | 1 << 7 | 2 << 5);
10924c87aefeSPatrick Mooney 		ata_string((uint8_t *)(buf+10), p->ident, 20);
1093bf21cd93STycho Nightingale 		ata_string((uint8_t *)(buf+23), "001", 8);
1094bf21cd93STycho Nightingale 		ata_string((uint8_t *)(buf+27), "BHYVE SATA DVD ROM", 40);
1095bf21cd93STycho Nightingale 		buf[49] = (1 << 9 | 1 << 8);
1096bf21cd93STycho Nightingale 		buf[50] = (1 << 14 | 1);
1097bf21cd93STycho Nightingale 		buf[53] = (1 << 2 | 1 << 1);
1098bf21cd93STycho Nightingale 		buf[62] = 0x3f;
1099bf21cd93STycho Nightingale 		buf[63] = 7;
11004c87aefeSPatrick Mooney 		if (p->xfermode & ATA_WDMA0)
11014c87aefeSPatrick Mooney 			buf[63] |= (1 << ((p->xfermode & 7) + 8));
1102bf21cd93STycho Nightingale 		buf[64] = 3;
11034c87aefeSPatrick Mooney 		buf[65] = 120;
11044c87aefeSPatrick Mooney 		buf[66] = 120;
11054c87aefeSPatrick Mooney 		buf[67] = 120;
11064c87aefeSPatrick Mooney 		buf[68] = 120;
11074c87aefeSPatrick Mooney 		buf[76] = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3);
11084c87aefeSPatrick Mooney 		buf[77] = ((p->ssts & ATA_SS_SPD_MASK) >> 3);
1109bf21cd93STycho Nightingale 		buf[78] = (1 << 5);
11104c87aefeSPatrick Mooney 		buf[80] = 0x3f0;
11114c87aefeSPatrick Mooney 		buf[82] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET |
11124c87aefeSPatrick Mooney 			   ATA_SUPPORT_RESET | ATA_SUPPORT_NOP);
1113bf21cd93STycho Nightingale 		buf[83] = (1 << 14);
1114bf21cd93STycho Nightingale 		buf[84] = (1 << 14);
11154c87aefeSPatrick Mooney 		buf[85] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET |
11164c87aefeSPatrick Mooney 			   ATA_SUPPORT_RESET | ATA_SUPPORT_NOP);
1117bf21cd93STycho Nightingale 		buf[87] = (1 << 14);
11184c87aefeSPatrick Mooney 		buf[88] = 0x7f;
11194c87aefeSPatrick Mooney 		if (p->xfermode & ATA_UDMA0)
11204c87aefeSPatrick Mooney 			buf[88] |= (1 << ((p->xfermode & 7) + 8));
11214c87aefeSPatrick Mooney 		buf[222] = 0x1020;
11224c87aefeSPatrick Mooney 		buf[255] = 0x00a5;
11234c87aefeSPatrick Mooney 		ahci_checksum((uint8_t *)buf, sizeof(buf));
1124bf21cd93STycho Nightingale 		ahci_write_fis_piosetup(p);
1125bf21cd93STycho Nightingale 		write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
11264c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY);
1127bf21cd93STycho Nightingale 	}
1128bf21cd93STycho Nightingale }
1129bf21cd93STycho Nightingale 
1130bf21cd93STycho Nightingale static void
1131bf21cd93STycho Nightingale atapi_inquiry(struct ahci_port *p, int slot, uint8_t *cfis)
1132bf21cd93STycho Nightingale {
1133bf21cd93STycho Nightingale 	uint8_t buf[36];
1134bf21cd93STycho Nightingale 	uint8_t *acmd;
1135bf21cd93STycho Nightingale 	int len;
11364c87aefeSPatrick Mooney 	uint32_t tfd;
1137bf21cd93STycho Nightingale 
1138bf21cd93STycho Nightingale 	acmd = cfis + 0x40;
1139bf21cd93STycho Nightingale 
11404c87aefeSPatrick Mooney 	if (acmd[1] & 1) {		/* VPD */
11414c87aefeSPatrick Mooney 		if (acmd[2] == 0) {	/* Supported VPD pages */
11424c87aefeSPatrick Mooney 			buf[0] = 0x05;
11434c87aefeSPatrick Mooney 			buf[1] = 0;
11444c87aefeSPatrick Mooney 			buf[2] = 0;
11454c87aefeSPatrick Mooney 			buf[3] = 1;
11464c87aefeSPatrick Mooney 			buf[4] = 0;
11474c87aefeSPatrick Mooney 			len = 4 + buf[3];
11484c87aefeSPatrick Mooney 		} else {
11494c87aefeSPatrick Mooney 			p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
11504c87aefeSPatrick Mooney 			p->asc = 0x24;
11514c87aefeSPatrick Mooney 			tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
11524c87aefeSPatrick Mooney 			cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
11534c87aefeSPatrick Mooney 			ahci_write_fis_d2h(p, slot, cfis, tfd);
11544c87aefeSPatrick Mooney 			return;
11554c87aefeSPatrick Mooney 		}
11564c87aefeSPatrick Mooney 	} else {
1157bf21cd93STycho Nightingale 		buf[0] = 0x05;
1158bf21cd93STycho Nightingale 		buf[1] = 0x80;
1159bf21cd93STycho Nightingale 		buf[2] = 0x00;
1160bf21cd93STycho Nightingale 		buf[3] = 0x21;
1161bf21cd93STycho Nightingale 		buf[4] = 31;
1162bf21cd93STycho Nightingale 		buf[5] = 0;
1163bf21cd93STycho Nightingale 		buf[6] = 0;
1164bf21cd93STycho Nightingale 		buf[7] = 0;
1165bf21cd93STycho Nightingale 		atapi_string(buf + 8, "BHYVE", 8);
1166bf21cd93STycho Nightingale 		atapi_string(buf + 16, "BHYVE DVD-ROM", 16);
1167bf21cd93STycho Nightingale 		atapi_string(buf + 32, "001", 4);
1168bf21cd93STycho Nightingale 		len = sizeof(buf);
11694c87aefeSPatrick Mooney 	}
11704c87aefeSPatrick Mooney 
1171bf21cd93STycho Nightingale 	if (len > acmd[4])
1172bf21cd93STycho Nightingale 		len = acmd[4];
1173bf21cd93STycho Nightingale 	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1174bf21cd93STycho Nightingale 	write_prdt(p, slot, cfis, buf, len);
1175bf21cd93STycho Nightingale 	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1176bf21cd93STycho Nightingale }
1177bf21cd93STycho Nightingale 
1178bf21cd93STycho Nightingale static void
1179bf21cd93STycho Nightingale atapi_read_capacity(struct ahci_port *p, int slot, uint8_t *cfis)
1180bf21cd93STycho Nightingale {
1181bf21cd93STycho Nightingale 	uint8_t buf[8];
1182bf21cd93STycho Nightingale 	uint64_t sectors;
1183bf21cd93STycho Nightingale 
1184bf21cd93STycho Nightingale 	sectors = blockif_size(p->bctx) / 2048;
1185bf21cd93STycho Nightingale 	be32enc(buf, sectors - 1);
1186bf21cd93STycho Nightingale 	be32enc(buf + 4, 2048);
1187bf21cd93STycho Nightingale 	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1188bf21cd93STycho Nightingale 	write_prdt(p, slot, cfis, buf, sizeof(buf));
1189bf21cd93STycho Nightingale 	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1190bf21cd93STycho Nightingale }
1191bf21cd93STycho Nightingale 
1192bf21cd93STycho Nightingale static void
1193bf21cd93STycho Nightingale atapi_read_toc(struct ahci_port *p, int slot, uint8_t *cfis)
1194bf21cd93STycho Nightingale {
1195bf21cd93STycho Nightingale 	uint8_t *acmd;
1196bf21cd93STycho Nightingale 	uint8_t format;
1197bf21cd93STycho Nightingale 	int len;
1198bf21cd93STycho Nightingale 
1199bf21cd93STycho Nightingale 	acmd = cfis + 0x40;
1200bf21cd93STycho Nightingale 
1201bf21cd93STycho Nightingale 	len = be16dec(acmd + 7);
1202bf21cd93STycho Nightingale 	format = acmd[9] >> 6;
1203bf21cd93STycho Nightingale 	switch (format) {
1204bf21cd93STycho Nightingale 	case 0:
1205bf21cd93STycho Nightingale 	{
1206bf21cd93STycho Nightingale 		int msf, size;
1207bf21cd93STycho Nightingale 		uint64_t sectors;
1208bf21cd93STycho Nightingale 		uint8_t start_track, buf[20], *bp;
1209bf21cd93STycho Nightingale 
1210bf21cd93STycho Nightingale 		msf = (acmd[1] >> 1) & 1;
1211bf21cd93STycho Nightingale 		start_track = acmd[6];
1212bf21cd93STycho Nightingale 		if (start_track > 1 && start_track != 0xaa) {
1213bf21cd93STycho Nightingale 			uint32_t tfd;
1214bf21cd93STycho Nightingale 			p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1215bf21cd93STycho Nightingale 			p->asc = 0x24;
1216bf21cd93STycho Nightingale 			tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1217bf21cd93STycho Nightingale 			cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1218bf21cd93STycho Nightingale 			ahci_write_fis_d2h(p, slot, cfis, tfd);
1219bf21cd93STycho Nightingale 			return;
1220bf21cd93STycho Nightingale 		}
1221bf21cd93STycho Nightingale 		bp = buf + 2;
1222bf21cd93STycho Nightingale 		*bp++ = 1;
1223bf21cd93STycho Nightingale 		*bp++ = 1;
1224bf21cd93STycho Nightingale 		if (start_track <= 1) {
1225bf21cd93STycho Nightingale 			*bp++ = 0;
1226bf21cd93STycho Nightingale 			*bp++ = 0x14;
1227bf21cd93STycho Nightingale 			*bp++ = 1;
1228bf21cd93STycho Nightingale 			*bp++ = 0;
1229bf21cd93STycho Nightingale 			if (msf) {
1230bf21cd93STycho Nightingale 				*bp++ = 0;
1231bf21cd93STycho Nightingale 				lba_to_msf(bp, 0);
1232bf21cd93STycho Nightingale 				bp += 3;
1233bf21cd93STycho Nightingale 			} else {
1234bf21cd93STycho Nightingale 				*bp++ = 0;
1235bf21cd93STycho Nightingale 				*bp++ = 0;
1236bf21cd93STycho Nightingale 				*bp++ = 0;
1237bf21cd93STycho Nightingale 				*bp++ = 0;
1238bf21cd93STycho Nightingale 			}
1239bf21cd93STycho Nightingale 		}
1240bf21cd93STycho Nightingale 		*bp++ = 0;
1241bf21cd93STycho Nightingale 		*bp++ = 0x14;
1242bf21cd93STycho Nightingale 		*bp++ = 0xaa;
1243bf21cd93STycho Nightingale 		*bp++ = 0;
1244bf21cd93STycho Nightingale 		sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
1245bf21cd93STycho Nightingale 		sectors >>= 2;
1246bf21cd93STycho Nightingale 		if (msf) {
1247bf21cd93STycho Nightingale 			*bp++ = 0;
1248bf21cd93STycho Nightingale 			lba_to_msf(bp, sectors);
1249bf21cd93STycho Nightingale 			bp += 3;
1250bf21cd93STycho Nightingale 		} else {
1251bf21cd93STycho Nightingale 			be32enc(bp, sectors);
1252bf21cd93STycho Nightingale 			bp += 4;
1253bf21cd93STycho Nightingale 		}
1254bf21cd93STycho Nightingale 		size = bp - buf;
1255bf21cd93STycho Nightingale 		be16enc(buf, size - 2);
1256bf21cd93STycho Nightingale 		if (len > size)
1257bf21cd93STycho Nightingale 			len = size;
1258bf21cd93STycho Nightingale 		write_prdt(p, slot, cfis, buf, len);
1259bf21cd93STycho Nightingale 		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1260bf21cd93STycho Nightingale 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1261bf21cd93STycho Nightingale 		break;
1262bf21cd93STycho Nightingale 	}
1263bf21cd93STycho Nightingale 	case 1:
1264bf21cd93STycho Nightingale 	{
1265bf21cd93STycho Nightingale 		uint8_t buf[12];
1266bf21cd93STycho Nightingale 
1267bf21cd93STycho Nightingale 		memset(buf, 0, sizeof(buf));
1268bf21cd93STycho Nightingale 		buf[1] = 0xa;
1269bf21cd93STycho Nightingale 		buf[2] = 0x1;
1270bf21cd93STycho Nightingale 		buf[3] = 0x1;
1271bf21cd93STycho Nightingale 		if (len > sizeof(buf))
1272bf21cd93STycho Nightingale 			len = sizeof(buf);
1273bf21cd93STycho Nightingale 		write_prdt(p, slot, cfis, buf, len);
1274bf21cd93STycho Nightingale 		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1275bf21cd93STycho Nightingale 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1276bf21cd93STycho Nightingale 		break;
1277bf21cd93STycho Nightingale 	}
1278bf21cd93STycho Nightingale 	case 2:
1279bf21cd93STycho Nightingale 	{
1280bf21cd93STycho Nightingale 		int msf, size;
1281bf21cd93STycho Nightingale 		uint64_t sectors;
12824c87aefeSPatrick Mooney 		uint8_t *bp, buf[50];
1283bf21cd93STycho Nightingale 
1284bf21cd93STycho Nightingale 		msf = (acmd[1] >> 1) & 1;
1285bf21cd93STycho Nightingale 		bp = buf + 2;
1286bf21cd93STycho Nightingale 		*bp++ = 1;
1287bf21cd93STycho Nightingale 		*bp++ = 1;
1288bf21cd93STycho Nightingale 
1289bf21cd93STycho Nightingale 		*bp++ = 1;
1290bf21cd93STycho Nightingale 		*bp++ = 0x14;
1291bf21cd93STycho Nightingale 		*bp++ = 0;
1292bf21cd93STycho Nightingale 		*bp++ = 0xa0;
1293bf21cd93STycho Nightingale 		*bp++ = 0;
1294bf21cd93STycho Nightingale 		*bp++ = 0;
1295bf21cd93STycho Nightingale 		*bp++ = 0;
1296bf21cd93STycho Nightingale 		*bp++ = 0;
1297bf21cd93STycho Nightingale 		*bp++ = 1;
1298bf21cd93STycho Nightingale 		*bp++ = 0;
1299bf21cd93STycho Nightingale 		*bp++ = 0;
1300bf21cd93STycho Nightingale 
1301bf21cd93STycho Nightingale 		*bp++ = 1;
1302bf21cd93STycho Nightingale 		*bp++ = 0x14;
1303bf21cd93STycho Nightingale 		*bp++ = 0;
1304bf21cd93STycho Nightingale 		*bp++ = 0xa1;
1305bf21cd93STycho Nightingale 		*bp++ = 0;
1306bf21cd93STycho Nightingale 		*bp++ = 0;
1307bf21cd93STycho Nightingale 		*bp++ = 0;
1308bf21cd93STycho Nightingale 		*bp++ = 0;
1309bf21cd93STycho Nightingale 		*bp++ = 1;
1310bf21cd93STycho Nightingale 		*bp++ = 0;
1311bf21cd93STycho Nightingale 		*bp++ = 0;
1312bf21cd93STycho Nightingale 
1313bf21cd93STycho Nightingale 		*bp++ = 1;
1314bf21cd93STycho Nightingale 		*bp++ = 0x14;
1315bf21cd93STycho Nightingale 		*bp++ = 0;
1316bf21cd93STycho Nightingale 		*bp++ = 0xa2;
1317bf21cd93STycho Nightingale 		*bp++ = 0;
1318bf21cd93STycho Nightingale 		*bp++ = 0;
1319bf21cd93STycho Nightingale 		*bp++ = 0;
1320bf21cd93STycho Nightingale 		sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx);
1321bf21cd93STycho Nightingale 		sectors >>= 2;
1322bf21cd93STycho Nightingale 		if (msf) {
1323bf21cd93STycho Nightingale 			*bp++ = 0;
1324bf21cd93STycho Nightingale 			lba_to_msf(bp, sectors);
1325bf21cd93STycho Nightingale 			bp += 3;
1326bf21cd93STycho Nightingale 		} else {
1327bf21cd93STycho Nightingale 			be32enc(bp, sectors);
1328bf21cd93STycho Nightingale 			bp += 4;
1329bf21cd93STycho Nightingale 		}
1330bf21cd93STycho Nightingale 
1331bf21cd93STycho Nightingale 		*bp++ = 1;
1332bf21cd93STycho Nightingale 		*bp++ = 0x14;
1333bf21cd93STycho Nightingale 		*bp++ = 0;
1334bf21cd93STycho Nightingale 		*bp++ = 1;
1335bf21cd93STycho Nightingale 		*bp++ = 0;
1336bf21cd93STycho Nightingale 		*bp++ = 0;
1337bf21cd93STycho Nightingale 		*bp++ = 0;
1338bf21cd93STycho Nightingale 		if (msf) {
1339bf21cd93STycho Nightingale 			*bp++ = 0;
1340bf21cd93STycho Nightingale 			lba_to_msf(bp, 0);
1341bf21cd93STycho Nightingale 			bp += 3;
1342bf21cd93STycho Nightingale 		} else {
1343bf21cd93STycho Nightingale 			*bp++ = 0;
1344bf21cd93STycho Nightingale 			*bp++ = 0;
1345bf21cd93STycho Nightingale 			*bp++ = 0;
1346bf21cd93STycho Nightingale 			*bp++ = 0;
1347bf21cd93STycho Nightingale 		}
1348bf21cd93STycho Nightingale 
1349bf21cd93STycho Nightingale 		size = bp - buf;
1350bf21cd93STycho Nightingale 		be16enc(buf, size - 2);
1351bf21cd93STycho Nightingale 		if (len > size)
1352bf21cd93STycho Nightingale 			len = size;
1353bf21cd93STycho Nightingale 		write_prdt(p, slot, cfis, buf, len);
1354bf21cd93STycho Nightingale 		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1355bf21cd93STycho Nightingale 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1356bf21cd93STycho Nightingale 		break;
1357bf21cd93STycho Nightingale 	}
1358bf21cd93STycho Nightingale 	default:
1359bf21cd93STycho Nightingale 	{
1360bf21cd93STycho Nightingale 		uint32_t tfd;
1361bf21cd93STycho Nightingale 
1362bf21cd93STycho Nightingale 		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1363bf21cd93STycho Nightingale 		p->asc = 0x24;
1364bf21cd93STycho Nightingale 		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1365bf21cd93STycho Nightingale 		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1366bf21cd93STycho Nightingale 		ahci_write_fis_d2h(p, slot, cfis, tfd);
1367bf21cd93STycho Nightingale 		break;
1368bf21cd93STycho Nightingale 	}
1369bf21cd93STycho Nightingale 	}
1370bf21cd93STycho Nightingale }
1371bf21cd93STycho Nightingale 
1372bf21cd93STycho Nightingale static void
13734c87aefeSPatrick Mooney atapi_report_luns(struct ahci_port *p, int slot, uint8_t *cfis)
13744c87aefeSPatrick Mooney {
13754c87aefeSPatrick Mooney 	uint8_t buf[16];
13764c87aefeSPatrick Mooney 
13774c87aefeSPatrick Mooney 	memset(buf, 0, sizeof(buf));
13784c87aefeSPatrick Mooney 	buf[3] = 8;
13794c87aefeSPatrick Mooney 
13804c87aefeSPatrick Mooney 	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
13814c87aefeSPatrick Mooney 	write_prdt(p, slot, cfis, buf, sizeof(buf));
13824c87aefeSPatrick Mooney 	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
13834c87aefeSPatrick Mooney }
13844c87aefeSPatrick Mooney 
13854c87aefeSPatrick Mooney static void
13864c87aefeSPatrick Mooney atapi_read(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done)
1387bf21cd93STycho Nightingale {
1388bf21cd93STycho Nightingale 	struct ahci_ioreq *aior;
1389bf21cd93STycho Nightingale 	struct ahci_cmd_hdr *hdr;
1390bf21cd93STycho Nightingale 	struct ahci_prdt_entry *prdt;
1391bf21cd93STycho Nightingale 	struct blockif_req *breq;
1392bf21cd93STycho Nightingale 	uint8_t *acmd;
1393bf21cd93STycho Nightingale 	uint64_t lba;
1394bf21cd93STycho Nightingale 	uint32_t len;
13954c87aefeSPatrick Mooney 	int err;
1396bf21cd93STycho Nightingale 
1397bf21cd93STycho Nightingale 	acmd = cfis + 0x40;
1398bf21cd93STycho Nightingale 	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
1399bf21cd93STycho Nightingale 	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
1400bf21cd93STycho Nightingale 
1401bf21cd93STycho Nightingale 	lba = be32dec(acmd + 2);
1402bf21cd93STycho Nightingale 	if (acmd[0] == READ_10)
1403bf21cd93STycho Nightingale 		len = be16dec(acmd + 7);
1404bf21cd93STycho Nightingale 	else
1405bf21cd93STycho Nightingale 		len = be32dec(acmd + 6);
1406bf21cd93STycho Nightingale 	if (len == 0) {
1407bf21cd93STycho Nightingale 		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1408bf21cd93STycho Nightingale 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1409bf21cd93STycho Nightingale 	}
1410bf21cd93STycho Nightingale 	lba *= 2048;
1411bf21cd93STycho Nightingale 	len *= 2048;
1412bf21cd93STycho Nightingale 
1413bf21cd93STycho Nightingale 	/*
1414bf21cd93STycho Nightingale 	 * Pull request off free list
1415bf21cd93STycho Nightingale 	 */
1416bf21cd93STycho Nightingale 	aior = STAILQ_FIRST(&p->iofhd);
1417bf21cd93STycho Nightingale 	assert(aior != NULL);
1418bf21cd93STycho Nightingale 	STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
1419bf21cd93STycho Nightingale 	aior->cfis = cfis;
1420bf21cd93STycho Nightingale 	aior->slot = slot;
1421bf21cd93STycho Nightingale 	aior->len = len;
1422bf21cd93STycho Nightingale 	aior->done = done;
1423bf21cd93STycho Nightingale 	breq = &aior->io_req;
1424bf21cd93STycho Nightingale 	breq->br_offset = lba + done;
14254c87aefeSPatrick Mooney 	ahci_build_iov(p, aior, prdt, hdr->prdtl);
1426bf21cd93STycho Nightingale 
14274c87aefeSPatrick Mooney 	/* Mark this command in-flight. */
1428bf21cd93STycho Nightingale 	p->pending |= 1 << slot;
1429bf21cd93STycho Nightingale 
14304c87aefeSPatrick Mooney 	/* Stuff request onto busy list. */
1431bf21cd93STycho Nightingale 	TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
1432bf21cd93STycho Nightingale 
1433bf21cd93STycho Nightingale 	err = blockif_read(p->bctx, breq);
1434bf21cd93STycho Nightingale 	assert(err == 0);
1435bf21cd93STycho Nightingale }
1436bf21cd93STycho Nightingale 
1437bf21cd93STycho Nightingale static void
1438bf21cd93STycho Nightingale atapi_request_sense(struct ahci_port *p, int slot, uint8_t *cfis)
1439bf21cd93STycho Nightingale {
1440bf21cd93STycho Nightingale 	uint8_t buf[64];
1441bf21cd93STycho Nightingale 	uint8_t *acmd;
1442bf21cd93STycho Nightingale 	int len;
1443bf21cd93STycho Nightingale 
1444bf21cd93STycho Nightingale 	acmd = cfis + 0x40;
1445bf21cd93STycho Nightingale 	len = acmd[4];
1446bf21cd93STycho Nightingale 	if (len > sizeof(buf))
1447bf21cd93STycho Nightingale 		len = sizeof(buf);
1448bf21cd93STycho Nightingale 	memset(buf, 0, len);
1449bf21cd93STycho Nightingale 	buf[0] = 0x70 | (1 << 7);
1450bf21cd93STycho Nightingale 	buf[2] = p->sense_key;
1451bf21cd93STycho Nightingale 	buf[7] = 10;
1452bf21cd93STycho Nightingale 	buf[12] = p->asc;
1453bf21cd93STycho Nightingale 	write_prdt(p, slot, cfis, buf, len);
1454bf21cd93STycho Nightingale 	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1455bf21cd93STycho Nightingale 	ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1456bf21cd93STycho Nightingale }
1457bf21cd93STycho Nightingale 
1458bf21cd93STycho Nightingale static void
1459bf21cd93STycho Nightingale atapi_start_stop_unit(struct ahci_port *p, int slot, uint8_t *cfis)
1460bf21cd93STycho Nightingale {
1461bf21cd93STycho Nightingale 	uint8_t *acmd = cfis + 0x40;
1462bf21cd93STycho Nightingale 	uint32_t tfd;
1463bf21cd93STycho Nightingale 
1464bf21cd93STycho Nightingale 	switch (acmd[4] & 3) {
1465bf21cd93STycho Nightingale 	case 0:
1466bf21cd93STycho Nightingale 	case 1:
1467bf21cd93STycho Nightingale 	case 3:
1468bf21cd93STycho Nightingale 		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1469bf21cd93STycho Nightingale 		tfd = ATA_S_READY | ATA_S_DSC;
1470bf21cd93STycho Nightingale 		break;
1471bf21cd93STycho Nightingale 	case 2:
1472bf21cd93STycho Nightingale 		/* TODO eject media */
1473bf21cd93STycho Nightingale 		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1474bf21cd93STycho Nightingale 		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1475bf21cd93STycho Nightingale 		p->asc = 0x53;
1476bf21cd93STycho Nightingale 		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1477bf21cd93STycho Nightingale 		break;
1478bf21cd93STycho Nightingale 	}
1479bf21cd93STycho Nightingale 	ahci_write_fis_d2h(p, slot, cfis, tfd);
1480bf21cd93STycho Nightingale }
1481bf21cd93STycho Nightingale 
1482bf21cd93STycho Nightingale static void
1483bf21cd93STycho Nightingale atapi_mode_sense(struct ahci_port *p, int slot, uint8_t *cfis)
1484bf21cd93STycho Nightingale {
1485bf21cd93STycho Nightingale 	uint8_t *acmd;
14864c87aefeSPatrick Mooney 	uint32_t tfd = 0;
1487bf21cd93STycho Nightingale 	uint8_t pc, code;
1488bf21cd93STycho Nightingale 	int len;
1489bf21cd93STycho Nightingale 
1490bf21cd93STycho Nightingale 	acmd = cfis + 0x40;
1491bf21cd93STycho Nightingale 	len = be16dec(acmd + 7);
1492bf21cd93STycho Nightingale 	pc = acmd[2] >> 6;
1493bf21cd93STycho Nightingale 	code = acmd[2] & 0x3f;
1494bf21cd93STycho Nightingale 
1495bf21cd93STycho Nightingale 	switch (pc) {
1496bf21cd93STycho Nightingale 	case 0:
1497bf21cd93STycho Nightingale 		switch (code) {
1498bf21cd93STycho Nightingale 		case MODEPAGE_RW_ERROR_RECOVERY:
1499bf21cd93STycho Nightingale 		{
1500bf21cd93STycho Nightingale 			uint8_t buf[16];
1501bf21cd93STycho Nightingale 
1502bf21cd93STycho Nightingale 			if (len > sizeof(buf))
1503bf21cd93STycho Nightingale 				len = sizeof(buf);
1504bf21cd93STycho Nightingale 
1505bf21cd93STycho Nightingale 			memset(buf, 0, sizeof(buf));
1506bf21cd93STycho Nightingale 			be16enc(buf, 16 - 2);
1507bf21cd93STycho Nightingale 			buf[2] = 0x70;
1508bf21cd93STycho Nightingale 			buf[8] = 0x01;
1509bf21cd93STycho Nightingale 			buf[9] = 16 - 10;
1510bf21cd93STycho Nightingale 			buf[11] = 0x05;
1511bf21cd93STycho Nightingale 			write_prdt(p, slot, cfis, buf, len);
1512bf21cd93STycho Nightingale 			tfd = ATA_S_READY | ATA_S_DSC;
1513bf21cd93STycho Nightingale 			break;
1514bf21cd93STycho Nightingale 		}
1515bf21cd93STycho Nightingale 		case MODEPAGE_CD_CAPABILITIES:
1516bf21cd93STycho Nightingale 		{
1517bf21cd93STycho Nightingale 			uint8_t buf[30];
1518bf21cd93STycho Nightingale 
1519bf21cd93STycho Nightingale 			if (len > sizeof(buf))
1520bf21cd93STycho Nightingale 				len = sizeof(buf);
1521bf21cd93STycho Nightingale 
1522bf21cd93STycho Nightingale 			memset(buf, 0, sizeof(buf));
1523bf21cd93STycho Nightingale 			be16enc(buf, 30 - 2);
1524bf21cd93STycho Nightingale 			buf[2] = 0x70;
1525bf21cd93STycho Nightingale 			buf[8] = 0x2A;
1526bf21cd93STycho Nightingale 			buf[9] = 30 - 10;
1527bf21cd93STycho Nightingale 			buf[10] = 0x08;
1528bf21cd93STycho Nightingale 			buf[12] = 0x71;
1529bf21cd93STycho Nightingale 			be16enc(&buf[18], 2);
1530bf21cd93STycho Nightingale 			be16enc(&buf[20], 512);
1531bf21cd93STycho Nightingale 			write_prdt(p, slot, cfis, buf, len);
1532bf21cd93STycho Nightingale 			tfd = ATA_S_READY | ATA_S_DSC;
1533bf21cd93STycho Nightingale 			break;
1534bf21cd93STycho Nightingale 		}
1535bf21cd93STycho Nightingale 		default:
1536bf21cd93STycho Nightingale 			goto error;
1537bf21cd93STycho Nightingale 			break;
1538bf21cd93STycho Nightingale 		}
1539bf21cd93STycho Nightingale 		break;
1540bf21cd93STycho Nightingale 	case 3:
1541bf21cd93STycho Nightingale 		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1542bf21cd93STycho Nightingale 		p->asc = 0x39;
1543bf21cd93STycho Nightingale 		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1544bf21cd93STycho Nightingale 		break;
1545bf21cd93STycho Nightingale error:
1546bf21cd93STycho Nightingale 	case 1:
1547bf21cd93STycho Nightingale 	case 2:
1548bf21cd93STycho Nightingale 		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1549bf21cd93STycho Nightingale 		p->asc = 0x24;
1550bf21cd93STycho Nightingale 		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1551bf21cd93STycho Nightingale 		break;
1552bf21cd93STycho Nightingale 	}
1553bf21cd93STycho Nightingale 	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1554bf21cd93STycho Nightingale 	ahci_write_fis_d2h(p, slot, cfis, tfd);
1555bf21cd93STycho Nightingale }
1556bf21cd93STycho Nightingale 
1557bf21cd93STycho Nightingale static void
1558bf21cd93STycho Nightingale atapi_get_event_status_notification(struct ahci_port *p, int slot,
1559bf21cd93STycho Nightingale     uint8_t *cfis)
1560bf21cd93STycho Nightingale {
1561bf21cd93STycho Nightingale 	uint8_t *acmd;
1562bf21cd93STycho Nightingale 	uint32_t tfd;
1563bf21cd93STycho Nightingale 
1564bf21cd93STycho Nightingale 	acmd = cfis + 0x40;
1565bf21cd93STycho Nightingale 
1566bf21cd93STycho Nightingale 	/* we don't support asynchronous operation */
1567bf21cd93STycho Nightingale 	if (!(acmd[1] & 1)) {
1568bf21cd93STycho Nightingale 		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1569bf21cd93STycho Nightingale 		p->asc = 0x24;
1570bf21cd93STycho Nightingale 		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
1571bf21cd93STycho Nightingale 	} else {
1572bf21cd93STycho Nightingale 		uint8_t buf[8];
1573bf21cd93STycho Nightingale 		int len;
1574bf21cd93STycho Nightingale 
1575bf21cd93STycho Nightingale 		len = be16dec(acmd + 7);
1576bf21cd93STycho Nightingale 		if (len > sizeof(buf))
1577bf21cd93STycho Nightingale 			len = sizeof(buf);
1578bf21cd93STycho Nightingale 
1579bf21cd93STycho Nightingale 		memset(buf, 0, sizeof(buf));
1580bf21cd93STycho Nightingale 		be16enc(buf, 8 - 2);
1581bf21cd93STycho Nightingale 		buf[2] = 0x04;
1582bf21cd93STycho Nightingale 		buf[3] = 0x10;
1583bf21cd93STycho Nightingale 		buf[5] = 0x02;
1584bf21cd93STycho Nightingale 		write_prdt(p, slot, cfis, buf, len);
1585bf21cd93STycho Nightingale 		tfd = ATA_S_READY | ATA_S_DSC;
1586bf21cd93STycho Nightingale 	}
1587bf21cd93STycho Nightingale 	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1588bf21cd93STycho Nightingale 	ahci_write_fis_d2h(p, slot, cfis, tfd);
1589bf21cd93STycho Nightingale }
1590bf21cd93STycho Nightingale 
1591bf21cd93STycho Nightingale static void
1592bf21cd93STycho Nightingale handle_packet_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
1593bf21cd93STycho Nightingale {
1594bf21cd93STycho Nightingale 	uint8_t *acmd;
1595bf21cd93STycho Nightingale 
1596bf21cd93STycho Nightingale 	acmd = cfis + 0x40;
1597bf21cd93STycho Nightingale 
1598bf21cd93STycho Nightingale #ifdef AHCI_DEBUG
1599bf21cd93STycho Nightingale 	{
1600bf21cd93STycho Nightingale 		int i;
1601bf21cd93STycho Nightingale 		DPRINTF("ACMD:");
1602bf21cd93STycho Nightingale 		for (i = 0; i < 16; i++)
1603bf21cd93STycho Nightingale 			DPRINTF("%02x ", acmd[i]);
1604*154972afSPatrick Mooney 		DPRINTF("");
1605bf21cd93STycho Nightingale 	}
1606bf21cd93STycho Nightingale #endif
1607bf21cd93STycho Nightingale 
1608bf21cd93STycho Nightingale 	switch (acmd[0]) {
1609bf21cd93STycho Nightingale 	case TEST_UNIT_READY:
1610bf21cd93STycho Nightingale 		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1611bf21cd93STycho Nightingale 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1612bf21cd93STycho Nightingale 		break;
1613bf21cd93STycho Nightingale 	case INQUIRY:
1614bf21cd93STycho Nightingale 		atapi_inquiry(p, slot, cfis);
1615bf21cd93STycho Nightingale 		break;
1616bf21cd93STycho Nightingale 	case READ_CAPACITY:
1617bf21cd93STycho Nightingale 		atapi_read_capacity(p, slot, cfis);
1618bf21cd93STycho Nightingale 		break;
1619bf21cd93STycho Nightingale 	case PREVENT_ALLOW:
1620bf21cd93STycho Nightingale 		/* TODO */
1621bf21cd93STycho Nightingale 		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1622bf21cd93STycho Nightingale 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1623bf21cd93STycho Nightingale 		break;
1624bf21cd93STycho Nightingale 	case READ_TOC:
1625bf21cd93STycho Nightingale 		atapi_read_toc(p, slot, cfis);
1626bf21cd93STycho Nightingale 		break;
16274c87aefeSPatrick Mooney 	case REPORT_LUNS:
16284c87aefeSPatrick Mooney 		atapi_report_luns(p, slot, cfis);
16294c87aefeSPatrick Mooney 		break;
1630bf21cd93STycho Nightingale 	case READ_10:
1631bf21cd93STycho Nightingale 	case READ_12:
16324c87aefeSPatrick Mooney 		atapi_read(p, slot, cfis, 0);
1633bf21cd93STycho Nightingale 		break;
1634bf21cd93STycho Nightingale 	case REQUEST_SENSE:
1635bf21cd93STycho Nightingale 		atapi_request_sense(p, slot, cfis);
1636bf21cd93STycho Nightingale 		break;
1637bf21cd93STycho Nightingale 	case START_STOP_UNIT:
1638bf21cd93STycho Nightingale 		atapi_start_stop_unit(p, slot, cfis);
1639bf21cd93STycho Nightingale 		break;
1640bf21cd93STycho Nightingale 	case MODE_SENSE_10:
1641bf21cd93STycho Nightingale 		atapi_mode_sense(p, slot, cfis);
1642bf21cd93STycho Nightingale 		break;
1643bf21cd93STycho Nightingale 	case GET_EVENT_STATUS_NOTIFICATION:
1644bf21cd93STycho Nightingale 		atapi_get_event_status_notification(p, slot, cfis);
1645bf21cd93STycho Nightingale 		break;
1646bf21cd93STycho Nightingale 	default:
1647bf21cd93STycho Nightingale 		cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
1648bf21cd93STycho Nightingale 		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1649bf21cd93STycho Nightingale 		p->asc = 0x20;
1650bf21cd93STycho Nightingale 		ahci_write_fis_d2h(p, slot, cfis, (p->sense_key << 12) |
1651bf21cd93STycho Nightingale 				ATA_S_READY | ATA_S_ERROR);
1652bf21cd93STycho Nightingale 		break;
1653bf21cd93STycho Nightingale 	}
1654bf21cd93STycho Nightingale }
1655bf21cd93STycho Nightingale 
1656bf21cd93STycho Nightingale static void
1657bf21cd93STycho Nightingale ahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
1658bf21cd93STycho Nightingale {
1659bf21cd93STycho Nightingale 
16604c87aefeSPatrick Mooney 	p->tfd |= ATA_S_BUSY;
1661bf21cd93STycho Nightingale 	switch (cfis[2]) {
1662bf21cd93STycho Nightingale 	case ATA_ATA_IDENTIFY:
1663bf21cd93STycho Nightingale 		handle_identify(p, slot, cfis);
1664bf21cd93STycho Nightingale 		break;
1665bf21cd93STycho Nightingale 	case ATA_SETFEATURES:
1666bf21cd93STycho Nightingale 	{
1667bf21cd93STycho Nightingale 		switch (cfis[3]) {
1668bf21cd93STycho Nightingale 		case ATA_SF_ENAB_SATA_SF:
1669bf21cd93STycho Nightingale 			switch (cfis[12]) {
1670bf21cd93STycho Nightingale 			case ATA_SATA_SF_AN:
1671bf21cd93STycho Nightingale 				p->tfd = ATA_S_DSC | ATA_S_READY;
1672bf21cd93STycho Nightingale 				break;
1673bf21cd93STycho Nightingale 			default:
1674bf21cd93STycho Nightingale 				p->tfd = ATA_S_ERROR | ATA_S_READY;
1675bf21cd93STycho Nightingale 				p->tfd |= (ATA_ERROR_ABORT << 8);
1676bf21cd93STycho Nightingale 				break;
1677bf21cd93STycho Nightingale 			}
1678bf21cd93STycho Nightingale 			break;
1679bf21cd93STycho Nightingale 		case ATA_SF_ENAB_WCACHE:
1680bf21cd93STycho Nightingale 		case ATA_SF_DIS_WCACHE:
1681bf21cd93STycho Nightingale 		case ATA_SF_ENAB_RCACHE:
1682bf21cd93STycho Nightingale 		case ATA_SF_DIS_RCACHE:
1683bf21cd93STycho Nightingale 			p->tfd = ATA_S_DSC | ATA_S_READY;
1684bf21cd93STycho Nightingale 			break;
1685bf21cd93STycho Nightingale 		case ATA_SF_SETXFER:
1686bf21cd93STycho Nightingale 		{
1687bf21cd93STycho Nightingale 			switch (cfis[12] & 0xf8) {
1688bf21cd93STycho Nightingale 			case ATA_PIO:
1689bf21cd93STycho Nightingale 			case ATA_PIO0:
1690bf21cd93STycho Nightingale 				break;
1691bf21cd93STycho Nightingale 			case ATA_WDMA0:
1692bf21cd93STycho Nightingale 			case ATA_UDMA0:
1693bf21cd93STycho Nightingale 				p->xfermode = (cfis[12] & 0x7);
1694bf21cd93STycho Nightingale 				break;
1695bf21cd93STycho Nightingale 			}
1696bf21cd93STycho Nightingale 			p->tfd = ATA_S_DSC | ATA_S_READY;
1697bf21cd93STycho Nightingale 			break;
1698bf21cd93STycho Nightingale 		}
1699bf21cd93STycho Nightingale 		default:
1700bf21cd93STycho Nightingale 			p->tfd = ATA_S_ERROR | ATA_S_READY;
1701bf21cd93STycho Nightingale 			p->tfd |= (ATA_ERROR_ABORT << 8);
1702bf21cd93STycho Nightingale 			break;
1703bf21cd93STycho Nightingale 		}
1704bf21cd93STycho Nightingale 		ahci_write_fis_d2h(p, slot, cfis, p->tfd);
1705bf21cd93STycho Nightingale 		break;
1706bf21cd93STycho Nightingale 	}
1707bf21cd93STycho Nightingale 	case ATA_SET_MULTI:
1708bf21cd93STycho Nightingale 		if (cfis[12] != 0 &&
1709bf21cd93STycho Nightingale 			(cfis[12] > 128 || (cfis[12] & (cfis[12] - 1)))) {
1710bf21cd93STycho Nightingale 			p->tfd = ATA_S_ERROR | ATA_S_READY;
1711bf21cd93STycho Nightingale 			p->tfd |= (ATA_ERROR_ABORT << 8);
1712bf21cd93STycho Nightingale 		} else {
1713bf21cd93STycho Nightingale 			p->mult_sectors = cfis[12];
1714bf21cd93STycho Nightingale 			p->tfd = ATA_S_DSC | ATA_S_READY;
1715bf21cd93STycho Nightingale 		}
17164c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis, p->tfd);
1717bf21cd93STycho Nightingale 		break;
17184c87aefeSPatrick Mooney 	case ATA_READ:
17194c87aefeSPatrick Mooney 	case ATA_WRITE:
17204c87aefeSPatrick Mooney 	case ATA_READ48:
17214c87aefeSPatrick Mooney 	case ATA_WRITE48:
17224c87aefeSPatrick Mooney 	case ATA_READ_MUL:
17234c87aefeSPatrick Mooney 	case ATA_WRITE_MUL:
17244c87aefeSPatrick Mooney 	case ATA_READ_MUL48:
17254c87aefeSPatrick Mooney 	case ATA_WRITE_MUL48:
1726bf21cd93STycho Nightingale 	case ATA_READ_DMA:
1727bf21cd93STycho Nightingale 	case ATA_WRITE_DMA:
1728bf21cd93STycho Nightingale 	case ATA_READ_DMA48:
1729bf21cd93STycho Nightingale 	case ATA_WRITE_DMA48:
1730bf21cd93STycho Nightingale 	case ATA_READ_FPDMA_QUEUED:
1731bf21cd93STycho Nightingale 	case ATA_WRITE_FPDMA_QUEUED:
17324c87aefeSPatrick Mooney 		ahci_handle_rw(p, slot, cfis, 0);
1733bf21cd93STycho Nightingale 		break;
1734bf21cd93STycho Nightingale 	case ATA_FLUSHCACHE:
1735bf21cd93STycho Nightingale 	case ATA_FLUSHCACHE48:
1736bf21cd93STycho Nightingale 		ahci_handle_flush(p, slot, cfis);
1737bf21cd93STycho Nightingale 		break;
17384c87aefeSPatrick Mooney 	case ATA_DATA_SET_MANAGEMENT:
17394c87aefeSPatrick Mooney 		if (cfis[11] == 0 && cfis[3] == ATA_DSM_TRIM &&
17404c87aefeSPatrick Mooney 		    cfis[13] == 0 && cfis[12] == 1) {
17414c87aefeSPatrick Mooney 			ahci_handle_dsm_trim(p, slot, cfis, 0);
1742bf21cd93STycho Nightingale 			break;
17434c87aefeSPatrick Mooney 		}
17444c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis,
17454c87aefeSPatrick Mooney 		    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
17464c87aefeSPatrick Mooney 		break;
17474c87aefeSPatrick Mooney 	case ATA_SEND_FPDMA_QUEUED:
17484c87aefeSPatrick Mooney 		if ((cfis[13] & 0x1f) == ATA_SFPDMA_DSM &&
17494c87aefeSPatrick Mooney 		    cfis[17] == 0 && cfis[16] == ATA_DSM_TRIM &&
17504c87aefeSPatrick Mooney 		    cfis[11] == 0 && cfis[3] == 1) {
17514c87aefeSPatrick Mooney 			ahci_handle_dsm_trim(p, slot, cfis, 0);
17524c87aefeSPatrick Mooney 			break;
17534c87aefeSPatrick Mooney 		}
17544c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis,
17554c87aefeSPatrick Mooney 		    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
17564c87aefeSPatrick Mooney 		break;
17574c87aefeSPatrick Mooney 	case ATA_READ_LOG_EXT:
17584c87aefeSPatrick Mooney 	case ATA_READ_LOG_DMA_EXT:
17594c87aefeSPatrick Mooney 		ahci_handle_read_log(p, slot, cfis);
17604c87aefeSPatrick Mooney 		break;
17614c87aefeSPatrick Mooney 	case ATA_SECURITY_FREEZE_LOCK:
17624c87aefeSPatrick Mooney 	case ATA_SMART_CMD:
1763bf21cd93STycho Nightingale 	case ATA_NOP:
17644c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis,
17654c87aefeSPatrick Mooney 		    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
17664c87aefeSPatrick Mooney 		break;
17674c87aefeSPatrick Mooney 	case ATA_CHECK_POWER_MODE:
17684c87aefeSPatrick Mooney 		cfis[12] = 0xff;	/* always on */
17694c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
17704c87aefeSPatrick Mooney 		break;
17714c87aefeSPatrick Mooney 	case ATA_STANDBY_CMD:
1772bf21cd93STycho Nightingale 	case ATA_STANDBY_IMMEDIATE:
17734c87aefeSPatrick Mooney 	case ATA_IDLE_CMD:
1774bf21cd93STycho Nightingale 	case ATA_IDLE_IMMEDIATE:
1775bf21cd93STycho Nightingale 	case ATA_SLEEP:
17764c87aefeSPatrick Mooney 	case ATA_READ_VERIFY:
17774c87aefeSPatrick Mooney 	case ATA_READ_VERIFY48:
1778bf21cd93STycho Nightingale 		ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
1779bf21cd93STycho Nightingale 		break;
1780bf21cd93STycho Nightingale 	case ATA_ATAPI_IDENTIFY:
1781bf21cd93STycho Nightingale 		handle_atapi_identify(p, slot, cfis);
1782bf21cd93STycho Nightingale 		break;
1783bf21cd93STycho Nightingale 	case ATA_PACKET_CMD:
1784bf21cd93STycho Nightingale 		if (!p->atapi) {
17854c87aefeSPatrick Mooney 			ahci_write_fis_d2h(p, slot, cfis,
17864c87aefeSPatrick Mooney 			    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
1787bf21cd93STycho Nightingale 		} else
1788bf21cd93STycho Nightingale 			handle_packet_cmd(p, slot, cfis);
1789bf21cd93STycho Nightingale 		break;
1790bf21cd93STycho Nightingale 	default:
1791*154972afSPatrick Mooney 		WPRINTF("Unsupported cmd:%02x", cfis[2]);
17924c87aefeSPatrick Mooney 		ahci_write_fis_d2h(p, slot, cfis,
17934c87aefeSPatrick Mooney 		    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
1794bf21cd93STycho Nightingale 		break;
1795bf21cd93STycho Nightingale 	}
1796bf21cd93STycho Nightingale }
1797bf21cd93STycho Nightingale 
1798bf21cd93STycho Nightingale static void
1799bf21cd93STycho Nightingale ahci_handle_slot(struct ahci_port *p, int slot)
1800bf21cd93STycho Nightingale {
1801bf21cd93STycho Nightingale 	struct ahci_cmd_hdr *hdr;
18024c87aefeSPatrick Mooney #ifdef AHCI_DEBUG
1803bf21cd93STycho Nightingale 	struct ahci_prdt_entry *prdt;
18044c87aefeSPatrick Mooney #endif
1805bf21cd93STycho Nightingale 	struct pci_ahci_softc *sc;
1806bf21cd93STycho Nightingale 	uint8_t *cfis;
18074c87aefeSPatrick Mooney #ifdef AHCI_DEBUG
18084c87aefeSPatrick Mooney 	int cfl, i;
18094c87aefeSPatrick Mooney #endif
1810bf21cd93STycho Nightingale 
1811bf21cd93STycho Nightingale 	sc = p->pr_sc;
1812bf21cd93STycho Nightingale 	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
18134c87aefeSPatrick Mooney #ifdef AHCI_DEBUG
1814bf21cd93STycho Nightingale 	cfl = (hdr->flags & 0x1f) * 4;
18154c87aefeSPatrick Mooney #endif
1816bf21cd93STycho Nightingale 	cfis = paddr_guest2host(ahci_ctx(sc), hdr->ctba,
1817bf21cd93STycho Nightingale 			0x80 + hdr->prdtl * sizeof(struct ahci_prdt_entry));
18184c87aefeSPatrick Mooney #ifdef AHCI_DEBUG
1819bf21cd93STycho Nightingale 	prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
1820bf21cd93STycho Nightingale 
1821*154972afSPatrick Mooney 	DPRINTF("cfis:");
1822bf21cd93STycho Nightingale 	for (i = 0; i < cfl; i++) {
1823bf21cd93STycho Nightingale 		if (i % 10 == 0)
1824*154972afSPatrick Mooney 			DPRINTF("");
1825bf21cd93STycho Nightingale 		DPRINTF("%02x ", cfis[i]);
1826bf21cd93STycho Nightingale 	}
1827*154972afSPatrick Mooney 	DPRINTF("");
1828bf21cd93STycho Nightingale 
1829bf21cd93STycho Nightingale 	for (i = 0; i < hdr->prdtl; i++) {
1830*154972afSPatrick Mooney 		DPRINTF("%d@%08"PRIx64"", prdt->dbc & 0x3fffff, prdt->dba);
1831bf21cd93STycho Nightingale 		prdt++;
1832bf21cd93STycho Nightingale 	}
1833bf21cd93STycho Nightingale #endif
1834bf21cd93STycho Nightingale 
1835bf21cd93STycho Nightingale 	if (cfis[0] != FIS_TYPE_REGH2D) {
1836*154972afSPatrick Mooney 		WPRINTF("Not a H2D FIS:%02x", cfis[0]);
1837bf21cd93STycho Nightingale 		return;
1838bf21cd93STycho Nightingale 	}
1839bf21cd93STycho Nightingale 
1840bf21cd93STycho Nightingale 	if (cfis[1] & 0x80) {
1841bf21cd93STycho Nightingale 		ahci_handle_cmd(p, slot, cfis);
1842bf21cd93STycho Nightingale 	} else {
1843bf21cd93STycho Nightingale 		if (cfis[15] & (1 << 2))
1844bf21cd93STycho Nightingale 			p->reset = 1;
1845bf21cd93STycho Nightingale 		else if (p->reset) {
1846bf21cd93STycho Nightingale 			p->reset = 0;
1847bf21cd93STycho Nightingale 			ahci_port_reset(p);
1848bf21cd93STycho Nightingale 		}
1849bf21cd93STycho Nightingale 		p->ci &= ~(1 << slot);
1850bf21cd93STycho Nightingale 	}
1851bf21cd93STycho Nightingale }
1852bf21cd93STycho Nightingale 
1853bf21cd93STycho Nightingale static void
1854bf21cd93STycho Nightingale ahci_handle_port(struct ahci_port *p)
1855bf21cd93STycho Nightingale {
1856bf21cd93STycho Nightingale 
1857bf21cd93STycho Nightingale 	if (!(p->cmd & AHCI_P_CMD_ST))
1858bf21cd93STycho Nightingale 		return;
1859bf21cd93STycho Nightingale 
1860bf21cd93STycho Nightingale 	/*
1861bf21cd93STycho Nightingale 	 * Search for any new commands to issue ignoring those that
18624c87aefeSPatrick Mooney 	 * are already in-flight.  Stop if device is busy or in error.
1863bf21cd93STycho Nightingale 	 */
18644c87aefeSPatrick Mooney 	for (; (p->ci & ~p->pending) != 0; p->ccs = ((p->ccs + 1) & 31)) {
18654c87aefeSPatrick Mooney 		if ((p->tfd & (ATA_S_BUSY | ATA_S_DRQ)) != 0)
18664c87aefeSPatrick Mooney 			break;
18674c87aefeSPatrick Mooney 		if (p->waitforclear)
18684c87aefeSPatrick Mooney 			break;
18694c87aefeSPatrick Mooney 		if ((p->ci & ~p->pending & (1 << p->ccs)) != 0) {
1870bf21cd93STycho Nightingale 			p->cmd &= ~AHCI_P_CMD_CCS_MASK;
18714c87aefeSPatrick Mooney 			p->cmd |= p->ccs << AHCI_P_CMD_CCS_SHIFT;
18724c87aefeSPatrick Mooney 			ahci_handle_slot(p, p->ccs);
1873bf21cd93STycho Nightingale 		}
1874bf21cd93STycho Nightingale 	}
1875bf21cd93STycho Nightingale }
1876bf21cd93STycho Nightingale 
1877bf21cd93STycho Nightingale /*
1878bf21cd93STycho Nightingale  * blockif callback routine - this runs in the context of the blockif
1879bf21cd93STycho Nightingale  * i/o thread, so the mutex needs to be acquired.
1880bf21cd93STycho Nightingale  */
1881bf21cd93STycho Nightingale static void
1882bf21cd93STycho Nightingale ata_ioreq_cb(struct blockif_req *br, int err)
1883bf21cd93STycho Nightingale {
1884bf21cd93STycho Nightingale 	struct ahci_cmd_hdr *hdr;
1885bf21cd93STycho Nightingale 	struct ahci_ioreq *aior;
1886bf21cd93STycho Nightingale 	struct ahci_port *p;
1887bf21cd93STycho Nightingale 	struct pci_ahci_softc *sc;
1888bf21cd93STycho Nightingale 	uint32_t tfd;
1889bf21cd93STycho Nightingale 	uint8_t *cfis;
18904c87aefeSPatrick Mooney 	int slot, ncq, dsm;
1891bf21cd93STycho Nightingale 
1892*154972afSPatrick Mooney 	DPRINTF("%s %d", __func__, err);
1893bf21cd93STycho Nightingale 
18944c87aefeSPatrick Mooney 	ncq = dsm = 0;
1895bf21cd93STycho Nightingale 	aior = br->br_param;
1896bf21cd93STycho Nightingale 	p = aior->io_pr;
1897bf21cd93STycho Nightingale 	cfis = aior->cfis;
1898bf21cd93STycho Nightingale 	slot = aior->slot;
1899bf21cd93STycho Nightingale 	sc = p->pr_sc;
1900bf21cd93STycho Nightingale 	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
1901bf21cd93STycho Nightingale 
1902bf21cd93STycho Nightingale 	if (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||
19034c87aefeSPatrick Mooney 	    cfis[2] == ATA_READ_FPDMA_QUEUED ||
19044c87aefeSPatrick Mooney 	    cfis[2] == ATA_SEND_FPDMA_QUEUED)
1905bf21cd93STycho Nightingale 		ncq = 1;
19064c87aefeSPatrick Mooney 	if (cfis[2] == ATA_DATA_SET_MANAGEMENT ||
19074c87aefeSPatrick Mooney 	    (cfis[2] == ATA_SEND_FPDMA_QUEUED &&
19084c87aefeSPatrick Mooney 	     (cfis[13] & 0x1f) == ATA_SFPDMA_DSM))
19094c87aefeSPatrick Mooney 		dsm = 1;
1910bf21cd93STycho Nightingale 
1911bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
1912bf21cd93STycho Nightingale 
1913bf21cd93STycho Nightingale 	/*
1914bf21cd93STycho Nightingale 	 * Delete the blockif request from the busy list
1915bf21cd93STycho Nightingale 	 */
1916bf21cd93STycho Nightingale 	TAILQ_REMOVE(&p->iobhd, aior, io_blist);
1917bf21cd93STycho Nightingale 
1918bf21cd93STycho Nightingale 	/*
1919bf21cd93STycho Nightingale 	 * Move the blockif request back to the free list
1920bf21cd93STycho Nightingale 	 */
1921bf21cd93STycho Nightingale 	STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
1922bf21cd93STycho Nightingale 
19234c87aefeSPatrick Mooney 	if (!err)
19244c87aefeSPatrick Mooney 		hdr->prdbc = aior->done;
19254c87aefeSPatrick Mooney 
19264c87aefeSPatrick Mooney 	if (!err && aior->more) {
19274c87aefeSPatrick Mooney 		if (dsm)
19284c87aefeSPatrick Mooney 			ahci_handle_dsm_trim(p, slot, cfis, aior->done);
19294c87aefeSPatrick Mooney 		else
19304c87aefeSPatrick Mooney 			ahci_handle_rw(p, slot, cfis, aior->done);
1931bf21cd93STycho Nightingale 		goto out;
1932bf21cd93STycho Nightingale 	}
1933bf21cd93STycho Nightingale 
19344c87aefeSPatrick Mooney 	if (!err)
1935bf21cd93STycho Nightingale 		tfd = ATA_S_READY | ATA_S_DSC;
1936bf21cd93STycho Nightingale 	else
1937bf21cd93STycho Nightingale 		tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
1938bf21cd93STycho Nightingale 	if (ncq)
19394c87aefeSPatrick Mooney 		ahci_write_fis_sdb(p, slot, cfis, tfd);
19404c87aefeSPatrick Mooney 	else
1941bf21cd93STycho Nightingale 		ahci_write_fis_d2h(p, slot, cfis, tfd);
1942bf21cd93STycho Nightingale 
1943bf21cd93STycho Nightingale 	/*
1944bf21cd93STycho Nightingale 	 * This command is now complete.
1945bf21cd93STycho Nightingale 	 */
1946bf21cd93STycho Nightingale 	p->pending &= ~(1 << slot);
1947bf21cd93STycho Nightingale 
1948bf21cd93STycho Nightingale 	ahci_check_stopped(p);
19494c87aefeSPatrick Mooney 	ahci_handle_port(p);
1950bf21cd93STycho Nightingale out:
1951bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
1952*154972afSPatrick Mooney 	DPRINTF("%s exit", __func__);
1953bf21cd93STycho Nightingale }
1954bf21cd93STycho Nightingale 
1955bf21cd93STycho Nightingale static void
1956bf21cd93STycho Nightingale atapi_ioreq_cb(struct blockif_req *br, int err)
1957bf21cd93STycho Nightingale {
1958bf21cd93STycho Nightingale 	struct ahci_cmd_hdr *hdr;
1959bf21cd93STycho Nightingale 	struct ahci_ioreq *aior;
1960bf21cd93STycho Nightingale 	struct ahci_port *p;
1961bf21cd93STycho Nightingale 	struct pci_ahci_softc *sc;
1962bf21cd93STycho Nightingale 	uint8_t *cfis;
1963bf21cd93STycho Nightingale 	uint32_t tfd;
19644c87aefeSPatrick Mooney 	int slot;
1965bf21cd93STycho Nightingale 
1966*154972afSPatrick Mooney 	DPRINTF("%s %d", __func__, err);
1967bf21cd93STycho Nightingale 
1968bf21cd93STycho Nightingale 	aior = br->br_param;
1969bf21cd93STycho Nightingale 	p = aior->io_pr;
1970bf21cd93STycho Nightingale 	cfis = aior->cfis;
1971bf21cd93STycho Nightingale 	slot = aior->slot;
1972bf21cd93STycho Nightingale 	sc = p->pr_sc;
1973bf21cd93STycho Nightingale 	hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + aior->slot * AHCI_CL_SIZE);
1974bf21cd93STycho Nightingale 
1975bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
1976bf21cd93STycho Nightingale 
1977bf21cd93STycho Nightingale 	/*
1978bf21cd93STycho Nightingale 	 * Delete the blockif request from the busy list
1979bf21cd93STycho Nightingale 	 */
1980bf21cd93STycho Nightingale 	TAILQ_REMOVE(&p->iobhd, aior, io_blist);
1981bf21cd93STycho Nightingale 
1982bf21cd93STycho Nightingale 	/*
1983bf21cd93STycho Nightingale 	 * Move the blockif request back to the free list
1984bf21cd93STycho Nightingale 	 */
1985bf21cd93STycho Nightingale 	STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
1986bf21cd93STycho Nightingale 
19874c87aefeSPatrick Mooney 	if (!err)
19884c87aefeSPatrick Mooney 		hdr->prdbc = aior->done;
19894c87aefeSPatrick Mooney 
19904c87aefeSPatrick Mooney 	if (!err && aior->more) {
19914c87aefeSPatrick Mooney 		atapi_read(p, slot, cfis, aior->done);
1992bf21cd93STycho Nightingale 		goto out;
1993bf21cd93STycho Nightingale 	}
1994bf21cd93STycho Nightingale 
19954c87aefeSPatrick Mooney 	if (!err) {
1996bf21cd93STycho Nightingale 		tfd = ATA_S_READY | ATA_S_DSC;
1997bf21cd93STycho Nightingale 	} else {
1998bf21cd93STycho Nightingale 		p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
1999bf21cd93STycho Nightingale 		p->asc = 0x21;
2000bf21cd93STycho Nightingale 		tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
2001bf21cd93STycho Nightingale 	}
2002bf21cd93STycho Nightingale 	cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
2003bf21cd93STycho Nightingale 	ahci_write_fis_d2h(p, slot, cfis, tfd);
2004bf21cd93STycho Nightingale 
2005bf21cd93STycho Nightingale 	/*
2006bf21cd93STycho Nightingale 	 * This command is now complete.
2007bf21cd93STycho Nightingale 	 */
2008bf21cd93STycho Nightingale 	p->pending &= ~(1 << slot);
2009bf21cd93STycho Nightingale 
2010bf21cd93STycho Nightingale 	ahci_check_stopped(p);
20114c87aefeSPatrick Mooney 	ahci_handle_port(p);
2012bf21cd93STycho Nightingale out:
2013bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
2014*154972afSPatrick Mooney 	DPRINTF("%s exit", __func__);
2015bf21cd93STycho Nightingale }
2016bf21cd93STycho Nightingale 
2017bf21cd93STycho Nightingale static void
2018bf21cd93STycho Nightingale pci_ahci_ioreq_init(struct ahci_port *pr)
2019bf21cd93STycho Nightingale {
2020bf21cd93STycho Nightingale 	struct ahci_ioreq *vr;
2021bf21cd93STycho Nightingale 	int i;
2022bf21cd93STycho Nightingale 
2023bf21cd93STycho Nightingale 	pr->ioqsz = blockif_queuesz(pr->bctx);
2024bf21cd93STycho Nightingale 	pr->ioreq = calloc(pr->ioqsz, sizeof(struct ahci_ioreq));
2025bf21cd93STycho Nightingale 	STAILQ_INIT(&pr->iofhd);
2026bf21cd93STycho Nightingale 
2027bf21cd93STycho Nightingale 	/*
2028bf21cd93STycho Nightingale 	 * Add all i/o request entries to the free queue
2029bf21cd93STycho Nightingale 	 */
2030bf21cd93STycho Nightingale 	for (i = 0; i < pr->ioqsz; i++) {
2031bf21cd93STycho Nightingale 		vr = &pr->ioreq[i];
2032bf21cd93STycho Nightingale 		vr->io_pr = pr;
2033bf21cd93STycho Nightingale 		if (!pr->atapi)
2034bf21cd93STycho Nightingale 			vr->io_req.br_callback = ata_ioreq_cb;
2035bf21cd93STycho Nightingale 		else
2036bf21cd93STycho Nightingale 			vr->io_req.br_callback = atapi_ioreq_cb;
2037bf21cd93STycho Nightingale 		vr->io_req.br_param = vr;
2038bf21cd93STycho Nightingale 		STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_flist);
2039bf21cd93STycho Nightingale 	}
2040bf21cd93STycho Nightingale 
2041bf21cd93STycho Nightingale 	TAILQ_INIT(&pr->iobhd);
2042bf21cd93STycho Nightingale }
2043bf21cd93STycho Nightingale 
2044bf21cd93STycho Nightingale static void
2045bf21cd93STycho Nightingale pci_ahci_port_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)
2046bf21cd93STycho Nightingale {
2047bf21cd93STycho Nightingale 	int port = (offset - AHCI_OFFSET) / AHCI_STEP;
2048bf21cd93STycho Nightingale 	offset = (offset - AHCI_OFFSET) % AHCI_STEP;
2049bf21cd93STycho Nightingale 	struct ahci_port *p = &sc->port[port];
2050bf21cd93STycho Nightingale 
2051*154972afSPatrick Mooney 	DPRINTF("pci_ahci_port %d: write offset 0x%"PRIx64" value 0x%"PRIx64"",
2052bf21cd93STycho Nightingale 		port, offset, value);
2053bf21cd93STycho Nightingale 
2054bf21cd93STycho Nightingale 	switch (offset) {
2055bf21cd93STycho Nightingale 	case AHCI_P_CLB:
2056bf21cd93STycho Nightingale 		p->clb = value;
2057bf21cd93STycho Nightingale 		break;
2058bf21cd93STycho Nightingale 	case AHCI_P_CLBU:
2059bf21cd93STycho Nightingale 		p->clbu = value;
2060bf21cd93STycho Nightingale 		break;
2061bf21cd93STycho Nightingale 	case AHCI_P_FB:
2062bf21cd93STycho Nightingale 		p->fb = value;
2063bf21cd93STycho Nightingale 		break;
2064bf21cd93STycho Nightingale 	case AHCI_P_FBU:
2065bf21cd93STycho Nightingale 		p->fbu = value;
2066bf21cd93STycho Nightingale 		break;
2067bf21cd93STycho Nightingale 	case AHCI_P_IS:
2068bf21cd93STycho Nightingale 		p->is &= ~value;
20694c87aefeSPatrick Mooney 		ahci_port_intr(p);
2070bf21cd93STycho Nightingale 		break;
2071bf21cd93STycho Nightingale 	case AHCI_P_IE:
2072bf21cd93STycho Nightingale 		p->ie = value & 0xFDC000FF;
20734c87aefeSPatrick Mooney 		ahci_port_intr(p);
2074bf21cd93STycho Nightingale 		break;
2075bf21cd93STycho Nightingale 	case AHCI_P_CMD:
2076bf21cd93STycho Nightingale 	{
20774c87aefeSPatrick Mooney 		p->cmd &= ~(AHCI_P_CMD_ST | AHCI_P_CMD_SUD | AHCI_P_CMD_POD |
20784c87aefeSPatrick Mooney 		    AHCI_P_CMD_CLO | AHCI_P_CMD_FRE | AHCI_P_CMD_APSTE |
20794c87aefeSPatrick Mooney 		    AHCI_P_CMD_ATAPI | AHCI_P_CMD_DLAE | AHCI_P_CMD_ALPE |
20804c87aefeSPatrick Mooney 		    AHCI_P_CMD_ASP | AHCI_P_CMD_ICC_MASK);
20814c87aefeSPatrick Mooney 		p->cmd |= (AHCI_P_CMD_ST | AHCI_P_CMD_SUD | AHCI_P_CMD_POD |
20824c87aefeSPatrick Mooney 		    AHCI_P_CMD_CLO | AHCI_P_CMD_FRE | AHCI_P_CMD_APSTE |
20834c87aefeSPatrick Mooney 		    AHCI_P_CMD_ATAPI | AHCI_P_CMD_DLAE | AHCI_P_CMD_ALPE |
20844c87aefeSPatrick Mooney 		    AHCI_P_CMD_ASP | AHCI_P_CMD_ICC_MASK) & value;
2085bf21cd93STycho Nightingale 
2086bf21cd93STycho Nightingale 		if (!(value & AHCI_P_CMD_ST)) {
2087bf21cd93STycho Nightingale 			ahci_port_stop(p);
2088bf21cd93STycho Nightingale 		} else {
2089bf21cd93STycho Nightingale 			uint64_t clb;
2090bf21cd93STycho Nightingale 
2091bf21cd93STycho Nightingale 			p->cmd |= AHCI_P_CMD_CR;
2092bf21cd93STycho Nightingale 			clb = (uint64_t)p->clbu << 32 | p->clb;
2093bf21cd93STycho Nightingale 			p->cmd_lst = paddr_guest2host(ahci_ctx(sc), clb,
2094bf21cd93STycho Nightingale 					AHCI_CL_SIZE * AHCI_MAX_SLOTS);
2095bf21cd93STycho Nightingale 		}
2096bf21cd93STycho Nightingale 
2097bf21cd93STycho Nightingale 		if (value & AHCI_P_CMD_FRE) {
2098bf21cd93STycho Nightingale 			uint64_t fb;
2099bf21cd93STycho Nightingale 
2100bf21cd93STycho Nightingale 			p->cmd |= AHCI_P_CMD_FR;
2101bf21cd93STycho Nightingale 			fb = (uint64_t)p->fbu << 32 | p->fb;
2102bf21cd93STycho Nightingale 			/* we don't support FBSCP, so rfis size is 256Bytes */
2103bf21cd93STycho Nightingale 			p->rfis = paddr_guest2host(ahci_ctx(sc), fb, 256);
2104bf21cd93STycho Nightingale 		} else {
2105bf21cd93STycho Nightingale 			p->cmd &= ~AHCI_P_CMD_FR;
2106bf21cd93STycho Nightingale 		}
2107bf21cd93STycho Nightingale 
2108bf21cd93STycho Nightingale 		if (value & AHCI_P_CMD_CLO) {
21094c87aefeSPatrick Mooney 			p->tfd &= ~(ATA_S_BUSY | ATA_S_DRQ);
2110bf21cd93STycho Nightingale 			p->cmd &= ~AHCI_P_CMD_CLO;
2111bf21cd93STycho Nightingale 		}
2112bf21cd93STycho Nightingale 
21134c87aefeSPatrick Mooney 		if (value & AHCI_P_CMD_ICC_MASK) {
21144c87aefeSPatrick Mooney 			p->cmd &= ~AHCI_P_CMD_ICC_MASK;
21154c87aefeSPatrick Mooney 		}
21164c87aefeSPatrick Mooney 
2117bf21cd93STycho Nightingale 		ahci_handle_port(p);
2118bf21cd93STycho Nightingale 		break;
2119bf21cd93STycho Nightingale 	}
2120bf21cd93STycho Nightingale 	case AHCI_P_TFD:
2121bf21cd93STycho Nightingale 	case AHCI_P_SIG:
2122bf21cd93STycho Nightingale 	case AHCI_P_SSTS:
2123*154972afSPatrick Mooney 		WPRINTF("pci_ahci_port: read only registers 0x%"PRIx64"", offset);
2124bf21cd93STycho Nightingale 		break;
2125bf21cd93STycho Nightingale 	case AHCI_P_SCTL:
21264c87aefeSPatrick Mooney 		p->sctl = value;
2127bf21cd93STycho Nightingale 		if (!(p->cmd & AHCI_P_CMD_ST)) {
2128bf21cd93STycho Nightingale 			if (value & ATA_SC_DET_RESET)
2129bf21cd93STycho Nightingale 				ahci_port_reset(p);
2130bf21cd93STycho Nightingale 		}
2131bf21cd93STycho Nightingale 		break;
2132bf21cd93STycho Nightingale 	case AHCI_P_SERR:
2133bf21cd93STycho Nightingale 		p->serr &= ~value;
2134bf21cd93STycho Nightingale 		break;
2135bf21cd93STycho Nightingale 	case AHCI_P_SACT:
2136bf21cd93STycho Nightingale 		p->sact |= value;
2137bf21cd93STycho Nightingale 		break;
2138bf21cd93STycho Nightingale 	case AHCI_P_CI:
2139bf21cd93STycho Nightingale 		p->ci |= value;
2140bf21cd93STycho Nightingale 		ahci_handle_port(p);
2141bf21cd93STycho Nightingale 		break;
2142bf21cd93STycho Nightingale 	case AHCI_P_SNTF:
2143bf21cd93STycho Nightingale 	case AHCI_P_FBS:
2144bf21cd93STycho Nightingale 	default:
2145bf21cd93STycho Nightingale 		break;
2146bf21cd93STycho Nightingale 	}
2147bf21cd93STycho Nightingale }
2148bf21cd93STycho Nightingale 
2149bf21cd93STycho Nightingale static void
2150bf21cd93STycho Nightingale pci_ahci_host_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)
2151bf21cd93STycho Nightingale {
2152*154972afSPatrick Mooney 	DPRINTF("pci_ahci_host: write offset 0x%"PRIx64" value 0x%"PRIx64"",
2153bf21cd93STycho Nightingale 		offset, value);
2154bf21cd93STycho Nightingale 
2155bf21cd93STycho Nightingale 	switch (offset) {
2156bf21cd93STycho Nightingale 	case AHCI_CAP:
2157bf21cd93STycho Nightingale 	case AHCI_PI:
2158bf21cd93STycho Nightingale 	case AHCI_VS:
2159bf21cd93STycho Nightingale 	case AHCI_CAP2:
2160*154972afSPatrick Mooney 		DPRINTF("pci_ahci_host: read only registers 0x%"PRIx64"", offset);
2161bf21cd93STycho Nightingale 		break;
2162bf21cd93STycho Nightingale 	case AHCI_GHC:
21634c87aefeSPatrick Mooney 		if (value & AHCI_GHC_HR) {
2164bf21cd93STycho Nightingale 			ahci_reset(sc);
21654c87aefeSPatrick Mooney 			break;
2166bf21cd93STycho Nightingale 		}
21674c87aefeSPatrick Mooney 		if (value & AHCI_GHC_IE)
21684c87aefeSPatrick Mooney 			sc->ghc |= AHCI_GHC_IE;
21694c87aefeSPatrick Mooney 		else
21704c87aefeSPatrick Mooney 			sc->ghc &= ~AHCI_GHC_IE;
21714c87aefeSPatrick Mooney 		ahci_generate_intr(sc, 0xffffffff);
2172bf21cd93STycho Nightingale 		break;
2173bf21cd93STycho Nightingale 	case AHCI_IS:
2174bf21cd93STycho Nightingale 		sc->is &= ~value;
21754c87aefeSPatrick Mooney 		ahci_generate_intr(sc, value);
2176bf21cd93STycho Nightingale 		break;
2177bf21cd93STycho Nightingale 	default:
2178bf21cd93STycho Nightingale 		break;
2179bf21cd93STycho Nightingale 	}
2180bf21cd93STycho Nightingale }
2181bf21cd93STycho Nightingale 
2182bf21cd93STycho Nightingale static void
2183bf21cd93STycho Nightingale pci_ahci_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
2184bf21cd93STycho Nightingale 		int baridx, uint64_t offset, int size, uint64_t value)
2185bf21cd93STycho Nightingale {
2186bf21cd93STycho Nightingale 	struct pci_ahci_softc *sc = pi->pi_arg;
2187bf21cd93STycho Nightingale 
2188bf21cd93STycho Nightingale 	assert(baridx == 5);
21894c87aefeSPatrick Mooney 	assert((offset % 4) == 0 && size == 4);
2190bf21cd93STycho Nightingale 
2191bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
2192bf21cd93STycho Nightingale 
2193bf21cd93STycho Nightingale 	if (offset < AHCI_OFFSET)
2194bf21cd93STycho Nightingale 		pci_ahci_host_write(sc, offset, value);
2195bf21cd93STycho Nightingale 	else if (offset < AHCI_OFFSET + sc->ports * AHCI_STEP)
2196bf21cd93STycho Nightingale 		pci_ahci_port_write(sc, offset, value);
2197bf21cd93STycho Nightingale 	else
2198*154972afSPatrick Mooney 		WPRINTF("pci_ahci: unknown i/o write offset 0x%"PRIx64"", offset);
2199bf21cd93STycho Nightingale 
2200bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
2201bf21cd93STycho Nightingale }
2202bf21cd93STycho Nightingale 
2203bf21cd93STycho Nightingale static uint64_t
2204bf21cd93STycho Nightingale pci_ahci_host_read(struct pci_ahci_softc *sc, uint64_t offset)
2205bf21cd93STycho Nightingale {
2206bf21cd93STycho Nightingale 	uint32_t value;
2207bf21cd93STycho Nightingale 
2208bf21cd93STycho Nightingale 	switch (offset) {
2209bf21cd93STycho Nightingale 	case AHCI_CAP:
2210bf21cd93STycho Nightingale 	case AHCI_GHC:
2211bf21cd93STycho Nightingale 	case AHCI_IS:
2212bf21cd93STycho Nightingale 	case AHCI_PI:
2213bf21cd93STycho Nightingale 	case AHCI_VS:
2214bf21cd93STycho Nightingale 	case AHCI_CCCC:
2215bf21cd93STycho Nightingale 	case AHCI_CCCP:
2216bf21cd93STycho Nightingale 	case AHCI_EM_LOC:
2217bf21cd93STycho Nightingale 	case AHCI_EM_CTL:
2218bf21cd93STycho Nightingale 	case AHCI_CAP2:
2219bf21cd93STycho Nightingale 	{
2220bf21cd93STycho Nightingale 		uint32_t *p = &sc->cap;
2221bf21cd93STycho Nightingale 		p += (offset - AHCI_CAP) / sizeof(uint32_t);
2222bf21cd93STycho Nightingale 		value = *p;
2223bf21cd93STycho Nightingale 		break;
2224bf21cd93STycho Nightingale 	}
2225bf21cd93STycho Nightingale 	default:
2226bf21cd93STycho Nightingale 		value = 0;
2227bf21cd93STycho Nightingale 		break;
2228bf21cd93STycho Nightingale 	}
2229*154972afSPatrick Mooney 	DPRINTF("pci_ahci_host: read offset 0x%"PRIx64" value 0x%x",
2230bf21cd93STycho Nightingale 		offset, value);
2231bf21cd93STycho Nightingale 
2232bf21cd93STycho Nightingale 	return (value);
2233bf21cd93STycho Nightingale }
2234bf21cd93STycho Nightingale 
2235bf21cd93STycho Nightingale static uint64_t
2236bf21cd93STycho Nightingale pci_ahci_port_read(struct pci_ahci_softc *sc, uint64_t offset)
2237bf21cd93STycho Nightingale {
2238bf21cd93STycho Nightingale 	uint32_t value;
2239bf21cd93STycho Nightingale 	int port = (offset - AHCI_OFFSET) / AHCI_STEP;
2240bf21cd93STycho Nightingale 	offset = (offset - AHCI_OFFSET) % AHCI_STEP;
2241bf21cd93STycho Nightingale 
2242bf21cd93STycho Nightingale 	switch (offset) {
2243bf21cd93STycho Nightingale 	case AHCI_P_CLB:
2244bf21cd93STycho Nightingale 	case AHCI_P_CLBU:
2245bf21cd93STycho Nightingale 	case AHCI_P_FB:
2246bf21cd93STycho Nightingale 	case AHCI_P_FBU:
2247bf21cd93STycho Nightingale 	case AHCI_P_IS:
2248bf21cd93STycho Nightingale 	case AHCI_P_IE:
2249bf21cd93STycho Nightingale 	case AHCI_P_CMD:
2250bf21cd93STycho Nightingale 	case AHCI_P_TFD:
2251bf21cd93STycho Nightingale 	case AHCI_P_SIG:
2252bf21cd93STycho Nightingale 	case AHCI_P_SSTS:
2253bf21cd93STycho Nightingale 	case AHCI_P_SCTL:
2254bf21cd93STycho Nightingale 	case AHCI_P_SERR:
2255bf21cd93STycho Nightingale 	case AHCI_P_SACT:
2256bf21cd93STycho Nightingale 	case AHCI_P_CI:
2257bf21cd93STycho Nightingale 	case AHCI_P_SNTF:
2258bf21cd93STycho Nightingale 	case AHCI_P_FBS:
2259bf21cd93STycho Nightingale 	{
2260bf21cd93STycho Nightingale 		uint32_t *p= &sc->port[port].clb;
2261bf21cd93STycho Nightingale 		p += (offset - AHCI_P_CLB) / sizeof(uint32_t);
2262bf21cd93STycho Nightingale 		value = *p;
2263bf21cd93STycho Nightingale 		break;
2264bf21cd93STycho Nightingale 	}
2265bf21cd93STycho Nightingale 	default:
2266bf21cd93STycho Nightingale 		value = 0;
2267bf21cd93STycho Nightingale 		break;
2268bf21cd93STycho Nightingale 	}
2269bf21cd93STycho Nightingale 
2270*154972afSPatrick Mooney 	DPRINTF("pci_ahci_port %d: read offset 0x%"PRIx64" value 0x%x",
2271bf21cd93STycho Nightingale 		port, offset, value);
2272bf21cd93STycho Nightingale 
2273bf21cd93STycho Nightingale 	return value;
2274bf21cd93STycho Nightingale }
2275bf21cd93STycho Nightingale 
2276bf21cd93STycho Nightingale static uint64_t
2277bf21cd93STycho Nightingale pci_ahci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
22784c87aefeSPatrick Mooney     uint64_t regoff, int size)
2279bf21cd93STycho Nightingale {
2280bf21cd93STycho Nightingale 	struct pci_ahci_softc *sc = pi->pi_arg;
22814c87aefeSPatrick Mooney 	uint64_t offset;
2282bf21cd93STycho Nightingale 	uint32_t value;
2283bf21cd93STycho Nightingale 
2284bf21cd93STycho Nightingale 	assert(baridx == 5);
22854c87aefeSPatrick Mooney 	assert(size == 1 || size == 2 || size == 4);
22864c87aefeSPatrick Mooney 	assert((regoff & (size - 1)) == 0);
2287bf21cd93STycho Nightingale 
2288bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
2289bf21cd93STycho Nightingale 
22904c87aefeSPatrick Mooney 	offset = regoff & ~0x3;	    /* round down to a multiple of 4 bytes */
2291bf21cd93STycho Nightingale 	if (offset < AHCI_OFFSET)
2292bf21cd93STycho Nightingale 		value = pci_ahci_host_read(sc, offset);
2293bf21cd93STycho Nightingale 	else if (offset < AHCI_OFFSET + sc->ports * AHCI_STEP)
2294bf21cd93STycho Nightingale 		value = pci_ahci_port_read(sc, offset);
2295bf21cd93STycho Nightingale 	else {
2296bf21cd93STycho Nightingale 		value = 0;
2297*154972afSPatrick Mooney 		WPRINTF("pci_ahci: unknown i/o read offset 0x%"PRIx64"",
22984c87aefeSPatrick Mooney 		    regoff);
2299bf21cd93STycho Nightingale 	}
23004c87aefeSPatrick Mooney 	value >>= 8 * (regoff & 0x3);
2301bf21cd93STycho Nightingale 
2302bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
2303bf21cd93STycho Nightingale 
2304bf21cd93STycho Nightingale 	return (value);
2305bf21cd93STycho Nightingale }
2306bf21cd93STycho Nightingale 
2307bf21cd93STycho Nightingale static int
2308bf21cd93STycho Nightingale pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi)
2309bf21cd93STycho Nightingale {
23104c87aefeSPatrick Mooney 	char bident[sizeof("XX:XX:XX")];
2311bf21cd93STycho Nightingale 	struct blockif_ctxt *bctxt;
2312bf21cd93STycho Nightingale 	struct pci_ahci_softc *sc;
23134c87aefeSPatrick Mooney 	int ret, slots, p;
23144c87aefeSPatrick Mooney 	MD5_CTX mdctx;
23154c87aefeSPatrick Mooney 	u_char digest[16];
23164c87aefeSPatrick Mooney 	char *next, *next2;
2317bf21cd93STycho Nightingale 
2318bf21cd93STycho Nightingale 	ret = 0;
2319bf21cd93STycho Nightingale 
2320bf21cd93STycho Nightingale #ifdef AHCI_DEBUG
2321bf21cd93STycho Nightingale 	dbg = fopen("/tmp/log", "w+");
2322bf21cd93STycho Nightingale #endif
2323bf21cd93STycho Nightingale 
2324bf21cd93STycho Nightingale 	sc = calloc(1, sizeof(struct pci_ahci_softc));
2325bf21cd93STycho Nightingale 	pi->pi_arg = sc;
2326bf21cd93STycho Nightingale 	sc->asc_pi = pi;
23274c87aefeSPatrick Mooney 	pthread_mutex_init(&sc->mtx, NULL);
23284c87aefeSPatrick Mooney 	sc->ports = 0;
23294c87aefeSPatrick Mooney 	sc->pi = 0;
23304c87aefeSPatrick Mooney 	slots = 32;
23314c87aefeSPatrick Mooney 
23324c87aefeSPatrick Mooney 	for (p = 0; p < MAX_PORTS && opts != NULL; p++, opts = next) {
23334c87aefeSPatrick Mooney 		/* Identify and cut off type of present port. */
23344c87aefeSPatrick Mooney 		if (strncmp(opts, "hd:", 3) == 0) {
23354c87aefeSPatrick Mooney 			atapi = 0;
23364c87aefeSPatrick Mooney 			opts += 3;
23374c87aefeSPatrick Mooney 		} else if (strncmp(opts, "cd:", 3) == 0) {
23384c87aefeSPatrick Mooney 			atapi = 1;
23394c87aefeSPatrick Mooney 			opts += 3;
23404c87aefeSPatrick Mooney 		}
23414c87aefeSPatrick Mooney 
23424c87aefeSPatrick Mooney 		/* Find and cut off the next port options. */
23434c87aefeSPatrick Mooney 		next = strstr(opts, ",hd:");
23444c87aefeSPatrick Mooney 		next2 = strstr(opts, ",cd:");
23454c87aefeSPatrick Mooney 		if (next == NULL || (next2 != NULL && next2 < next))
23464c87aefeSPatrick Mooney 			next = next2;
23474c87aefeSPatrick Mooney 		if (next != NULL) {
23484c87aefeSPatrick Mooney 			next[0] = 0;
23494c87aefeSPatrick Mooney 			next++;
23504c87aefeSPatrick Mooney 		}
23514c87aefeSPatrick Mooney 
23524c87aefeSPatrick Mooney 		if (opts[0] == 0)
23534c87aefeSPatrick Mooney 			continue;
2354bf21cd93STycho Nightingale 
2355bf21cd93STycho Nightingale 		/*
23564c87aefeSPatrick Mooney 		 * Attempt to open the backing image. Use the PCI slot/func
23574c87aefeSPatrick Mooney 		 * and the port number for the identifier string.
2358bf21cd93STycho Nightingale 		 */
23594c87aefeSPatrick Mooney 		snprintf(bident, sizeof(bident), "%d:%d:%d", pi->pi_slot,
23604c87aefeSPatrick Mooney 		    pi->pi_func, p);
2361bf21cd93STycho Nightingale 		bctxt = blockif_open(opts, bident);
2362bf21cd93STycho Nightingale 		if (bctxt == NULL) {
23634c87aefeSPatrick Mooney 			sc->ports = p;
2364bf21cd93STycho Nightingale 			ret = 1;
2365bf21cd93STycho Nightingale 			goto open_fail;
2366bf21cd93STycho Nightingale 		}
23674c87aefeSPatrick Mooney 		sc->port[p].bctx = bctxt;
23684c87aefeSPatrick Mooney 		sc->port[p].pr_sc = sc;
23694c87aefeSPatrick Mooney 		sc->port[p].port = p;
23704c87aefeSPatrick Mooney 		sc->port[p].atapi = atapi;
23714c87aefeSPatrick Mooney 
23724c87aefeSPatrick Mooney #ifndef __FreeBSD__
23734c87aefeSPatrick Mooney 		/*
23744c87aefeSPatrick Mooney 		 * Attempt to enable the write cache for this device, as the
23754c87aefeSPatrick Mooney 		 * guest will issue FLUSH commands when it requires durability.
23764c87aefeSPatrick Mooney 		 *
23774c87aefeSPatrick Mooney 		 * Failure here is fine, since an always-sync device will not
23784c87aefeSPatrick Mooney 		 * have an impact on correctness.
23794c87aefeSPatrick Mooney 		 */
23804c87aefeSPatrick Mooney 		(void) blockif_set_wce(bctxt, 1);
23814c87aefeSPatrick Mooney #endif
23824c87aefeSPatrick Mooney 
23834c87aefeSPatrick Mooney 		/*
23844c87aefeSPatrick Mooney 		 * Create an identifier for the backing file.
23854c87aefeSPatrick Mooney 		 * Use parts of the md5 sum of the filename
23864c87aefeSPatrick Mooney 		 */
23874c87aefeSPatrick Mooney 		MD5Init(&mdctx);
23884c87aefeSPatrick Mooney 		MD5Update(&mdctx, opts, strlen(opts));
23894c87aefeSPatrick Mooney 		MD5Final(digest, &mdctx);
23904c87aefeSPatrick Mooney 		snprintf(sc->port[p].ident, AHCI_PORT_IDENT,
23914c87aefeSPatrick Mooney 		    "BHYVE-%02X%02X-%02X%02X-%02X%02X",
23924c87aefeSPatrick Mooney 		    digest[0], digest[1], digest[2], digest[3], digest[4],
23934c87aefeSPatrick Mooney 		    digest[5]);
2394bf21cd93STycho Nightingale 
2395bf21cd93STycho Nightingale 		/*
2396bf21cd93STycho Nightingale 		 * Allocate blockif request structures and add them
2397bf21cd93STycho Nightingale 		 * to the free list
2398bf21cd93STycho Nightingale 		 */
23994c87aefeSPatrick Mooney 		pci_ahci_ioreq_init(&sc->port[p]);
2400bf21cd93STycho Nightingale 
24014c87aefeSPatrick Mooney 		sc->pi |= (1 << p);
24024c87aefeSPatrick Mooney 		if (sc->port[p].ioqsz < slots)
24034c87aefeSPatrick Mooney 			slots = sc->port[p].ioqsz;
24044c87aefeSPatrick Mooney 	}
24054c87aefeSPatrick Mooney 	sc->ports = p;
2406bf21cd93STycho Nightingale 
2407bf21cd93STycho Nightingale 	/* Intel ICH8 AHCI */
2408bf21cd93STycho Nightingale 	--slots;
24094c87aefeSPatrick Mooney 	if (sc->ports < DEF_PORTS)
24104c87aefeSPatrick Mooney 		sc->ports = DEF_PORTS;
2411bf21cd93STycho Nightingale 	sc->cap = AHCI_CAP_64BIT | AHCI_CAP_SNCQ | AHCI_CAP_SSNTF |
2412bf21cd93STycho Nightingale 	    AHCI_CAP_SMPS | AHCI_CAP_SSS | AHCI_CAP_SALP |
2413bf21cd93STycho Nightingale 	    AHCI_CAP_SAL | AHCI_CAP_SCLO | (0x3 << AHCI_CAP_ISS_SHIFT)|
2414bf21cd93STycho Nightingale 	    AHCI_CAP_PMD | AHCI_CAP_SSC | AHCI_CAP_PSC |
2415bf21cd93STycho Nightingale 	    (slots << AHCI_CAP_NCS_SHIFT) | AHCI_CAP_SXS | (sc->ports - 1);
2416bf21cd93STycho Nightingale 
2417bf21cd93STycho Nightingale 	sc->vs = 0x10300;
2418bf21cd93STycho Nightingale 	sc->cap2 = AHCI_CAP2_APST;
2419bf21cd93STycho Nightingale 	ahci_reset(sc);
2420bf21cd93STycho Nightingale 
2421bf21cd93STycho Nightingale 	pci_set_cfgdata16(pi, PCIR_DEVICE, 0x2821);
2422bf21cd93STycho Nightingale 	pci_set_cfgdata16(pi, PCIR_VENDOR, 0x8086);
2423bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE);
2424bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_STORAGE_SATA);
2425bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, PCIR_PROGIF, PCIP_STORAGE_SATA_AHCI_1_0);
24264c87aefeSPatrick Mooney 	p = MIN(sc->ports, 16);
24274c87aefeSPatrick Mooney 	p = flsl(p) - ((p & (p - 1)) ? 0 : 1);
24284c87aefeSPatrick Mooney 	pci_emul_add_msicap(pi, 1 << p);
2429bf21cd93STycho Nightingale 	pci_emul_alloc_bar(pi, 5, PCIBAR_MEM32,
2430bf21cd93STycho Nightingale 	    AHCI_OFFSET + sc->ports * AHCI_STEP);
2431bf21cd93STycho Nightingale 
2432bf21cd93STycho Nightingale 	pci_lintr_request(pi);
2433bf21cd93STycho Nightingale 
2434bf21cd93STycho Nightingale open_fail:
2435bf21cd93STycho Nightingale 	if (ret) {
24364c87aefeSPatrick Mooney 		for (p = 0; p < sc->ports; p++) {
24374c87aefeSPatrick Mooney 			if (sc->port[p].bctx != NULL)
24384c87aefeSPatrick Mooney 				blockif_close(sc->port[p].bctx);
24394c87aefeSPatrick Mooney 		}
2440bf21cd93STycho Nightingale 		free(sc);
2441bf21cd93STycho Nightingale 	}
2442bf21cd93STycho Nightingale 
2443bf21cd93STycho Nightingale 	return (ret);
2444bf21cd93STycho Nightingale }
2445bf21cd93STycho Nightingale 
2446bf21cd93STycho Nightingale static int
2447bf21cd93STycho Nightingale pci_ahci_hd_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
2448bf21cd93STycho Nightingale {
2449bf21cd93STycho Nightingale 
2450bf21cd93STycho Nightingale 	return (pci_ahci_init(ctx, pi, opts, 0));
2451bf21cd93STycho Nightingale }
2452bf21cd93STycho Nightingale 
2453bf21cd93STycho Nightingale static int
2454bf21cd93STycho Nightingale pci_ahci_atapi_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
2455bf21cd93STycho Nightingale {
2456bf21cd93STycho Nightingale 
2457bf21cd93STycho Nightingale 	return (pci_ahci_init(ctx, pi, opts, 1));
2458bf21cd93STycho Nightingale }
2459bf21cd93STycho Nightingale 
2460bf21cd93STycho Nightingale /*
2461bf21cd93STycho Nightingale  * Use separate emulation names to distinguish drive and atapi devices
2462bf21cd93STycho Nightingale  */
24634c87aefeSPatrick Mooney struct pci_devemu pci_de_ahci = {
24644c87aefeSPatrick Mooney 	.pe_emu =	"ahci",
24654c87aefeSPatrick Mooney 	.pe_init =	pci_ahci_hd_init,
24664c87aefeSPatrick Mooney 	.pe_barwrite =	pci_ahci_write,
24674c87aefeSPatrick Mooney 	.pe_barread =	pci_ahci_read
24684c87aefeSPatrick Mooney };
24694c87aefeSPatrick Mooney PCI_EMUL_SET(pci_de_ahci);
24704c87aefeSPatrick Mooney 
2471bf21cd93STycho Nightingale struct pci_devemu pci_de_ahci_hd = {
2472bf21cd93STycho Nightingale 	.pe_emu =	"ahci-hd",
2473bf21cd93STycho Nightingale 	.pe_init =	pci_ahci_hd_init,
2474bf21cd93STycho Nightingale 	.pe_barwrite =	pci_ahci_write,
2475bf21cd93STycho Nightingale 	.pe_barread =	pci_ahci_read
2476bf21cd93STycho Nightingale };
2477bf21cd93STycho Nightingale PCI_EMUL_SET(pci_de_ahci_hd);
2478bf21cd93STycho Nightingale 
2479bf21cd93STycho Nightingale struct pci_devemu pci_de_ahci_cd = {
2480bf21cd93STycho Nightingale 	.pe_emu =	"ahci-cd",
2481bf21cd93STycho Nightingale 	.pe_init =	pci_ahci_atapi_init,
2482bf21cd93STycho Nightingale 	.pe_barwrite =	pci_ahci_write,
2483bf21cd93STycho Nightingale 	.pe_barread =	pci_ahci_read
2484bf21cd93STycho Nightingale };
2485bf21cd93STycho Nightingale PCI_EMUL_SET(pci_de_ahci_cd);
2486