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