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