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