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" 592b948146SAndy Fiddaman #include "config.h" 602b948146SAndy Fiddaman #include "debug.h" 61bf21cd93STycho Nightingale #include "pci_emul.h" 62bf21cd93STycho Nightingale #include "ahci.h" 63bf21cd93STycho Nightingale #include "block_if.h" 64bf21cd93STycho Nightingale 654c87aefeSPatrick Mooney #define DEF_PORTS 6 /* Intel ICH8 AHCI supports 6 ports */ 664c87aefeSPatrick Mooney #define MAX_PORTS 32 /* AHCI supports 32 ports */ 67bf21cd93STycho Nightingale 68bf21cd93STycho Nightingale #define PxSIG_ATA 0x00000101 /* ATA drive */ 69bf21cd93STycho Nightingale #define PxSIG_ATAPI 0xeb140101 /* ATAPI drive */ 70bf21cd93STycho Nightingale 71bf21cd93STycho Nightingale enum sata_fis_type { 72bf21cd93STycho Nightingale FIS_TYPE_REGH2D = 0x27, /* Register FIS - host to device */ 73bf21cd93STycho Nightingale FIS_TYPE_REGD2H = 0x34, /* Register FIS - device to host */ 74bf21cd93STycho Nightingale FIS_TYPE_DMAACT = 0x39, /* DMA activate FIS - device to host */ 75bf21cd93STycho Nightingale FIS_TYPE_DMASETUP = 0x41, /* DMA setup FIS - bidirectional */ 76bf21cd93STycho Nightingale FIS_TYPE_DATA = 0x46, /* Data FIS - bidirectional */ 77bf21cd93STycho Nightingale FIS_TYPE_BIST = 0x58, /* BIST activate FIS - bidirectional */ 78bf21cd93STycho Nightingale FIS_TYPE_PIOSETUP = 0x5F, /* PIO setup FIS - device to host */ 79bf21cd93STycho Nightingale FIS_TYPE_SETDEVBITS = 0xA1, /* Set dev bits FIS - device to host */ 80bf21cd93STycho Nightingale }; 81bf21cd93STycho Nightingale 82bf21cd93STycho Nightingale /* 83bf21cd93STycho Nightingale * SCSI opcodes 84bf21cd93STycho Nightingale */ 85bf21cd93STycho Nightingale #define TEST_UNIT_READY 0x00 86bf21cd93STycho Nightingale #define REQUEST_SENSE 0x03 87bf21cd93STycho Nightingale #define INQUIRY 0x12 88bf21cd93STycho Nightingale #define START_STOP_UNIT 0x1B 89bf21cd93STycho Nightingale #define PREVENT_ALLOW 0x1E 90bf21cd93STycho Nightingale #define READ_CAPACITY 0x25 91bf21cd93STycho Nightingale #define READ_10 0x28 92bf21cd93STycho Nightingale #define POSITION_TO_ELEMENT 0x2B 93bf21cd93STycho Nightingale #define READ_TOC 0x43 94bf21cd93STycho Nightingale #define GET_EVENT_STATUS_NOTIFICATION 0x4A 95bf21cd93STycho Nightingale #define MODE_SENSE_10 0x5A 964c87aefeSPatrick Mooney #define REPORT_LUNS 0xA0 97bf21cd93STycho Nightingale #define READ_12 0xA8 98bf21cd93STycho Nightingale #define READ_CD 0xBE 99bf21cd93STycho Nightingale 100bf21cd93STycho Nightingale /* 101bf21cd93STycho Nightingale * SCSI mode page codes 102bf21cd93STycho Nightingale */ 103bf21cd93STycho Nightingale #define MODEPAGE_RW_ERROR_RECOVERY 0x01 104bf21cd93STycho Nightingale #define MODEPAGE_CD_CAPABILITIES 0x2A 105bf21cd93STycho Nightingale 106bf21cd93STycho Nightingale /* 107bf21cd93STycho Nightingale * ATA commands 108bf21cd93STycho Nightingale */ 109bf21cd93STycho Nightingale #define ATA_SF_ENAB_SATA_SF 0x10 110bf21cd93STycho Nightingale #define ATA_SATA_SF_AN 0x05 111bf21cd93STycho Nightingale #define ATA_SF_DIS_SATA_SF 0x90 112bf21cd93STycho Nightingale 113bf21cd93STycho Nightingale /* 114bf21cd93STycho Nightingale * Debug printf 115bf21cd93STycho Nightingale */ 116bf21cd93STycho Nightingale #ifdef AHCI_DEBUG 117bf21cd93STycho Nightingale static FILE *dbg; 118bf21cd93STycho Nightingale #define DPRINTF(format, arg...) do{fprintf(dbg, format, ##arg);fflush(dbg);}while(0) 119bf21cd93STycho Nightingale #else 120bf21cd93STycho Nightingale #define DPRINTF(format, arg...) 121bf21cd93STycho Nightingale #endif 122bf21cd93STycho Nightingale #define WPRINTF(format, arg...) printf(format, ##arg) 123bf21cd93STycho Nightingale 1244c87aefeSPatrick Mooney #define AHCI_PORT_IDENT 20 + 1 1254c87aefeSPatrick Mooney 126bf21cd93STycho Nightingale struct ahci_ioreq { 127bf21cd93STycho Nightingale struct blockif_req io_req; 128bf21cd93STycho Nightingale struct ahci_port *io_pr; 129bf21cd93STycho Nightingale STAILQ_ENTRY(ahci_ioreq) io_flist; 130bf21cd93STycho Nightingale TAILQ_ENTRY(ahci_ioreq) io_blist; 131bf21cd93STycho Nightingale uint8_t *cfis; 132bf21cd93STycho Nightingale uint32_t len; 133bf21cd93STycho Nightingale uint32_t done; 134bf21cd93STycho Nightingale int slot; 1354c87aefeSPatrick Mooney int more; 136bf21cd93STycho Nightingale }; 137bf21cd93STycho Nightingale 138bf21cd93STycho Nightingale struct ahci_port { 139bf21cd93STycho Nightingale struct blockif_ctxt *bctx; 140bf21cd93STycho Nightingale struct pci_ahci_softc *pr_sc; 1416960cd89SAndy Fiddaman struct ata_params ata_ident; 142bf21cd93STycho Nightingale uint8_t *cmd_lst; 143bf21cd93STycho Nightingale uint8_t *rfis; 1444c87aefeSPatrick Mooney int port; 145bf21cd93STycho Nightingale int atapi; 146bf21cd93STycho Nightingale int reset; 1474c87aefeSPatrick Mooney int waitforclear; 148bf21cd93STycho Nightingale int mult_sectors; 149bf21cd93STycho Nightingale uint8_t xfermode; 1504c87aefeSPatrick Mooney uint8_t err_cfis[20]; 151bf21cd93STycho Nightingale uint8_t sense_key; 152bf21cd93STycho Nightingale uint8_t asc; 1534c87aefeSPatrick Mooney u_int ccs; 154bf21cd93STycho Nightingale uint32_t pending; 155bf21cd93STycho Nightingale 156bf21cd93STycho Nightingale uint32_t clb; 157bf21cd93STycho Nightingale uint32_t clbu; 158bf21cd93STycho Nightingale uint32_t fb; 159bf21cd93STycho Nightingale uint32_t fbu; 160bf21cd93STycho Nightingale uint32_t is; 161bf21cd93STycho Nightingale uint32_t ie; 162bf21cd93STycho Nightingale uint32_t cmd; 163bf21cd93STycho Nightingale uint32_t unused0; 164bf21cd93STycho Nightingale uint32_t tfd; 165bf21cd93STycho Nightingale uint32_t sig; 166bf21cd93STycho Nightingale uint32_t ssts; 167bf21cd93STycho Nightingale uint32_t sctl; 168bf21cd93STycho Nightingale uint32_t serr; 169bf21cd93STycho Nightingale uint32_t sact; 170bf21cd93STycho Nightingale uint32_t ci; 171bf21cd93STycho Nightingale uint32_t sntf; 172bf21cd93STycho Nightingale uint32_t fbs; 173bf21cd93STycho Nightingale 174bf21cd93STycho Nightingale /* 175bf21cd93STycho Nightingale * i/o request info 176bf21cd93STycho Nightingale */ 177bf21cd93STycho Nightingale struct ahci_ioreq *ioreq; 178bf21cd93STycho Nightingale int ioqsz; 179bf21cd93STycho Nightingale STAILQ_HEAD(ahci_fhead, ahci_ioreq) iofhd; 180bf21cd93STycho Nightingale TAILQ_HEAD(ahci_bhead, ahci_ioreq) iobhd; 181bf21cd93STycho Nightingale }; 182bf21cd93STycho Nightingale 183bf21cd93STycho Nightingale struct ahci_cmd_hdr { 184bf21cd93STycho Nightingale uint16_t flags; 185bf21cd93STycho Nightingale uint16_t prdtl; 186bf21cd93STycho Nightingale uint32_t prdbc; 187bf21cd93STycho Nightingale uint64_t ctba; 188bf21cd93STycho Nightingale uint32_t reserved[4]; 189bf21cd93STycho Nightingale }; 190bf21cd93STycho Nightingale 191bf21cd93STycho Nightingale struct ahci_prdt_entry { 192bf21cd93STycho Nightingale uint64_t dba; 193bf21cd93STycho Nightingale uint32_t reserved; 194bf21cd93STycho Nightingale #define DBCMASK 0x3fffff 195bf21cd93STycho Nightingale uint32_t dbc; 196bf21cd93STycho Nightingale }; 197bf21cd93STycho Nightingale 198bf21cd93STycho Nightingale struct pci_ahci_softc { 199bf21cd93STycho Nightingale struct pci_devinst *asc_pi; 200bf21cd93STycho Nightingale pthread_mutex_t mtx; 201bf21cd93STycho Nightingale int ports; 202bf21cd93STycho Nightingale uint32_t cap; 203bf21cd93STycho Nightingale uint32_t ghc; 204bf21cd93STycho Nightingale uint32_t is; 205bf21cd93STycho Nightingale uint32_t pi; 206bf21cd93STycho Nightingale uint32_t vs; 207bf21cd93STycho Nightingale uint32_t ccc_ctl; 208bf21cd93STycho Nightingale uint32_t ccc_pts; 209bf21cd93STycho Nightingale uint32_t em_loc; 210bf21cd93STycho Nightingale uint32_t em_ctl; 211bf21cd93STycho Nightingale uint32_t cap2; 212bf21cd93STycho Nightingale uint32_t bohc; 213bf21cd93STycho Nightingale uint32_t lintr; 214bf21cd93STycho Nightingale struct ahci_port port[MAX_PORTS]; 215bf21cd93STycho Nightingale }; 216bf21cd93STycho Nightingale #define ahci_ctx(sc) ((sc)->asc_pi->pi_vmctx) 217bf21cd93STycho Nightingale 2184c87aefeSPatrick Mooney static void ahci_handle_port(struct ahci_port *p); 2194c87aefeSPatrick Mooney 220bf21cd93STycho Nightingale static inline void lba_to_msf(uint8_t *buf, int lba) 221bf21cd93STycho Nightingale { 222bf21cd93STycho Nightingale lba += 150; 223bf21cd93STycho Nightingale buf[0] = (lba / 75) / 60; 224bf21cd93STycho Nightingale buf[1] = (lba / 75) % 60; 225bf21cd93STycho Nightingale buf[2] = lba % 75; 226bf21cd93STycho Nightingale } 227bf21cd93STycho Nightingale 228bf21cd93STycho Nightingale /* 2294c87aefeSPatrick Mooney * Generate HBA interrupts on global IS register write. 230bf21cd93STycho Nightingale */ 231bf21cd93STycho Nightingale static void 2324c87aefeSPatrick Mooney ahci_generate_intr(struct pci_ahci_softc *sc, uint32_t mask) 233bf21cd93STycho Nightingale { 2344c87aefeSPatrick Mooney struct pci_devinst *pi = sc->asc_pi; 2354c87aefeSPatrick Mooney struct ahci_port *p; 2364c87aefeSPatrick Mooney int i, nmsg; 2374c87aefeSPatrick Mooney uint32_t mmask; 238bf21cd93STycho Nightingale 2394c87aefeSPatrick Mooney /* Update global IS from PxIS/PxIE. */ 240bf21cd93STycho Nightingale for (i = 0; i < sc->ports; i++) { 2414c87aefeSPatrick Mooney p = &sc->port[i]; 2424c87aefeSPatrick Mooney if (p->is & p->ie) 243bf21cd93STycho Nightingale sc->is |= (1 << i); 244bf21cd93STycho Nightingale } 245154972afSPatrick Mooney DPRINTF("%s(%08x) %08x", __func__, mask, sc->is); 246bf21cd93STycho Nightingale 2474c87aefeSPatrick Mooney /* If there is nothing enabled -- clear legacy interrupt and exit. */ 2484c87aefeSPatrick Mooney if (sc->is == 0 || (sc->ghc & AHCI_GHC_IE) == 0) { 2494c87aefeSPatrick Mooney if (sc->lintr) { 2504c87aefeSPatrick Mooney pci_lintr_deassert(pi); 2514c87aefeSPatrick Mooney sc->lintr = 0; 2524c87aefeSPatrick Mooney } 2534c87aefeSPatrick Mooney return; 2544c87aefeSPatrick Mooney } 255bf21cd93STycho Nightingale 2564c87aefeSPatrick Mooney /* If there is anything and no MSI -- assert legacy interrupt. */ 2574c87aefeSPatrick Mooney nmsg = pci_msi_maxmsgnum(pi); 2584c87aefeSPatrick Mooney if (nmsg == 0) { 2594c87aefeSPatrick Mooney if (!sc->lintr) { 260bf21cd93STycho Nightingale sc->lintr = 1; 261bf21cd93STycho Nightingale pci_lintr_assert(pi); 262bf21cd93STycho Nightingale } 2634c87aefeSPatrick Mooney return; 2644c87aefeSPatrick Mooney } 2654c87aefeSPatrick Mooney 2664c87aefeSPatrick Mooney /* Assert respective MSIs for ports that were touched. */ 2674c87aefeSPatrick Mooney for (i = 0; i < nmsg; i++) { 2684c87aefeSPatrick Mooney if (sc->ports <= nmsg || i < nmsg - 1) 2694c87aefeSPatrick Mooney mmask = 1 << i; 2704c87aefeSPatrick Mooney else 2714c87aefeSPatrick Mooney mmask = 0xffffffff << i; 2724c87aefeSPatrick Mooney if (sc->is & mask && mmask & mask) 2734c87aefeSPatrick Mooney pci_generate_msi(pi, i); 2744c87aefeSPatrick Mooney } 2754c87aefeSPatrick Mooney } 2764c87aefeSPatrick Mooney 277bf21cd93STycho Nightingale /* 2784c87aefeSPatrick Mooney * Generate HBA interrupt on specific port event. 279bf21cd93STycho Nightingale */ 2804c87aefeSPatrick Mooney static void 2814c87aefeSPatrick Mooney ahci_port_intr(struct ahci_port *p) 2824c87aefeSPatrick Mooney { 2834c87aefeSPatrick Mooney struct pci_ahci_softc *sc = p->pr_sc; 2844c87aefeSPatrick Mooney struct pci_devinst *pi = sc->asc_pi; 2854c87aefeSPatrick Mooney int nmsg; 2864c87aefeSPatrick Mooney 287154972afSPatrick Mooney DPRINTF("%s(%d) %08x/%08x %08x", __func__, 2884c87aefeSPatrick Mooney p->port, p->is, p->ie, sc->is); 2894c87aefeSPatrick Mooney 2904c87aefeSPatrick Mooney /* If there is nothing enabled -- we are done. */ 2914c87aefeSPatrick Mooney if ((p->is & p->ie) == 0) 2924c87aefeSPatrick Mooney return; 2934c87aefeSPatrick Mooney 2944c87aefeSPatrick Mooney /* In case of non-shared MSI always generate interrupt. */ 2954c87aefeSPatrick Mooney nmsg = pci_msi_maxmsgnum(pi); 2964c87aefeSPatrick Mooney if (sc->ports <= nmsg || p->port < nmsg - 1) { 2974c87aefeSPatrick Mooney sc->is |= (1 << p->port); 2984c87aefeSPatrick Mooney if ((sc->ghc & AHCI_GHC_IE) == 0) 2994c87aefeSPatrick Mooney return; 3004c87aefeSPatrick Mooney pci_generate_msi(pi, p->port); 3014c87aefeSPatrick Mooney return; 3024c87aefeSPatrick Mooney } 3034c87aefeSPatrick Mooney 3044c87aefeSPatrick Mooney /* If IS for this port is already set -- do nothing. */ 3054c87aefeSPatrick Mooney if (sc->is & (1 << p->port)) 3064c87aefeSPatrick Mooney return; 3074c87aefeSPatrick Mooney 3084c87aefeSPatrick Mooney sc->is |= (1 << p->port); 3094c87aefeSPatrick Mooney 3104c87aefeSPatrick Mooney /* If interrupts are enabled -- generate one. */ 3114c87aefeSPatrick Mooney if ((sc->ghc & AHCI_GHC_IE) == 0) 3124c87aefeSPatrick Mooney return; 3134c87aefeSPatrick Mooney if (nmsg > 0) { 3144c87aefeSPatrick Mooney pci_generate_msi(pi, nmsg - 1); 3154c87aefeSPatrick Mooney } else if (!sc->lintr) { 3164c87aefeSPatrick Mooney sc->lintr = 1; 3174c87aefeSPatrick Mooney pci_lintr_assert(pi); 318bf21cd93STycho Nightingale } 319bf21cd93STycho Nightingale } 320bf21cd93STycho Nightingale 321bf21cd93STycho Nightingale static void 322bf21cd93STycho Nightingale ahci_write_fis(struct ahci_port *p, enum sata_fis_type ft, uint8_t *fis) 323bf21cd93STycho Nightingale { 324bf21cd93STycho Nightingale int offset, len, irq; 325bf21cd93STycho Nightingale 326bf21cd93STycho Nightingale if (p->rfis == NULL || !(p->cmd & AHCI_P_CMD_FRE)) 327bf21cd93STycho Nightingale return; 328bf21cd93STycho Nightingale 329bf21cd93STycho Nightingale switch (ft) { 330bf21cd93STycho Nightingale case FIS_TYPE_REGD2H: 331bf21cd93STycho Nightingale offset = 0x40; 332bf21cd93STycho Nightingale len = 20; 3334c87aefeSPatrick Mooney irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_DHR : 0; 334bf21cd93STycho Nightingale break; 335bf21cd93STycho Nightingale case FIS_TYPE_SETDEVBITS: 336bf21cd93STycho Nightingale offset = 0x58; 337bf21cd93STycho Nightingale len = 8; 3384c87aefeSPatrick Mooney irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_SDB : 0; 339bf21cd93STycho Nightingale break; 340bf21cd93STycho Nightingale case FIS_TYPE_PIOSETUP: 341bf21cd93STycho Nightingale offset = 0x20; 342bf21cd93STycho Nightingale len = 20; 3434c87aefeSPatrick Mooney irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_PS : 0; 344bf21cd93STycho Nightingale break; 345bf21cd93STycho Nightingale default: 346154972afSPatrick Mooney WPRINTF("unsupported fis type %d", ft); 347bf21cd93STycho Nightingale return; 348bf21cd93STycho Nightingale } 3494c87aefeSPatrick Mooney if (fis[2] & ATA_S_ERROR) { 3504c87aefeSPatrick Mooney p->waitforclear = 1; 3514c87aefeSPatrick Mooney irq |= AHCI_P_IX_TFE; 3524c87aefeSPatrick Mooney } 353bf21cd93STycho Nightingale memcpy(p->rfis + offset, fis, len); 354bf21cd93STycho Nightingale if (irq) { 3554c87aefeSPatrick Mooney if (~p->is & irq) { 356bf21cd93STycho Nightingale p->is |= irq; 3574c87aefeSPatrick Mooney ahci_port_intr(p); 3584c87aefeSPatrick Mooney } 359bf21cd93STycho Nightingale } 360bf21cd93STycho Nightingale } 361bf21cd93STycho Nightingale 362bf21cd93STycho Nightingale static void 363bf21cd93STycho Nightingale ahci_write_fis_piosetup(struct ahci_port *p) 364bf21cd93STycho Nightingale { 365bf21cd93STycho Nightingale uint8_t fis[20]; 366bf21cd93STycho Nightingale 367bf21cd93STycho Nightingale memset(fis, 0, sizeof(fis)); 368bf21cd93STycho Nightingale fis[0] = FIS_TYPE_PIOSETUP; 369bf21cd93STycho Nightingale ahci_write_fis(p, FIS_TYPE_PIOSETUP, fis); 370bf21cd93STycho Nightingale } 371bf21cd93STycho Nightingale 372bf21cd93STycho Nightingale static void 3734c87aefeSPatrick Mooney ahci_write_fis_sdb(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd) 374bf21cd93STycho Nightingale { 375bf21cd93STycho Nightingale uint8_t fis[8]; 376bf21cd93STycho Nightingale uint8_t error; 377bf21cd93STycho Nightingale 378bf21cd93STycho Nightingale error = (tfd >> 8) & 0xff; 3794c87aefeSPatrick Mooney tfd &= 0x77; 380bf21cd93STycho Nightingale memset(fis, 0, sizeof(fis)); 3814c87aefeSPatrick Mooney fis[0] = FIS_TYPE_SETDEVBITS; 3824c87aefeSPatrick Mooney fis[1] = (1 << 6); 3834c87aefeSPatrick Mooney fis[2] = tfd; 3844c87aefeSPatrick Mooney fis[3] = error; 3854c87aefeSPatrick Mooney if (fis[2] & ATA_S_ERROR) { 3864c87aefeSPatrick Mooney p->err_cfis[0] = slot; 3874c87aefeSPatrick Mooney p->err_cfis[2] = tfd; 3884c87aefeSPatrick Mooney p->err_cfis[3] = error; 3894c87aefeSPatrick Mooney memcpy(&p->err_cfis[4], cfis + 4, 16); 3904c87aefeSPatrick Mooney } else { 391bf21cd93STycho Nightingale *(uint32_t *)(fis + 4) = (1 << slot); 3924c87aefeSPatrick Mooney p->sact &= ~(1 << slot); 3934c87aefeSPatrick Mooney } 3944c87aefeSPatrick Mooney p->tfd &= ~0x77; 3954c87aefeSPatrick Mooney p->tfd |= tfd; 396bf21cd93STycho Nightingale ahci_write_fis(p, FIS_TYPE_SETDEVBITS, fis); 397bf21cd93STycho Nightingale } 398bf21cd93STycho Nightingale 399bf21cd93STycho Nightingale static void 400bf21cd93STycho Nightingale ahci_write_fis_d2h(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd) 401bf21cd93STycho Nightingale { 402bf21cd93STycho Nightingale uint8_t fis[20]; 403bf21cd93STycho Nightingale uint8_t error; 404bf21cd93STycho Nightingale 405bf21cd93STycho Nightingale error = (tfd >> 8) & 0xff; 406bf21cd93STycho Nightingale memset(fis, 0, sizeof(fis)); 407bf21cd93STycho Nightingale fis[0] = FIS_TYPE_REGD2H; 408bf21cd93STycho Nightingale fis[1] = (1 << 6); 409bf21cd93STycho Nightingale fis[2] = tfd & 0xff; 410bf21cd93STycho Nightingale fis[3] = error; 411bf21cd93STycho Nightingale fis[4] = cfis[4]; 412bf21cd93STycho Nightingale fis[5] = cfis[5]; 413bf21cd93STycho Nightingale fis[6] = cfis[6]; 414bf21cd93STycho Nightingale fis[7] = cfis[7]; 415bf21cd93STycho Nightingale fis[8] = cfis[8]; 416bf21cd93STycho Nightingale fis[9] = cfis[9]; 417bf21cd93STycho Nightingale fis[10] = cfis[10]; 418bf21cd93STycho Nightingale fis[11] = cfis[11]; 419bf21cd93STycho Nightingale fis[12] = cfis[12]; 420bf21cd93STycho Nightingale fis[13] = cfis[13]; 4214c87aefeSPatrick Mooney if (fis[2] & ATA_S_ERROR) { 4224c87aefeSPatrick Mooney p->err_cfis[0] = 0x80; 4234c87aefeSPatrick Mooney p->err_cfis[2] = tfd & 0xff; 4244c87aefeSPatrick Mooney p->err_cfis[3] = error; 4254c87aefeSPatrick Mooney memcpy(&p->err_cfis[4], cfis + 4, 16); 4264c87aefeSPatrick Mooney } else 427bf21cd93STycho Nightingale p->ci &= ~(1 << slot); 428bf21cd93STycho Nightingale p->tfd = tfd; 429bf21cd93STycho Nightingale ahci_write_fis(p, FIS_TYPE_REGD2H, fis); 430bf21cd93STycho Nightingale } 431bf21cd93STycho Nightingale 432bf21cd93STycho Nightingale static void 4334c87aefeSPatrick Mooney ahci_write_fis_d2h_ncq(struct ahci_port *p, int slot) 4344c87aefeSPatrick Mooney { 4354c87aefeSPatrick Mooney uint8_t fis[20]; 4364c87aefeSPatrick Mooney 4374c87aefeSPatrick Mooney p->tfd = ATA_S_READY | ATA_S_DSC; 4384c87aefeSPatrick Mooney memset(fis, 0, sizeof(fis)); 4394c87aefeSPatrick Mooney fis[0] = FIS_TYPE_REGD2H; 4404c87aefeSPatrick Mooney fis[1] = 0; /* No interrupt */ 4414c87aefeSPatrick Mooney fis[2] = p->tfd; /* Status */ 4424c87aefeSPatrick Mooney fis[3] = 0; /* No error */ 4434c87aefeSPatrick Mooney p->ci &= ~(1 << slot); 4444c87aefeSPatrick Mooney ahci_write_fis(p, FIS_TYPE_REGD2H, fis); 4454c87aefeSPatrick Mooney } 4464c87aefeSPatrick Mooney 4474c87aefeSPatrick Mooney static void 448bf21cd93STycho Nightingale ahci_write_reset_fis_d2h(struct ahci_port *p) 449bf21cd93STycho Nightingale { 450bf21cd93STycho Nightingale uint8_t fis[20]; 451bf21cd93STycho Nightingale 452bf21cd93STycho Nightingale memset(fis, 0, sizeof(fis)); 453bf21cd93STycho Nightingale fis[0] = FIS_TYPE_REGD2H; 454bf21cd93STycho Nightingale fis[3] = 1; 455bf21cd93STycho Nightingale fis[4] = 1; 456bf21cd93STycho Nightingale if (p->atapi) { 457bf21cd93STycho Nightingale fis[5] = 0x14; 458bf21cd93STycho Nightingale fis[6] = 0xeb; 459bf21cd93STycho Nightingale } 460bf21cd93STycho Nightingale fis[12] = 1; 461bf21cd93STycho Nightingale ahci_write_fis(p, FIS_TYPE_REGD2H, fis); 462bf21cd93STycho Nightingale } 463bf21cd93STycho Nightingale 464bf21cd93STycho Nightingale static void 465bf21cd93STycho Nightingale ahci_check_stopped(struct ahci_port *p) 466bf21cd93STycho Nightingale { 467bf21cd93STycho Nightingale /* 468bf21cd93STycho Nightingale * If we are no longer processing the command list and nothing 469bf21cd93STycho Nightingale * is in-flight, clear the running bit, the current command 470bf21cd93STycho Nightingale * slot, the command issue and active bits. 471bf21cd93STycho Nightingale */ 472bf21cd93STycho Nightingale if (!(p->cmd & AHCI_P_CMD_ST)) { 473bf21cd93STycho Nightingale if (p->pending == 0) { 4744c87aefeSPatrick Mooney p->ccs = 0; 475bf21cd93STycho Nightingale p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK); 476bf21cd93STycho Nightingale p->ci = 0; 477bf21cd93STycho Nightingale p->sact = 0; 4784c87aefeSPatrick Mooney p->waitforclear = 0; 479bf21cd93STycho Nightingale } 480bf21cd93STycho Nightingale } 481bf21cd93STycho Nightingale } 482bf21cd93STycho Nightingale 483bf21cd93STycho Nightingale static void 484bf21cd93STycho Nightingale ahci_port_stop(struct ahci_port *p) 485bf21cd93STycho Nightingale { 486bf21cd93STycho Nightingale struct ahci_ioreq *aior; 487bf21cd93STycho Nightingale uint8_t *cfis; 488bf21cd93STycho Nightingale int slot; 489bf21cd93STycho Nightingale int error; 490bf21cd93STycho Nightingale 491bf21cd93STycho Nightingale assert(pthread_mutex_isowned_np(&p->pr_sc->mtx)); 492bf21cd93STycho Nightingale 493bf21cd93STycho Nightingale TAILQ_FOREACH(aior, &p->iobhd, io_blist) { 494bf21cd93STycho Nightingale /* 495bf21cd93STycho Nightingale * Try to cancel the outstanding blockif request. 496bf21cd93STycho Nightingale */ 497bf21cd93STycho Nightingale error = blockif_cancel(p->bctx, &aior->io_req); 498bf21cd93STycho Nightingale if (error != 0) 499bf21cd93STycho Nightingale continue; 500bf21cd93STycho Nightingale 501bf21cd93STycho Nightingale slot = aior->slot; 502bf21cd93STycho Nightingale cfis = aior->cfis; 503bf21cd93STycho Nightingale if (cfis[2] == ATA_WRITE_FPDMA_QUEUED || 5044c87aefeSPatrick Mooney cfis[2] == ATA_READ_FPDMA_QUEUED || 5054c87aefeSPatrick Mooney cfis[2] == ATA_SEND_FPDMA_QUEUED) 5064c87aefeSPatrick Mooney p->sact &= ~(1 << slot); /* NCQ */ 507bf21cd93STycho Nightingale else 508bf21cd93STycho Nightingale p->ci &= ~(1 << slot); 509bf21cd93STycho Nightingale 510bf21cd93STycho Nightingale /* 511bf21cd93STycho Nightingale * This command is now done. 512bf21cd93STycho Nightingale */ 513bf21cd93STycho Nightingale p->pending &= ~(1 << slot); 514bf21cd93STycho Nightingale 515bf21cd93STycho Nightingale /* 516bf21cd93STycho Nightingale * Delete the blockif request from the busy list 517bf21cd93STycho Nightingale */ 518bf21cd93STycho Nightingale TAILQ_REMOVE(&p->iobhd, aior, io_blist); 519bf21cd93STycho Nightingale 520bf21cd93STycho Nightingale /* 521bf21cd93STycho Nightingale * Move the blockif request back to the free list 522bf21cd93STycho Nightingale */ 523bf21cd93STycho Nightingale STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist); 524bf21cd93STycho Nightingale } 525bf21cd93STycho Nightingale 526bf21cd93STycho Nightingale ahci_check_stopped(p); 527bf21cd93STycho Nightingale } 528bf21cd93STycho Nightingale 529bf21cd93STycho Nightingale static void 530bf21cd93STycho Nightingale ahci_port_reset(struct ahci_port *pr) 531bf21cd93STycho Nightingale { 532bf21cd93STycho Nightingale pr->serr = 0; 533bf21cd93STycho Nightingale pr->sact = 0; 534bf21cd93STycho Nightingale pr->xfermode = ATA_UDMA6; 535bf21cd93STycho Nightingale pr->mult_sectors = 128; 536bf21cd93STycho Nightingale 537bf21cd93STycho Nightingale if (!pr->bctx) { 538bf21cd93STycho Nightingale pr->ssts = ATA_SS_DET_NO_DEVICE; 539bf21cd93STycho Nightingale pr->sig = 0xFFFFFFFF; 540bf21cd93STycho Nightingale pr->tfd = 0x7F; 541bf21cd93STycho Nightingale return; 542bf21cd93STycho Nightingale } 5434c87aefeSPatrick Mooney pr->ssts = ATA_SS_DET_PHY_ONLINE | ATA_SS_IPM_ACTIVE; 5444c87aefeSPatrick Mooney if (pr->sctl & ATA_SC_SPD_MASK) 5454c87aefeSPatrick Mooney pr->ssts |= (pr->sctl & ATA_SC_SPD_MASK); 5464c87aefeSPatrick Mooney else 5474c87aefeSPatrick Mooney pr->ssts |= ATA_SS_SPD_GEN3; 548bf21cd93STycho Nightingale pr->tfd = (1 << 8) | ATA_S_DSC | ATA_S_DMA; 549bf21cd93STycho Nightingale if (!pr->atapi) { 550bf21cd93STycho Nightingale pr->sig = PxSIG_ATA; 551bf21cd93STycho Nightingale pr->tfd |= ATA_S_READY; 552bf21cd93STycho Nightingale } else 553bf21cd93STycho Nightingale pr->sig = PxSIG_ATAPI; 554bf21cd93STycho Nightingale ahci_write_reset_fis_d2h(pr); 555bf21cd93STycho Nightingale } 556bf21cd93STycho Nightingale 557bf21cd93STycho Nightingale static void 558bf21cd93STycho Nightingale ahci_reset(struct pci_ahci_softc *sc) 559bf21cd93STycho Nightingale { 560bf21cd93STycho Nightingale int i; 561bf21cd93STycho Nightingale 562bf21cd93STycho Nightingale sc->ghc = AHCI_GHC_AE; 563bf21cd93STycho Nightingale sc->is = 0; 564bf21cd93STycho Nightingale 565bf21cd93STycho Nightingale if (sc->lintr) { 566bf21cd93STycho Nightingale pci_lintr_deassert(sc->asc_pi); 567bf21cd93STycho Nightingale sc->lintr = 0; 568bf21cd93STycho Nightingale } 569bf21cd93STycho Nightingale 570bf21cd93STycho Nightingale for (i = 0; i < sc->ports; i++) { 571bf21cd93STycho Nightingale sc->port[i].ie = 0; 572bf21cd93STycho Nightingale sc->port[i].is = 0; 5734c87aefeSPatrick Mooney sc->port[i].cmd = (AHCI_P_CMD_SUD | AHCI_P_CMD_POD); 5744c87aefeSPatrick Mooney if (sc->port[i].bctx) 5754c87aefeSPatrick Mooney sc->port[i].cmd |= AHCI_P_CMD_CPS; 5764c87aefeSPatrick Mooney sc->port[i].sctl = 0; 577bf21cd93STycho Nightingale ahci_port_reset(&sc->port[i]); 578bf21cd93STycho Nightingale } 579bf21cd93STycho Nightingale } 580bf21cd93STycho Nightingale 581bf21cd93STycho Nightingale static void 582bf21cd93STycho Nightingale ata_string(uint8_t *dest, const char *src, int len) 583bf21cd93STycho Nightingale { 584bf21cd93STycho Nightingale int i; 585bf21cd93STycho Nightingale 586bf21cd93STycho Nightingale for (i = 0; i < len; i++) { 587bf21cd93STycho Nightingale if (*src) 588bf21cd93STycho Nightingale dest[i ^ 1] = *src++; 589bf21cd93STycho Nightingale else 590bf21cd93STycho Nightingale dest[i ^ 1] = ' '; 591bf21cd93STycho Nightingale } 592bf21cd93STycho Nightingale } 593bf21cd93STycho Nightingale 594bf21cd93STycho Nightingale static void 595bf21cd93STycho Nightingale atapi_string(uint8_t *dest, const char *src, int len) 596bf21cd93STycho Nightingale { 597bf21cd93STycho Nightingale int i; 598bf21cd93STycho Nightingale 599bf21cd93STycho Nightingale for (i = 0; i < len; i++) { 600bf21cd93STycho Nightingale if (*src) 601bf21cd93STycho Nightingale dest[i] = *src++; 602bf21cd93STycho Nightingale else 603bf21cd93STycho Nightingale dest[i] = ' '; 604bf21cd93STycho Nightingale } 605bf21cd93STycho Nightingale } 606bf21cd93STycho Nightingale 6074c87aefeSPatrick Mooney /* 6084c87aefeSPatrick Mooney * Build up the iovec based on the PRDT, 'done' and 'len'. 6094c87aefeSPatrick Mooney */ 610bf21cd93STycho Nightingale static void 6114c87aefeSPatrick Mooney ahci_build_iov(struct ahci_port *p, struct ahci_ioreq *aior, 6124c87aefeSPatrick Mooney struct ahci_prdt_entry *prdt, uint16_t prdtl) 6134c87aefeSPatrick Mooney { 6144c87aefeSPatrick Mooney struct blockif_req *breq = &aior->io_req; 6154c87aefeSPatrick Mooney int i, j, skip, todo, left, extra; 6164c87aefeSPatrick Mooney uint32_t dbcsz; 6174c87aefeSPatrick Mooney 6184c87aefeSPatrick Mooney /* Copy part of PRDT between 'done' and 'len' bytes into the iov. */ 6194c87aefeSPatrick Mooney skip = aior->done; 6204c87aefeSPatrick Mooney left = aior->len - aior->done; 6214c87aefeSPatrick Mooney todo = 0; 6224c87aefeSPatrick Mooney for (i = 0, j = 0; i < prdtl && j < BLOCKIF_IOV_MAX && left > 0; 6234c87aefeSPatrick Mooney i++, prdt++) { 6244c87aefeSPatrick Mooney dbcsz = (prdt->dbc & DBCMASK) + 1; 6254c87aefeSPatrick Mooney /* Skip already done part of the PRDT */ 6264c87aefeSPatrick Mooney if (dbcsz <= skip) { 6274c87aefeSPatrick Mooney skip -= dbcsz; 6284c87aefeSPatrick Mooney continue; 6294c87aefeSPatrick Mooney } 6304c87aefeSPatrick Mooney dbcsz -= skip; 6314c87aefeSPatrick Mooney if (dbcsz > left) 6324c87aefeSPatrick Mooney dbcsz = left; 6334c87aefeSPatrick Mooney breq->br_iov[j].iov_base = paddr_guest2host(ahci_ctx(p->pr_sc), 6344c87aefeSPatrick Mooney prdt->dba + skip, dbcsz); 6354c87aefeSPatrick Mooney breq->br_iov[j].iov_len = dbcsz; 6364c87aefeSPatrick Mooney todo += dbcsz; 6374c87aefeSPatrick Mooney left -= dbcsz; 6384c87aefeSPatrick Mooney skip = 0; 6394c87aefeSPatrick Mooney j++; 6404c87aefeSPatrick Mooney } 6414c87aefeSPatrick Mooney 6424c87aefeSPatrick Mooney /* If we got limited by IOV length, round I/O down to sector size. */ 6434c87aefeSPatrick Mooney if (j == BLOCKIF_IOV_MAX) { 6444c87aefeSPatrick Mooney extra = todo % blockif_sectsz(p->bctx); 6454c87aefeSPatrick Mooney todo -= extra; 6464c87aefeSPatrick Mooney assert(todo > 0); 6474c87aefeSPatrick Mooney while (extra > 0) { 6484c87aefeSPatrick Mooney if (breq->br_iov[j - 1].iov_len > extra) { 6494c87aefeSPatrick Mooney breq->br_iov[j - 1].iov_len -= extra; 6504c87aefeSPatrick Mooney break; 6514c87aefeSPatrick Mooney } 6524c87aefeSPatrick Mooney extra -= breq->br_iov[j - 1].iov_len; 6534c87aefeSPatrick Mooney j--; 6544c87aefeSPatrick Mooney } 6554c87aefeSPatrick Mooney } 6564c87aefeSPatrick Mooney 6574c87aefeSPatrick Mooney breq->br_iovcnt = j; 6584c87aefeSPatrick Mooney breq->br_resid = todo; 6594c87aefeSPatrick Mooney aior->done += todo; 6604c87aefeSPatrick Mooney aior->more = (aior->done < aior->len && i < prdtl); 6614c87aefeSPatrick Mooney } 6624c87aefeSPatrick Mooney 6634c87aefeSPatrick Mooney static void 6644c87aefeSPatrick Mooney ahci_handle_rw(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done) 665bf21cd93STycho Nightingale { 666bf21cd93STycho Nightingale struct ahci_ioreq *aior; 667bf21cd93STycho Nightingale struct blockif_req *breq; 668bf21cd93STycho Nightingale struct ahci_prdt_entry *prdt; 669bf21cd93STycho Nightingale struct ahci_cmd_hdr *hdr; 670bf21cd93STycho Nightingale uint64_t lba; 671bf21cd93STycho Nightingale uint32_t len; 6724c87aefeSPatrick Mooney int err, first, ncq, readop; 673bf21cd93STycho Nightingale 674bf21cd93STycho Nightingale prdt = (struct ahci_prdt_entry *)(cfis + 0x80); 675bf21cd93STycho Nightingale hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 676bf21cd93STycho Nightingale ncq = 0; 677bf21cd93STycho Nightingale readop = 1; 6784c87aefeSPatrick Mooney first = (done == 0); 679bf21cd93STycho Nightingale 6804c87aefeSPatrick Mooney if (cfis[2] == ATA_WRITE || cfis[2] == ATA_WRITE48 || 6814c87aefeSPatrick Mooney cfis[2] == ATA_WRITE_MUL || cfis[2] == ATA_WRITE_MUL48 || 6824c87aefeSPatrick Mooney cfis[2] == ATA_WRITE_DMA || cfis[2] == ATA_WRITE_DMA48 || 683bf21cd93STycho Nightingale cfis[2] == ATA_WRITE_FPDMA_QUEUED) 684bf21cd93STycho Nightingale readop = 0; 685bf21cd93STycho Nightingale 686bf21cd93STycho Nightingale if (cfis[2] == ATA_WRITE_FPDMA_QUEUED || 687bf21cd93STycho Nightingale cfis[2] == ATA_READ_FPDMA_QUEUED) { 688bf21cd93STycho Nightingale lba = ((uint64_t)cfis[10] << 40) | 689bf21cd93STycho Nightingale ((uint64_t)cfis[9] << 32) | 690bf21cd93STycho Nightingale ((uint64_t)cfis[8] << 24) | 691bf21cd93STycho Nightingale ((uint64_t)cfis[6] << 16) | 692bf21cd93STycho Nightingale ((uint64_t)cfis[5] << 8) | 693bf21cd93STycho Nightingale cfis[4]; 694bf21cd93STycho Nightingale len = cfis[11] << 8 | cfis[3]; 695bf21cd93STycho Nightingale if (!len) 696bf21cd93STycho Nightingale len = 65536; 697bf21cd93STycho Nightingale ncq = 1; 6984c87aefeSPatrick Mooney } else if (cfis[2] == ATA_READ48 || cfis[2] == ATA_WRITE48 || 6994c87aefeSPatrick Mooney cfis[2] == ATA_READ_MUL48 || cfis[2] == ATA_WRITE_MUL48 || 7004c87aefeSPatrick Mooney cfis[2] == ATA_READ_DMA48 || cfis[2] == ATA_WRITE_DMA48) { 701bf21cd93STycho Nightingale lba = ((uint64_t)cfis[10] << 40) | 702bf21cd93STycho Nightingale ((uint64_t)cfis[9] << 32) | 703bf21cd93STycho Nightingale ((uint64_t)cfis[8] << 24) | 704bf21cd93STycho Nightingale ((uint64_t)cfis[6] << 16) | 705bf21cd93STycho Nightingale ((uint64_t)cfis[5] << 8) | 706bf21cd93STycho Nightingale cfis[4]; 707bf21cd93STycho Nightingale len = cfis[13] << 8 | cfis[12]; 708bf21cd93STycho Nightingale if (!len) 709bf21cd93STycho Nightingale len = 65536; 710bf21cd93STycho Nightingale } else { 711bf21cd93STycho Nightingale lba = ((cfis[7] & 0xf) << 24) | (cfis[6] << 16) | 712bf21cd93STycho Nightingale (cfis[5] << 8) | cfis[4]; 713bf21cd93STycho Nightingale len = cfis[12]; 714bf21cd93STycho Nightingale if (!len) 715bf21cd93STycho Nightingale len = 256; 716bf21cd93STycho Nightingale } 717bf21cd93STycho Nightingale lba *= blockif_sectsz(p->bctx); 718bf21cd93STycho Nightingale len *= blockif_sectsz(p->bctx); 719bf21cd93STycho Nightingale 7204c87aefeSPatrick Mooney /* Pull request off free list */ 721bf21cd93STycho Nightingale aior = STAILQ_FIRST(&p->iofhd); 722bf21cd93STycho Nightingale assert(aior != NULL); 723bf21cd93STycho Nightingale STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); 7244c87aefeSPatrick Mooney 725bf21cd93STycho Nightingale aior->cfis = cfis; 726bf21cd93STycho Nightingale aior->slot = slot; 727bf21cd93STycho Nightingale aior->len = len; 728bf21cd93STycho Nightingale aior->done = done; 729bf21cd93STycho Nightingale breq = &aior->io_req; 730bf21cd93STycho Nightingale breq->br_offset = lba + done; 7314c87aefeSPatrick Mooney ahci_build_iov(p, aior, prdt, hdr->prdtl); 732bf21cd93STycho Nightingale 7334c87aefeSPatrick Mooney /* Mark this command in-flight. */ 734bf21cd93STycho Nightingale p->pending |= 1 << slot; 735bf21cd93STycho Nightingale 7364c87aefeSPatrick Mooney /* Stuff request onto busy list. */ 737bf21cd93STycho Nightingale TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); 738bf21cd93STycho Nightingale 7394c87aefeSPatrick Mooney if (ncq && first) 7404c87aefeSPatrick Mooney ahci_write_fis_d2h_ncq(p, slot); 741bf21cd93STycho Nightingale 742bf21cd93STycho Nightingale if (readop) 743bf21cd93STycho Nightingale err = blockif_read(p->bctx, breq); 744bf21cd93STycho Nightingale else 745bf21cd93STycho Nightingale err = blockif_write(p->bctx, breq); 746bf21cd93STycho Nightingale assert(err == 0); 747bf21cd93STycho Nightingale } 748bf21cd93STycho Nightingale 749bf21cd93STycho Nightingale static void 750bf21cd93STycho Nightingale ahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis) 751bf21cd93STycho Nightingale { 752bf21cd93STycho Nightingale struct ahci_ioreq *aior; 753bf21cd93STycho Nightingale struct blockif_req *breq; 754bf21cd93STycho Nightingale int err; 755bf21cd93STycho Nightingale 756bf21cd93STycho Nightingale /* 757bf21cd93STycho Nightingale * Pull request off free list 758bf21cd93STycho Nightingale */ 759bf21cd93STycho Nightingale aior = STAILQ_FIRST(&p->iofhd); 760bf21cd93STycho Nightingale assert(aior != NULL); 761bf21cd93STycho Nightingale STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); 762bf21cd93STycho Nightingale aior->cfis = cfis; 763bf21cd93STycho Nightingale aior->slot = slot; 764bf21cd93STycho Nightingale aior->len = 0; 765bf21cd93STycho Nightingale aior->done = 0; 7664c87aefeSPatrick Mooney aior->more = 0; 767bf21cd93STycho Nightingale breq = &aior->io_req; 768bf21cd93STycho Nightingale 769bf21cd93STycho Nightingale /* 770bf21cd93STycho Nightingale * Mark this command in-flight. 771bf21cd93STycho Nightingale */ 772bf21cd93STycho Nightingale p->pending |= 1 << slot; 773bf21cd93STycho Nightingale 774bf21cd93STycho Nightingale /* 775bf21cd93STycho Nightingale * Stuff request onto busy list 776bf21cd93STycho Nightingale */ 777bf21cd93STycho Nightingale TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); 778bf21cd93STycho Nightingale 779bf21cd93STycho Nightingale err = blockif_flush(p->bctx, breq); 780bf21cd93STycho Nightingale assert(err == 0); 781bf21cd93STycho Nightingale } 782bf21cd93STycho Nightingale 783bf21cd93STycho Nightingale static inline void 7844c87aefeSPatrick Mooney read_prdt(struct ahci_port *p, int slot, uint8_t *cfis, 7854c87aefeSPatrick Mooney void *buf, int size) 7864c87aefeSPatrick Mooney { 7874c87aefeSPatrick Mooney struct ahci_cmd_hdr *hdr; 7884c87aefeSPatrick Mooney struct ahci_prdt_entry *prdt; 7894c87aefeSPatrick Mooney void *to; 7904c87aefeSPatrick Mooney int i, len; 7914c87aefeSPatrick Mooney 7924c87aefeSPatrick Mooney hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 7934c87aefeSPatrick Mooney len = size; 7944c87aefeSPatrick Mooney to = buf; 7954c87aefeSPatrick Mooney prdt = (struct ahci_prdt_entry *)(cfis + 0x80); 7964c87aefeSPatrick Mooney for (i = 0; i < hdr->prdtl && len; i++) { 7974c87aefeSPatrick Mooney uint8_t *ptr; 7984c87aefeSPatrick Mooney uint32_t dbcsz; 7994c87aefeSPatrick Mooney int sublen; 8004c87aefeSPatrick Mooney 8014c87aefeSPatrick Mooney dbcsz = (prdt->dbc & DBCMASK) + 1; 8024c87aefeSPatrick Mooney ptr = paddr_guest2host(ahci_ctx(p->pr_sc), prdt->dba, dbcsz); 8034c87aefeSPatrick Mooney sublen = MIN(len, dbcsz); 8044c87aefeSPatrick Mooney memcpy(to, ptr, sublen); 8054c87aefeSPatrick Mooney len -= sublen; 8064c87aefeSPatrick Mooney to += sublen; 8074c87aefeSPatrick Mooney prdt++; 8084c87aefeSPatrick Mooney } 8094c87aefeSPatrick Mooney } 8104c87aefeSPatrick Mooney 8114c87aefeSPatrick Mooney static void 8124c87aefeSPatrick Mooney ahci_handle_dsm_trim(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done) 8134c87aefeSPatrick Mooney { 8144c87aefeSPatrick Mooney struct ahci_ioreq *aior; 8154c87aefeSPatrick Mooney struct blockif_req *breq; 8164c87aefeSPatrick Mooney uint8_t *entry; 8174c87aefeSPatrick Mooney uint64_t elba; 8184c87aefeSPatrick Mooney uint32_t len, elen; 8194c87aefeSPatrick Mooney int err, first, ncq; 8204c87aefeSPatrick Mooney uint8_t buf[512]; 8214c87aefeSPatrick Mooney 8224c87aefeSPatrick Mooney first = (done == 0); 8234c87aefeSPatrick Mooney if (cfis[2] == ATA_DATA_SET_MANAGEMENT) { 8244c87aefeSPatrick Mooney len = (uint16_t)cfis[13] << 8 | cfis[12]; 8254c87aefeSPatrick Mooney len *= 512; 8264c87aefeSPatrick Mooney ncq = 0; 8274c87aefeSPatrick Mooney } else { /* ATA_SEND_FPDMA_QUEUED */ 8284c87aefeSPatrick Mooney len = (uint16_t)cfis[11] << 8 | cfis[3]; 8294c87aefeSPatrick Mooney len *= 512; 8304c87aefeSPatrick Mooney ncq = 1; 8314c87aefeSPatrick Mooney } 8324c87aefeSPatrick Mooney read_prdt(p, slot, cfis, buf, sizeof(buf)); 8334c87aefeSPatrick Mooney 8344c87aefeSPatrick Mooney next: 8354c87aefeSPatrick Mooney entry = &buf[done]; 8364c87aefeSPatrick Mooney elba = ((uint64_t)entry[5] << 40) | 8374c87aefeSPatrick Mooney ((uint64_t)entry[4] << 32) | 8384c87aefeSPatrick Mooney ((uint64_t)entry[3] << 24) | 8394c87aefeSPatrick Mooney ((uint64_t)entry[2] << 16) | 8404c87aefeSPatrick Mooney ((uint64_t)entry[1] << 8) | 8414c87aefeSPatrick Mooney entry[0]; 8424c87aefeSPatrick Mooney elen = (uint16_t)entry[7] << 8 | entry[6]; 8434c87aefeSPatrick Mooney done += 8; 8444c87aefeSPatrick Mooney if (elen == 0) { 8454c87aefeSPatrick Mooney if (done >= len) { 8464c87aefeSPatrick Mooney if (ncq) { 8474c87aefeSPatrick Mooney if (first) 8484c87aefeSPatrick Mooney ahci_write_fis_d2h_ncq(p, slot); 8494c87aefeSPatrick Mooney ahci_write_fis_sdb(p, slot, cfis, 8504c87aefeSPatrick Mooney ATA_S_READY | ATA_S_DSC); 8514c87aefeSPatrick Mooney } else { 8524c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, 8534c87aefeSPatrick Mooney ATA_S_READY | ATA_S_DSC); 8544c87aefeSPatrick Mooney } 8554c87aefeSPatrick Mooney p->pending &= ~(1 << slot); 8564c87aefeSPatrick Mooney ahci_check_stopped(p); 8574c87aefeSPatrick Mooney if (!first) 8584c87aefeSPatrick Mooney ahci_handle_port(p); 8594c87aefeSPatrick Mooney return; 8604c87aefeSPatrick Mooney } 8614c87aefeSPatrick Mooney goto next; 8624c87aefeSPatrick Mooney } 8634c87aefeSPatrick Mooney 8644c87aefeSPatrick Mooney /* 8654c87aefeSPatrick Mooney * Pull request off free list 8664c87aefeSPatrick Mooney */ 8674c87aefeSPatrick Mooney aior = STAILQ_FIRST(&p->iofhd); 8684c87aefeSPatrick Mooney assert(aior != NULL); 8694c87aefeSPatrick Mooney STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); 8704c87aefeSPatrick Mooney aior->cfis = cfis; 8714c87aefeSPatrick Mooney aior->slot = slot; 8724c87aefeSPatrick Mooney aior->len = len; 8734c87aefeSPatrick Mooney aior->done = done; 8744c87aefeSPatrick Mooney aior->more = (len != done); 8754c87aefeSPatrick Mooney 8764c87aefeSPatrick Mooney breq = &aior->io_req; 8774c87aefeSPatrick Mooney breq->br_offset = elba * blockif_sectsz(p->bctx); 8784c87aefeSPatrick Mooney breq->br_resid = elen * blockif_sectsz(p->bctx); 8794c87aefeSPatrick Mooney 8804c87aefeSPatrick Mooney /* 8814c87aefeSPatrick Mooney * Mark this command in-flight. 8824c87aefeSPatrick Mooney */ 8834c87aefeSPatrick Mooney p->pending |= 1 << slot; 8844c87aefeSPatrick Mooney 8854c87aefeSPatrick Mooney /* 8864c87aefeSPatrick Mooney * Stuff request onto busy list 8874c87aefeSPatrick Mooney */ 8884c87aefeSPatrick Mooney TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); 8894c87aefeSPatrick Mooney 8904c87aefeSPatrick Mooney if (ncq && first) 8914c87aefeSPatrick Mooney ahci_write_fis_d2h_ncq(p, slot); 8924c87aefeSPatrick Mooney 8934c87aefeSPatrick Mooney err = blockif_delete(p->bctx, breq); 8944c87aefeSPatrick Mooney assert(err == 0); 8954c87aefeSPatrick Mooney } 8964c87aefeSPatrick Mooney 8974c87aefeSPatrick Mooney static inline void 898bf21cd93STycho Nightingale write_prdt(struct ahci_port *p, int slot, uint8_t *cfis, 899bf21cd93STycho Nightingale void *buf, int size) 900bf21cd93STycho Nightingale { 901bf21cd93STycho Nightingale struct ahci_cmd_hdr *hdr; 902bf21cd93STycho Nightingale struct ahci_prdt_entry *prdt; 903bf21cd93STycho Nightingale void *from; 904bf21cd93STycho Nightingale int i, len; 905bf21cd93STycho Nightingale 906bf21cd93STycho Nightingale hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 907bf21cd93STycho Nightingale len = size; 908bf21cd93STycho Nightingale from = buf; 909bf21cd93STycho Nightingale prdt = (struct ahci_prdt_entry *)(cfis + 0x80); 910bf21cd93STycho Nightingale for (i = 0; i < hdr->prdtl && len; i++) { 911bf21cd93STycho Nightingale uint8_t *ptr; 912bf21cd93STycho Nightingale uint32_t dbcsz; 913bf21cd93STycho Nightingale int sublen; 914bf21cd93STycho Nightingale 915bf21cd93STycho Nightingale dbcsz = (prdt->dbc & DBCMASK) + 1; 916bf21cd93STycho Nightingale ptr = paddr_guest2host(ahci_ctx(p->pr_sc), prdt->dba, dbcsz); 9174c87aefeSPatrick Mooney sublen = MIN(len, dbcsz); 918bf21cd93STycho Nightingale memcpy(ptr, from, sublen); 919bf21cd93STycho Nightingale len -= sublen; 920bf21cd93STycho Nightingale from += sublen; 921bf21cd93STycho Nightingale prdt++; 922bf21cd93STycho Nightingale } 923bf21cd93STycho Nightingale hdr->prdbc = size - len; 924bf21cd93STycho Nightingale } 925bf21cd93STycho Nightingale 926bf21cd93STycho Nightingale static void 9274c87aefeSPatrick Mooney ahci_checksum(uint8_t *buf, int size) 9284c87aefeSPatrick Mooney { 9294c87aefeSPatrick Mooney int i; 9304c87aefeSPatrick Mooney uint8_t sum = 0; 9314c87aefeSPatrick Mooney 9324c87aefeSPatrick Mooney for (i = 0; i < size - 1; i++) 9334c87aefeSPatrick Mooney sum += buf[i]; 9344c87aefeSPatrick Mooney buf[size - 1] = 0x100 - sum; 9354c87aefeSPatrick Mooney } 9364c87aefeSPatrick Mooney 9374c87aefeSPatrick Mooney static void 9384c87aefeSPatrick Mooney ahci_handle_read_log(struct ahci_port *p, int slot, uint8_t *cfis) 9394c87aefeSPatrick Mooney { 9404c87aefeSPatrick Mooney struct ahci_cmd_hdr *hdr; 9414c87aefeSPatrick Mooney uint32_t buf[128]; 9424c87aefeSPatrick Mooney uint8_t *buf8 = (uint8_t *)buf; 9434c87aefeSPatrick Mooney uint16_t *buf16 = (uint16_t *)buf; 9444c87aefeSPatrick Mooney 9454c87aefeSPatrick Mooney hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 9464c87aefeSPatrick Mooney if (p->atapi || hdr->prdtl == 0 || cfis[5] != 0 || 9474c87aefeSPatrick Mooney cfis[9] != 0 || cfis[12] != 1 || cfis[13] != 0) { 9484c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, 9494c87aefeSPatrick Mooney (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 9504c87aefeSPatrick Mooney return; 9514c87aefeSPatrick Mooney } 9524c87aefeSPatrick Mooney 9534c87aefeSPatrick Mooney memset(buf, 0, sizeof(buf)); 9544c87aefeSPatrick Mooney if (cfis[4] == 0x00) { /* Log directory */ 9554c87aefeSPatrick Mooney buf16[0x00] = 1; /* Version -- 1 */ 9564c87aefeSPatrick Mooney buf16[0x10] = 1; /* NCQ Command Error Log -- 1 page */ 9574c87aefeSPatrick Mooney buf16[0x13] = 1; /* SATA NCQ Send and Receive Log -- 1 page */ 9584c87aefeSPatrick Mooney } else if (cfis[4] == 0x10) { /* NCQ Command Error Log */ 9594c87aefeSPatrick Mooney memcpy(buf8, p->err_cfis, sizeof(p->err_cfis)); 9604c87aefeSPatrick Mooney ahci_checksum(buf8, sizeof(buf)); 9614c87aefeSPatrick Mooney } else if (cfis[4] == 0x13) { /* SATA NCQ Send and Receive Log */ 9624c87aefeSPatrick Mooney if (blockif_candelete(p->bctx) && !blockif_is_ro(p->bctx)) { 9634c87aefeSPatrick Mooney buf[0x00] = 1; /* SFQ DSM supported */ 9644c87aefeSPatrick Mooney buf[0x01] = 1; /* SFQ DSM TRIM supported */ 9654c87aefeSPatrick Mooney } 9664c87aefeSPatrick Mooney } else { 9674c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, 9684c87aefeSPatrick Mooney (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 9694c87aefeSPatrick Mooney return; 9704c87aefeSPatrick Mooney } 9714c87aefeSPatrick Mooney 9724c87aefeSPatrick Mooney if (cfis[2] == ATA_READ_LOG_EXT) 9734c87aefeSPatrick Mooney ahci_write_fis_piosetup(p); 9744c87aefeSPatrick Mooney write_prdt(p, slot, cfis, (void *)buf, sizeof(buf)); 9754c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY); 9764c87aefeSPatrick Mooney } 9774c87aefeSPatrick Mooney 9784c87aefeSPatrick Mooney static void 979bf21cd93STycho Nightingale handle_identify(struct ahci_port *p, int slot, uint8_t *cfis) 980bf21cd93STycho Nightingale { 981bf21cd93STycho Nightingale struct ahci_cmd_hdr *hdr; 982bf21cd93STycho Nightingale 983bf21cd93STycho Nightingale hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 984bf21cd93STycho Nightingale if (p->atapi || hdr->prdtl == 0) { 9854c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, 9864c87aefeSPatrick Mooney (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 987bf21cd93STycho Nightingale } else { 9886960cd89SAndy Fiddaman ahci_write_fis_piosetup(p); 9896960cd89SAndy Fiddaman write_prdt(p, slot, cfis, (void*)&p->ata_ident, sizeof(struct ata_params)); 9906960cd89SAndy Fiddaman ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY); 9916960cd89SAndy Fiddaman } 9926960cd89SAndy Fiddaman } 9936960cd89SAndy Fiddaman 9946960cd89SAndy Fiddaman static void 9956960cd89SAndy Fiddaman ata_identify_init(struct ahci_port* p, int atapi) 9966960cd89SAndy Fiddaman { 9976960cd89SAndy Fiddaman struct ata_params* ata_ident = &p->ata_ident; 9986960cd89SAndy Fiddaman 9996960cd89SAndy Fiddaman if (atapi) { 10006960cd89SAndy Fiddaman ata_ident->config = ATA_PROTO_ATAPI | ATA_ATAPI_TYPE_CDROM | 10016960cd89SAndy Fiddaman ATA_ATAPI_REMOVABLE | ATA_DRQ_FAST; 10026960cd89SAndy Fiddaman ata_ident->capabilities1 = ATA_SUPPORT_LBA | 10036960cd89SAndy Fiddaman ATA_SUPPORT_DMA; 10046960cd89SAndy Fiddaman ata_ident->capabilities2 = (1 << 14 | 1); 10056960cd89SAndy Fiddaman ata_ident->atavalid = ATA_FLAG_64_70 | ATA_FLAG_88; 10066960cd89SAndy Fiddaman ata_ident->obsolete62 = 0x3f; 10076960cd89SAndy Fiddaman ata_ident->mwdmamodes = 7; 10086960cd89SAndy Fiddaman if (p->xfermode & ATA_WDMA0) 10096960cd89SAndy Fiddaman ata_ident->mwdmamodes |= (1 << ((p->xfermode & 7) + 8)); 10106960cd89SAndy Fiddaman ata_ident->apiomodes = 3; 10116960cd89SAndy Fiddaman ata_ident->mwdmamin = 0x0078; 10126960cd89SAndy Fiddaman ata_ident->mwdmarec = 0x0078; 10136960cd89SAndy Fiddaman ata_ident->pioblind = 0x0078; 10146960cd89SAndy Fiddaman ata_ident->pioiordy = 0x0078; 10156960cd89SAndy Fiddaman ata_ident->satacapabilities = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3); 10166960cd89SAndy Fiddaman ata_ident->satacapabilities2 = ((p->ssts & ATA_SS_SPD_MASK) >> 3); 10176960cd89SAndy Fiddaman ata_ident->satasupport = ATA_SUPPORT_NCQ_STREAM; 10186960cd89SAndy Fiddaman ata_ident->version_major = 0x3f0; 10196960cd89SAndy Fiddaman ata_ident->support.command1 = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET | 10206960cd89SAndy Fiddaman ATA_SUPPORT_RESET | ATA_SUPPORT_NOP); 10216960cd89SAndy Fiddaman ata_ident->support.command2 = (1 << 14); 10226960cd89SAndy Fiddaman ata_ident->support.extension = (1 << 14); 10236960cd89SAndy Fiddaman ata_ident->enabled.command1 = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET | 10246960cd89SAndy Fiddaman ATA_SUPPORT_RESET | ATA_SUPPORT_NOP); 10256960cd89SAndy Fiddaman ata_ident->enabled.extension = (1 << 14); 10266960cd89SAndy Fiddaman ata_ident->udmamodes = 0x7f; 10276960cd89SAndy Fiddaman if (p->xfermode & ATA_UDMA0) 10286960cd89SAndy Fiddaman ata_ident->udmamodes |= (1 << ((p->xfermode & 7) + 8)); 10296960cd89SAndy Fiddaman ata_ident->transport_major = 0x1020; 10306960cd89SAndy Fiddaman ata_ident->integrity = 0x00a5; 10316960cd89SAndy Fiddaman } else { 1032bf21cd93STycho Nightingale uint64_t sectors; 10334c87aefeSPatrick Mooney int sectsz, psectsz, psectoff, candelete, ro; 1034bf21cd93STycho Nightingale uint16_t cyl; 1035bf21cd93STycho Nightingale uint8_t sech, heads; 1036bf21cd93STycho Nightingale 10374c87aefeSPatrick Mooney ro = blockif_is_ro(p->bctx); 10384c87aefeSPatrick Mooney candelete = blockif_candelete(p->bctx); 10394c87aefeSPatrick Mooney sectsz = blockif_sectsz(p->bctx); 10404c87aefeSPatrick Mooney sectors = blockif_size(p->bctx) / sectsz; 1041bf21cd93STycho Nightingale blockif_chs(p->bctx, &cyl, &heads, &sech); 10424c87aefeSPatrick Mooney blockif_psectsz(p->bctx, &psectsz, &psectoff); 10436960cd89SAndy Fiddaman ata_ident->config = ATA_DRQ_FAST; 10446960cd89SAndy Fiddaman ata_ident->cylinders = cyl; 10456960cd89SAndy Fiddaman ata_ident->heads = heads; 10466960cd89SAndy Fiddaman ata_ident->sectors = sech; 10476960cd89SAndy Fiddaman 10486960cd89SAndy Fiddaman ata_ident->sectors_intr = (0x8000 | 128); 10496960cd89SAndy Fiddaman ata_ident->tcg = 0; 10506960cd89SAndy Fiddaman 10516960cd89SAndy Fiddaman ata_ident->capabilities1 = ATA_SUPPORT_DMA | 10526960cd89SAndy Fiddaman ATA_SUPPORT_LBA | ATA_SUPPORT_IORDY; 10536960cd89SAndy Fiddaman ata_ident->capabilities2 = (1 << 14); 10546960cd89SAndy Fiddaman ata_ident->atavalid = ATA_FLAG_64_70 | ATA_FLAG_88; 1055bf21cd93STycho Nightingale if (p->mult_sectors) 10566960cd89SAndy Fiddaman ata_ident->multi = (ATA_MULTI_VALID | p->mult_sectors); 10574c87aefeSPatrick Mooney if (sectors <= 0x0fffffff) { 10586960cd89SAndy Fiddaman ata_ident->lba_size_1 = sectors; 10596960cd89SAndy Fiddaman ata_ident->lba_size_2 = (sectors >> 16); 10604c87aefeSPatrick Mooney } else { 10616960cd89SAndy Fiddaman ata_ident->lba_size_1 = 0xffff; 10626960cd89SAndy Fiddaman ata_ident->lba_size_2 = 0x0fff; 10634c87aefeSPatrick Mooney } 10646960cd89SAndy Fiddaman ata_ident->mwdmamodes = 0x7; 1065bf21cd93STycho Nightingale if (p->xfermode & ATA_WDMA0) 10666960cd89SAndy Fiddaman ata_ident->mwdmamodes |= (1 << ((p->xfermode & 7) + 8)); 10676960cd89SAndy Fiddaman ata_ident->apiomodes = 0x3; 10686960cd89SAndy Fiddaman ata_ident->mwdmamin = 0x0078; 10696960cd89SAndy Fiddaman ata_ident->mwdmarec = 0x0078; 10706960cd89SAndy Fiddaman ata_ident->pioblind = 0x0078; 10716960cd89SAndy Fiddaman ata_ident->pioiordy = 0x0078; 10726960cd89SAndy Fiddaman ata_ident->support3 = 0; 10736960cd89SAndy Fiddaman ata_ident->queue = 31; 10746960cd89SAndy Fiddaman ata_ident->satacapabilities = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3 | 10754c87aefeSPatrick Mooney ATA_SUPPORT_NCQ); 10766960cd89SAndy Fiddaman ata_ident->satacapabilities2 = (ATA_SUPPORT_RCVSND_FPDMA_QUEUED | 10774c87aefeSPatrick Mooney (p->ssts & ATA_SS_SPD_MASK) >> 3); 10786960cd89SAndy Fiddaman ata_ident->version_major = 0x3f0; 10796960cd89SAndy Fiddaman ata_ident->version_minor = 0x28; 10806960cd89SAndy Fiddaman ata_ident->support.command1 = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE | 10814c87aefeSPatrick Mooney ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP); 10826960cd89SAndy Fiddaman ata_ident->support.command2 = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE | 10834c87aefeSPatrick Mooney ATA_SUPPORT_FLUSHCACHE48 | 1 << 14); 10846960cd89SAndy Fiddaman ata_ident->support.extension = (1 << 14); 10856960cd89SAndy Fiddaman ata_ident->enabled.command1 = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE | 10864c87aefeSPatrick Mooney ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP); 10876960cd89SAndy Fiddaman ata_ident->enabled.command2 = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE | 10884c87aefeSPatrick Mooney ATA_SUPPORT_FLUSHCACHE48 | 1 << 15); 10896960cd89SAndy Fiddaman ata_ident->enabled.extension = (1 << 14); 10906960cd89SAndy Fiddaman ata_ident->udmamodes = 0x7f; 1091bf21cd93STycho Nightingale if (p->xfermode & ATA_UDMA0) 10926960cd89SAndy Fiddaman ata_ident->udmamodes |= (1 << ((p->xfermode & 7) + 8)); 10936960cd89SAndy Fiddaman ata_ident->lba_size48_1 = sectors; 10946960cd89SAndy Fiddaman ata_ident->lba_size48_2 = (sectors >> 16); 10956960cd89SAndy Fiddaman ata_ident->lba_size48_3 = (sectors >> 32); 10966960cd89SAndy Fiddaman ata_ident->lba_size48_4 = (sectors >> 48); 10976960cd89SAndy Fiddaman 10984c87aefeSPatrick Mooney if (candelete && !ro) { 10996960cd89SAndy Fiddaman ata_ident->support3 |= ATA_SUPPORT_RZAT | ATA_SUPPORT_DRAT; 11006960cd89SAndy Fiddaman ata_ident->max_dsm_blocks = 1; 11016960cd89SAndy Fiddaman ata_ident->support_dsm = ATA_SUPPORT_DSM_TRIM; 11024c87aefeSPatrick Mooney } 11036960cd89SAndy Fiddaman ata_ident->pss = ATA_PSS_VALID_VALUE; 11046960cd89SAndy Fiddaman ata_ident->lsalign = 0x4000; 11054c87aefeSPatrick Mooney if (psectsz > sectsz) { 11066960cd89SAndy Fiddaman ata_ident->pss |= ATA_PSS_MULTLS; 11076960cd89SAndy Fiddaman ata_ident->pss |= ffsl(psectsz / sectsz) - 1; 11086960cd89SAndy Fiddaman ata_ident->lsalign |= (psectoff / sectsz); 11094c87aefeSPatrick Mooney } 11104c87aefeSPatrick Mooney if (sectsz > 512) { 11116960cd89SAndy Fiddaman ata_ident->pss |= ATA_PSS_LSSABOVE512; 11126960cd89SAndy Fiddaman ata_ident->lss_1 = sectsz / 2; 11136960cd89SAndy Fiddaman ata_ident->lss_2 = ((sectsz / 2) >> 16); 11144c87aefeSPatrick Mooney } 11156960cd89SAndy Fiddaman ata_ident->support2 = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14); 11166960cd89SAndy Fiddaman ata_ident->enabled2 = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14); 11176960cd89SAndy Fiddaman ata_ident->transport_major = 0x1020; 11186960cd89SAndy Fiddaman ata_ident->integrity = 0x00a5; 1119bf21cd93STycho Nightingale } 11206960cd89SAndy Fiddaman ahci_checksum((uint8_t*)ata_ident, sizeof(struct ata_params)); 1121bf21cd93STycho Nightingale } 1122bf21cd93STycho Nightingale 1123bf21cd93STycho Nightingale static void 1124bf21cd93STycho Nightingale handle_atapi_identify(struct ahci_port *p, int slot, uint8_t *cfis) 1125bf21cd93STycho Nightingale { 1126bf21cd93STycho Nightingale if (!p->atapi) { 11274c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, 11284c87aefeSPatrick Mooney (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 1129bf21cd93STycho Nightingale } else { 1130bf21cd93STycho Nightingale ahci_write_fis_piosetup(p); 11316960cd89SAndy Fiddaman write_prdt(p, slot, cfis, (void *)&p->ata_ident, sizeof(struct ata_params)); 11324c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY); 1133bf21cd93STycho Nightingale } 1134bf21cd93STycho Nightingale } 1135bf21cd93STycho Nightingale 1136bf21cd93STycho Nightingale static void 1137bf21cd93STycho Nightingale atapi_inquiry(struct ahci_port *p, int slot, uint8_t *cfis) 1138bf21cd93STycho Nightingale { 1139bf21cd93STycho Nightingale uint8_t buf[36]; 1140bf21cd93STycho Nightingale uint8_t *acmd; 1141bf21cd93STycho Nightingale int len; 11424c87aefeSPatrick Mooney uint32_t tfd; 1143bf21cd93STycho Nightingale 1144bf21cd93STycho Nightingale acmd = cfis + 0x40; 1145bf21cd93STycho Nightingale 11464c87aefeSPatrick Mooney if (acmd[1] & 1) { /* VPD */ 11474c87aefeSPatrick Mooney if (acmd[2] == 0) { /* Supported VPD pages */ 11484c87aefeSPatrick Mooney buf[0] = 0x05; 11494c87aefeSPatrick Mooney buf[1] = 0; 11504c87aefeSPatrick Mooney buf[2] = 0; 11514c87aefeSPatrick Mooney buf[3] = 1; 11524c87aefeSPatrick Mooney buf[4] = 0; 11534c87aefeSPatrick Mooney len = 4 + buf[3]; 11544c87aefeSPatrick Mooney } else { 11554c87aefeSPatrick Mooney p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 11564c87aefeSPatrick Mooney p->asc = 0x24; 11574c87aefeSPatrick Mooney tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 11584c87aefeSPatrick Mooney cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 11594c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, tfd); 11604c87aefeSPatrick Mooney return; 11614c87aefeSPatrick Mooney } 11624c87aefeSPatrick Mooney } else { 1163bf21cd93STycho Nightingale buf[0] = 0x05; 1164bf21cd93STycho Nightingale buf[1] = 0x80; 1165bf21cd93STycho Nightingale buf[2] = 0x00; 1166bf21cd93STycho Nightingale buf[3] = 0x21; 1167bf21cd93STycho Nightingale buf[4] = 31; 1168bf21cd93STycho Nightingale buf[5] = 0; 1169bf21cd93STycho Nightingale buf[6] = 0; 1170bf21cd93STycho Nightingale buf[7] = 0; 1171bf21cd93STycho Nightingale atapi_string(buf + 8, "BHYVE", 8); 1172bf21cd93STycho Nightingale atapi_string(buf + 16, "BHYVE DVD-ROM", 16); 1173bf21cd93STycho Nightingale atapi_string(buf + 32, "001", 4); 1174bf21cd93STycho Nightingale len = sizeof(buf); 11754c87aefeSPatrick Mooney } 11764c87aefeSPatrick Mooney 1177bf21cd93STycho Nightingale if (len > acmd[4]) 1178bf21cd93STycho Nightingale len = acmd[4]; 1179bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1180bf21cd93STycho Nightingale write_prdt(p, slot, cfis, buf, len); 1181bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1182bf21cd93STycho Nightingale } 1183bf21cd93STycho Nightingale 1184bf21cd93STycho Nightingale static void 1185bf21cd93STycho Nightingale atapi_read_capacity(struct ahci_port *p, int slot, uint8_t *cfis) 1186bf21cd93STycho Nightingale { 1187bf21cd93STycho Nightingale uint8_t buf[8]; 1188bf21cd93STycho Nightingale uint64_t sectors; 1189bf21cd93STycho Nightingale 1190bf21cd93STycho Nightingale sectors = blockif_size(p->bctx) / 2048; 1191bf21cd93STycho Nightingale be32enc(buf, sectors - 1); 1192bf21cd93STycho Nightingale be32enc(buf + 4, 2048); 1193bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1194bf21cd93STycho Nightingale write_prdt(p, slot, cfis, buf, sizeof(buf)); 1195bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1196bf21cd93STycho Nightingale } 1197bf21cd93STycho Nightingale 1198bf21cd93STycho Nightingale static void 1199bf21cd93STycho Nightingale atapi_read_toc(struct ahci_port *p, int slot, uint8_t *cfis) 1200bf21cd93STycho Nightingale { 1201bf21cd93STycho Nightingale uint8_t *acmd; 1202bf21cd93STycho Nightingale uint8_t format; 1203bf21cd93STycho Nightingale int len; 1204bf21cd93STycho Nightingale 1205bf21cd93STycho Nightingale acmd = cfis + 0x40; 1206bf21cd93STycho Nightingale 1207bf21cd93STycho Nightingale len = be16dec(acmd + 7); 1208bf21cd93STycho Nightingale format = acmd[9] >> 6; 1209bf21cd93STycho Nightingale switch (format) { 1210bf21cd93STycho Nightingale case 0: 1211bf21cd93STycho Nightingale { 1212bf21cd93STycho Nightingale int msf, size; 1213bf21cd93STycho Nightingale uint64_t sectors; 1214bf21cd93STycho Nightingale uint8_t start_track, buf[20], *bp; 1215bf21cd93STycho Nightingale 1216bf21cd93STycho Nightingale msf = (acmd[1] >> 1) & 1; 1217bf21cd93STycho Nightingale start_track = acmd[6]; 1218bf21cd93STycho Nightingale if (start_track > 1 && start_track != 0xaa) { 1219bf21cd93STycho Nightingale uint32_t tfd; 1220bf21cd93STycho Nightingale p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1221bf21cd93STycho Nightingale p->asc = 0x24; 1222bf21cd93STycho Nightingale tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1223bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1224bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, tfd); 1225bf21cd93STycho Nightingale return; 1226bf21cd93STycho Nightingale } 1227bf21cd93STycho Nightingale bp = buf + 2; 1228bf21cd93STycho Nightingale *bp++ = 1; 1229bf21cd93STycho Nightingale *bp++ = 1; 1230bf21cd93STycho Nightingale if (start_track <= 1) { 1231bf21cd93STycho Nightingale *bp++ = 0; 1232bf21cd93STycho Nightingale *bp++ = 0x14; 1233bf21cd93STycho Nightingale *bp++ = 1; 1234bf21cd93STycho Nightingale *bp++ = 0; 1235bf21cd93STycho Nightingale if (msf) { 1236bf21cd93STycho Nightingale *bp++ = 0; 1237bf21cd93STycho Nightingale lba_to_msf(bp, 0); 1238bf21cd93STycho Nightingale bp += 3; 1239bf21cd93STycho Nightingale } else { 1240bf21cd93STycho Nightingale *bp++ = 0; 1241bf21cd93STycho Nightingale *bp++ = 0; 1242bf21cd93STycho Nightingale *bp++ = 0; 1243bf21cd93STycho Nightingale *bp++ = 0; 1244bf21cd93STycho Nightingale } 1245bf21cd93STycho Nightingale } 1246bf21cd93STycho Nightingale *bp++ = 0; 1247bf21cd93STycho Nightingale *bp++ = 0x14; 1248bf21cd93STycho Nightingale *bp++ = 0xaa; 1249bf21cd93STycho Nightingale *bp++ = 0; 1250bf21cd93STycho Nightingale sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx); 1251bf21cd93STycho Nightingale sectors >>= 2; 1252bf21cd93STycho Nightingale if (msf) { 1253bf21cd93STycho Nightingale *bp++ = 0; 1254bf21cd93STycho Nightingale lba_to_msf(bp, sectors); 1255bf21cd93STycho Nightingale bp += 3; 1256bf21cd93STycho Nightingale } else { 1257bf21cd93STycho Nightingale be32enc(bp, sectors); 1258bf21cd93STycho Nightingale bp += 4; 1259bf21cd93STycho Nightingale } 1260bf21cd93STycho Nightingale size = bp - buf; 1261bf21cd93STycho Nightingale be16enc(buf, size - 2); 1262bf21cd93STycho Nightingale if (len > size) 1263bf21cd93STycho Nightingale len = size; 1264bf21cd93STycho Nightingale write_prdt(p, slot, cfis, buf, len); 1265bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1266bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1267bf21cd93STycho Nightingale break; 1268bf21cd93STycho Nightingale } 1269bf21cd93STycho Nightingale case 1: 1270bf21cd93STycho Nightingale { 1271bf21cd93STycho Nightingale uint8_t buf[12]; 1272bf21cd93STycho Nightingale 1273bf21cd93STycho Nightingale memset(buf, 0, sizeof(buf)); 1274bf21cd93STycho Nightingale buf[1] = 0xa; 1275bf21cd93STycho Nightingale buf[2] = 0x1; 1276bf21cd93STycho Nightingale buf[3] = 0x1; 1277bf21cd93STycho Nightingale if (len > sizeof(buf)) 1278bf21cd93STycho Nightingale len = sizeof(buf); 1279bf21cd93STycho Nightingale write_prdt(p, slot, cfis, buf, len); 1280bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1281bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1282bf21cd93STycho Nightingale break; 1283bf21cd93STycho Nightingale } 1284bf21cd93STycho Nightingale case 2: 1285bf21cd93STycho Nightingale { 1286bf21cd93STycho Nightingale int msf, size; 1287bf21cd93STycho Nightingale uint64_t sectors; 12884c87aefeSPatrick Mooney uint8_t *bp, buf[50]; 1289bf21cd93STycho Nightingale 1290bf21cd93STycho Nightingale msf = (acmd[1] >> 1) & 1; 1291bf21cd93STycho Nightingale bp = buf + 2; 1292bf21cd93STycho Nightingale *bp++ = 1; 1293bf21cd93STycho Nightingale *bp++ = 1; 1294bf21cd93STycho Nightingale 1295bf21cd93STycho Nightingale *bp++ = 1; 1296bf21cd93STycho Nightingale *bp++ = 0x14; 1297bf21cd93STycho Nightingale *bp++ = 0; 1298bf21cd93STycho Nightingale *bp++ = 0xa0; 1299bf21cd93STycho Nightingale *bp++ = 0; 1300bf21cd93STycho Nightingale *bp++ = 0; 1301bf21cd93STycho Nightingale *bp++ = 0; 1302bf21cd93STycho Nightingale *bp++ = 0; 1303bf21cd93STycho Nightingale *bp++ = 1; 1304bf21cd93STycho Nightingale *bp++ = 0; 1305bf21cd93STycho Nightingale *bp++ = 0; 1306bf21cd93STycho Nightingale 1307bf21cd93STycho Nightingale *bp++ = 1; 1308bf21cd93STycho Nightingale *bp++ = 0x14; 1309bf21cd93STycho Nightingale *bp++ = 0; 1310bf21cd93STycho Nightingale *bp++ = 0xa1; 1311bf21cd93STycho Nightingale *bp++ = 0; 1312bf21cd93STycho Nightingale *bp++ = 0; 1313bf21cd93STycho Nightingale *bp++ = 0; 1314bf21cd93STycho Nightingale *bp++ = 0; 1315bf21cd93STycho Nightingale *bp++ = 1; 1316bf21cd93STycho Nightingale *bp++ = 0; 1317bf21cd93STycho Nightingale *bp++ = 0; 1318bf21cd93STycho Nightingale 1319bf21cd93STycho Nightingale *bp++ = 1; 1320bf21cd93STycho Nightingale *bp++ = 0x14; 1321bf21cd93STycho Nightingale *bp++ = 0; 1322bf21cd93STycho Nightingale *bp++ = 0xa2; 1323bf21cd93STycho Nightingale *bp++ = 0; 1324bf21cd93STycho Nightingale *bp++ = 0; 1325bf21cd93STycho Nightingale *bp++ = 0; 1326bf21cd93STycho Nightingale sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx); 1327bf21cd93STycho Nightingale sectors >>= 2; 1328bf21cd93STycho Nightingale if (msf) { 1329bf21cd93STycho Nightingale *bp++ = 0; 1330bf21cd93STycho Nightingale lba_to_msf(bp, sectors); 1331bf21cd93STycho Nightingale bp += 3; 1332bf21cd93STycho Nightingale } else { 1333bf21cd93STycho Nightingale be32enc(bp, sectors); 1334bf21cd93STycho Nightingale bp += 4; 1335bf21cd93STycho Nightingale } 1336bf21cd93STycho Nightingale 1337bf21cd93STycho Nightingale *bp++ = 1; 1338bf21cd93STycho Nightingale *bp++ = 0x14; 1339bf21cd93STycho Nightingale *bp++ = 0; 1340bf21cd93STycho Nightingale *bp++ = 1; 1341bf21cd93STycho Nightingale *bp++ = 0; 1342bf21cd93STycho Nightingale *bp++ = 0; 1343bf21cd93STycho Nightingale *bp++ = 0; 1344bf21cd93STycho Nightingale if (msf) { 1345bf21cd93STycho Nightingale *bp++ = 0; 1346bf21cd93STycho Nightingale lba_to_msf(bp, 0); 1347bf21cd93STycho Nightingale bp += 3; 1348bf21cd93STycho Nightingale } else { 1349bf21cd93STycho Nightingale *bp++ = 0; 1350bf21cd93STycho Nightingale *bp++ = 0; 1351bf21cd93STycho Nightingale *bp++ = 0; 1352bf21cd93STycho Nightingale *bp++ = 0; 1353bf21cd93STycho Nightingale } 1354bf21cd93STycho Nightingale 1355bf21cd93STycho Nightingale size = bp - buf; 1356bf21cd93STycho Nightingale be16enc(buf, size - 2); 1357bf21cd93STycho Nightingale if (len > size) 1358bf21cd93STycho Nightingale len = size; 1359bf21cd93STycho Nightingale write_prdt(p, slot, cfis, buf, len); 1360bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1361bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1362bf21cd93STycho Nightingale break; 1363bf21cd93STycho Nightingale } 1364bf21cd93STycho Nightingale default: 1365bf21cd93STycho Nightingale { 1366bf21cd93STycho Nightingale uint32_t tfd; 1367bf21cd93STycho Nightingale 1368bf21cd93STycho Nightingale p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1369bf21cd93STycho Nightingale p->asc = 0x24; 1370bf21cd93STycho Nightingale tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1371bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1372bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, tfd); 1373bf21cd93STycho Nightingale break; 1374bf21cd93STycho Nightingale } 1375bf21cd93STycho Nightingale } 1376bf21cd93STycho Nightingale } 1377bf21cd93STycho Nightingale 1378bf21cd93STycho Nightingale static void 13794c87aefeSPatrick Mooney atapi_report_luns(struct ahci_port *p, int slot, uint8_t *cfis) 13804c87aefeSPatrick Mooney { 13814c87aefeSPatrick Mooney uint8_t buf[16]; 13824c87aefeSPatrick Mooney 13834c87aefeSPatrick Mooney memset(buf, 0, sizeof(buf)); 13844c87aefeSPatrick Mooney buf[3] = 8; 13854c87aefeSPatrick Mooney 13864c87aefeSPatrick Mooney cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 13874c87aefeSPatrick Mooney write_prdt(p, slot, cfis, buf, sizeof(buf)); 13884c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 13894c87aefeSPatrick Mooney } 13904c87aefeSPatrick Mooney 13914c87aefeSPatrick Mooney static void 13924c87aefeSPatrick Mooney atapi_read(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done) 1393bf21cd93STycho Nightingale { 1394bf21cd93STycho Nightingale struct ahci_ioreq *aior; 1395bf21cd93STycho Nightingale struct ahci_cmd_hdr *hdr; 1396bf21cd93STycho Nightingale struct ahci_prdt_entry *prdt; 1397bf21cd93STycho Nightingale struct blockif_req *breq; 1398bf21cd93STycho Nightingale uint8_t *acmd; 1399bf21cd93STycho Nightingale uint64_t lba; 1400bf21cd93STycho Nightingale uint32_t len; 14014c87aefeSPatrick Mooney int err; 1402bf21cd93STycho Nightingale 1403bf21cd93STycho Nightingale acmd = cfis + 0x40; 1404bf21cd93STycho Nightingale hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 1405bf21cd93STycho Nightingale prdt = (struct ahci_prdt_entry *)(cfis + 0x80); 1406bf21cd93STycho Nightingale 1407bf21cd93STycho Nightingale lba = be32dec(acmd + 2); 1408bf21cd93STycho Nightingale if (acmd[0] == READ_10) 1409bf21cd93STycho Nightingale len = be16dec(acmd + 7); 1410bf21cd93STycho Nightingale else 1411bf21cd93STycho Nightingale len = be32dec(acmd + 6); 1412bf21cd93STycho Nightingale if (len == 0) { 1413bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1414bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1415bf21cd93STycho Nightingale } 1416bf21cd93STycho Nightingale lba *= 2048; 1417bf21cd93STycho Nightingale len *= 2048; 1418bf21cd93STycho Nightingale 1419bf21cd93STycho Nightingale /* 1420bf21cd93STycho Nightingale * Pull request off free list 1421bf21cd93STycho Nightingale */ 1422bf21cd93STycho Nightingale aior = STAILQ_FIRST(&p->iofhd); 1423bf21cd93STycho Nightingale assert(aior != NULL); 1424bf21cd93STycho Nightingale STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); 1425bf21cd93STycho Nightingale aior->cfis = cfis; 1426bf21cd93STycho Nightingale aior->slot = slot; 1427bf21cd93STycho Nightingale aior->len = len; 1428bf21cd93STycho Nightingale aior->done = done; 1429bf21cd93STycho Nightingale breq = &aior->io_req; 1430bf21cd93STycho Nightingale breq->br_offset = lba + done; 14314c87aefeSPatrick Mooney ahci_build_iov(p, aior, prdt, hdr->prdtl); 1432bf21cd93STycho Nightingale 14334c87aefeSPatrick Mooney /* Mark this command in-flight. */ 1434bf21cd93STycho Nightingale p->pending |= 1 << slot; 1435bf21cd93STycho Nightingale 14364c87aefeSPatrick Mooney /* Stuff request onto busy list. */ 1437bf21cd93STycho Nightingale TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); 1438bf21cd93STycho Nightingale 1439bf21cd93STycho Nightingale err = blockif_read(p->bctx, breq); 1440bf21cd93STycho Nightingale assert(err == 0); 1441bf21cd93STycho Nightingale } 1442bf21cd93STycho Nightingale 1443bf21cd93STycho Nightingale static void 1444bf21cd93STycho Nightingale atapi_request_sense(struct ahci_port *p, int slot, uint8_t *cfis) 1445bf21cd93STycho Nightingale { 1446bf21cd93STycho Nightingale uint8_t buf[64]; 1447bf21cd93STycho Nightingale uint8_t *acmd; 1448bf21cd93STycho Nightingale int len; 1449bf21cd93STycho Nightingale 1450bf21cd93STycho Nightingale acmd = cfis + 0x40; 1451bf21cd93STycho Nightingale len = acmd[4]; 1452bf21cd93STycho Nightingale if (len > sizeof(buf)) 1453bf21cd93STycho Nightingale len = sizeof(buf); 1454bf21cd93STycho Nightingale memset(buf, 0, len); 1455bf21cd93STycho Nightingale buf[0] = 0x70 | (1 << 7); 1456bf21cd93STycho Nightingale buf[2] = p->sense_key; 1457bf21cd93STycho Nightingale buf[7] = 10; 1458bf21cd93STycho Nightingale buf[12] = p->asc; 1459bf21cd93STycho Nightingale write_prdt(p, slot, cfis, buf, len); 1460bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1461bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1462bf21cd93STycho Nightingale } 1463bf21cd93STycho Nightingale 1464bf21cd93STycho Nightingale static void 1465bf21cd93STycho Nightingale atapi_start_stop_unit(struct ahci_port *p, int slot, uint8_t *cfis) 1466bf21cd93STycho Nightingale { 1467bf21cd93STycho Nightingale uint8_t *acmd = cfis + 0x40; 1468bf21cd93STycho Nightingale uint32_t tfd; 1469bf21cd93STycho Nightingale 1470bf21cd93STycho Nightingale switch (acmd[4] & 3) { 1471bf21cd93STycho Nightingale case 0: 1472bf21cd93STycho Nightingale case 1: 1473bf21cd93STycho Nightingale case 3: 1474bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1475bf21cd93STycho Nightingale tfd = ATA_S_READY | ATA_S_DSC; 1476bf21cd93STycho Nightingale break; 1477bf21cd93STycho Nightingale case 2: 1478bf21cd93STycho Nightingale /* TODO eject media */ 1479bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1480bf21cd93STycho Nightingale p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1481bf21cd93STycho Nightingale p->asc = 0x53; 1482bf21cd93STycho Nightingale tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1483bf21cd93STycho Nightingale break; 1484bf21cd93STycho Nightingale } 1485bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, tfd); 1486bf21cd93STycho Nightingale } 1487bf21cd93STycho Nightingale 1488bf21cd93STycho Nightingale static void 1489bf21cd93STycho Nightingale atapi_mode_sense(struct ahci_port *p, int slot, uint8_t *cfis) 1490bf21cd93STycho Nightingale { 1491bf21cd93STycho Nightingale uint8_t *acmd; 14924c87aefeSPatrick Mooney uint32_t tfd = 0; 1493bf21cd93STycho Nightingale uint8_t pc, code; 1494bf21cd93STycho Nightingale int len; 1495bf21cd93STycho Nightingale 1496bf21cd93STycho Nightingale acmd = cfis + 0x40; 1497bf21cd93STycho Nightingale len = be16dec(acmd + 7); 1498bf21cd93STycho Nightingale pc = acmd[2] >> 6; 1499bf21cd93STycho Nightingale code = acmd[2] & 0x3f; 1500bf21cd93STycho Nightingale 1501bf21cd93STycho Nightingale switch (pc) { 1502bf21cd93STycho Nightingale case 0: 1503bf21cd93STycho Nightingale switch (code) { 1504bf21cd93STycho Nightingale case MODEPAGE_RW_ERROR_RECOVERY: 1505bf21cd93STycho Nightingale { 1506bf21cd93STycho Nightingale uint8_t buf[16]; 1507bf21cd93STycho Nightingale 1508bf21cd93STycho Nightingale if (len > sizeof(buf)) 1509bf21cd93STycho Nightingale len = sizeof(buf); 1510bf21cd93STycho Nightingale 1511bf21cd93STycho Nightingale memset(buf, 0, sizeof(buf)); 1512bf21cd93STycho Nightingale be16enc(buf, 16 - 2); 1513bf21cd93STycho Nightingale buf[2] = 0x70; 1514bf21cd93STycho Nightingale buf[8] = 0x01; 1515bf21cd93STycho Nightingale buf[9] = 16 - 10; 1516bf21cd93STycho Nightingale buf[11] = 0x05; 1517bf21cd93STycho Nightingale write_prdt(p, slot, cfis, buf, len); 1518bf21cd93STycho Nightingale tfd = ATA_S_READY | ATA_S_DSC; 1519bf21cd93STycho Nightingale break; 1520bf21cd93STycho Nightingale } 1521bf21cd93STycho Nightingale case MODEPAGE_CD_CAPABILITIES: 1522bf21cd93STycho Nightingale { 1523bf21cd93STycho Nightingale uint8_t buf[30]; 1524bf21cd93STycho Nightingale 1525bf21cd93STycho Nightingale if (len > sizeof(buf)) 1526bf21cd93STycho Nightingale len = sizeof(buf); 1527bf21cd93STycho Nightingale 1528bf21cd93STycho Nightingale memset(buf, 0, sizeof(buf)); 1529bf21cd93STycho Nightingale be16enc(buf, 30 - 2); 1530bf21cd93STycho Nightingale buf[2] = 0x70; 1531bf21cd93STycho Nightingale buf[8] = 0x2A; 1532bf21cd93STycho Nightingale buf[9] = 30 - 10; 1533bf21cd93STycho Nightingale buf[10] = 0x08; 1534bf21cd93STycho Nightingale buf[12] = 0x71; 1535bf21cd93STycho Nightingale be16enc(&buf[18], 2); 1536bf21cd93STycho Nightingale be16enc(&buf[20], 512); 1537bf21cd93STycho Nightingale write_prdt(p, slot, cfis, buf, len); 1538bf21cd93STycho Nightingale tfd = ATA_S_READY | ATA_S_DSC; 1539bf21cd93STycho Nightingale break; 1540bf21cd93STycho Nightingale } 1541bf21cd93STycho Nightingale default: 1542bf21cd93STycho Nightingale goto error; 1543bf21cd93STycho Nightingale break; 1544bf21cd93STycho Nightingale } 1545bf21cd93STycho Nightingale break; 1546bf21cd93STycho Nightingale case 3: 1547bf21cd93STycho Nightingale p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1548bf21cd93STycho Nightingale p->asc = 0x39; 1549bf21cd93STycho Nightingale tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1550bf21cd93STycho Nightingale break; 1551bf21cd93STycho Nightingale error: 1552bf21cd93STycho Nightingale case 1: 1553bf21cd93STycho Nightingale case 2: 1554bf21cd93STycho Nightingale p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1555bf21cd93STycho Nightingale p->asc = 0x24; 1556bf21cd93STycho Nightingale tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1557bf21cd93STycho Nightingale break; 1558bf21cd93STycho Nightingale } 1559bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1560bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, tfd); 1561bf21cd93STycho Nightingale } 1562bf21cd93STycho Nightingale 1563bf21cd93STycho Nightingale static void 1564bf21cd93STycho Nightingale atapi_get_event_status_notification(struct ahci_port *p, int slot, 1565bf21cd93STycho Nightingale uint8_t *cfis) 1566bf21cd93STycho Nightingale { 1567bf21cd93STycho Nightingale uint8_t *acmd; 1568bf21cd93STycho Nightingale uint32_t tfd; 1569bf21cd93STycho Nightingale 1570bf21cd93STycho Nightingale acmd = cfis + 0x40; 1571bf21cd93STycho Nightingale 1572bf21cd93STycho Nightingale /* we don't support asynchronous operation */ 1573bf21cd93STycho Nightingale if (!(acmd[1] & 1)) { 1574bf21cd93STycho Nightingale p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1575bf21cd93STycho Nightingale p->asc = 0x24; 1576bf21cd93STycho Nightingale tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1577bf21cd93STycho Nightingale } else { 1578bf21cd93STycho Nightingale uint8_t buf[8]; 1579bf21cd93STycho Nightingale int len; 1580bf21cd93STycho Nightingale 1581bf21cd93STycho Nightingale len = be16dec(acmd + 7); 1582bf21cd93STycho Nightingale if (len > sizeof(buf)) 1583bf21cd93STycho Nightingale len = sizeof(buf); 1584bf21cd93STycho Nightingale 1585bf21cd93STycho Nightingale memset(buf, 0, sizeof(buf)); 1586bf21cd93STycho Nightingale be16enc(buf, 8 - 2); 1587bf21cd93STycho Nightingale buf[2] = 0x04; 1588bf21cd93STycho Nightingale buf[3] = 0x10; 1589bf21cd93STycho Nightingale buf[5] = 0x02; 1590bf21cd93STycho Nightingale write_prdt(p, slot, cfis, buf, len); 1591bf21cd93STycho Nightingale tfd = ATA_S_READY | ATA_S_DSC; 1592bf21cd93STycho Nightingale } 1593bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1594bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, tfd); 1595bf21cd93STycho Nightingale } 1596bf21cd93STycho Nightingale 1597bf21cd93STycho Nightingale static void 1598bf21cd93STycho Nightingale handle_packet_cmd(struct ahci_port *p, int slot, uint8_t *cfis) 1599bf21cd93STycho Nightingale { 1600bf21cd93STycho Nightingale uint8_t *acmd; 1601bf21cd93STycho Nightingale 1602bf21cd93STycho Nightingale acmd = cfis + 0x40; 1603bf21cd93STycho Nightingale 1604bf21cd93STycho Nightingale #ifdef AHCI_DEBUG 1605bf21cd93STycho Nightingale { 1606bf21cd93STycho Nightingale int i; 1607bf21cd93STycho Nightingale DPRINTF("ACMD:"); 1608bf21cd93STycho Nightingale for (i = 0; i < 16; i++) 1609bf21cd93STycho Nightingale DPRINTF("%02x ", acmd[i]); 1610154972afSPatrick Mooney DPRINTF(""); 1611bf21cd93STycho Nightingale } 1612bf21cd93STycho Nightingale #endif 1613bf21cd93STycho Nightingale 1614bf21cd93STycho Nightingale switch (acmd[0]) { 1615bf21cd93STycho Nightingale case TEST_UNIT_READY: 1616bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1617bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1618bf21cd93STycho Nightingale break; 1619bf21cd93STycho Nightingale case INQUIRY: 1620bf21cd93STycho Nightingale atapi_inquiry(p, slot, cfis); 1621bf21cd93STycho Nightingale break; 1622bf21cd93STycho Nightingale case READ_CAPACITY: 1623bf21cd93STycho Nightingale atapi_read_capacity(p, slot, cfis); 1624bf21cd93STycho Nightingale break; 1625bf21cd93STycho Nightingale case PREVENT_ALLOW: 1626bf21cd93STycho Nightingale /* TODO */ 1627bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1628bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1629bf21cd93STycho Nightingale break; 1630bf21cd93STycho Nightingale case READ_TOC: 1631bf21cd93STycho Nightingale atapi_read_toc(p, slot, cfis); 1632bf21cd93STycho Nightingale break; 16334c87aefeSPatrick Mooney case REPORT_LUNS: 16344c87aefeSPatrick Mooney atapi_report_luns(p, slot, cfis); 16354c87aefeSPatrick Mooney break; 1636bf21cd93STycho Nightingale case READ_10: 1637bf21cd93STycho Nightingale case READ_12: 16384c87aefeSPatrick Mooney atapi_read(p, slot, cfis, 0); 1639bf21cd93STycho Nightingale break; 1640bf21cd93STycho Nightingale case REQUEST_SENSE: 1641bf21cd93STycho Nightingale atapi_request_sense(p, slot, cfis); 1642bf21cd93STycho Nightingale break; 1643bf21cd93STycho Nightingale case START_STOP_UNIT: 1644bf21cd93STycho Nightingale atapi_start_stop_unit(p, slot, cfis); 1645bf21cd93STycho Nightingale break; 1646bf21cd93STycho Nightingale case MODE_SENSE_10: 1647bf21cd93STycho Nightingale atapi_mode_sense(p, slot, cfis); 1648bf21cd93STycho Nightingale break; 1649bf21cd93STycho Nightingale case GET_EVENT_STATUS_NOTIFICATION: 1650bf21cd93STycho Nightingale atapi_get_event_status_notification(p, slot, cfis); 1651bf21cd93STycho Nightingale break; 1652bf21cd93STycho Nightingale default: 1653bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1654bf21cd93STycho Nightingale p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1655bf21cd93STycho Nightingale p->asc = 0x20; 1656bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, (p->sense_key << 12) | 1657bf21cd93STycho Nightingale ATA_S_READY | ATA_S_ERROR); 1658bf21cd93STycho Nightingale break; 1659bf21cd93STycho Nightingale } 1660bf21cd93STycho Nightingale } 1661bf21cd93STycho Nightingale 1662bf21cd93STycho Nightingale static void 1663bf21cd93STycho Nightingale ahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis) 1664bf21cd93STycho Nightingale { 1665bf21cd93STycho Nightingale 16664c87aefeSPatrick Mooney p->tfd |= ATA_S_BUSY; 1667bf21cd93STycho Nightingale switch (cfis[2]) { 1668bf21cd93STycho Nightingale case ATA_ATA_IDENTIFY: 1669bf21cd93STycho Nightingale handle_identify(p, slot, cfis); 1670bf21cd93STycho Nightingale break; 1671bf21cd93STycho Nightingale case ATA_SETFEATURES: 1672bf21cd93STycho Nightingale { 1673bf21cd93STycho Nightingale switch (cfis[3]) { 1674bf21cd93STycho Nightingale case ATA_SF_ENAB_SATA_SF: 1675bf21cd93STycho Nightingale switch (cfis[12]) { 1676bf21cd93STycho Nightingale case ATA_SATA_SF_AN: 1677bf21cd93STycho Nightingale p->tfd = ATA_S_DSC | ATA_S_READY; 1678bf21cd93STycho Nightingale break; 1679bf21cd93STycho Nightingale default: 1680bf21cd93STycho Nightingale p->tfd = ATA_S_ERROR | ATA_S_READY; 1681bf21cd93STycho Nightingale p->tfd |= (ATA_ERROR_ABORT << 8); 1682bf21cd93STycho Nightingale break; 1683bf21cd93STycho Nightingale } 1684bf21cd93STycho Nightingale break; 1685bf21cd93STycho Nightingale case ATA_SF_ENAB_WCACHE: 1686bf21cd93STycho Nightingale case ATA_SF_DIS_WCACHE: 1687bf21cd93STycho Nightingale case ATA_SF_ENAB_RCACHE: 1688bf21cd93STycho Nightingale case ATA_SF_DIS_RCACHE: 1689bf21cd93STycho Nightingale p->tfd = ATA_S_DSC | ATA_S_READY; 1690bf21cd93STycho Nightingale break; 1691bf21cd93STycho Nightingale case ATA_SF_SETXFER: 1692bf21cd93STycho Nightingale { 1693bf21cd93STycho Nightingale switch (cfis[12] & 0xf8) { 1694bf21cd93STycho Nightingale case ATA_PIO: 1695bf21cd93STycho Nightingale case ATA_PIO0: 1696bf21cd93STycho Nightingale break; 1697bf21cd93STycho Nightingale case ATA_WDMA0: 1698bf21cd93STycho Nightingale case ATA_UDMA0: 1699bf21cd93STycho Nightingale p->xfermode = (cfis[12] & 0x7); 1700bf21cd93STycho Nightingale break; 1701bf21cd93STycho Nightingale } 1702bf21cd93STycho Nightingale p->tfd = ATA_S_DSC | ATA_S_READY; 1703bf21cd93STycho Nightingale break; 1704bf21cd93STycho Nightingale } 1705bf21cd93STycho Nightingale default: 1706bf21cd93STycho Nightingale p->tfd = ATA_S_ERROR | ATA_S_READY; 1707bf21cd93STycho Nightingale p->tfd |= (ATA_ERROR_ABORT << 8); 1708bf21cd93STycho Nightingale break; 1709bf21cd93STycho Nightingale } 1710bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, p->tfd); 1711bf21cd93STycho Nightingale break; 1712bf21cd93STycho Nightingale } 1713bf21cd93STycho Nightingale case ATA_SET_MULTI: 1714bf21cd93STycho Nightingale if (cfis[12] != 0 && 1715bf21cd93STycho Nightingale (cfis[12] > 128 || (cfis[12] & (cfis[12] - 1)))) { 1716bf21cd93STycho Nightingale p->tfd = ATA_S_ERROR | ATA_S_READY; 1717bf21cd93STycho Nightingale p->tfd |= (ATA_ERROR_ABORT << 8); 1718bf21cd93STycho Nightingale } else { 1719bf21cd93STycho Nightingale p->mult_sectors = cfis[12]; 1720bf21cd93STycho Nightingale p->tfd = ATA_S_DSC | ATA_S_READY; 1721bf21cd93STycho Nightingale } 17224c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, p->tfd); 1723bf21cd93STycho Nightingale break; 17244c87aefeSPatrick Mooney case ATA_READ: 17254c87aefeSPatrick Mooney case ATA_WRITE: 17264c87aefeSPatrick Mooney case ATA_READ48: 17274c87aefeSPatrick Mooney case ATA_WRITE48: 17284c87aefeSPatrick Mooney case ATA_READ_MUL: 17294c87aefeSPatrick Mooney case ATA_WRITE_MUL: 17304c87aefeSPatrick Mooney case ATA_READ_MUL48: 17314c87aefeSPatrick Mooney case ATA_WRITE_MUL48: 1732bf21cd93STycho Nightingale case ATA_READ_DMA: 1733bf21cd93STycho Nightingale case ATA_WRITE_DMA: 1734bf21cd93STycho Nightingale case ATA_READ_DMA48: 1735bf21cd93STycho Nightingale case ATA_WRITE_DMA48: 1736bf21cd93STycho Nightingale case ATA_READ_FPDMA_QUEUED: 1737bf21cd93STycho Nightingale case ATA_WRITE_FPDMA_QUEUED: 17384c87aefeSPatrick Mooney ahci_handle_rw(p, slot, cfis, 0); 1739bf21cd93STycho Nightingale break; 1740bf21cd93STycho Nightingale case ATA_FLUSHCACHE: 1741bf21cd93STycho Nightingale case ATA_FLUSHCACHE48: 1742bf21cd93STycho Nightingale ahci_handle_flush(p, slot, cfis); 1743bf21cd93STycho Nightingale break; 17444c87aefeSPatrick Mooney case ATA_DATA_SET_MANAGEMENT: 17454c87aefeSPatrick Mooney if (cfis[11] == 0 && cfis[3] == ATA_DSM_TRIM && 17464c87aefeSPatrick Mooney cfis[13] == 0 && cfis[12] == 1) { 17474c87aefeSPatrick Mooney ahci_handle_dsm_trim(p, slot, cfis, 0); 1748bf21cd93STycho Nightingale break; 17494c87aefeSPatrick Mooney } 17504c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, 17514c87aefeSPatrick Mooney (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 17524c87aefeSPatrick Mooney break; 17534c87aefeSPatrick Mooney case ATA_SEND_FPDMA_QUEUED: 17544c87aefeSPatrick Mooney if ((cfis[13] & 0x1f) == ATA_SFPDMA_DSM && 17554c87aefeSPatrick Mooney cfis[17] == 0 && cfis[16] == ATA_DSM_TRIM && 17564c87aefeSPatrick Mooney cfis[11] == 0 && cfis[3] == 1) { 17574c87aefeSPatrick Mooney ahci_handle_dsm_trim(p, slot, cfis, 0); 17584c87aefeSPatrick Mooney break; 17594c87aefeSPatrick Mooney } 17604c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, 17614c87aefeSPatrick Mooney (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 17624c87aefeSPatrick Mooney break; 17634c87aefeSPatrick Mooney case ATA_READ_LOG_EXT: 17644c87aefeSPatrick Mooney case ATA_READ_LOG_DMA_EXT: 17654c87aefeSPatrick Mooney ahci_handle_read_log(p, slot, cfis); 17664c87aefeSPatrick Mooney break; 17674c87aefeSPatrick Mooney case ATA_SECURITY_FREEZE_LOCK: 17684c87aefeSPatrick Mooney case ATA_SMART_CMD: 1769bf21cd93STycho Nightingale case ATA_NOP: 17704c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, 17714c87aefeSPatrick Mooney (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 17724c87aefeSPatrick Mooney break; 17734c87aefeSPatrick Mooney case ATA_CHECK_POWER_MODE: 17744c87aefeSPatrick Mooney cfis[12] = 0xff; /* always on */ 17754c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 17764c87aefeSPatrick Mooney break; 17774c87aefeSPatrick Mooney case ATA_STANDBY_CMD: 1778bf21cd93STycho Nightingale case ATA_STANDBY_IMMEDIATE: 17794c87aefeSPatrick Mooney case ATA_IDLE_CMD: 1780bf21cd93STycho Nightingale case ATA_IDLE_IMMEDIATE: 1781bf21cd93STycho Nightingale case ATA_SLEEP: 17824c87aefeSPatrick Mooney case ATA_READ_VERIFY: 17834c87aefeSPatrick Mooney case ATA_READ_VERIFY48: 1784bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1785bf21cd93STycho Nightingale break; 1786bf21cd93STycho Nightingale case ATA_ATAPI_IDENTIFY: 1787bf21cd93STycho Nightingale handle_atapi_identify(p, slot, cfis); 1788bf21cd93STycho Nightingale break; 1789bf21cd93STycho Nightingale case ATA_PACKET_CMD: 1790bf21cd93STycho Nightingale if (!p->atapi) { 17914c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, 17924c87aefeSPatrick Mooney (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 1793bf21cd93STycho Nightingale } else 1794bf21cd93STycho Nightingale handle_packet_cmd(p, slot, cfis); 1795bf21cd93STycho Nightingale break; 1796bf21cd93STycho Nightingale default: 1797154972afSPatrick Mooney WPRINTF("Unsupported cmd:%02x", cfis[2]); 17984c87aefeSPatrick Mooney ahci_write_fis_d2h(p, slot, cfis, 17994c87aefeSPatrick Mooney (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 1800bf21cd93STycho Nightingale break; 1801bf21cd93STycho Nightingale } 1802bf21cd93STycho Nightingale } 1803bf21cd93STycho Nightingale 1804bf21cd93STycho Nightingale static void 1805bf21cd93STycho Nightingale ahci_handle_slot(struct ahci_port *p, int slot) 1806bf21cd93STycho Nightingale { 1807bf21cd93STycho Nightingale struct ahci_cmd_hdr *hdr; 18084c87aefeSPatrick Mooney #ifdef AHCI_DEBUG 1809bf21cd93STycho Nightingale struct ahci_prdt_entry *prdt; 18104c87aefeSPatrick Mooney #endif 1811bf21cd93STycho Nightingale struct pci_ahci_softc *sc; 1812bf21cd93STycho Nightingale uint8_t *cfis; 18134c87aefeSPatrick Mooney #ifdef AHCI_DEBUG 18144c87aefeSPatrick Mooney int cfl, i; 18154c87aefeSPatrick Mooney #endif 1816bf21cd93STycho Nightingale 1817bf21cd93STycho Nightingale sc = p->pr_sc; 1818bf21cd93STycho Nightingale hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 18194c87aefeSPatrick Mooney #ifdef AHCI_DEBUG 1820bf21cd93STycho Nightingale cfl = (hdr->flags & 0x1f) * 4; 18214c87aefeSPatrick Mooney #endif 1822bf21cd93STycho Nightingale cfis = paddr_guest2host(ahci_ctx(sc), hdr->ctba, 1823bf21cd93STycho Nightingale 0x80 + hdr->prdtl * sizeof(struct ahci_prdt_entry)); 18244c87aefeSPatrick Mooney #ifdef AHCI_DEBUG 1825bf21cd93STycho Nightingale prdt = (struct ahci_prdt_entry *)(cfis + 0x80); 1826bf21cd93STycho Nightingale 1827154972afSPatrick Mooney DPRINTF("cfis:"); 1828bf21cd93STycho Nightingale for (i = 0; i < cfl; i++) { 1829bf21cd93STycho Nightingale if (i % 10 == 0) 1830154972afSPatrick Mooney DPRINTF(""); 1831bf21cd93STycho Nightingale DPRINTF("%02x ", cfis[i]); 1832bf21cd93STycho Nightingale } 1833154972afSPatrick Mooney DPRINTF(""); 1834bf21cd93STycho Nightingale 1835bf21cd93STycho Nightingale for (i = 0; i < hdr->prdtl; i++) { 1836154972afSPatrick Mooney DPRINTF("%d@%08"PRIx64"", prdt->dbc & 0x3fffff, prdt->dba); 1837bf21cd93STycho Nightingale prdt++; 1838bf21cd93STycho Nightingale } 1839bf21cd93STycho Nightingale #endif 1840bf21cd93STycho Nightingale 1841bf21cd93STycho Nightingale if (cfis[0] != FIS_TYPE_REGH2D) { 1842154972afSPatrick Mooney WPRINTF("Not a H2D FIS:%02x", cfis[0]); 1843bf21cd93STycho Nightingale return; 1844bf21cd93STycho Nightingale } 1845bf21cd93STycho Nightingale 1846bf21cd93STycho Nightingale if (cfis[1] & 0x80) { 1847bf21cd93STycho Nightingale ahci_handle_cmd(p, slot, cfis); 1848bf21cd93STycho Nightingale } else { 1849bf21cd93STycho Nightingale if (cfis[15] & (1 << 2)) 1850bf21cd93STycho Nightingale p->reset = 1; 1851bf21cd93STycho Nightingale else if (p->reset) { 1852bf21cd93STycho Nightingale p->reset = 0; 1853bf21cd93STycho Nightingale ahci_port_reset(p); 1854bf21cd93STycho Nightingale } 1855bf21cd93STycho Nightingale p->ci &= ~(1 << slot); 1856bf21cd93STycho Nightingale } 1857bf21cd93STycho Nightingale } 1858bf21cd93STycho Nightingale 1859bf21cd93STycho Nightingale static void 1860bf21cd93STycho Nightingale ahci_handle_port(struct ahci_port *p) 1861bf21cd93STycho Nightingale { 1862bf21cd93STycho Nightingale 1863bf21cd93STycho Nightingale if (!(p->cmd & AHCI_P_CMD_ST)) 1864bf21cd93STycho Nightingale return; 1865bf21cd93STycho Nightingale 1866bf21cd93STycho Nightingale /* 1867bf21cd93STycho Nightingale * Search for any new commands to issue ignoring those that 18684c87aefeSPatrick Mooney * are already in-flight. Stop if device is busy or in error. 1869bf21cd93STycho Nightingale */ 18704c87aefeSPatrick Mooney for (; (p->ci & ~p->pending) != 0; p->ccs = ((p->ccs + 1) & 31)) { 18714c87aefeSPatrick Mooney if ((p->tfd & (ATA_S_BUSY | ATA_S_DRQ)) != 0) 18724c87aefeSPatrick Mooney break; 18734c87aefeSPatrick Mooney if (p->waitforclear) 18744c87aefeSPatrick Mooney break; 18754c87aefeSPatrick Mooney if ((p->ci & ~p->pending & (1 << p->ccs)) != 0) { 1876bf21cd93STycho Nightingale p->cmd &= ~AHCI_P_CMD_CCS_MASK; 18774c87aefeSPatrick Mooney p->cmd |= p->ccs << AHCI_P_CMD_CCS_SHIFT; 18784c87aefeSPatrick Mooney ahci_handle_slot(p, p->ccs); 1879bf21cd93STycho Nightingale } 1880bf21cd93STycho Nightingale } 1881bf21cd93STycho Nightingale } 1882bf21cd93STycho Nightingale 1883bf21cd93STycho Nightingale /* 1884bf21cd93STycho Nightingale * blockif callback routine - this runs in the context of the blockif 1885bf21cd93STycho Nightingale * i/o thread, so the mutex needs to be acquired. 1886bf21cd93STycho Nightingale */ 1887bf21cd93STycho Nightingale static void 1888bf21cd93STycho Nightingale ata_ioreq_cb(struct blockif_req *br, int err) 1889bf21cd93STycho Nightingale { 1890bf21cd93STycho Nightingale struct ahci_cmd_hdr *hdr; 1891bf21cd93STycho Nightingale struct ahci_ioreq *aior; 1892bf21cd93STycho Nightingale struct ahci_port *p; 1893bf21cd93STycho Nightingale struct pci_ahci_softc *sc; 1894bf21cd93STycho Nightingale uint32_t tfd; 1895bf21cd93STycho Nightingale uint8_t *cfis; 18964c87aefeSPatrick Mooney int slot, ncq, dsm; 1897bf21cd93STycho Nightingale 1898154972afSPatrick Mooney DPRINTF("%s %d", __func__, err); 1899bf21cd93STycho Nightingale 19004c87aefeSPatrick Mooney ncq = dsm = 0; 1901bf21cd93STycho Nightingale aior = br->br_param; 1902bf21cd93STycho Nightingale p = aior->io_pr; 1903bf21cd93STycho Nightingale cfis = aior->cfis; 1904bf21cd93STycho Nightingale slot = aior->slot; 1905bf21cd93STycho Nightingale sc = p->pr_sc; 1906bf21cd93STycho Nightingale hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 1907bf21cd93STycho Nightingale 1908bf21cd93STycho Nightingale if (cfis[2] == ATA_WRITE_FPDMA_QUEUED || 19094c87aefeSPatrick Mooney cfis[2] == ATA_READ_FPDMA_QUEUED || 19104c87aefeSPatrick Mooney cfis[2] == ATA_SEND_FPDMA_QUEUED) 1911bf21cd93STycho Nightingale ncq = 1; 19124c87aefeSPatrick Mooney if (cfis[2] == ATA_DATA_SET_MANAGEMENT || 19134c87aefeSPatrick Mooney (cfis[2] == ATA_SEND_FPDMA_QUEUED && 19144c87aefeSPatrick Mooney (cfis[13] & 0x1f) == ATA_SFPDMA_DSM)) 19154c87aefeSPatrick Mooney dsm = 1; 1916bf21cd93STycho Nightingale 1917bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 1918bf21cd93STycho Nightingale 1919bf21cd93STycho Nightingale /* 1920bf21cd93STycho Nightingale * Delete the blockif request from the busy list 1921bf21cd93STycho Nightingale */ 1922bf21cd93STycho Nightingale TAILQ_REMOVE(&p->iobhd, aior, io_blist); 1923bf21cd93STycho Nightingale 1924bf21cd93STycho Nightingale /* 1925bf21cd93STycho Nightingale * Move the blockif request back to the free list 1926bf21cd93STycho Nightingale */ 1927bf21cd93STycho Nightingale STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist); 1928bf21cd93STycho Nightingale 19294c87aefeSPatrick Mooney if (!err) 19304c87aefeSPatrick Mooney hdr->prdbc = aior->done; 19314c87aefeSPatrick Mooney 19324c87aefeSPatrick Mooney if (!err && aior->more) { 19334c87aefeSPatrick Mooney if (dsm) 19344c87aefeSPatrick Mooney ahci_handle_dsm_trim(p, slot, cfis, aior->done); 19354c87aefeSPatrick Mooney else 19364c87aefeSPatrick Mooney ahci_handle_rw(p, slot, cfis, aior->done); 1937bf21cd93STycho Nightingale goto out; 1938bf21cd93STycho Nightingale } 1939bf21cd93STycho Nightingale 19404c87aefeSPatrick Mooney if (!err) 1941bf21cd93STycho Nightingale tfd = ATA_S_READY | ATA_S_DSC; 1942bf21cd93STycho Nightingale else 1943bf21cd93STycho Nightingale tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR; 1944bf21cd93STycho Nightingale if (ncq) 19454c87aefeSPatrick Mooney ahci_write_fis_sdb(p, slot, cfis, tfd); 19464c87aefeSPatrick Mooney else 1947bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, tfd); 1948bf21cd93STycho Nightingale 1949bf21cd93STycho Nightingale /* 1950bf21cd93STycho Nightingale * This command is now complete. 1951bf21cd93STycho Nightingale */ 1952bf21cd93STycho Nightingale p->pending &= ~(1 << slot); 1953bf21cd93STycho Nightingale 1954bf21cd93STycho Nightingale ahci_check_stopped(p); 19554c87aefeSPatrick Mooney ahci_handle_port(p); 1956bf21cd93STycho Nightingale out: 1957bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 1958154972afSPatrick Mooney DPRINTF("%s exit", __func__); 1959bf21cd93STycho Nightingale } 1960bf21cd93STycho Nightingale 1961bf21cd93STycho Nightingale static void 1962bf21cd93STycho Nightingale atapi_ioreq_cb(struct blockif_req *br, int err) 1963bf21cd93STycho Nightingale { 1964bf21cd93STycho Nightingale struct ahci_cmd_hdr *hdr; 1965bf21cd93STycho Nightingale struct ahci_ioreq *aior; 1966bf21cd93STycho Nightingale struct ahci_port *p; 1967bf21cd93STycho Nightingale struct pci_ahci_softc *sc; 1968bf21cd93STycho Nightingale uint8_t *cfis; 1969bf21cd93STycho Nightingale uint32_t tfd; 19704c87aefeSPatrick Mooney int slot; 1971bf21cd93STycho Nightingale 1972154972afSPatrick Mooney DPRINTF("%s %d", __func__, err); 1973bf21cd93STycho Nightingale 1974bf21cd93STycho Nightingale aior = br->br_param; 1975bf21cd93STycho Nightingale p = aior->io_pr; 1976bf21cd93STycho Nightingale cfis = aior->cfis; 1977bf21cd93STycho Nightingale slot = aior->slot; 1978bf21cd93STycho Nightingale sc = p->pr_sc; 1979bf21cd93STycho Nightingale hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + aior->slot * AHCI_CL_SIZE); 1980bf21cd93STycho Nightingale 1981bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 1982bf21cd93STycho Nightingale 1983bf21cd93STycho Nightingale /* 1984bf21cd93STycho Nightingale * Delete the blockif request from the busy list 1985bf21cd93STycho Nightingale */ 1986bf21cd93STycho Nightingale TAILQ_REMOVE(&p->iobhd, aior, io_blist); 1987bf21cd93STycho Nightingale 1988bf21cd93STycho Nightingale /* 1989bf21cd93STycho Nightingale * Move the blockif request back to the free list 1990bf21cd93STycho Nightingale */ 1991bf21cd93STycho Nightingale STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist); 1992bf21cd93STycho Nightingale 19934c87aefeSPatrick Mooney if (!err) 19944c87aefeSPatrick Mooney hdr->prdbc = aior->done; 19954c87aefeSPatrick Mooney 19964c87aefeSPatrick Mooney if (!err && aior->more) { 19974c87aefeSPatrick Mooney atapi_read(p, slot, cfis, aior->done); 1998bf21cd93STycho Nightingale goto out; 1999bf21cd93STycho Nightingale } 2000bf21cd93STycho Nightingale 20014c87aefeSPatrick Mooney if (!err) { 2002bf21cd93STycho Nightingale tfd = ATA_S_READY | ATA_S_DSC; 2003bf21cd93STycho Nightingale } else { 2004bf21cd93STycho Nightingale p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 2005bf21cd93STycho Nightingale p->asc = 0x21; 2006bf21cd93STycho Nightingale tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 2007bf21cd93STycho Nightingale } 2008bf21cd93STycho Nightingale cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 2009bf21cd93STycho Nightingale ahci_write_fis_d2h(p, slot, cfis, tfd); 2010bf21cd93STycho Nightingale 2011bf21cd93STycho Nightingale /* 2012bf21cd93STycho Nightingale * This command is now complete. 2013bf21cd93STycho Nightingale */ 2014bf21cd93STycho Nightingale p->pending &= ~(1 << slot); 2015bf21cd93STycho Nightingale 2016bf21cd93STycho Nightingale ahci_check_stopped(p); 20174c87aefeSPatrick Mooney ahci_handle_port(p); 2018bf21cd93STycho Nightingale out: 2019bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 2020154972afSPatrick Mooney DPRINTF("%s exit", __func__); 2021bf21cd93STycho Nightingale } 2022bf21cd93STycho Nightingale 2023bf21cd93STycho Nightingale static void 2024bf21cd93STycho Nightingale pci_ahci_ioreq_init(struct ahci_port *pr) 2025bf21cd93STycho Nightingale { 2026bf21cd93STycho Nightingale struct ahci_ioreq *vr; 2027bf21cd93STycho Nightingale int i; 2028bf21cd93STycho Nightingale 2029bf21cd93STycho Nightingale pr->ioqsz = blockif_queuesz(pr->bctx); 2030bf21cd93STycho Nightingale pr->ioreq = calloc(pr->ioqsz, sizeof(struct ahci_ioreq)); 2031bf21cd93STycho Nightingale STAILQ_INIT(&pr->iofhd); 2032bf21cd93STycho Nightingale 2033bf21cd93STycho Nightingale /* 2034bf21cd93STycho Nightingale * Add all i/o request entries to the free queue 2035bf21cd93STycho Nightingale */ 2036bf21cd93STycho Nightingale for (i = 0; i < pr->ioqsz; i++) { 2037bf21cd93STycho Nightingale vr = &pr->ioreq[i]; 2038bf21cd93STycho Nightingale vr->io_pr = pr; 2039bf21cd93STycho Nightingale if (!pr->atapi) 2040bf21cd93STycho Nightingale vr->io_req.br_callback = ata_ioreq_cb; 2041bf21cd93STycho Nightingale else 2042bf21cd93STycho Nightingale vr->io_req.br_callback = atapi_ioreq_cb; 2043bf21cd93STycho Nightingale vr->io_req.br_param = vr; 2044bf21cd93STycho Nightingale STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_flist); 2045bf21cd93STycho Nightingale } 2046bf21cd93STycho Nightingale 2047bf21cd93STycho Nightingale TAILQ_INIT(&pr->iobhd); 2048bf21cd93STycho Nightingale } 2049bf21cd93STycho Nightingale 2050bf21cd93STycho Nightingale static void 2051bf21cd93STycho Nightingale pci_ahci_port_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value) 2052bf21cd93STycho Nightingale { 2053bf21cd93STycho Nightingale int port = (offset - AHCI_OFFSET) / AHCI_STEP; 2054bf21cd93STycho Nightingale offset = (offset - AHCI_OFFSET) % AHCI_STEP; 2055bf21cd93STycho Nightingale struct ahci_port *p = &sc->port[port]; 2056bf21cd93STycho Nightingale 2057154972afSPatrick Mooney DPRINTF("pci_ahci_port %d: write offset 0x%"PRIx64" value 0x%"PRIx64"", 2058bf21cd93STycho Nightingale port, offset, value); 2059bf21cd93STycho Nightingale 2060bf21cd93STycho Nightingale switch (offset) { 2061bf21cd93STycho Nightingale case AHCI_P_CLB: 2062bf21cd93STycho Nightingale p->clb = value; 2063bf21cd93STycho Nightingale break; 2064bf21cd93STycho Nightingale case AHCI_P_CLBU: 2065bf21cd93STycho Nightingale p->clbu = value; 2066bf21cd93STycho Nightingale break; 2067bf21cd93STycho Nightingale case AHCI_P_FB: 2068bf21cd93STycho Nightingale p->fb = value; 2069bf21cd93STycho Nightingale break; 2070bf21cd93STycho Nightingale case AHCI_P_FBU: 2071bf21cd93STycho Nightingale p->fbu = value; 2072bf21cd93STycho Nightingale break; 2073bf21cd93STycho Nightingale case AHCI_P_IS: 2074bf21cd93STycho Nightingale p->is &= ~value; 20754c87aefeSPatrick Mooney ahci_port_intr(p); 2076bf21cd93STycho Nightingale break; 2077bf21cd93STycho Nightingale case AHCI_P_IE: 2078bf21cd93STycho Nightingale p->ie = value & 0xFDC000FF; 20794c87aefeSPatrick Mooney ahci_port_intr(p); 2080bf21cd93STycho Nightingale break; 2081bf21cd93STycho Nightingale case AHCI_P_CMD: 2082bf21cd93STycho Nightingale { 20834c87aefeSPatrick Mooney p->cmd &= ~(AHCI_P_CMD_ST | AHCI_P_CMD_SUD | AHCI_P_CMD_POD | 20844c87aefeSPatrick Mooney AHCI_P_CMD_CLO | AHCI_P_CMD_FRE | AHCI_P_CMD_APSTE | 20854c87aefeSPatrick Mooney AHCI_P_CMD_ATAPI | AHCI_P_CMD_DLAE | AHCI_P_CMD_ALPE | 20864c87aefeSPatrick Mooney AHCI_P_CMD_ASP | AHCI_P_CMD_ICC_MASK); 20874c87aefeSPatrick Mooney p->cmd |= (AHCI_P_CMD_ST | AHCI_P_CMD_SUD | AHCI_P_CMD_POD | 20884c87aefeSPatrick Mooney AHCI_P_CMD_CLO | AHCI_P_CMD_FRE | AHCI_P_CMD_APSTE | 20894c87aefeSPatrick Mooney AHCI_P_CMD_ATAPI | AHCI_P_CMD_DLAE | AHCI_P_CMD_ALPE | 20904c87aefeSPatrick Mooney AHCI_P_CMD_ASP | AHCI_P_CMD_ICC_MASK) & value; 2091bf21cd93STycho Nightingale 2092bf21cd93STycho Nightingale if (!(value & AHCI_P_CMD_ST)) { 2093bf21cd93STycho Nightingale ahci_port_stop(p); 2094bf21cd93STycho Nightingale } else { 2095bf21cd93STycho Nightingale uint64_t clb; 2096bf21cd93STycho Nightingale 2097bf21cd93STycho Nightingale p->cmd |= AHCI_P_CMD_CR; 2098bf21cd93STycho Nightingale clb = (uint64_t)p->clbu << 32 | p->clb; 2099bf21cd93STycho Nightingale p->cmd_lst = paddr_guest2host(ahci_ctx(sc), clb, 2100bf21cd93STycho Nightingale AHCI_CL_SIZE * AHCI_MAX_SLOTS); 2101bf21cd93STycho Nightingale } 2102bf21cd93STycho Nightingale 2103bf21cd93STycho Nightingale if (value & AHCI_P_CMD_FRE) { 2104bf21cd93STycho Nightingale uint64_t fb; 2105bf21cd93STycho Nightingale 2106bf21cd93STycho Nightingale p->cmd |= AHCI_P_CMD_FR; 2107bf21cd93STycho Nightingale fb = (uint64_t)p->fbu << 32 | p->fb; 2108bf21cd93STycho Nightingale /* we don't support FBSCP, so rfis size is 256Bytes */ 2109bf21cd93STycho Nightingale p->rfis = paddr_guest2host(ahci_ctx(sc), fb, 256); 2110bf21cd93STycho Nightingale } else { 2111bf21cd93STycho Nightingale p->cmd &= ~AHCI_P_CMD_FR; 2112bf21cd93STycho Nightingale } 2113bf21cd93STycho Nightingale 2114bf21cd93STycho Nightingale if (value & AHCI_P_CMD_CLO) { 21154c87aefeSPatrick Mooney p->tfd &= ~(ATA_S_BUSY | ATA_S_DRQ); 2116bf21cd93STycho Nightingale p->cmd &= ~AHCI_P_CMD_CLO; 2117bf21cd93STycho Nightingale } 2118bf21cd93STycho Nightingale 21194c87aefeSPatrick Mooney if (value & AHCI_P_CMD_ICC_MASK) { 21204c87aefeSPatrick Mooney p->cmd &= ~AHCI_P_CMD_ICC_MASK; 21214c87aefeSPatrick Mooney } 21224c87aefeSPatrick Mooney 2123bf21cd93STycho Nightingale ahci_handle_port(p); 2124bf21cd93STycho Nightingale break; 2125bf21cd93STycho Nightingale } 2126bf21cd93STycho Nightingale case AHCI_P_TFD: 2127bf21cd93STycho Nightingale case AHCI_P_SIG: 2128bf21cd93STycho Nightingale case AHCI_P_SSTS: 2129154972afSPatrick Mooney WPRINTF("pci_ahci_port: read only registers 0x%"PRIx64"", offset); 2130bf21cd93STycho Nightingale break; 2131bf21cd93STycho Nightingale case AHCI_P_SCTL: 21324c87aefeSPatrick Mooney p->sctl = value; 2133bf21cd93STycho Nightingale if (!(p->cmd & AHCI_P_CMD_ST)) { 2134bf21cd93STycho Nightingale if (value & ATA_SC_DET_RESET) 2135bf21cd93STycho Nightingale ahci_port_reset(p); 2136bf21cd93STycho Nightingale } 2137bf21cd93STycho Nightingale break; 2138bf21cd93STycho Nightingale case AHCI_P_SERR: 2139bf21cd93STycho Nightingale p->serr &= ~value; 2140bf21cd93STycho Nightingale break; 2141bf21cd93STycho Nightingale case AHCI_P_SACT: 2142bf21cd93STycho Nightingale p->sact |= value; 2143bf21cd93STycho Nightingale break; 2144bf21cd93STycho Nightingale case AHCI_P_CI: 2145bf21cd93STycho Nightingale p->ci |= value; 2146bf21cd93STycho Nightingale ahci_handle_port(p); 2147bf21cd93STycho Nightingale break; 2148bf21cd93STycho Nightingale case AHCI_P_SNTF: 2149bf21cd93STycho Nightingale case AHCI_P_FBS: 2150bf21cd93STycho Nightingale default: 2151bf21cd93STycho Nightingale break; 2152bf21cd93STycho Nightingale } 2153bf21cd93STycho Nightingale } 2154bf21cd93STycho Nightingale 2155bf21cd93STycho Nightingale static void 2156bf21cd93STycho Nightingale pci_ahci_host_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value) 2157bf21cd93STycho Nightingale { 2158154972afSPatrick Mooney DPRINTF("pci_ahci_host: write offset 0x%"PRIx64" value 0x%"PRIx64"", 2159bf21cd93STycho Nightingale offset, value); 2160bf21cd93STycho Nightingale 2161bf21cd93STycho Nightingale switch (offset) { 2162bf21cd93STycho Nightingale case AHCI_CAP: 2163bf21cd93STycho Nightingale case AHCI_PI: 2164bf21cd93STycho Nightingale case AHCI_VS: 2165bf21cd93STycho Nightingale case AHCI_CAP2: 2166154972afSPatrick Mooney DPRINTF("pci_ahci_host: read only registers 0x%"PRIx64"", offset); 2167bf21cd93STycho Nightingale break; 2168bf21cd93STycho Nightingale case AHCI_GHC: 21694c87aefeSPatrick Mooney if (value & AHCI_GHC_HR) { 2170bf21cd93STycho Nightingale ahci_reset(sc); 21714c87aefeSPatrick Mooney break; 2172bf21cd93STycho Nightingale } 21734c87aefeSPatrick Mooney if (value & AHCI_GHC_IE) 21744c87aefeSPatrick Mooney sc->ghc |= AHCI_GHC_IE; 21754c87aefeSPatrick Mooney else 21764c87aefeSPatrick Mooney sc->ghc &= ~AHCI_GHC_IE; 21774c87aefeSPatrick Mooney ahci_generate_intr(sc, 0xffffffff); 2178bf21cd93STycho Nightingale break; 2179bf21cd93STycho Nightingale case AHCI_IS: 2180bf21cd93STycho Nightingale sc->is &= ~value; 21814c87aefeSPatrick Mooney ahci_generate_intr(sc, value); 2182bf21cd93STycho Nightingale break; 2183bf21cd93STycho Nightingale default: 2184bf21cd93STycho Nightingale break; 2185bf21cd93STycho Nightingale } 2186bf21cd93STycho Nightingale } 2187bf21cd93STycho Nightingale 2188bf21cd93STycho Nightingale static void 2189bf21cd93STycho Nightingale pci_ahci_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 2190bf21cd93STycho Nightingale int baridx, uint64_t offset, int size, uint64_t value) 2191bf21cd93STycho Nightingale { 2192bf21cd93STycho Nightingale struct pci_ahci_softc *sc = pi->pi_arg; 2193bf21cd93STycho Nightingale 2194bf21cd93STycho Nightingale assert(baridx == 5); 21954c87aefeSPatrick Mooney assert((offset % 4) == 0 && size == 4); 2196bf21cd93STycho Nightingale 2197bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 2198bf21cd93STycho Nightingale 2199bf21cd93STycho Nightingale if (offset < AHCI_OFFSET) 2200bf21cd93STycho Nightingale pci_ahci_host_write(sc, offset, value); 2201bf21cd93STycho Nightingale else if (offset < AHCI_OFFSET + sc->ports * AHCI_STEP) 2202bf21cd93STycho Nightingale pci_ahci_port_write(sc, offset, value); 2203bf21cd93STycho Nightingale else 2204154972afSPatrick Mooney WPRINTF("pci_ahci: unknown i/o write offset 0x%"PRIx64"", offset); 2205bf21cd93STycho Nightingale 2206bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 2207bf21cd93STycho Nightingale } 2208bf21cd93STycho Nightingale 2209bf21cd93STycho Nightingale static uint64_t 2210bf21cd93STycho Nightingale pci_ahci_host_read(struct pci_ahci_softc *sc, uint64_t offset) 2211bf21cd93STycho Nightingale { 2212bf21cd93STycho Nightingale uint32_t value; 2213bf21cd93STycho Nightingale 2214bf21cd93STycho Nightingale switch (offset) { 2215bf21cd93STycho Nightingale case AHCI_CAP: 2216bf21cd93STycho Nightingale case AHCI_GHC: 2217bf21cd93STycho Nightingale case AHCI_IS: 2218bf21cd93STycho Nightingale case AHCI_PI: 2219bf21cd93STycho Nightingale case AHCI_VS: 2220bf21cd93STycho Nightingale case AHCI_CCCC: 2221bf21cd93STycho Nightingale case AHCI_CCCP: 2222bf21cd93STycho Nightingale case AHCI_EM_LOC: 2223bf21cd93STycho Nightingale case AHCI_EM_CTL: 2224bf21cd93STycho Nightingale case AHCI_CAP2: 2225bf21cd93STycho Nightingale { 2226bf21cd93STycho Nightingale uint32_t *p = &sc->cap; 2227bf21cd93STycho Nightingale p += (offset - AHCI_CAP) / sizeof(uint32_t); 2228bf21cd93STycho Nightingale value = *p; 2229bf21cd93STycho Nightingale break; 2230bf21cd93STycho Nightingale } 2231bf21cd93STycho Nightingale default: 2232bf21cd93STycho Nightingale value = 0; 2233bf21cd93STycho Nightingale break; 2234bf21cd93STycho Nightingale } 2235154972afSPatrick Mooney DPRINTF("pci_ahci_host: read offset 0x%"PRIx64" value 0x%x", 2236bf21cd93STycho Nightingale offset, value); 2237bf21cd93STycho Nightingale 2238bf21cd93STycho Nightingale return (value); 2239bf21cd93STycho Nightingale } 2240bf21cd93STycho Nightingale 2241bf21cd93STycho Nightingale static uint64_t 2242bf21cd93STycho Nightingale pci_ahci_port_read(struct pci_ahci_softc *sc, uint64_t offset) 2243bf21cd93STycho Nightingale { 2244bf21cd93STycho Nightingale uint32_t value; 2245bf21cd93STycho Nightingale int port = (offset - AHCI_OFFSET) / AHCI_STEP; 2246bf21cd93STycho Nightingale offset = (offset - AHCI_OFFSET) % AHCI_STEP; 2247bf21cd93STycho Nightingale 2248bf21cd93STycho Nightingale switch (offset) { 2249bf21cd93STycho Nightingale case AHCI_P_CLB: 2250bf21cd93STycho Nightingale case AHCI_P_CLBU: 2251bf21cd93STycho Nightingale case AHCI_P_FB: 2252bf21cd93STycho Nightingale case AHCI_P_FBU: 2253bf21cd93STycho Nightingale case AHCI_P_IS: 2254bf21cd93STycho Nightingale case AHCI_P_IE: 2255bf21cd93STycho Nightingale case AHCI_P_CMD: 2256bf21cd93STycho Nightingale case AHCI_P_TFD: 2257bf21cd93STycho Nightingale case AHCI_P_SIG: 2258bf21cd93STycho Nightingale case AHCI_P_SSTS: 2259bf21cd93STycho Nightingale case AHCI_P_SCTL: 2260bf21cd93STycho Nightingale case AHCI_P_SERR: 2261bf21cd93STycho Nightingale case AHCI_P_SACT: 2262bf21cd93STycho Nightingale case AHCI_P_CI: 2263bf21cd93STycho Nightingale case AHCI_P_SNTF: 2264bf21cd93STycho Nightingale case AHCI_P_FBS: 2265bf21cd93STycho Nightingale { 2266bf21cd93STycho Nightingale uint32_t *p= &sc->port[port].clb; 2267bf21cd93STycho Nightingale p += (offset - AHCI_P_CLB) / sizeof(uint32_t); 2268bf21cd93STycho Nightingale value = *p; 2269bf21cd93STycho Nightingale break; 2270bf21cd93STycho Nightingale } 2271bf21cd93STycho Nightingale default: 2272bf21cd93STycho Nightingale value = 0; 2273bf21cd93STycho Nightingale break; 2274bf21cd93STycho Nightingale } 2275bf21cd93STycho Nightingale 2276154972afSPatrick Mooney DPRINTF("pci_ahci_port %d: read offset 0x%"PRIx64" value 0x%x", 2277bf21cd93STycho Nightingale port, offset, value); 2278bf21cd93STycho Nightingale 2279bf21cd93STycho Nightingale return value; 2280bf21cd93STycho Nightingale } 2281bf21cd93STycho Nightingale 2282bf21cd93STycho Nightingale static uint64_t 2283bf21cd93STycho Nightingale pci_ahci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, 22844c87aefeSPatrick Mooney uint64_t regoff, int size) 2285bf21cd93STycho Nightingale { 2286bf21cd93STycho Nightingale struct pci_ahci_softc *sc = pi->pi_arg; 22874c87aefeSPatrick Mooney uint64_t offset; 2288bf21cd93STycho Nightingale uint32_t value; 2289bf21cd93STycho Nightingale 2290bf21cd93STycho Nightingale assert(baridx == 5); 22914c87aefeSPatrick Mooney assert(size == 1 || size == 2 || size == 4); 22924c87aefeSPatrick Mooney assert((regoff & (size - 1)) == 0); 2293bf21cd93STycho Nightingale 2294bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 2295bf21cd93STycho Nightingale 22964c87aefeSPatrick Mooney offset = regoff & ~0x3; /* round down to a multiple of 4 bytes */ 2297bf21cd93STycho Nightingale if (offset < AHCI_OFFSET) 2298bf21cd93STycho Nightingale value = pci_ahci_host_read(sc, offset); 2299bf21cd93STycho Nightingale else if (offset < AHCI_OFFSET + sc->ports * AHCI_STEP) 2300bf21cd93STycho Nightingale value = pci_ahci_port_read(sc, offset); 2301bf21cd93STycho Nightingale else { 2302bf21cd93STycho Nightingale value = 0; 2303154972afSPatrick Mooney WPRINTF("pci_ahci: unknown i/o read offset 0x%"PRIx64"", 23044c87aefeSPatrick Mooney regoff); 2305bf21cd93STycho Nightingale } 23064c87aefeSPatrick Mooney value >>= 8 * (regoff & 0x3); 2307bf21cd93STycho Nightingale 2308bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 2309bf21cd93STycho Nightingale 2310bf21cd93STycho Nightingale return (value); 2311bf21cd93STycho Nightingale } 2312bf21cd93STycho Nightingale 23132b948146SAndy Fiddaman /* 23142b948146SAndy Fiddaman * Each AHCI controller has a "port" node which contains nodes for 23152b948146SAndy Fiddaman * each port named after the decimal number of the port (no leading 23162b948146SAndy Fiddaman * zeroes). Port nodes contain a "type" ("hd" or "cd"), as well as 23172b948146SAndy Fiddaman * options for blockif. For example: 23182b948146SAndy Fiddaman * 23192b948146SAndy Fiddaman * pci.0.1.0 23202b948146SAndy Fiddaman * .device="ahci" 23212b948146SAndy Fiddaman * .port 23222b948146SAndy Fiddaman * .0 23232b948146SAndy Fiddaman * .type="hd" 23242b948146SAndy Fiddaman * .path="/path/to/image" 23252b948146SAndy Fiddaman */ 2326bf21cd93STycho Nightingale static int 23272b948146SAndy Fiddaman pci_ahci_legacy_config_port(nvlist_t *nvl, int port, const char *type, 23282b948146SAndy Fiddaman const char *opts) 23292b948146SAndy Fiddaman { 23302b948146SAndy Fiddaman char node_name[sizeof("XX")]; 23312b948146SAndy Fiddaman nvlist_t *port_nvl; 23322b948146SAndy Fiddaman 23332b948146SAndy Fiddaman snprintf(node_name, sizeof(node_name), "%d", port); 23342b948146SAndy Fiddaman port_nvl = create_relative_config_node(nvl, node_name); 23352b948146SAndy Fiddaman set_config_value_node(port_nvl, "type", type); 23362b948146SAndy Fiddaman return (blockif_legacy_config(port_nvl, opts)); 23372b948146SAndy Fiddaman } 23382b948146SAndy Fiddaman 23392b948146SAndy Fiddaman static int 23402b948146SAndy Fiddaman pci_ahci_legacy_config(nvlist_t *nvl, const char *opts) 23412b948146SAndy Fiddaman { 23422b948146SAndy Fiddaman nvlist_t *ports_nvl; 23432b948146SAndy Fiddaman const char *type; 23442b948146SAndy Fiddaman char *next, *next2, *str, *tofree; 23452b948146SAndy Fiddaman int p, ret; 23462b948146SAndy Fiddaman 23472b948146SAndy Fiddaman if (opts == NULL) 23482b948146SAndy Fiddaman return (0); 23492b948146SAndy Fiddaman 23502b948146SAndy Fiddaman ports_nvl = create_relative_config_node(nvl, "port"); 23512b948146SAndy Fiddaman ret = 1; 23522b948146SAndy Fiddaman tofree = str = strdup(opts); 23532b948146SAndy Fiddaman for (p = 0; p < MAX_PORTS && str != NULL; p++, str = next) { 23542b948146SAndy Fiddaman /* Identify and cut off type of present port. */ 23552b948146SAndy Fiddaman if (strncmp(str, "hd:", 3) == 0) { 23562b948146SAndy Fiddaman type = "hd"; 23572b948146SAndy Fiddaman str += 3; 23582b948146SAndy Fiddaman } else if (strncmp(str, "cd:", 3) == 0) { 23592b948146SAndy Fiddaman type = "cd"; 23602b948146SAndy Fiddaman str += 3; 23612b948146SAndy Fiddaman } else 23622b948146SAndy Fiddaman type = NULL; 23632b948146SAndy Fiddaman 23642b948146SAndy Fiddaman /* Find and cut off the next port options. */ 23652b948146SAndy Fiddaman next = strstr(str, ",hd:"); 23662b948146SAndy Fiddaman next2 = strstr(str, ",cd:"); 23672b948146SAndy Fiddaman if (next == NULL || (next2 != NULL && next2 < next)) 23682b948146SAndy Fiddaman next = next2; 23692b948146SAndy Fiddaman if (next != NULL) { 23702b948146SAndy Fiddaman next[0] = 0; 23712b948146SAndy Fiddaman next++; 23722b948146SAndy Fiddaman } 23732b948146SAndy Fiddaman 23742b948146SAndy Fiddaman if (str[0] == 0) 23752b948146SAndy Fiddaman continue; 23762b948146SAndy Fiddaman 23772b948146SAndy Fiddaman if (type == NULL) { 23782b948146SAndy Fiddaman EPRINTLN("Missing or invalid type for port %d: \"%s\"", 23792b948146SAndy Fiddaman p, str); 23802b948146SAndy Fiddaman goto out; 23812b948146SAndy Fiddaman } 23822b948146SAndy Fiddaman 23832b948146SAndy Fiddaman if (pci_ahci_legacy_config_port(ports_nvl, p, type, str) != 0) 23842b948146SAndy Fiddaman goto out; 23852b948146SAndy Fiddaman } 23862b948146SAndy Fiddaman ret = 0; 23872b948146SAndy Fiddaman out: 23882b948146SAndy Fiddaman free(tofree); 23892b948146SAndy Fiddaman return (ret); 23902b948146SAndy Fiddaman } 23912b948146SAndy Fiddaman 23922b948146SAndy Fiddaman static int 23932b948146SAndy Fiddaman pci_ahci_cd_legacy_config(nvlist_t *nvl, const char *opts) 23942b948146SAndy Fiddaman { 23952b948146SAndy Fiddaman nvlist_t *ports_nvl; 23962b948146SAndy Fiddaman 23972b948146SAndy Fiddaman ports_nvl = create_relative_config_node(nvl, "port"); 23982b948146SAndy Fiddaman return (pci_ahci_legacy_config_port(ports_nvl, 0, "cd", opts)); 23992b948146SAndy Fiddaman } 24002b948146SAndy Fiddaman 24012b948146SAndy Fiddaman static int 24022b948146SAndy Fiddaman pci_ahci_hd_legacy_config(nvlist_t *nvl, const char *opts) 24032b948146SAndy Fiddaman { 24042b948146SAndy Fiddaman nvlist_t *ports_nvl; 24052b948146SAndy Fiddaman 24062b948146SAndy Fiddaman ports_nvl = create_relative_config_node(nvl, "port"); 24072b948146SAndy Fiddaman return (pci_ahci_legacy_config_port(ports_nvl, 0, "hd", opts)); 24082b948146SAndy Fiddaman } 24092b948146SAndy Fiddaman 24102b948146SAndy Fiddaman static int 24112b948146SAndy Fiddaman pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) 2412bf21cd93STycho Nightingale { 24134c87aefeSPatrick Mooney char bident[sizeof("XX:XX:XX")]; 24142b948146SAndy Fiddaman char node_name[sizeof("XX")]; 2415bf21cd93STycho Nightingale struct blockif_ctxt *bctxt; 2416bf21cd93STycho Nightingale struct pci_ahci_softc *sc; 24172b948146SAndy Fiddaman int atapi, ret, slots, p; 24184c87aefeSPatrick Mooney MD5_CTX mdctx; 24194c87aefeSPatrick Mooney u_char digest[16]; 24202b948146SAndy Fiddaman const char *path, *type, *value; 24212b948146SAndy Fiddaman nvlist_t *ports_nvl, *port_nvl; 2422bf21cd93STycho Nightingale 2423bf21cd93STycho Nightingale ret = 0; 2424bf21cd93STycho Nightingale 2425bf21cd93STycho Nightingale #ifdef AHCI_DEBUG 2426bf21cd93STycho Nightingale dbg = fopen("/tmp/log", "w+"); 2427bf21cd93STycho Nightingale #endif 2428bf21cd93STycho Nightingale 2429bf21cd93STycho Nightingale sc = calloc(1, sizeof(struct pci_ahci_softc)); 2430bf21cd93STycho Nightingale pi->pi_arg = sc; 2431bf21cd93STycho Nightingale sc->asc_pi = pi; 24324c87aefeSPatrick Mooney pthread_mutex_init(&sc->mtx, NULL); 24334c87aefeSPatrick Mooney sc->ports = 0; 24344c87aefeSPatrick Mooney sc->pi = 0; 24354c87aefeSPatrick Mooney slots = 32; 24364c87aefeSPatrick Mooney 24372b948146SAndy Fiddaman ports_nvl = find_relative_config_node(nvl, "port"); 2438*d7b72f7bSAndy Fiddaman for (p = 0; ports_nvl != NULL && p < MAX_PORTS; p++) { 24396960cd89SAndy Fiddaman struct ata_params *ata_ident = &sc->port[p].ata_ident; 24402b948146SAndy Fiddaman char ident[AHCI_PORT_IDENT]; 24416960cd89SAndy Fiddaman 24422b948146SAndy Fiddaman snprintf(node_name, sizeof(node_name), "%d", p); 24432b948146SAndy Fiddaman port_nvl = find_relative_config_node(ports_nvl, node_name); 24442b948146SAndy Fiddaman if (port_nvl == NULL) 24454c87aefeSPatrick Mooney continue; 2446bf21cd93STycho Nightingale 24472b948146SAndy Fiddaman type = get_config_value_node(port_nvl, "type"); 24482b948146SAndy Fiddaman if (type == NULL) 24492b948146SAndy Fiddaman continue; 24506960cd89SAndy Fiddaman 24512b948146SAndy Fiddaman if (strcmp(type, "hd") == 0) 24522b948146SAndy Fiddaman atapi = 0; 24532b948146SAndy Fiddaman else 24542b948146SAndy Fiddaman atapi = 1; 24556960cd89SAndy Fiddaman 2456bf21cd93STycho Nightingale /* 24574c87aefeSPatrick Mooney * Attempt to open the backing image. Use the PCI slot/func 24584c87aefeSPatrick Mooney * and the port number for the identifier string. 2459bf21cd93STycho Nightingale */ 24604c87aefeSPatrick Mooney snprintf(bident, sizeof(bident), "%d:%d:%d", pi->pi_slot, 24614c87aefeSPatrick Mooney pi->pi_func, p); 24626960cd89SAndy Fiddaman 24632b948146SAndy Fiddaman bctxt = blockif_open(port_nvl, bident); 2464bf21cd93STycho Nightingale if (bctxt == NULL) { 24654c87aefeSPatrick Mooney sc->ports = p; 2466bf21cd93STycho Nightingale ret = 1; 2467bf21cd93STycho Nightingale goto open_fail; 2468bf21cd93STycho Nightingale } 24694c87aefeSPatrick Mooney sc->port[p].bctx = bctxt; 24704c87aefeSPatrick Mooney sc->port[p].pr_sc = sc; 24714c87aefeSPatrick Mooney sc->port[p].port = p; 24724c87aefeSPatrick Mooney sc->port[p].atapi = atapi; 24734c87aefeSPatrick Mooney 24742b948146SAndy Fiddaman /* 24752b948146SAndy Fiddaman * Create an identifier for the backing file. 24762b948146SAndy Fiddaman * Use parts of the md5 sum of the filename 24772b948146SAndy Fiddaman */ 24782b948146SAndy Fiddaman path = get_config_value_node(port_nvl, "path"); 24792b948146SAndy Fiddaman MD5Init(&mdctx); 24802b948146SAndy Fiddaman MD5Update(&mdctx, path, strlen(path)); 24812b948146SAndy Fiddaman MD5Final(digest, &mdctx); 24822b948146SAndy Fiddaman snprintf(ident, AHCI_PORT_IDENT, 24832b948146SAndy Fiddaman "BHYVE-%02X%02X-%02X%02X-%02X%02X", 24842b948146SAndy Fiddaman digest[0], digest[1], digest[2], digest[3], digest[4], 24852b948146SAndy Fiddaman digest[5]); 24862b948146SAndy Fiddaman 24872b948146SAndy Fiddaman memset(ata_ident, 0, sizeof(struct ata_params)); 24882b948146SAndy Fiddaman ata_string((uint8_t*)&ata_ident->serial, ident, 20); 24892b948146SAndy Fiddaman ata_string((uint8_t*)&ata_ident->revision, "001", 8); 24902b948146SAndy Fiddaman if (atapi) 24912b948146SAndy Fiddaman ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DVD ROM", 40); 24922b948146SAndy Fiddaman else 24932b948146SAndy Fiddaman ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DISK", 40); 24942b948146SAndy Fiddaman value = get_config_value_node(port_nvl, "nmrr"); 24952b948146SAndy Fiddaman if (value != NULL) 24962b948146SAndy Fiddaman ata_ident->media_rotation_rate = atoi(value); 24972b948146SAndy Fiddaman value = get_config_value_node(port_nvl, "ser"); 24982b948146SAndy Fiddaman if (value != NULL) 24992b948146SAndy Fiddaman ata_string((uint8_t*)(&ata_ident->serial), value, 20); 25002b948146SAndy Fiddaman value = get_config_value_node(port_nvl, "rev"); 25012b948146SAndy Fiddaman if (value != NULL) 25022b948146SAndy Fiddaman ata_string((uint8_t*)(&ata_ident->revision), value, 8); 25032b948146SAndy Fiddaman value = get_config_value_node(port_nvl, "model"); 25042b948146SAndy Fiddaman if (value != NULL) 25052b948146SAndy Fiddaman ata_string((uint8_t*)(&ata_ident->model), value, 40); 25062b948146SAndy Fiddaman ata_identify_init(&sc->port[p], atapi); 25072b948146SAndy Fiddaman 25084c87aefeSPatrick Mooney #ifndef __FreeBSD__ 25094c87aefeSPatrick Mooney /* 25104c87aefeSPatrick Mooney * Attempt to enable the write cache for this device, as the 25114c87aefeSPatrick Mooney * guest will issue FLUSH commands when it requires durability. 25124c87aefeSPatrick Mooney * 25134c87aefeSPatrick Mooney * Failure here is fine, since an always-sync device will not 25144c87aefeSPatrick Mooney * have an impact on correctness. 25154c87aefeSPatrick Mooney */ 25164c87aefeSPatrick Mooney (void) blockif_set_wce(bctxt, 1); 25174c87aefeSPatrick Mooney #endif 25184c87aefeSPatrick Mooney 2519bf21cd93STycho Nightingale /* 2520bf21cd93STycho Nightingale * Allocate blockif request structures and add them 2521bf21cd93STycho Nightingale * to the free list 2522bf21cd93STycho Nightingale */ 25234c87aefeSPatrick Mooney pci_ahci_ioreq_init(&sc->port[p]); 2524bf21cd93STycho Nightingale 25254c87aefeSPatrick Mooney sc->pi |= (1 << p); 25264c87aefeSPatrick Mooney if (sc->port[p].ioqsz < slots) 25274c87aefeSPatrick Mooney slots = sc->port[p].ioqsz; 25284c87aefeSPatrick Mooney } 25294c87aefeSPatrick Mooney sc->ports = p; 2530bf21cd93STycho Nightingale 2531bf21cd93STycho Nightingale /* Intel ICH8 AHCI */ 2532bf21cd93STycho Nightingale --slots; 25334c87aefeSPatrick Mooney if (sc->ports < DEF_PORTS) 25344c87aefeSPatrick Mooney sc->ports = DEF_PORTS; 2535bf21cd93STycho Nightingale sc->cap = AHCI_CAP_64BIT | AHCI_CAP_SNCQ | AHCI_CAP_SSNTF | 2536bf21cd93STycho Nightingale AHCI_CAP_SMPS | AHCI_CAP_SSS | AHCI_CAP_SALP | 2537bf21cd93STycho Nightingale AHCI_CAP_SAL | AHCI_CAP_SCLO | (0x3 << AHCI_CAP_ISS_SHIFT)| 2538bf21cd93STycho Nightingale AHCI_CAP_PMD | AHCI_CAP_SSC | AHCI_CAP_PSC | 2539bf21cd93STycho Nightingale (slots << AHCI_CAP_NCS_SHIFT) | AHCI_CAP_SXS | (sc->ports - 1); 2540bf21cd93STycho Nightingale 2541bf21cd93STycho Nightingale sc->vs = 0x10300; 2542bf21cd93STycho Nightingale sc->cap2 = AHCI_CAP2_APST; 2543bf21cd93STycho Nightingale ahci_reset(sc); 2544bf21cd93STycho Nightingale 2545bf21cd93STycho Nightingale pci_set_cfgdata16(pi, PCIR_DEVICE, 0x2821); 2546bf21cd93STycho Nightingale pci_set_cfgdata16(pi, PCIR_VENDOR, 0x8086); 2547bf21cd93STycho Nightingale pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE); 2548bf21cd93STycho Nightingale pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_STORAGE_SATA); 2549bf21cd93STycho Nightingale pci_set_cfgdata8(pi, PCIR_PROGIF, PCIP_STORAGE_SATA_AHCI_1_0); 25504c87aefeSPatrick Mooney p = MIN(sc->ports, 16); 25514c87aefeSPatrick Mooney p = flsl(p) - ((p & (p - 1)) ? 0 : 1); 25524c87aefeSPatrick Mooney pci_emul_add_msicap(pi, 1 << p); 2553bf21cd93STycho Nightingale pci_emul_alloc_bar(pi, 5, PCIBAR_MEM32, 2554bf21cd93STycho Nightingale AHCI_OFFSET + sc->ports * AHCI_STEP); 2555bf21cd93STycho Nightingale 2556bf21cd93STycho Nightingale pci_lintr_request(pi); 2557bf21cd93STycho Nightingale 2558bf21cd93STycho Nightingale open_fail: 2559bf21cd93STycho Nightingale if (ret) { 25604c87aefeSPatrick Mooney for (p = 0; p < sc->ports; p++) { 25614c87aefeSPatrick Mooney if (sc->port[p].bctx != NULL) 25624c87aefeSPatrick Mooney blockif_close(sc->port[p].bctx); 25634c87aefeSPatrick Mooney } 2564bf21cd93STycho Nightingale free(sc); 2565bf21cd93STycho Nightingale } 2566bf21cd93STycho Nightingale 2567bf21cd93STycho Nightingale return (ret); 2568bf21cd93STycho Nightingale } 2569bf21cd93STycho Nightingale 2570bf21cd93STycho Nightingale /* 2571bf21cd93STycho Nightingale * Use separate emulation names to distinguish drive and atapi devices 2572bf21cd93STycho Nightingale */ 25734c87aefeSPatrick Mooney struct pci_devemu pci_de_ahci = { 25744c87aefeSPatrick Mooney .pe_emu = "ahci", 25752b948146SAndy Fiddaman .pe_init = pci_ahci_init, 25762b948146SAndy Fiddaman .pe_legacy_config = pci_ahci_legacy_config, 25774c87aefeSPatrick Mooney .pe_barwrite = pci_ahci_write, 25782b948146SAndy Fiddaman .pe_barread = pci_ahci_read, 25794c87aefeSPatrick Mooney }; 25804c87aefeSPatrick Mooney PCI_EMUL_SET(pci_de_ahci); 25814c87aefeSPatrick Mooney 2582bf21cd93STycho Nightingale struct pci_devemu pci_de_ahci_hd = { 2583bf21cd93STycho Nightingale .pe_emu = "ahci-hd", 25842b948146SAndy Fiddaman .pe_legacy_config = pci_ahci_hd_legacy_config, 25852b948146SAndy Fiddaman .pe_alias = "ahci", 2586bf21cd93STycho Nightingale }; 2587bf21cd93STycho Nightingale PCI_EMUL_SET(pci_de_ahci_hd); 2588bf21cd93STycho Nightingale 2589bf21cd93STycho Nightingale struct pci_devemu pci_de_ahci_cd = { 2590bf21cd93STycho Nightingale .pe_emu = "ahci-cd", 25912b948146SAndy Fiddaman .pe_legacy_config = pci_ahci_cd_legacy_config, 25922b948146SAndy Fiddaman .pe_alias = "ahci", 2593bf21cd93STycho Nightingale }; 2594bf21cd93STycho Nightingale PCI_EMUL_SET(pci_de_ahci_cd); 2595