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: releng/11.0/usr.sbin/bhyve/pci_ahci.c 303138 2016-07-21 11:57:41Z mav $ 27256056Sgrehan */ 28256056Sgrehan 29256056Sgrehan#include <sys/cdefs.h> 30256056Sgrehan__FBSDID("$FreeBSD: releng/11.0/usr.sbin/bhyve/pci_ahci.c 303138 2016-07-21 11:57:41Z mav $"); 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> 51273212Stychon#include <pthread_np.h> 52256056Sgrehan#include <inttypes.h> 53280040Smav#include <md5.h> 54256056Sgrehan 55256056Sgrehan#include "bhyverun.h" 56256056Sgrehan#include "pci_emul.h" 57256056Sgrehan#include "ahci.h" 58256056Sgrehan#include "block_if.h" 59256056Sgrehan 60256056Sgrehan#define MAX_PORTS 6 /* Intel ICH8 AHCI supports 6 ports */ 61256056Sgrehan 62256056Sgrehan#define PxSIG_ATA 0x00000101 /* ATA drive */ 63256056Sgrehan#define PxSIG_ATAPI 0xeb140101 /* ATAPI drive */ 64256056Sgrehan 65256056Sgrehanenum sata_fis_type { 66256056Sgrehan FIS_TYPE_REGH2D = 0x27, /* Register FIS - host to device */ 67256056Sgrehan FIS_TYPE_REGD2H = 0x34, /* Register FIS - device to host */ 68256056Sgrehan FIS_TYPE_DMAACT = 0x39, /* DMA activate FIS - device to host */ 69256056Sgrehan FIS_TYPE_DMASETUP = 0x41, /* DMA setup FIS - bidirectional */ 70256056Sgrehan FIS_TYPE_DATA = 0x46, /* Data FIS - bidirectional */ 71256056Sgrehan FIS_TYPE_BIST = 0x58, /* BIST activate FIS - bidirectional */ 72256056Sgrehan FIS_TYPE_PIOSETUP = 0x5F, /* PIO setup FIS - device to host */ 73256056Sgrehan FIS_TYPE_SETDEVBITS = 0xA1, /* Set dev bits FIS - device to host */ 74256056Sgrehan}; 75256056Sgrehan 76256056Sgrehan/* 77256056Sgrehan * SCSI opcodes 78256056Sgrehan */ 79256056Sgrehan#define TEST_UNIT_READY 0x00 80256056Sgrehan#define REQUEST_SENSE 0x03 81256056Sgrehan#define INQUIRY 0x12 82256056Sgrehan#define START_STOP_UNIT 0x1B 83256056Sgrehan#define PREVENT_ALLOW 0x1E 84256056Sgrehan#define READ_CAPACITY 0x25 85256056Sgrehan#define READ_10 0x28 86256056Sgrehan#define POSITION_TO_ELEMENT 0x2B 87256056Sgrehan#define READ_TOC 0x43 88256056Sgrehan#define GET_EVENT_STATUS_NOTIFICATION 0x4A 89256056Sgrehan#define MODE_SENSE_10 0x5A 90279979Smav#define REPORT_LUNS 0xA0 91256056Sgrehan#define READ_12 0xA8 92256056Sgrehan#define READ_CD 0xBE 93256056Sgrehan 94256056Sgrehan/* 95256056Sgrehan * SCSI mode page codes 96256056Sgrehan */ 97256056Sgrehan#define MODEPAGE_RW_ERROR_RECOVERY 0x01 98256056Sgrehan#define MODEPAGE_CD_CAPABILITIES 0x2A 99256056Sgrehan 100256056Sgrehan/* 101263238Stychon * ATA commands 102263238Stychon */ 103263238Stychon#define ATA_SF_ENAB_SATA_SF 0x10 104263238Stychon#define ATA_SATA_SF_AN 0x05 105263238Stychon#define ATA_SF_DIS_SATA_SF 0x90 106263238Stychon 107263238Stychon/* 108256056Sgrehan * Debug printf 109256056Sgrehan */ 110256056Sgrehan#ifdef AHCI_DEBUG 111256056Sgrehanstatic FILE *dbg; 112256056Sgrehan#define DPRINTF(format, arg...) do{fprintf(dbg, format, ##arg);fflush(dbg);}while(0) 113256056Sgrehan#else 114256056Sgrehan#define DPRINTF(format, arg...) 115256056Sgrehan#endif 116256056Sgrehan#define WPRINTF(format, arg...) printf(format, ##arg) 117256056Sgrehan 118256056Sgrehanstruct ahci_ioreq { 119256056Sgrehan struct blockif_req io_req; 120256056Sgrehan struct ahci_port *io_pr; 121273212Stychon STAILQ_ENTRY(ahci_ioreq) io_flist; 122273212Stychon TAILQ_ENTRY(ahci_ioreq) io_blist; 123256056Sgrehan uint8_t *cfis; 124256056Sgrehan uint32_t len; 125256056Sgrehan uint32_t done; 126256056Sgrehan int slot; 127281666Smav int more; 128256056Sgrehan}; 129256056Sgrehan 130256056Sgrehanstruct ahci_port { 131256056Sgrehan struct blockif_ctxt *bctx; 132256056Sgrehan struct pci_ahci_softc *pr_sc; 133256164Sdim uint8_t *cmd_lst; 134256164Sdim uint8_t *rfis; 135280040Smav char ident[20 + 1]; 136256056Sgrehan int atapi; 137256056Sgrehan int reset; 138282524Smav int waitforclear; 139256056Sgrehan int mult_sectors; 140256056Sgrehan uint8_t xfermode; 141279975Smav uint8_t err_cfis[20]; 142256056Sgrehan uint8_t sense_key; 143256056Sgrehan uint8_t asc; 144282429Smav u_int ccs; 145263322Stychon uint32_t pending; 146256056Sgrehan 147256056Sgrehan uint32_t clb; 148256056Sgrehan uint32_t clbu; 149256056Sgrehan uint32_t fb; 150256056Sgrehan uint32_t fbu; 151256056Sgrehan uint32_t is; 152256056Sgrehan uint32_t ie; 153256056Sgrehan uint32_t cmd; 154256056Sgrehan uint32_t unused0; 155256056Sgrehan uint32_t tfd; 156256056Sgrehan uint32_t sig; 157256056Sgrehan uint32_t ssts; 158256056Sgrehan uint32_t sctl; 159256056Sgrehan uint32_t serr; 160256056Sgrehan uint32_t sact; 161256056Sgrehan uint32_t ci; 162256056Sgrehan uint32_t sntf; 163256056Sgrehan uint32_t fbs; 164256056Sgrehan 165256056Sgrehan /* 166256056Sgrehan * i/o request info 167256056Sgrehan */ 168256056Sgrehan struct ahci_ioreq *ioreq; 169256056Sgrehan int ioqsz; 170256056Sgrehan STAILQ_HEAD(ahci_fhead, ahci_ioreq) iofhd; 171273212Stychon TAILQ_HEAD(ahci_bhead, ahci_ioreq) iobhd; 172256056Sgrehan}; 173256056Sgrehan 174256056Sgrehanstruct ahci_cmd_hdr { 175256056Sgrehan uint16_t flags; 176256056Sgrehan uint16_t prdtl; 177256056Sgrehan uint32_t prdbc; 178256056Sgrehan uint64_t ctba; 179256056Sgrehan uint32_t reserved[4]; 180256056Sgrehan}; 181256056Sgrehan 182256056Sgrehanstruct ahci_prdt_entry { 183256056Sgrehan uint64_t dba; 184256056Sgrehan uint32_t reserved; 185258614Sgrehan#define DBCMASK 0x3fffff 186256056Sgrehan uint32_t dbc; 187256056Sgrehan}; 188256056Sgrehan 189256056Sgrehanstruct pci_ahci_softc { 190256056Sgrehan struct pci_devinst *asc_pi; 191256056Sgrehan pthread_mutex_t mtx; 192256056Sgrehan int ports; 193256056Sgrehan uint32_t cap; 194256056Sgrehan uint32_t ghc; 195256056Sgrehan uint32_t is; 196256056Sgrehan uint32_t pi; 197256056Sgrehan uint32_t vs; 198256056Sgrehan uint32_t ccc_ctl; 199256056Sgrehan uint32_t ccc_pts; 200256056Sgrehan uint32_t em_loc; 201256056Sgrehan uint32_t em_ctl; 202256056Sgrehan uint32_t cap2; 203256056Sgrehan uint32_t bohc; 204265058Sgrehan uint32_t lintr; 205256056Sgrehan struct ahci_port port[MAX_PORTS]; 206256056Sgrehan}; 207256056Sgrehan#define ahci_ctx(sc) ((sc)->asc_pi->pi_vmctx) 208256056Sgrehan 209282429Smavstatic void ahci_handle_port(struct ahci_port *p); 210282429Smav 211256056Sgrehanstatic inline void lba_to_msf(uint8_t *buf, int lba) 212256056Sgrehan{ 213256056Sgrehan lba += 150; 214256056Sgrehan buf[0] = (lba / 75) / 60; 215256056Sgrehan buf[1] = (lba / 75) % 60; 216256056Sgrehan buf[2] = lba % 75; 217256056Sgrehan} 218256056Sgrehan 219256056Sgrehan/* 220256056Sgrehan * generate HBA intr depending on whether or not ports within 221256056Sgrehan * the controller have an interrupt pending. 222256056Sgrehan */ 223256056Sgrehanstatic void 224256056Sgrehanahci_generate_intr(struct pci_ahci_softc *sc) 225256056Sgrehan{ 226265058Sgrehan struct pci_devinst *pi; 227256056Sgrehan int i; 228256056Sgrehan 229265058Sgrehan pi = sc->asc_pi; 230265058Sgrehan 231256056Sgrehan for (i = 0; i < sc->ports; i++) { 232256056Sgrehan struct ahci_port *pr; 233256056Sgrehan pr = &sc->port[i]; 234256056Sgrehan if (pr->is & pr->ie) 235256056Sgrehan sc->is |= (1 << i); 236256056Sgrehan } 237256056Sgrehan 238256056Sgrehan DPRINTF("%s %x\n", __func__, sc->is); 239256056Sgrehan 240265058Sgrehan if (sc->is && (sc->ghc & AHCI_GHC_IE)) { 241265058Sgrehan if (pci_msi_enabled(pi)) { 242265058Sgrehan /* 243265058Sgrehan * Generate an MSI interrupt on every edge 244265058Sgrehan */ 245265058Sgrehan pci_generate_msi(pi, 0); 246265058Sgrehan } else if (!sc->lintr) { 247265058Sgrehan /* 248265058Sgrehan * Only generate a pin-based interrupt if one wasn't 249265058Sgrehan * in progress 250265058Sgrehan */ 251265058Sgrehan sc->lintr = 1; 252265058Sgrehan pci_lintr_assert(pi); 253265058Sgrehan } 254265058Sgrehan } else if (sc->lintr) { 255265058Sgrehan /* 256265058Sgrehan * No interrupts: deassert pin-based signal if it had 257265058Sgrehan * been asserted 258265058Sgrehan */ 259265058Sgrehan pci_lintr_deassert(pi); 260265058Sgrehan sc->lintr = 0; 261265058Sgrehan } 262256056Sgrehan} 263256056Sgrehan 264256056Sgrehanstatic void 265256056Sgrehanahci_write_fis(struct ahci_port *p, enum sata_fis_type ft, uint8_t *fis) 266256056Sgrehan{ 267256056Sgrehan int offset, len, irq; 268256056Sgrehan 269256164Sdim if (p->rfis == NULL || !(p->cmd & AHCI_P_CMD_FRE)) 270256056Sgrehan return; 271256056Sgrehan 272256056Sgrehan switch (ft) { 273256056Sgrehan case FIS_TYPE_REGD2H: 274256056Sgrehan offset = 0x40; 275256056Sgrehan len = 20; 276282364Smav irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_DHR : 0; 277256056Sgrehan break; 278256056Sgrehan case FIS_TYPE_SETDEVBITS: 279256056Sgrehan offset = 0x58; 280256056Sgrehan len = 8; 281282364Smav irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_SDB : 0; 282256056Sgrehan break; 283256056Sgrehan case FIS_TYPE_PIOSETUP: 284256056Sgrehan offset = 0x20; 285256056Sgrehan len = 20; 286282364Smav irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_PS : 0; 287256056Sgrehan break; 288256056Sgrehan default: 289256056Sgrehan WPRINTF("unsupported fis type %d\n", ft); 290256056Sgrehan return; 291256056Sgrehan } 292282524Smav if (fis[2] & ATA_S_ERROR) { 293282524Smav p->waitforclear = 1; 294282364Smav irq |= AHCI_P_IX_TFE; 295282524Smav } 296256056Sgrehan memcpy(p->rfis + offset, fis, len); 297256056Sgrehan if (irq) { 298256056Sgrehan p->is |= irq; 299256056Sgrehan ahci_generate_intr(p->pr_sc); 300256056Sgrehan } 301256056Sgrehan} 302256056Sgrehan 303256056Sgrehanstatic void 304261785Stychonahci_write_fis_piosetup(struct ahci_port *p) 305261785Stychon{ 306261785Stychon uint8_t fis[20]; 307261785Stychon 308261785Stychon memset(fis, 0, sizeof(fis)); 309261785Stychon fis[0] = FIS_TYPE_PIOSETUP; 310261785Stychon ahci_write_fis(p, FIS_TYPE_PIOSETUP, fis); 311261785Stychon} 312261785Stychon 313261785Stychonstatic void 314279975Smavahci_write_fis_sdb(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd) 315256056Sgrehan{ 316256056Sgrehan uint8_t fis[8]; 317256056Sgrehan uint8_t error; 318256056Sgrehan 319256056Sgrehan error = (tfd >> 8) & 0xff; 320282364Smav tfd &= 0x77; 321256056Sgrehan memset(fis, 0, sizeof(fis)); 322279975Smav fis[0] = FIS_TYPE_SETDEVBITS; 323279975Smav fis[1] = (1 << 6); 324282364Smav fis[2] = tfd; 325279975Smav fis[3] = error; 326279975Smav if (fis[2] & ATA_S_ERROR) { 327279975Smav p->err_cfis[0] = slot; 328282364Smav p->err_cfis[2] = tfd; 329279975Smav p->err_cfis[3] = error; 330279975Smav memcpy(&p->err_cfis[4], cfis + 4, 16); 331279975Smav } else { 332279975Smav *(uint32_t *)(fis + 4) = (1 << slot); 333279975Smav p->sact &= ~(1 << slot); 334279975Smav } 335282364Smav p->tfd &= ~0x77; 336282364Smav p->tfd |= tfd; 337256056Sgrehan ahci_write_fis(p, FIS_TYPE_SETDEVBITS, fis); 338256056Sgrehan} 339256056Sgrehan 340256056Sgrehanstatic void 341256056Sgrehanahci_write_fis_d2h(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd) 342256056Sgrehan{ 343256056Sgrehan uint8_t fis[20]; 344256056Sgrehan uint8_t error; 345256056Sgrehan 346256056Sgrehan error = (tfd >> 8) & 0xff; 347256056Sgrehan memset(fis, 0, sizeof(fis)); 348256056Sgrehan fis[0] = FIS_TYPE_REGD2H; 349256056Sgrehan fis[1] = (1 << 6); 350256056Sgrehan fis[2] = tfd & 0xff; 351256056Sgrehan fis[3] = error; 352256056Sgrehan fis[4] = cfis[4]; 353256056Sgrehan fis[5] = cfis[5]; 354256056Sgrehan fis[6] = cfis[6]; 355256056Sgrehan fis[7] = cfis[7]; 356256056Sgrehan fis[8] = cfis[8]; 357256056Sgrehan fis[9] = cfis[9]; 358256056Sgrehan fis[10] = cfis[10]; 359256056Sgrehan fis[11] = cfis[11]; 360256056Sgrehan fis[12] = cfis[12]; 361256056Sgrehan fis[13] = cfis[13]; 362279975Smav if (fis[2] & ATA_S_ERROR) { 363279975Smav p->err_cfis[0] = 0x80; 364279975Smav p->err_cfis[2] = tfd & 0xff; 365279975Smav p->err_cfis[3] = error; 366279975Smav memcpy(&p->err_cfis[4], cfis + 4, 16); 367279975Smav } else 368269317Stychon p->ci &= ~(1 << slot); 369256056Sgrehan p->tfd = tfd; 370256056Sgrehan ahci_write_fis(p, FIS_TYPE_REGD2H, fis); 371256056Sgrehan} 372256056Sgrehan 373256056Sgrehanstatic void 374282364Smavahci_write_fis_d2h_ncq(struct ahci_port *p, int slot) 375282364Smav{ 376282364Smav uint8_t fis[20]; 377282364Smav 378282364Smav p->tfd = ATA_S_READY | ATA_S_DSC; 379282364Smav memset(fis, 0, sizeof(fis)); 380282364Smav fis[0] = FIS_TYPE_REGD2H; 381282364Smav fis[1] = 0; /* No interrupt */ 382282364Smav fis[2] = p->tfd; /* Status */ 383282364Smav fis[3] = 0; /* No error */ 384282364Smav p->ci &= ~(1 << slot); 385282364Smav ahci_write_fis(p, FIS_TYPE_REGD2H, fis); 386282364Smav} 387282364Smav 388282364Smavstatic void 389256056Sgrehanahci_write_reset_fis_d2h(struct ahci_port *p) 390256056Sgrehan{ 391256056Sgrehan uint8_t fis[20]; 392256056Sgrehan 393256056Sgrehan memset(fis, 0, sizeof(fis)); 394256056Sgrehan fis[0] = FIS_TYPE_REGD2H; 395256056Sgrehan fis[3] = 1; 396256056Sgrehan fis[4] = 1; 397256056Sgrehan if (p->atapi) { 398256056Sgrehan fis[5] = 0x14; 399256056Sgrehan fis[6] = 0xeb; 400256056Sgrehan } 401256056Sgrehan fis[12] = 1; 402256056Sgrehan ahci_write_fis(p, FIS_TYPE_REGD2H, fis); 403256056Sgrehan} 404256056Sgrehan 405256056Sgrehanstatic void 406273212Stychonahci_check_stopped(struct ahci_port *p) 407273212Stychon{ 408273212Stychon /* 409273212Stychon * If we are no longer processing the command list and nothing 410274045Stychon * is in-flight, clear the running bit, the current command 411274045Stychon * slot, the command issue and active bits. 412273212Stychon */ 413273212Stychon if (!(p->cmd & AHCI_P_CMD_ST)) { 414274045Stychon if (p->pending == 0) { 415282429Smav p->ccs = 0; 416273212Stychon p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK); 417274045Stychon p->ci = 0; 418274045Stychon p->sact = 0; 419282524Smav p->waitforclear = 0; 420274045Stychon } 421273212Stychon } 422273212Stychon} 423273212Stychon 424273212Stychonstatic void 425273212Stychonahci_port_stop(struct ahci_port *p) 426273212Stychon{ 427273212Stychon struct ahci_ioreq *aior; 428273212Stychon uint8_t *cfis; 429273212Stychon int slot; 430273212Stychon int error; 431273212Stychon 432273212Stychon assert(pthread_mutex_isowned_np(&p->pr_sc->mtx)); 433273212Stychon 434273212Stychon TAILQ_FOREACH(aior, &p->iobhd, io_blist) { 435273212Stychon /* 436273212Stychon * Try to cancel the outstanding blockif request. 437273212Stychon */ 438273212Stychon error = blockif_cancel(p->bctx, &aior->io_req); 439273212Stychon if (error != 0) 440273212Stychon continue; 441273212Stychon 442273212Stychon slot = aior->slot; 443273212Stychon cfis = aior->cfis; 444273212Stychon if (cfis[2] == ATA_WRITE_FPDMA_QUEUED || 445282344Smav cfis[2] == ATA_READ_FPDMA_QUEUED || 446282344Smav cfis[2] == ATA_SEND_FPDMA_QUEUED) 447297589Spfg p->sact &= ~(1 << slot); /* NCQ */ 448273212Stychon else 449273212Stychon p->ci &= ~(1 << slot); 450273212Stychon 451273212Stychon /* 452273212Stychon * This command is now done. 453273212Stychon */ 454273212Stychon p->pending &= ~(1 << slot); 455273212Stychon 456273212Stychon /* 457273212Stychon * Delete the blockif request from the busy list 458273212Stychon */ 459273212Stychon TAILQ_REMOVE(&p->iobhd, aior, io_blist); 460273212Stychon 461273212Stychon /* 462273212Stychon * Move the blockif request back to the free list 463273212Stychon */ 464273212Stychon STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist); 465273212Stychon } 466273212Stychon 467273212Stychon ahci_check_stopped(p); 468273212Stychon} 469273212Stychon 470273212Stychonstatic void 471256056Sgrehanahci_port_reset(struct ahci_port *pr) 472256056Sgrehan{ 473256056Sgrehan pr->serr = 0; 474256056Sgrehan pr->sact = 0; 475256056Sgrehan pr->xfermode = ATA_UDMA6; 476256056Sgrehan pr->mult_sectors = 128; 477256056Sgrehan 478256056Sgrehan if (!pr->bctx) { 479256056Sgrehan pr->ssts = ATA_SS_DET_NO_DEVICE; 480256056Sgrehan pr->sig = 0xFFFFFFFF; 481256056Sgrehan pr->tfd = 0x7F; 482256056Sgrehan return; 483256056Sgrehan } 484279965Smav pr->ssts = ATA_SS_DET_PHY_ONLINE | ATA_SS_IPM_ACTIVE; 485279965Smav if (pr->sctl & ATA_SC_SPD_MASK) 486279965Smav pr->ssts |= (pr->sctl & ATA_SC_SPD_MASK); 487279965Smav else 488279965Smav pr->ssts |= ATA_SS_SPD_GEN3; 489256056Sgrehan pr->tfd = (1 << 8) | ATA_S_DSC | ATA_S_DMA; 490256056Sgrehan if (!pr->atapi) { 491256056Sgrehan pr->sig = PxSIG_ATA; 492256056Sgrehan pr->tfd |= ATA_S_READY; 493256056Sgrehan } else 494256056Sgrehan pr->sig = PxSIG_ATAPI; 495256056Sgrehan ahci_write_reset_fis_d2h(pr); 496256056Sgrehan} 497256056Sgrehan 498256056Sgrehanstatic void 499256056Sgrehanahci_reset(struct pci_ahci_softc *sc) 500256056Sgrehan{ 501256056Sgrehan int i; 502256056Sgrehan 503256056Sgrehan sc->ghc = AHCI_GHC_AE; 504256056Sgrehan sc->is = 0; 505265058Sgrehan 506265058Sgrehan if (sc->lintr) { 507265058Sgrehan pci_lintr_deassert(sc->asc_pi); 508265058Sgrehan sc->lintr = 0; 509265058Sgrehan } 510265058Sgrehan 511256056Sgrehan for (i = 0; i < sc->ports; i++) { 512256056Sgrehan sc->port[i].ie = 0; 513256056Sgrehan sc->port[i].is = 0; 514282345Smav sc->port[i].cmd = (AHCI_P_CMD_SUD | AHCI_P_CMD_POD); 515282345Smav if (sc->port[i].bctx) 516282345Smav sc->port[i].cmd |= AHCI_P_CMD_CPS; 517279965Smav sc->port[i].sctl = 0; 518256056Sgrehan ahci_port_reset(&sc->port[i]); 519256056Sgrehan } 520256056Sgrehan} 521256056Sgrehan 522256056Sgrehanstatic void 523256056Sgrehanata_string(uint8_t *dest, const char *src, int len) 524256056Sgrehan{ 525256056Sgrehan int i; 526256056Sgrehan 527256056Sgrehan for (i = 0; i < len; i++) { 528256056Sgrehan if (*src) 529256056Sgrehan dest[i ^ 1] = *src++; 530256056Sgrehan else 531256056Sgrehan dest[i ^ 1] = ' '; 532256056Sgrehan } 533256056Sgrehan} 534256056Sgrehan 535256056Sgrehanstatic void 536256056Sgrehanatapi_string(uint8_t *dest, const char *src, int len) 537256056Sgrehan{ 538256056Sgrehan int i; 539256056Sgrehan 540256056Sgrehan for (i = 0; i < len; i++) { 541256056Sgrehan if (*src) 542256056Sgrehan dest[i] = *src++; 543256056Sgrehan else 544256056Sgrehan dest[i] = ' '; 545256056Sgrehan } 546256056Sgrehan} 547256056Sgrehan 548281666Smav/* 549281666Smav * Build up the iovec based on the PRDT, 'done' and 'len'. 550281666Smav */ 551256056Sgrehanstatic void 552281666Smavahci_build_iov(struct ahci_port *p, struct ahci_ioreq *aior, 553281666Smav struct ahci_prdt_entry *prdt, uint16_t prdtl) 554256056Sgrehan{ 555281666Smav struct blockif_req *breq = &aior->io_req; 556281666Smav int i, j, skip, todo, left, extra; 557281666Smav uint32_t dbcsz; 558281666Smav 559281666Smav /* Copy part of PRDT between 'done' and 'len' bytes into the iov. */ 560281666Smav skip = aior->done; 561281666Smav left = aior->len - aior->done; 562281666Smav todo = 0; 563281666Smav for (i = 0, j = 0; i < prdtl && j < BLOCKIF_IOV_MAX && left > 0; 564281666Smav i++, prdt++) { 565281666Smav dbcsz = (prdt->dbc & DBCMASK) + 1; 566281666Smav /* Skip already done part of the PRDT */ 567281666Smav if (dbcsz <= skip) { 568281666Smav skip -= dbcsz; 569281666Smav continue; 570281666Smav } 571281666Smav dbcsz -= skip; 572281666Smav if (dbcsz > left) 573281666Smav dbcsz = left; 574281666Smav breq->br_iov[j].iov_base = paddr_guest2host(ahci_ctx(p->pr_sc), 575281666Smav prdt->dba + skip, dbcsz); 576281666Smav breq->br_iov[j].iov_len = dbcsz; 577281666Smav todo += dbcsz; 578281666Smav left -= dbcsz; 579281666Smav skip = 0; 580281666Smav j++; 581281666Smav } 582281666Smav 583281666Smav /* If we got limited by IOV length, round I/O down to sector size. */ 584281666Smav if (j == BLOCKIF_IOV_MAX) { 585281666Smav extra = todo % blockif_sectsz(p->bctx); 586281666Smav todo -= extra; 587281666Smav assert(todo > 0); 588281666Smav while (extra > 0) { 589281666Smav if (breq->br_iov[j - 1].iov_len > extra) { 590281666Smav breq->br_iov[j - 1].iov_len -= extra; 591281666Smav break; 592281666Smav } 593281666Smav extra -= breq->br_iov[j - 1].iov_len; 594281666Smav j--; 595281666Smav } 596281666Smav } 597281666Smav 598281666Smav breq->br_iovcnt = j; 599281700Smav breq->br_resid = todo; 600281666Smav aior->done += todo; 601281666Smav aior->more = (aior->done < aior->len && i < prdtl); 602281666Smav} 603281666Smav 604281666Smavstatic void 605281666Smavahci_handle_rw(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done) 606281666Smav{ 607256056Sgrehan struct ahci_ioreq *aior; 608256056Sgrehan struct blockif_req *breq; 609256056Sgrehan struct ahci_prdt_entry *prdt; 610256056Sgrehan struct ahci_cmd_hdr *hdr; 611256056Sgrehan uint64_t lba; 612256056Sgrehan uint32_t len; 613282364Smav int err, first, ncq, readop; 614256056Sgrehan 615256056Sgrehan prdt = (struct ahci_prdt_entry *)(cfis + 0x80); 616256164Sdim hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 617256056Sgrehan ncq = 0; 618256056Sgrehan readop = 1; 619282364Smav first = (done == 0); 620256056Sgrehan 621279960Smav if (cfis[2] == ATA_WRITE || cfis[2] == ATA_WRITE48 || 622279960Smav cfis[2] == ATA_WRITE_MUL || cfis[2] == ATA_WRITE_MUL48 || 623279960Smav cfis[2] == ATA_WRITE_DMA || cfis[2] == ATA_WRITE_DMA48 || 624279960Smav cfis[2] == ATA_WRITE_FPDMA_QUEUED) 625256056Sgrehan readop = 0; 626256056Sgrehan 627256056Sgrehan if (cfis[2] == ATA_WRITE_FPDMA_QUEUED || 628279960Smav cfis[2] == ATA_READ_FPDMA_QUEUED) { 629256056Sgrehan lba = ((uint64_t)cfis[10] << 40) | 630256056Sgrehan ((uint64_t)cfis[9] << 32) | 631256056Sgrehan ((uint64_t)cfis[8] << 24) | 632256056Sgrehan ((uint64_t)cfis[6] << 16) | 633256056Sgrehan ((uint64_t)cfis[5] << 8) | 634256056Sgrehan cfis[4]; 635256056Sgrehan len = cfis[11] << 8 | cfis[3]; 636256056Sgrehan if (!len) 637256056Sgrehan len = 65536; 638256056Sgrehan ncq = 1; 639279960Smav } else if (cfis[2] == ATA_READ48 || cfis[2] == ATA_WRITE48 || 640279960Smav cfis[2] == ATA_READ_MUL48 || cfis[2] == ATA_WRITE_MUL48 || 641279960Smav cfis[2] == ATA_READ_DMA48 || cfis[2] == ATA_WRITE_DMA48) { 642256056Sgrehan lba = ((uint64_t)cfis[10] << 40) | 643256056Sgrehan ((uint64_t)cfis[9] << 32) | 644256056Sgrehan ((uint64_t)cfis[8] << 24) | 645256056Sgrehan ((uint64_t)cfis[6] << 16) | 646256056Sgrehan ((uint64_t)cfis[5] << 8) | 647256056Sgrehan cfis[4]; 648256056Sgrehan len = cfis[13] << 8 | cfis[12]; 649256056Sgrehan if (!len) 650256056Sgrehan len = 65536; 651256056Sgrehan } else { 652256056Sgrehan lba = ((cfis[7] & 0xf) << 24) | (cfis[6] << 16) | 653256056Sgrehan (cfis[5] << 8) | cfis[4]; 654256056Sgrehan len = cfis[12]; 655256056Sgrehan if (!len) 656256056Sgrehan len = 256; 657256056Sgrehan } 658256056Sgrehan lba *= blockif_sectsz(p->bctx); 659256056Sgrehan len *= blockif_sectsz(p->bctx); 660256056Sgrehan 661281666Smav /* Pull request off free list */ 662256056Sgrehan aior = STAILQ_FIRST(&p->iofhd); 663256056Sgrehan assert(aior != NULL); 664273212Stychon STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); 665281666Smav 666256056Sgrehan aior->cfis = cfis; 667256056Sgrehan aior->slot = slot; 668256056Sgrehan aior->len = len; 669256056Sgrehan aior->done = done; 670256056Sgrehan breq = &aior->io_req; 671256056Sgrehan breq->br_offset = lba + done; 672281666Smav ahci_build_iov(p, aior, prdt, hdr->prdtl); 673256056Sgrehan 674281666Smav /* Mark this command in-flight. */ 675273212Stychon p->pending |= 1 << slot; 676273212Stychon 677281666Smav /* Stuff request onto busy list. */ 678273212Stychon TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); 679273212Stychon 680282364Smav if (ncq && first) 681282364Smav ahci_write_fis_d2h_ncq(p, slot); 682282364Smav 683256056Sgrehan if (readop) 684256056Sgrehan err = blockif_read(p->bctx, breq); 685256056Sgrehan else 686256056Sgrehan err = blockif_write(p->bctx, breq); 687256056Sgrehan assert(err == 0); 688256056Sgrehan} 689256056Sgrehan 690256056Sgrehanstatic void 691256056Sgrehanahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis) 692256056Sgrehan{ 693256056Sgrehan struct ahci_ioreq *aior; 694256056Sgrehan struct blockif_req *breq; 695256056Sgrehan int err; 696256056Sgrehan 697256056Sgrehan /* 698256056Sgrehan * Pull request off free list 699256056Sgrehan */ 700256056Sgrehan aior = STAILQ_FIRST(&p->iofhd); 701256056Sgrehan assert(aior != NULL); 702273212Stychon STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); 703256056Sgrehan aior->cfis = cfis; 704256056Sgrehan aior->slot = slot; 705256056Sgrehan aior->len = 0; 706261000Stychon aior->done = 0; 707281666Smav aior->more = 0; 708256056Sgrehan breq = &aior->io_req; 709256056Sgrehan 710273212Stychon /* 711273212Stychon * Mark this command in-flight. 712273212Stychon */ 713273212Stychon p->pending |= 1 << slot; 714273212Stychon 715273212Stychon /* 716273212Stychon * Stuff request onto busy list 717273212Stychon */ 718273212Stychon TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); 719273212Stychon 720256056Sgrehan err = blockif_flush(p->bctx, breq); 721256056Sgrehan assert(err == 0); 722256056Sgrehan} 723256056Sgrehan 724256056Sgrehanstatic inline void 725279957Smavread_prdt(struct ahci_port *p, int slot, uint8_t *cfis, 726279957Smav void *buf, int size) 727279957Smav{ 728279957Smav struct ahci_cmd_hdr *hdr; 729279957Smav struct ahci_prdt_entry *prdt; 730279957Smav void *to; 731279957Smav int i, len; 732279957Smav 733279957Smav hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 734279957Smav len = size; 735279957Smav to = buf; 736279957Smav prdt = (struct ahci_prdt_entry *)(cfis + 0x80); 737279957Smav for (i = 0; i < hdr->prdtl && len; i++) { 738279957Smav uint8_t *ptr; 739279957Smav uint32_t dbcsz; 740279957Smav int sublen; 741279957Smav 742279957Smav dbcsz = (prdt->dbc & DBCMASK) + 1; 743279957Smav ptr = paddr_guest2host(ahci_ctx(p->pr_sc), prdt->dba, dbcsz); 744298454Saraujo sublen = MIN(len, dbcsz); 745279957Smav memcpy(to, ptr, sublen); 746279957Smav len -= sublen; 747279957Smav to += sublen; 748279957Smav prdt++; 749279957Smav } 750279957Smav} 751279957Smav 752279957Smavstatic void 753279957Smavahci_handle_dsm_trim(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done) 754279957Smav{ 755279957Smav struct ahci_ioreq *aior; 756279957Smav struct blockif_req *breq; 757279957Smav uint8_t *entry; 758279957Smav uint64_t elba; 759279957Smav uint32_t len, elen; 760282364Smav int err, first, ncq; 761279957Smav uint8_t buf[512]; 762279957Smav 763282364Smav first = (done == 0); 764279976Smav if (cfis[2] == ATA_DATA_SET_MANAGEMENT) { 765279976Smav len = (uint16_t)cfis[13] << 8 | cfis[12]; 766279976Smav len *= 512; 767282364Smav ncq = 0; 768279976Smav } else { /* ATA_SEND_FPDMA_QUEUED */ 769279976Smav len = (uint16_t)cfis[11] << 8 | cfis[3]; 770279976Smav len *= 512; 771282364Smav ncq = 1; 772279976Smav } 773279957Smav read_prdt(p, slot, cfis, buf, sizeof(buf)); 774279957Smav 775279957Smavnext: 776279957Smav entry = &buf[done]; 777279957Smav elba = ((uint64_t)entry[5] << 40) | 778279957Smav ((uint64_t)entry[4] << 32) | 779279957Smav ((uint64_t)entry[3] << 24) | 780279957Smav ((uint64_t)entry[2] << 16) | 781279957Smav ((uint64_t)entry[1] << 8) | 782279957Smav entry[0]; 783279957Smav elen = (uint16_t)entry[7] << 8 | entry[6]; 784279957Smav done += 8; 785279957Smav if (elen == 0) { 786279957Smav if (done >= len) { 787303138Smav if (ncq) { 788303138Smav if (first) 789303138Smav ahci_write_fis_d2h_ncq(p, slot); 790303138Smav ahci_write_fis_sdb(p, slot, cfis, 791303138Smav ATA_S_READY | ATA_S_DSC); 792303138Smav } else { 793303138Smav ahci_write_fis_d2h(p, slot, cfis, 794303138Smav ATA_S_READY | ATA_S_DSC); 795303138Smav } 796279957Smav p->pending &= ~(1 << slot); 797279957Smav ahci_check_stopped(p); 798282429Smav if (!first) 799282429Smav ahci_handle_port(p); 800279957Smav return; 801279957Smav } 802279957Smav goto next; 803279957Smav } 804279957Smav 805279957Smav /* 806279957Smav * Pull request off free list 807279957Smav */ 808279957Smav aior = STAILQ_FIRST(&p->iofhd); 809279957Smav assert(aior != NULL); 810279957Smav STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); 811279957Smav aior->cfis = cfis; 812279957Smav aior->slot = slot; 813279957Smav aior->len = len; 814279957Smav aior->done = done; 815281666Smav aior->more = (len != done); 816279957Smav 817279957Smav breq = &aior->io_req; 818279957Smav breq->br_offset = elba * blockif_sectsz(p->bctx); 819281700Smav breq->br_resid = elen * blockif_sectsz(p->bctx); 820279957Smav 821279957Smav /* 822279957Smav * Mark this command in-flight. 823279957Smav */ 824279957Smav p->pending |= 1 << slot; 825279957Smav 826279957Smav /* 827279957Smav * Stuff request onto busy list 828279957Smav */ 829279957Smav TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); 830279957Smav 831282364Smav if (ncq && first) 832282364Smav ahci_write_fis_d2h_ncq(p, slot); 833282364Smav 834279957Smav err = blockif_delete(p->bctx, breq); 835279957Smav assert(err == 0); 836279957Smav} 837279957Smav 838279957Smavstatic inline void 839256056Sgrehanwrite_prdt(struct ahci_port *p, int slot, uint8_t *cfis, 840256056Sgrehan void *buf, int size) 841256056Sgrehan{ 842256056Sgrehan struct ahci_cmd_hdr *hdr; 843256056Sgrehan struct ahci_prdt_entry *prdt; 844256056Sgrehan void *from; 845256056Sgrehan int i, len; 846256056Sgrehan 847256164Sdim hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 848256056Sgrehan len = size; 849256056Sgrehan from = buf; 850256056Sgrehan prdt = (struct ahci_prdt_entry *)(cfis + 0x80); 851256056Sgrehan for (i = 0; i < hdr->prdtl && len; i++) { 852258614Sgrehan uint8_t *ptr; 853258614Sgrehan uint32_t dbcsz; 854264302Stychon int sublen; 855258614Sgrehan 856258614Sgrehan dbcsz = (prdt->dbc & DBCMASK) + 1; 857258614Sgrehan ptr = paddr_guest2host(ahci_ctx(p->pr_sc), prdt->dba, dbcsz); 858298454Saraujo sublen = MIN(len, dbcsz); 859264302Stychon memcpy(ptr, from, sublen); 860264302Stychon len -= sublen; 861264302Stychon from += sublen; 862256056Sgrehan prdt++; 863256056Sgrehan } 864256056Sgrehan hdr->prdbc = size - len; 865256056Sgrehan} 866256056Sgrehan 867256056Sgrehanstatic void 868279987Smavahci_checksum(uint8_t *buf, int size) 869279987Smav{ 870279987Smav int i; 871279987Smav uint8_t sum = 0; 872279987Smav 873279987Smav for (i = 0; i < size - 1; i++) 874279987Smav sum += buf[i]; 875279987Smav buf[size - 1] = 0x100 - sum; 876279987Smav} 877279987Smav 878279987Smavstatic void 879279975Smavahci_handle_read_log(struct ahci_port *p, int slot, uint8_t *cfis) 880279975Smav{ 881279975Smav struct ahci_cmd_hdr *hdr; 882279975Smav uint8_t buf[512]; 883279975Smav 884279975Smav hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 885279975Smav if (p->atapi || hdr->prdtl == 0 || cfis[4] != 0x10 || 886279975Smav cfis[5] != 0 || cfis[9] != 0 || cfis[12] != 1 || cfis[13] != 0) { 887279975Smav ahci_write_fis_d2h(p, slot, cfis, 888279975Smav (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 889279975Smav return; 890279975Smav } 891279975Smav 892279975Smav memset(buf, 0, sizeof(buf)); 893279975Smav memcpy(buf, p->err_cfis, sizeof(p->err_cfis)); 894279987Smav ahci_checksum(buf, sizeof(buf)); 895279975Smav 896279975Smav if (cfis[2] == ATA_READ_LOG_EXT) 897279975Smav ahci_write_fis_piosetup(p); 898279975Smav write_prdt(p, slot, cfis, (void *)buf, sizeof(buf)); 899279975Smav ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY); 900279975Smav} 901279975Smav 902279975Smavstatic void 903256056Sgrehanhandle_identify(struct ahci_port *p, int slot, uint8_t *cfis) 904256056Sgrehan{ 905256056Sgrehan struct ahci_cmd_hdr *hdr; 906256056Sgrehan 907256164Sdim hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 908256056Sgrehan if (p->atapi || hdr->prdtl == 0) { 909279959Smav ahci_write_fis_d2h(p, slot, cfis, 910279959Smav (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 911256056Sgrehan } else { 912256056Sgrehan uint16_t buf[256]; 913256056Sgrehan uint64_t sectors; 914280017Smav int sectsz, psectsz, psectoff, candelete, ro; 915268639Sgrehan uint16_t cyl; 916268639Sgrehan uint8_t sech, heads; 917256056Sgrehan 918280017Smav ro = blockif_is_ro(p->bctx); 919279957Smav candelete = blockif_candelete(p->bctx); 920279654Smav sectsz = blockif_sectsz(p->bctx); 921279654Smav sectors = blockif_size(p->bctx) / sectsz; 922268639Sgrehan blockif_chs(p->bctx, &cyl, &heads, &sech); 923279654Smav blockif_psectsz(p->bctx, &psectsz, &psectoff); 924256056Sgrehan memset(buf, 0, sizeof(buf)); 925256056Sgrehan buf[0] = 0x0040; 926268639Sgrehan buf[1] = cyl; 927268639Sgrehan buf[3] = heads; 928268639Sgrehan buf[6] = sech; 929280040Smav ata_string((uint8_t *)(buf+10), p->ident, 20); 930256056Sgrehan ata_string((uint8_t *)(buf+23), "001", 8); 931256056Sgrehan ata_string((uint8_t *)(buf+27), "BHYVE SATA DISK", 40); 932256056Sgrehan buf[47] = (0x8000 | 128); 933288826Sgrehan buf[48] = 0; 934256056Sgrehan buf[49] = (1 << 8 | 1 << 9 | 1 << 11); 935256056Sgrehan buf[50] = (1 << 14); 936256056Sgrehan buf[53] = (1 << 1 | 1 << 2); 937256056Sgrehan if (p->mult_sectors) 938256056Sgrehan buf[59] = (0x100 | p->mult_sectors); 939279965Smav if (sectors <= 0x0fffffff) { 940279965Smav buf[60] = sectors; 941279965Smav buf[61] = (sectors >> 16); 942279965Smav } else { 943279965Smav buf[60] = 0xffff; 944279965Smav buf[61] = 0x0fff; 945279965Smav } 946256056Sgrehan buf[63] = 0x7; 947256056Sgrehan if (p->xfermode & ATA_WDMA0) 948256056Sgrehan buf[63] |= (1 << ((p->xfermode & 7) + 8)); 949256056Sgrehan buf[64] = 0x3; 950279965Smav buf[65] = 120; 951279965Smav buf[66] = 120; 952279965Smav buf[67] = 120; 953279965Smav buf[68] = 120; 954279957Smav buf[69] = 0; 955256056Sgrehan buf[75] = 31; 956279965Smav buf[76] = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3 | 957279965Smav ATA_SUPPORT_NCQ); 958279976Smav buf[77] = (ATA_SUPPORT_RCVSND_FPDMA_QUEUED | 959279976Smav (p->ssts & ATA_SS_SPD_MASK) >> 3); 960279979Smav buf[80] = 0x3f0; 961256056Sgrehan buf[81] = 0x28; 962279965Smav buf[82] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE| 963279965Smav ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP); 964279965Smav buf[83] = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE | 965279965Smav ATA_SUPPORT_FLUSHCACHE48 | 1 << 14); 966256056Sgrehan buf[84] = (1 << 14); 967279965Smav buf[85] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE| 968279965Smav ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP); 969279965Smav buf[86] = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE | 970279975Smav ATA_SUPPORT_FLUSHCACHE48 | 1 << 15); 971256056Sgrehan buf[87] = (1 << 14); 972256056Sgrehan buf[88] = 0x7f; 973256056Sgrehan if (p->xfermode & ATA_UDMA0) 974256056Sgrehan buf[88] |= (1 << ((p->xfermode & 7) + 8)); 975256056Sgrehan buf[100] = sectors; 976256056Sgrehan buf[101] = (sectors >> 16); 977256056Sgrehan buf[102] = (sectors >> 32); 978256056Sgrehan buf[103] = (sectors >> 48); 979280017Smav if (candelete && !ro) { 980279957Smav buf[69] |= ATA_SUPPORT_RZAT | ATA_SUPPORT_DRAT; 981279957Smav buf[105] = 1; 982279957Smav buf[169] = ATA_SUPPORT_DSM_TRIM; 983279957Smav } 984279654Smav buf[106] = 0x4000; 985279654Smav buf[209] = 0x4000; 986279654Smav if (psectsz > sectsz) { 987279654Smav buf[106] |= 0x2000; 988279654Smav buf[106] |= ffsl(psectsz / sectsz) - 1; 989279654Smav buf[209] |= (psectoff / sectsz); 990279654Smav } 991279654Smav if (sectsz > 512) { 992279654Smav buf[106] |= 0x1000; 993279654Smav buf[117] = sectsz / 2; 994279654Smav buf[118] = ((sectsz / 2) >> 16); 995279654Smav } 996279975Smav buf[119] = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14); 997279975Smav buf[120] = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14); 998279965Smav buf[222] = 0x1020; 999279987Smav buf[255] = 0x00a5; 1000279987Smav ahci_checksum((uint8_t *)buf, sizeof(buf)); 1001261785Stychon ahci_write_fis_piosetup(p); 1002256056Sgrehan write_prdt(p, slot, cfis, (void *)buf, sizeof(buf)); 1003279959Smav ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY); 1004256056Sgrehan } 1005256056Sgrehan} 1006256056Sgrehan 1007256056Sgrehanstatic void 1008256056Sgrehanhandle_atapi_identify(struct ahci_port *p, int slot, uint8_t *cfis) 1009256056Sgrehan{ 1010256056Sgrehan if (!p->atapi) { 1011279959Smav ahci_write_fis_d2h(p, slot, cfis, 1012279959Smav (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 1013256056Sgrehan } else { 1014256056Sgrehan uint16_t buf[256]; 1015256056Sgrehan 1016256056Sgrehan memset(buf, 0, sizeof(buf)); 1017256056Sgrehan buf[0] = (2 << 14 | 5 << 8 | 1 << 7 | 2 << 5); 1018280040Smav ata_string((uint8_t *)(buf+10), p->ident, 20); 1019256056Sgrehan ata_string((uint8_t *)(buf+23), "001", 8); 1020256056Sgrehan ata_string((uint8_t *)(buf+27), "BHYVE SATA DVD ROM", 40); 1021256056Sgrehan buf[49] = (1 << 9 | 1 << 8); 1022256056Sgrehan buf[50] = (1 << 14 | 1); 1023256056Sgrehan buf[53] = (1 << 2 | 1 << 1); 1024256056Sgrehan buf[62] = 0x3f; 1025256056Sgrehan buf[63] = 7; 1026279979Smav if (p->xfermode & ATA_WDMA0) 1027279979Smav buf[63] |= (1 << ((p->xfermode & 7) + 8)); 1028256056Sgrehan buf[64] = 3; 1029279979Smav buf[65] = 120; 1030279979Smav buf[66] = 120; 1031279979Smav buf[67] = 120; 1032279979Smav buf[68] = 120; 1033279979Smav buf[76] = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3); 1034279979Smav buf[77] = ((p->ssts & ATA_SS_SPD_MASK) >> 3); 1035256056Sgrehan buf[78] = (1 << 5); 1036279979Smav buf[80] = 0x3f0; 1037279979Smav buf[82] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET | 1038279979Smav ATA_SUPPORT_RESET | ATA_SUPPORT_NOP); 1039256056Sgrehan buf[83] = (1 << 14); 1040256056Sgrehan buf[84] = (1 << 14); 1041279979Smav buf[85] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET | 1042279979Smav ATA_SUPPORT_RESET | ATA_SUPPORT_NOP); 1043256056Sgrehan buf[87] = (1 << 14); 1044279979Smav buf[88] = 0x7f; 1045279979Smav if (p->xfermode & ATA_UDMA0) 1046279979Smav buf[88] |= (1 << ((p->xfermode & 7) + 8)); 1047279979Smav buf[222] = 0x1020; 1048279987Smav buf[255] = 0x00a5; 1049279987Smav ahci_checksum((uint8_t *)buf, sizeof(buf)); 1050261785Stychon ahci_write_fis_piosetup(p); 1051256056Sgrehan write_prdt(p, slot, cfis, (void *)buf, sizeof(buf)); 1052279959Smav ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY); 1053256056Sgrehan } 1054256056Sgrehan} 1055256056Sgrehan 1056256056Sgrehanstatic void 1057256056Sgrehanatapi_inquiry(struct ahci_port *p, int slot, uint8_t *cfis) 1058256056Sgrehan{ 1059256056Sgrehan uint8_t buf[36]; 1060256056Sgrehan uint8_t *acmd; 1061256056Sgrehan int len; 1062279979Smav uint32_t tfd; 1063256056Sgrehan 1064256056Sgrehan acmd = cfis + 0x40; 1065256056Sgrehan 1066279979Smav if (acmd[1] & 1) { /* VPD */ 1067279979Smav if (acmd[2] == 0) { /* Supported VPD pages */ 1068279979Smav buf[0] = 0x05; 1069279979Smav buf[1] = 0; 1070279979Smav buf[2] = 0; 1071279979Smav buf[3] = 1; 1072279979Smav buf[4] = 0; 1073279979Smav len = 4 + buf[3]; 1074279979Smav } else { 1075279979Smav p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1076279979Smav p->asc = 0x24; 1077279979Smav tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1078279979Smav cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1079279979Smav ahci_write_fis_d2h(p, slot, cfis, tfd); 1080279979Smav return; 1081279979Smav } 1082279979Smav } else { 1083279979Smav buf[0] = 0x05; 1084279979Smav buf[1] = 0x80; 1085279979Smav buf[2] = 0x00; 1086279979Smav buf[3] = 0x21; 1087279979Smav buf[4] = 31; 1088279979Smav buf[5] = 0; 1089279979Smav buf[6] = 0; 1090279979Smav buf[7] = 0; 1091279979Smav atapi_string(buf + 8, "BHYVE", 8); 1092279979Smav atapi_string(buf + 16, "BHYVE DVD-ROM", 16); 1093279979Smav atapi_string(buf + 32, "001", 4); 1094279979Smav len = sizeof(buf); 1095279979Smav } 1096256056Sgrehan 1097256056Sgrehan if (len > acmd[4]) 1098256056Sgrehan len = acmd[4]; 1099256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1100256056Sgrehan write_prdt(p, slot, cfis, buf, len); 1101256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1102256056Sgrehan} 1103256056Sgrehan 1104256056Sgrehanstatic void 1105256056Sgrehanatapi_read_capacity(struct ahci_port *p, int slot, uint8_t *cfis) 1106256056Sgrehan{ 1107256056Sgrehan uint8_t buf[8]; 1108256056Sgrehan uint64_t sectors; 1109256056Sgrehan 1110256926Sgrehan sectors = blockif_size(p->bctx) / 2048; 1111256056Sgrehan be32enc(buf, sectors - 1); 1112256056Sgrehan be32enc(buf + 4, 2048); 1113256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1114256056Sgrehan write_prdt(p, slot, cfis, buf, sizeof(buf)); 1115256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1116256056Sgrehan} 1117256056Sgrehan 1118256056Sgrehanstatic void 1119256056Sgrehanatapi_read_toc(struct ahci_port *p, int slot, uint8_t *cfis) 1120256056Sgrehan{ 1121256056Sgrehan uint8_t *acmd; 1122256056Sgrehan uint8_t format; 1123256056Sgrehan int len; 1124256056Sgrehan 1125256056Sgrehan acmd = cfis + 0x40; 1126256056Sgrehan 1127256056Sgrehan len = be16dec(acmd + 7); 1128256056Sgrehan format = acmd[9] >> 6; 1129256056Sgrehan switch (format) { 1130256056Sgrehan case 0: 1131256056Sgrehan { 1132256056Sgrehan int msf, size; 1133256056Sgrehan uint64_t sectors; 1134256056Sgrehan uint8_t start_track, buf[20], *bp; 1135256056Sgrehan 1136256056Sgrehan msf = (acmd[1] >> 1) & 1; 1137256056Sgrehan start_track = acmd[6]; 1138256056Sgrehan if (start_track > 1 && start_track != 0xaa) { 1139256056Sgrehan uint32_t tfd; 1140256056Sgrehan p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1141256056Sgrehan p->asc = 0x24; 1142256056Sgrehan tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1143256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1144256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, tfd); 1145256056Sgrehan return; 1146256056Sgrehan } 1147256056Sgrehan bp = buf + 2; 1148256056Sgrehan *bp++ = 1; 1149256056Sgrehan *bp++ = 1; 1150256056Sgrehan if (start_track <= 1) { 1151256056Sgrehan *bp++ = 0; 1152256056Sgrehan *bp++ = 0x14; 1153256056Sgrehan *bp++ = 1; 1154256056Sgrehan *bp++ = 0; 1155256056Sgrehan if (msf) { 1156256056Sgrehan *bp++ = 0; 1157256056Sgrehan lba_to_msf(bp, 0); 1158256056Sgrehan bp += 3; 1159256056Sgrehan } else { 1160256056Sgrehan *bp++ = 0; 1161256056Sgrehan *bp++ = 0; 1162256056Sgrehan *bp++ = 0; 1163256056Sgrehan *bp++ = 0; 1164256056Sgrehan } 1165256056Sgrehan } 1166256056Sgrehan *bp++ = 0; 1167256056Sgrehan *bp++ = 0x14; 1168256056Sgrehan *bp++ = 0xaa; 1169256056Sgrehan *bp++ = 0; 1170256056Sgrehan sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx); 1171256056Sgrehan sectors >>= 2; 1172256056Sgrehan if (msf) { 1173256056Sgrehan *bp++ = 0; 1174256056Sgrehan lba_to_msf(bp, sectors); 1175256056Sgrehan bp += 3; 1176256056Sgrehan } else { 1177256056Sgrehan be32enc(bp, sectors); 1178256056Sgrehan bp += 4; 1179256056Sgrehan } 1180256056Sgrehan size = bp - buf; 1181256056Sgrehan be16enc(buf, size - 2); 1182256056Sgrehan if (len > size) 1183256056Sgrehan len = size; 1184256056Sgrehan write_prdt(p, slot, cfis, buf, len); 1185256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1186256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1187256056Sgrehan break; 1188256056Sgrehan } 1189256056Sgrehan case 1: 1190256056Sgrehan { 1191256056Sgrehan uint8_t buf[12]; 1192256056Sgrehan 1193256056Sgrehan memset(buf, 0, sizeof(buf)); 1194256056Sgrehan buf[1] = 0xa; 1195256056Sgrehan buf[2] = 0x1; 1196256056Sgrehan buf[3] = 0x1; 1197256056Sgrehan if (len > sizeof(buf)) 1198256056Sgrehan len = sizeof(buf); 1199256056Sgrehan write_prdt(p, slot, cfis, buf, len); 1200256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1201256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1202256056Sgrehan break; 1203256056Sgrehan } 1204256056Sgrehan case 2: 1205256056Sgrehan { 1206256056Sgrehan int msf, size; 1207256056Sgrehan uint64_t sectors; 1208294774Saraujo uint8_t *bp, buf[50]; 1209256056Sgrehan 1210256056Sgrehan msf = (acmd[1] >> 1) & 1; 1211256056Sgrehan bp = buf + 2; 1212256056Sgrehan *bp++ = 1; 1213256056Sgrehan *bp++ = 1; 1214256056Sgrehan 1215256056Sgrehan *bp++ = 1; 1216256056Sgrehan *bp++ = 0x14; 1217256056Sgrehan *bp++ = 0; 1218256056Sgrehan *bp++ = 0xa0; 1219256056Sgrehan *bp++ = 0; 1220256056Sgrehan *bp++ = 0; 1221256056Sgrehan *bp++ = 0; 1222256056Sgrehan *bp++ = 0; 1223256056Sgrehan *bp++ = 1; 1224256056Sgrehan *bp++ = 0; 1225256056Sgrehan *bp++ = 0; 1226256056Sgrehan 1227256056Sgrehan *bp++ = 1; 1228256056Sgrehan *bp++ = 0x14; 1229256056Sgrehan *bp++ = 0; 1230256056Sgrehan *bp++ = 0xa1; 1231256056Sgrehan *bp++ = 0; 1232256056Sgrehan *bp++ = 0; 1233256056Sgrehan *bp++ = 0; 1234256056Sgrehan *bp++ = 0; 1235256056Sgrehan *bp++ = 1; 1236256056Sgrehan *bp++ = 0; 1237256056Sgrehan *bp++ = 0; 1238256056Sgrehan 1239256056Sgrehan *bp++ = 1; 1240256056Sgrehan *bp++ = 0x14; 1241256056Sgrehan *bp++ = 0; 1242256056Sgrehan *bp++ = 0xa2; 1243256056Sgrehan *bp++ = 0; 1244256056Sgrehan *bp++ = 0; 1245256056Sgrehan *bp++ = 0; 1246256056Sgrehan sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx); 1247256056Sgrehan sectors >>= 2; 1248256056Sgrehan if (msf) { 1249256056Sgrehan *bp++ = 0; 1250256056Sgrehan lba_to_msf(bp, sectors); 1251256056Sgrehan bp += 3; 1252256056Sgrehan } else { 1253256056Sgrehan be32enc(bp, sectors); 1254256056Sgrehan bp += 4; 1255256056Sgrehan } 1256256056Sgrehan 1257256056Sgrehan *bp++ = 1; 1258256056Sgrehan *bp++ = 0x14; 1259256056Sgrehan *bp++ = 0; 1260256056Sgrehan *bp++ = 1; 1261256056Sgrehan *bp++ = 0; 1262256056Sgrehan *bp++ = 0; 1263256056Sgrehan *bp++ = 0; 1264256056Sgrehan if (msf) { 1265256056Sgrehan *bp++ = 0; 1266256056Sgrehan lba_to_msf(bp, 0); 1267256056Sgrehan bp += 3; 1268256056Sgrehan } else { 1269256056Sgrehan *bp++ = 0; 1270256056Sgrehan *bp++ = 0; 1271256056Sgrehan *bp++ = 0; 1272256056Sgrehan *bp++ = 0; 1273256056Sgrehan } 1274256056Sgrehan 1275256056Sgrehan size = bp - buf; 1276256056Sgrehan be16enc(buf, size - 2); 1277256056Sgrehan if (len > size) 1278256056Sgrehan len = size; 1279256056Sgrehan write_prdt(p, slot, cfis, buf, len); 1280256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1281256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1282256056Sgrehan break; 1283256056Sgrehan } 1284256056Sgrehan default: 1285256056Sgrehan { 1286256056Sgrehan uint32_t tfd; 1287256056Sgrehan 1288256056Sgrehan p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1289256056Sgrehan p->asc = 0x24; 1290256056Sgrehan tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1291256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1292256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, tfd); 1293256056Sgrehan break; 1294256056Sgrehan } 1295256056Sgrehan } 1296256056Sgrehan} 1297256056Sgrehan 1298256056Sgrehanstatic void 1299279979Smavatapi_report_luns(struct ahci_port *p, int slot, uint8_t *cfis) 1300279979Smav{ 1301279979Smav uint8_t buf[16]; 1302279979Smav 1303279979Smav memset(buf, 0, sizeof(buf)); 1304279979Smav buf[3] = 8; 1305279979Smav 1306279979Smav cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1307279979Smav write_prdt(p, slot, cfis, buf, sizeof(buf)); 1308279979Smav ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1309279979Smav} 1310279979Smav 1311279979Smavstatic void 1312281666Smavatapi_read(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done) 1313256056Sgrehan{ 1314256056Sgrehan struct ahci_ioreq *aior; 1315256056Sgrehan struct ahci_cmd_hdr *hdr; 1316256056Sgrehan struct ahci_prdt_entry *prdt; 1317256056Sgrehan struct blockif_req *breq; 1318256056Sgrehan uint8_t *acmd; 1319256056Sgrehan uint64_t lba; 1320256056Sgrehan uint32_t len; 1321281666Smav int err; 1322256056Sgrehan 1323256056Sgrehan acmd = cfis + 0x40; 1324256164Sdim hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 1325256056Sgrehan prdt = (struct ahci_prdt_entry *)(cfis + 0x80); 1326256056Sgrehan 1327256056Sgrehan lba = be32dec(acmd + 2); 1328256056Sgrehan if (acmd[0] == READ_10) 1329256056Sgrehan len = be16dec(acmd + 7); 1330256056Sgrehan else 1331256056Sgrehan len = be32dec(acmd + 6); 1332256056Sgrehan if (len == 0) { 1333256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1334256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1335256056Sgrehan } 1336256056Sgrehan lba *= 2048; 1337256056Sgrehan len *= 2048; 1338256056Sgrehan 1339256056Sgrehan /* 1340256056Sgrehan * Pull request off free list 1341256056Sgrehan */ 1342256056Sgrehan aior = STAILQ_FIRST(&p->iofhd); 1343256056Sgrehan assert(aior != NULL); 1344273212Stychon STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); 1345256056Sgrehan aior->cfis = cfis; 1346256056Sgrehan aior->slot = slot; 1347256056Sgrehan aior->len = len; 1348256056Sgrehan aior->done = done; 1349256056Sgrehan breq = &aior->io_req; 1350256056Sgrehan breq->br_offset = lba + done; 1351281666Smav ahci_build_iov(p, aior, prdt, hdr->prdtl); 1352256056Sgrehan 1353281666Smav /* Mark this command in-flight. */ 1354273212Stychon p->pending |= 1 << slot; 1355273212Stychon 1356281666Smav /* Stuff request onto busy list. */ 1357273212Stychon TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); 1358273212Stychon 1359256056Sgrehan err = blockif_read(p->bctx, breq); 1360256056Sgrehan assert(err == 0); 1361256056Sgrehan} 1362256056Sgrehan 1363256056Sgrehanstatic void 1364256056Sgrehanatapi_request_sense(struct ahci_port *p, int slot, uint8_t *cfis) 1365256056Sgrehan{ 1366256056Sgrehan uint8_t buf[64]; 1367256056Sgrehan uint8_t *acmd; 1368256056Sgrehan int len; 1369256056Sgrehan 1370256056Sgrehan acmd = cfis + 0x40; 1371256056Sgrehan len = acmd[4]; 1372256056Sgrehan if (len > sizeof(buf)) 1373256056Sgrehan len = sizeof(buf); 1374256056Sgrehan memset(buf, 0, len); 1375256056Sgrehan buf[0] = 0x70 | (1 << 7); 1376256056Sgrehan buf[2] = p->sense_key; 1377256056Sgrehan buf[7] = 10; 1378256056Sgrehan buf[12] = p->asc; 1379256056Sgrehan write_prdt(p, slot, cfis, buf, len); 1380256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1381256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1382256056Sgrehan} 1383256056Sgrehan 1384256056Sgrehanstatic void 1385256056Sgrehanatapi_start_stop_unit(struct ahci_port *p, int slot, uint8_t *cfis) 1386256056Sgrehan{ 1387256056Sgrehan uint8_t *acmd = cfis + 0x40; 1388256056Sgrehan uint32_t tfd; 1389256056Sgrehan 1390256056Sgrehan switch (acmd[4] & 3) { 1391256056Sgrehan case 0: 1392256056Sgrehan case 1: 1393256056Sgrehan case 3: 1394256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1395256056Sgrehan tfd = ATA_S_READY | ATA_S_DSC; 1396256056Sgrehan break; 1397256056Sgrehan case 2: 1398256056Sgrehan /* TODO eject media */ 1399256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1400256056Sgrehan p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1401256056Sgrehan p->asc = 0x53; 1402256056Sgrehan tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1403256056Sgrehan break; 1404256056Sgrehan } 1405256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, tfd); 1406256056Sgrehan} 1407256056Sgrehan 1408256056Sgrehanstatic void 1409256056Sgrehanatapi_mode_sense(struct ahci_port *p, int slot, uint8_t *cfis) 1410256056Sgrehan{ 1411256056Sgrehan uint8_t *acmd; 1412256056Sgrehan uint32_t tfd; 1413256056Sgrehan uint8_t pc, code; 1414256056Sgrehan int len; 1415256056Sgrehan 1416256056Sgrehan acmd = cfis + 0x40; 1417256056Sgrehan len = be16dec(acmd + 7); 1418256056Sgrehan pc = acmd[2] >> 6; 1419256056Sgrehan code = acmd[2] & 0x3f; 1420256056Sgrehan 1421256056Sgrehan switch (pc) { 1422256056Sgrehan case 0: 1423256056Sgrehan switch (code) { 1424256056Sgrehan case MODEPAGE_RW_ERROR_RECOVERY: 1425256056Sgrehan { 1426256056Sgrehan uint8_t buf[16]; 1427256056Sgrehan 1428256056Sgrehan if (len > sizeof(buf)) 1429256056Sgrehan len = sizeof(buf); 1430256056Sgrehan 1431256056Sgrehan memset(buf, 0, sizeof(buf)); 1432256056Sgrehan be16enc(buf, 16 - 2); 1433256056Sgrehan buf[2] = 0x70; 1434256056Sgrehan buf[8] = 0x01; 1435256056Sgrehan buf[9] = 16 - 10; 1436256056Sgrehan buf[11] = 0x05; 1437256056Sgrehan write_prdt(p, slot, cfis, buf, len); 1438256056Sgrehan tfd = ATA_S_READY | ATA_S_DSC; 1439256056Sgrehan break; 1440256056Sgrehan } 1441256056Sgrehan case MODEPAGE_CD_CAPABILITIES: 1442256056Sgrehan { 1443256056Sgrehan uint8_t buf[30]; 1444256056Sgrehan 1445256056Sgrehan if (len > sizeof(buf)) 1446256056Sgrehan len = sizeof(buf); 1447256056Sgrehan 1448256056Sgrehan memset(buf, 0, sizeof(buf)); 1449256056Sgrehan be16enc(buf, 30 - 2); 1450256056Sgrehan buf[2] = 0x70; 1451256056Sgrehan buf[8] = 0x2A; 1452256056Sgrehan buf[9] = 30 - 10; 1453256056Sgrehan buf[10] = 0x08; 1454256056Sgrehan buf[12] = 0x71; 1455256056Sgrehan be16enc(&buf[18], 2); 1456256056Sgrehan be16enc(&buf[20], 512); 1457256056Sgrehan write_prdt(p, slot, cfis, buf, len); 1458256056Sgrehan tfd = ATA_S_READY | ATA_S_DSC; 1459256056Sgrehan break; 1460256056Sgrehan } 1461256056Sgrehan default: 1462256056Sgrehan goto error; 1463256056Sgrehan break; 1464256056Sgrehan } 1465256056Sgrehan break; 1466256056Sgrehan case 3: 1467256056Sgrehan p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1468256056Sgrehan p->asc = 0x39; 1469256056Sgrehan tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1470256056Sgrehan break; 1471256056Sgrehanerror: 1472256056Sgrehan case 1: 1473256056Sgrehan case 2: 1474256056Sgrehan p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1475256056Sgrehan p->asc = 0x24; 1476256056Sgrehan tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1477256056Sgrehan break; 1478256056Sgrehan } 1479256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1480256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, tfd); 1481256056Sgrehan} 1482256056Sgrehan 1483256056Sgrehanstatic void 1484256056Sgrehanatapi_get_event_status_notification(struct ahci_port *p, int slot, 1485256056Sgrehan uint8_t *cfis) 1486256056Sgrehan{ 1487256056Sgrehan uint8_t *acmd; 1488256056Sgrehan uint32_t tfd; 1489256056Sgrehan 1490256056Sgrehan acmd = cfis + 0x40; 1491256056Sgrehan 1492256056Sgrehan /* we don't support asynchronous operation */ 1493256056Sgrehan if (!(acmd[1] & 1)) { 1494256056Sgrehan p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1495256056Sgrehan p->asc = 0x24; 1496256056Sgrehan tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1497256056Sgrehan } else { 1498256056Sgrehan uint8_t buf[8]; 1499256056Sgrehan int len; 1500256056Sgrehan 1501256056Sgrehan len = be16dec(acmd + 7); 1502256056Sgrehan if (len > sizeof(buf)) 1503256056Sgrehan len = sizeof(buf); 1504256056Sgrehan 1505256056Sgrehan memset(buf, 0, sizeof(buf)); 1506256056Sgrehan be16enc(buf, 8 - 2); 1507256056Sgrehan buf[2] = 0x04; 1508256056Sgrehan buf[3] = 0x10; 1509256056Sgrehan buf[5] = 0x02; 1510256056Sgrehan write_prdt(p, slot, cfis, buf, len); 1511256056Sgrehan tfd = ATA_S_READY | ATA_S_DSC; 1512256056Sgrehan } 1513256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1514256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, tfd); 1515256056Sgrehan} 1516256056Sgrehan 1517256056Sgrehanstatic void 1518256056Sgrehanhandle_packet_cmd(struct ahci_port *p, int slot, uint8_t *cfis) 1519256056Sgrehan{ 1520256056Sgrehan uint8_t *acmd; 1521256056Sgrehan 1522256056Sgrehan acmd = cfis + 0x40; 1523256056Sgrehan 1524256056Sgrehan#ifdef AHCI_DEBUG 1525256056Sgrehan { 1526256056Sgrehan int i; 1527256056Sgrehan DPRINTF("ACMD:"); 1528256056Sgrehan for (i = 0; i < 16; i++) 1529256056Sgrehan DPRINTF("%02x ", acmd[i]); 1530256056Sgrehan DPRINTF("\n"); 1531256056Sgrehan } 1532256056Sgrehan#endif 1533256056Sgrehan 1534256056Sgrehan switch (acmd[0]) { 1535256056Sgrehan case TEST_UNIT_READY: 1536256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1537256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1538256056Sgrehan break; 1539256056Sgrehan case INQUIRY: 1540256056Sgrehan atapi_inquiry(p, slot, cfis); 1541256056Sgrehan break; 1542256056Sgrehan case READ_CAPACITY: 1543256056Sgrehan atapi_read_capacity(p, slot, cfis); 1544256056Sgrehan break; 1545256056Sgrehan case PREVENT_ALLOW: 1546256056Sgrehan /* TODO */ 1547256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1548256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1549256056Sgrehan break; 1550256056Sgrehan case READ_TOC: 1551256056Sgrehan atapi_read_toc(p, slot, cfis); 1552256056Sgrehan break; 1553279979Smav case REPORT_LUNS: 1554279979Smav atapi_report_luns(p, slot, cfis); 1555279979Smav break; 1556256056Sgrehan case READ_10: 1557256056Sgrehan case READ_12: 1558281666Smav atapi_read(p, slot, cfis, 0); 1559256056Sgrehan break; 1560256056Sgrehan case REQUEST_SENSE: 1561256056Sgrehan atapi_request_sense(p, slot, cfis); 1562256056Sgrehan break; 1563256056Sgrehan case START_STOP_UNIT: 1564256056Sgrehan atapi_start_stop_unit(p, slot, cfis); 1565256056Sgrehan break; 1566256056Sgrehan case MODE_SENSE_10: 1567256056Sgrehan atapi_mode_sense(p, slot, cfis); 1568256056Sgrehan break; 1569256056Sgrehan case GET_EVENT_STATUS_NOTIFICATION: 1570256056Sgrehan atapi_get_event_status_notification(p, slot, cfis); 1571256056Sgrehan break; 1572256056Sgrehan default: 1573256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1574256056Sgrehan p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1575256056Sgrehan p->asc = 0x20; 1576256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, (p->sense_key << 12) | 1577256056Sgrehan ATA_S_READY | ATA_S_ERROR); 1578256056Sgrehan break; 1579256056Sgrehan } 1580256056Sgrehan} 1581256056Sgrehan 1582256056Sgrehanstatic void 1583256056Sgrehanahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis) 1584256056Sgrehan{ 1585256056Sgrehan 1586282364Smav p->tfd |= ATA_S_BUSY; 1587256056Sgrehan switch (cfis[2]) { 1588256056Sgrehan case ATA_ATA_IDENTIFY: 1589256056Sgrehan handle_identify(p, slot, cfis); 1590256056Sgrehan break; 1591256056Sgrehan case ATA_SETFEATURES: 1592256056Sgrehan { 1593256056Sgrehan switch (cfis[3]) { 1594263238Stychon case ATA_SF_ENAB_SATA_SF: 1595263238Stychon switch (cfis[12]) { 1596263238Stychon case ATA_SATA_SF_AN: 1597263238Stychon p->tfd = ATA_S_DSC | ATA_S_READY; 1598263238Stychon break; 1599263238Stychon default: 1600263238Stychon p->tfd = ATA_S_ERROR | ATA_S_READY; 1601263238Stychon p->tfd |= (ATA_ERROR_ABORT << 8); 1602263238Stychon break; 1603263238Stychon } 1604263238Stychon break; 1605256056Sgrehan case ATA_SF_ENAB_WCACHE: 1606256056Sgrehan case ATA_SF_DIS_WCACHE: 1607256056Sgrehan case ATA_SF_ENAB_RCACHE: 1608256056Sgrehan case ATA_SF_DIS_RCACHE: 1609256056Sgrehan p->tfd = ATA_S_DSC | ATA_S_READY; 1610256056Sgrehan break; 1611256056Sgrehan case ATA_SF_SETXFER: 1612256056Sgrehan { 1613256056Sgrehan switch (cfis[12] & 0xf8) { 1614256056Sgrehan case ATA_PIO: 1615256056Sgrehan case ATA_PIO0: 1616256056Sgrehan break; 1617256056Sgrehan case ATA_WDMA0: 1618256056Sgrehan case ATA_UDMA0: 1619256056Sgrehan p->xfermode = (cfis[12] & 0x7); 1620256056Sgrehan break; 1621256056Sgrehan } 1622256056Sgrehan p->tfd = ATA_S_DSC | ATA_S_READY; 1623256056Sgrehan break; 1624256056Sgrehan } 1625256056Sgrehan default: 1626256056Sgrehan p->tfd = ATA_S_ERROR | ATA_S_READY; 1627256056Sgrehan p->tfd |= (ATA_ERROR_ABORT << 8); 1628256056Sgrehan break; 1629256056Sgrehan } 1630261785Stychon ahci_write_fis_d2h(p, slot, cfis, p->tfd); 1631256056Sgrehan break; 1632256056Sgrehan } 1633256056Sgrehan case ATA_SET_MULTI: 1634256056Sgrehan if (cfis[12] != 0 && 1635256164Sdim (cfis[12] > 128 || (cfis[12] & (cfis[12] - 1)))) { 1636256056Sgrehan p->tfd = ATA_S_ERROR | ATA_S_READY; 1637256056Sgrehan p->tfd |= (ATA_ERROR_ABORT << 8); 1638256056Sgrehan } else { 1639256056Sgrehan p->mult_sectors = cfis[12]; 1640256056Sgrehan p->tfd = ATA_S_DSC | ATA_S_READY; 1641256056Sgrehan } 1642279959Smav ahci_write_fis_d2h(p, slot, cfis, p->tfd); 1643256056Sgrehan break; 1644279960Smav case ATA_READ: 1645279960Smav case ATA_WRITE: 1646279960Smav case ATA_READ48: 1647279960Smav case ATA_WRITE48: 1648279960Smav case ATA_READ_MUL: 1649279960Smav case ATA_WRITE_MUL: 1650279960Smav case ATA_READ_MUL48: 1651279960Smav case ATA_WRITE_MUL48: 1652256056Sgrehan case ATA_READ_DMA: 1653256056Sgrehan case ATA_WRITE_DMA: 1654256056Sgrehan case ATA_READ_DMA48: 1655256056Sgrehan case ATA_WRITE_DMA48: 1656256056Sgrehan case ATA_READ_FPDMA_QUEUED: 1657256056Sgrehan case ATA_WRITE_FPDMA_QUEUED: 1658281666Smav ahci_handle_rw(p, slot, cfis, 0); 1659256056Sgrehan break; 1660256056Sgrehan case ATA_FLUSHCACHE: 1661256056Sgrehan case ATA_FLUSHCACHE48: 1662256056Sgrehan ahci_handle_flush(p, slot, cfis); 1663256056Sgrehan break; 1664279957Smav case ATA_DATA_SET_MANAGEMENT: 1665279957Smav if (cfis[11] == 0 && cfis[3] == ATA_DSM_TRIM && 1666279957Smav cfis[13] == 0 && cfis[12] == 1) { 1667279957Smav ahci_handle_dsm_trim(p, slot, cfis, 0); 1668279957Smav break; 1669279957Smav } 1670279957Smav ahci_write_fis_d2h(p, slot, cfis, 1671279957Smav (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 1672279957Smav break; 1673279976Smav case ATA_SEND_FPDMA_QUEUED: 1674279976Smav if ((cfis[13] & 0x1f) == ATA_SFPDMA_DSM && 1675279976Smav cfis[17] == 0 && cfis[16] == ATA_DSM_TRIM && 1676303138Smav cfis[11] == 0 && cfis[3] == 1) { 1677279976Smav ahci_handle_dsm_trim(p, slot, cfis, 0); 1678279976Smav break; 1679279976Smav } 1680279976Smav ahci_write_fis_d2h(p, slot, cfis, 1681279976Smav (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 1682279976Smav break; 1683279975Smav case ATA_READ_LOG_EXT: 1684279975Smav case ATA_READ_LOG_DMA_EXT: 1685279975Smav ahci_handle_read_log(p, slot, cfis); 1686279975Smav break; 1687288826Sgrehan case ATA_SECURITY_FREEZE_LOCK: 1688288826Sgrehan case ATA_SMART_CMD: 1689279977Smav case ATA_NOP: 1690279977Smav ahci_write_fis_d2h(p, slot, cfis, 1691279977Smav (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 1692279977Smav break; 1693286838Sgrehan case ATA_CHECK_POWER_MODE: 1694286838Sgrehan cfis[12] = 0xff; /* always on */ 1695286838Sgrehan ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1696286838Sgrehan break; 1697256056Sgrehan case ATA_STANDBY_CMD: 1698256056Sgrehan case ATA_STANDBY_IMMEDIATE: 1699279977Smav case ATA_IDLE_CMD: 1700256056Sgrehan case ATA_IDLE_IMMEDIATE: 1701256056Sgrehan case ATA_SLEEP: 1702286838Sgrehan case ATA_READ_VERIFY: 1703286838Sgrehan case ATA_READ_VERIFY48: 1704256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); 1705256056Sgrehan break; 1706256056Sgrehan case ATA_ATAPI_IDENTIFY: 1707256056Sgrehan handle_atapi_identify(p, slot, cfis); 1708256056Sgrehan break; 1709256056Sgrehan case ATA_PACKET_CMD: 1710256056Sgrehan if (!p->atapi) { 1711279959Smav ahci_write_fis_d2h(p, slot, cfis, 1712279959Smav (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 1713256056Sgrehan } else 1714256056Sgrehan handle_packet_cmd(p, slot, cfis); 1715256056Sgrehan break; 1716256056Sgrehan default: 1717256056Sgrehan WPRINTF("Unsupported cmd:%02x\n", cfis[2]); 1718279959Smav ahci_write_fis_d2h(p, slot, cfis, 1719279959Smav (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); 1720256056Sgrehan break; 1721256056Sgrehan } 1722256056Sgrehan} 1723256056Sgrehan 1724256056Sgrehanstatic void 1725256056Sgrehanahci_handle_slot(struct ahci_port *p, int slot) 1726256056Sgrehan{ 1727256056Sgrehan struct ahci_cmd_hdr *hdr; 1728302363Sngie#ifdef AHCI_DEBUG 1729256056Sgrehan struct ahci_prdt_entry *prdt; 1730302363Sngie#endif 1731256056Sgrehan struct pci_ahci_softc *sc; 1732256056Sgrehan uint8_t *cfis; 1733302363Sngie#ifdef AHCI_DEBUG 1734256056Sgrehan int cfl; 1735302363Sngie#endif 1736256056Sgrehan 1737256056Sgrehan sc = p->pr_sc; 1738256164Sdim hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 1739302363Sngie#ifdef AHCI_DEBUG 1740256056Sgrehan cfl = (hdr->flags & 0x1f) * 4; 1741302363Sngie#endif 1742256056Sgrehan cfis = paddr_guest2host(ahci_ctx(sc), hdr->ctba, 1743256056Sgrehan 0x80 + hdr->prdtl * sizeof(struct ahci_prdt_entry)); 1744302363Sngie#ifdef AHCI_DEBUG 1745256056Sgrehan prdt = (struct ahci_prdt_entry *)(cfis + 0x80); 1746256056Sgrehan 1747256056Sgrehan DPRINTF("\ncfis:"); 1748256056Sgrehan for (i = 0; i < cfl; i++) { 1749256056Sgrehan if (i % 10 == 0) 1750256056Sgrehan DPRINTF("\n"); 1751256056Sgrehan DPRINTF("%02x ", cfis[i]); 1752256056Sgrehan } 1753256056Sgrehan DPRINTF("\n"); 1754256056Sgrehan 1755256056Sgrehan for (i = 0; i < hdr->prdtl; i++) { 1756256056Sgrehan DPRINTF("%d@%08"PRIx64"\n", prdt->dbc & 0x3fffff, prdt->dba); 1757256056Sgrehan prdt++; 1758256056Sgrehan } 1759256056Sgrehan#endif 1760256056Sgrehan 1761256056Sgrehan if (cfis[0] != FIS_TYPE_REGH2D) { 1762256056Sgrehan WPRINTF("Not a H2D FIS:%02x\n", cfis[0]); 1763256056Sgrehan return; 1764256056Sgrehan } 1765256056Sgrehan 1766256056Sgrehan if (cfis[1] & 0x80) { 1767256056Sgrehan ahci_handle_cmd(p, slot, cfis); 1768256056Sgrehan } else { 1769256056Sgrehan if (cfis[15] & (1 << 2)) 1770256056Sgrehan p->reset = 1; 1771256056Sgrehan else if (p->reset) { 1772256056Sgrehan p->reset = 0; 1773256056Sgrehan ahci_port_reset(p); 1774256056Sgrehan } 1775256056Sgrehan p->ci &= ~(1 << slot); 1776256056Sgrehan } 1777256056Sgrehan} 1778256056Sgrehan 1779256056Sgrehanstatic void 1780256056Sgrehanahci_handle_port(struct ahci_port *p) 1781256056Sgrehan{ 1782256056Sgrehan 1783256056Sgrehan if (!(p->cmd & AHCI_P_CMD_ST)) 1784256056Sgrehan return; 1785256056Sgrehan 1786263322Stychon /* 1787263322Stychon * Search for any new commands to issue ignoring those that 1788282429Smav * are already in-flight. Stop if device is busy or in error. 1789263322Stychon */ 1790282429Smav for (; (p->ci & ~p->pending) != 0; p->ccs = ((p->ccs + 1) & 31)) { 1791282524Smav if ((p->tfd & (ATA_S_BUSY | ATA_S_DRQ)) != 0) 1792282429Smav break; 1793282524Smav if (p->waitforclear) 1794282524Smav break; 1795282429Smav if ((p->ci & ~p->pending & (1 << p->ccs)) != 0) { 1796269317Stychon p->cmd &= ~AHCI_P_CMD_CCS_MASK; 1797282429Smav p->cmd |= p->ccs << AHCI_P_CMD_CCS_SHIFT; 1798282429Smav ahci_handle_slot(p, p->ccs); 1799269317Stychon } 1800256056Sgrehan } 1801256056Sgrehan} 1802256056Sgrehan 1803256056Sgrehan/* 1804256056Sgrehan * blockif callback routine - this runs in the context of the blockif 1805256056Sgrehan * i/o thread, so the mutex needs to be acquired. 1806256056Sgrehan */ 1807256056Sgrehanstatic void 1808256056Sgrehanata_ioreq_cb(struct blockif_req *br, int err) 1809256056Sgrehan{ 1810256056Sgrehan struct ahci_cmd_hdr *hdr; 1811256056Sgrehan struct ahci_ioreq *aior; 1812256056Sgrehan struct ahci_port *p; 1813256056Sgrehan struct pci_ahci_softc *sc; 1814256056Sgrehan uint32_t tfd; 1815256056Sgrehan uint8_t *cfis; 1816281666Smav int slot, ncq, dsm; 1817256056Sgrehan 1818256056Sgrehan DPRINTF("%s %d\n", __func__, err); 1819256056Sgrehan 1820280293Smav ncq = dsm = 0; 1821256056Sgrehan aior = br->br_param; 1822256056Sgrehan p = aior->io_pr; 1823256056Sgrehan cfis = aior->cfis; 1824256056Sgrehan slot = aior->slot; 1825256056Sgrehan sc = p->pr_sc; 1826256164Sdim hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE); 1827256056Sgrehan 1828256056Sgrehan if (cfis[2] == ATA_WRITE_FPDMA_QUEUED || 1829279976Smav cfis[2] == ATA_READ_FPDMA_QUEUED || 1830279976Smav cfis[2] == ATA_SEND_FPDMA_QUEUED) 1831256056Sgrehan ncq = 1; 1832279976Smav if (cfis[2] == ATA_DATA_SET_MANAGEMENT || 1833279976Smav (cfis[2] == ATA_SEND_FPDMA_QUEUED && 1834279976Smav (cfis[13] & 0x1f) == ATA_SFPDMA_DSM)) 1835279957Smav dsm = 1; 1836256056Sgrehan 1837256056Sgrehan pthread_mutex_lock(&sc->mtx); 1838256056Sgrehan 1839256056Sgrehan /* 1840273212Stychon * Delete the blockif request from the busy list 1841273212Stychon */ 1842273212Stychon TAILQ_REMOVE(&p->iobhd, aior, io_blist); 1843273212Stychon 1844273212Stychon /* 1845256056Sgrehan * Move the blockif request back to the free list 1846256056Sgrehan */ 1847273212Stychon STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist); 1848256056Sgrehan 1849279967Smav if (!err) 1850279967Smav hdr->prdbc = aior->done; 1851279967Smav 1852281666Smav if (!err && aior->more) { 1853281666Smav if (dsm) 1854279957Smav ahci_handle_dsm_trim(p, slot, cfis, aior->done); 1855281666Smav else 1856281666Smav ahci_handle_rw(p, slot, cfis, aior->done); 1857281666Smav goto out; 1858256056Sgrehan } 1859256056Sgrehan 1860281666Smav if (!err) 1861256056Sgrehan tfd = ATA_S_READY | ATA_S_DSC; 1862281666Smav else 1863256056Sgrehan tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR; 1864279975Smav if (ncq) 1865279975Smav ahci_write_fis_sdb(p, slot, cfis, tfd); 1866279975Smav else 1867256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, tfd); 1868256056Sgrehan 1869273212Stychon /* 1870273212Stychon * This command is now complete. 1871273212Stychon */ 1872273212Stychon p->pending &= ~(1 << slot); 1873273212Stychon 1874273212Stychon ahci_check_stopped(p); 1875282429Smav ahci_handle_port(p); 1876256056Sgrehanout: 1877256056Sgrehan pthread_mutex_unlock(&sc->mtx); 1878256056Sgrehan DPRINTF("%s exit\n", __func__); 1879256056Sgrehan} 1880256056Sgrehan 1881256056Sgrehanstatic void 1882256056Sgrehanatapi_ioreq_cb(struct blockif_req *br, int err) 1883256056Sgrehan{ 1884256056Sgrehan struct ahci_cmd_hdr *hdr; 1885256056Sgrehan struct ahci_ioreq *aior; 1886256056Sgrehan struct ahci_port *p; 1887256056Sgrehan struct pci_ahci_softc *sc; 1888256056Sgrehan uint8_t *cfis; 1889256056Sgrehan uint32_t tfd; 1890281666Smav int slot; 1891256056Sgrehan 1892256056Sgrehan DPRINTF("%s %d\n", __func__, err); 1893256056Sgrehan 1894256056Sgrehan aior = br->br_param; 1895256056Sgrehan p = aior->io_pr; 1896256056Sgrehan cfis = aior->cfis; 1897256056Sgrehan slot = aior->slot; 1898256056Sgrehan sc = p->pr_sc; 1899256164Sdim hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + aior->slot * AHCI_CL_SIZE); 1900256056Sgrehan 1901256056Sgrehan pthread_mutex_lock(&sc->mtx); 1902256056Sgrehan 1903256056Sgrehan /* 1904273212Stychon * Delete the blockif request from the busy list 1905273212Stychon */ 1906273212Stychon TAILQ_REMOVE(&p->iobhd, aior, io_blist); 1907273212Stychon 1908273212Stychon /* 1909256056Sgrehan * Move the blockif request back to the free list 1910256056Sgrehan */ 1911273212Stychon STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist); 1912256056Sgrehan 1913279967Smav if (!err) 1914279967Smav hdr->prdbc = aior->done; 1915279967Smav 1916281666Smav if (!err && aior->more) { 1917281666Smav atapi_read(p, slot, cfis, aior->done); 1918256056Sgrehan goto out; 1919256056Sgrehan } 1920256056Sgrehan 1921281666Smav if (!err) { 1922256056Sgrehan tfd = ATA_S_READY | ATA_S_DSC; 1923256056Sgrehan } else { 1924256056Sgrehan p->sense_key = ATA_SENSE_ILLEGAL_REQUEST; 1925256056Sgrehan p->asc = 0x21; 1926256056Sgrehan tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR; 1927256056Sgrehan } 1928256056Sgrehan cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; 1929256056Sgrehan ahci_write_fis_d2h(p, slot, cfis, tfd); 1930256056Sgrehan 1931273212Stychon /* 1932273212Stychon * This command is now complete. 1933273212Stychon */ 1934273212Stychon p->pending &= ~(1 << slot); 1935273212Stychon 1936273212Stychon ahci_check_stopped(p); 1937282429Smav ahci_handle_port(p); 1938256056Sgrehanout: 1939256056Sgrehan pthread_mutex_unlock(&sc->mtx); 1940256056Sgrehan DPRINTF("%s exit\n", __func__); 1941256056Sgrehan} 1942256056Sgrehan 1943256056Sgrehanstatic void 1944256056Sgrehanpci_ahci_ioreq_init(struct ahci_port *pr) 1945256056Sgrehan{ 1946256056Sgrehan struct ahci_ioreq *vr; 1947256056Sgrehan int i; 1948256056Sgrehan 1949256056Sgrehan pr->ioqsz = blockif_queuesz(pr->bctx); 1950256056Sgrehan pr->ioreq = calloc(pr->ioqsz, sizeof(struct ahci_ioreq)); 1951256056Sgrehan STAILQ_INIT(&pr->iofhd); 1952256056Sgrehan 1953256056Sgrehan /* 1954256056Sgrehan * Add all i/o request entries to the free queue 1955256056Sgrehan */ 1956256056Sgrehan for (i = 0; i < pr->ioqsz; i++) { 1957256056Sgrehan vr = &pr->ioreq[i]; 1958256056Sgrehan vr->io_pr = pr; 1959256056Sgrehan if (!pr->atapi) 1960256056Sgrehan vr->io_req.br_callback = ata_ioreq_cb; 1961256056Sgrehan else 1962256056Sgrehan vr->io_req.br_callback = atapi_ioreq_cb; 1963256056Sgrehan vr->io_req.br_param = vr; 1964273212Stychon STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_flist); 1965256056Sgrehan } 1966273212Stychon 1967273212Stychon TAILQ_INIT(&pr->iobhd); 1968256056Sgrehan} 1969256056Sgrehan 1970256056Sgrehanstatic void 1971256056Sgrehanpci_ahci_port_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value) 1972256056Sgrehan{ 1973256056Sgrehan int port = (offset - AHCI_OFFSET) / AHCI_STEP; 1974256056Sgrehan offset = (offset - AHCI_OFFSET) % AHCI_STEP; 1975256056Sgrehan struct ahci_port *p = &sc->port[port]; 1976256056Sgrehan 1977256056Sgrehan DPRINTF("pci_ahci_port %d: write offset 0x%"PRIx64" value 0x%"PRIx64"\n", 1978256056Sgrehan port, offset, value); 1979256056Sgrehan 1980256056Sgrehan switch (offset) { 1981256056Sgrehan case AHCI_P_CLB: 1982256056Sgrehan p->clb = value; 1983256056Sgrehan break; 1984256056Sgrehan case AHCI_P_CLBU: 1985256056Sgrehan p->clbu = value; 1986256056Sgrehan break; 1987256056Sgrehan case AHCI_P_FB: 1988256056Sgrehan p->fb = value; 1989256056Sgrehan break; 1990256056Sgrehan case AHCI_P_FBU: 1991256056Sgrehan p->fbu = value; 1992256056Sgrehan break; 1993256056Sgrehan case AHCI_P_IS: 1994256056Sgrehan p->is &= ~value; 1995256056Sgrehan break; 1996256056Sgrehan case AHCI_P_IE: 1997256056Sgrehan p->ie = value & 0xFDC000FF; 1998256056Sgrehan ahci_generate_intr(sc); 1999256056Sgrehan break; 2000256056Sgrehan case AHCI_P_CMD: 2001256056Sgrehan { 2002282345Smav p->cmd &= ~(AHCI_P_CMD_ST | AHCI_P_CMD_SUD | AHCI_P_CMD_POD | 2003282345Smav AHCI_P_CMD_CLO | AHCI_P_CMD_FRE | AHCI_P_CMD_APSTE | 2004282345Smav AHCI_P_CMD_ATAPI | AHCI_P_CMD_DLAE | AHCI_P_CMD_ALPE | 2005282345Smav AHCI_P_CMD_ASP | AHCI_P_CMD_ICC_MASK); 2006282345Smav p->cmd |= (AHCI_P_CMD_ST | AHCI_P_CMD_SUD | AHCI_P_CMD_POD | 2007282345Smav AHCI_P_CMD_CLO | AHCI_P_CMD_FRE | AHCI_P_CMD_APSTE | 2008282345Smav AHCI_P_CMD_ATAPI | AHCI_P_CMD_DLAE | AHCI_P_CMD_ALPE | 2009282345Smav AHCI_P_CMD_ASP | AHCI_P_CMD_ICC_MASK) & value; 2010282345Smav 2011256056Sgrehan if (!(value & AHCI_P_CMD_ST)) { 2012273212Stychon ahci_port_stop(p); 2013256056Sgrehan } else { 2014256056Sgrehan uint64_t clb; 2015256056Sgrehan 2016256056Sgrehan p->cmd |= AHCI_P_CMD_CR; 2017256056Sgrehan clb = (uint64_t)p->clbu << 32 | p->clb; 2018256056Sgrehan p->cmd_lst = paddr_guest2host(ahci_ctx(sc), clb, 2019256056Sgrehan AHCI_CL_SIZE * AHCI_MAX_SLOTS); 2020256056Sgrehan } 2021256056Sgrehan 2022256056Sgrehan if (value & AHCI_P_CMD_FRE) { 2023256056Sgrehan uint64_t fb; 2024256056Sgrehan 2025256056Sgrehan p->cmd |= AHCI_P_CMD_FR; 2026256056Sgrehan fb = (uint64_t)p->fbu << 32 | p->fb; 2027256056Sgrehan /* we don't support FBSCP, so rfis size is 256Bytes */ 2028256056Sgrehan p->rfis = paddr_guest2host(ahci_ctx(sc), fb, 256); 2029256056Sgrehan } else { 2030256056Sgrehan p->cmd &= ~AHCI_P_CMD_FR; 2031256056Sgrehan } 2032256056Sgrehan 2033256056Sgrehan if (value & AHCI_P_CMD_CLO) { 2034282524Smav p->tfd &= ~(ATA_S_BUSY | ATA_S_DRQ); 2035256056Sgrehan p->cmd &= ~AHCI_P_CMD_CLO; 2036256056Sgrehan } 2037256056Sgrehan 2038282345Smav if (value & AHCI_P_CMD_ICC_MASK) { 2039282345Smav p->cmd &= ~AHCI_P_CMD_ICC_MASK; 2040282345Smav } 2041282345Smav 2042256056Sgrehan ahci_handle_port(p); 2043256056Sgrehan break; 2044256056Sgrehan } 2045256056Sgrehan case AHCI_P_TFD: 2046256056Sgrehan case AHCI_P_SIG: 2047256056Sgrehan case AHCI_P_SSTS: 2048256056Sgrehan WPRINTF("pci_ahci_port: read only registers 0x%"PRIx64"\n", offset); 2049256056Sgrehan break; 2050256056Sgrehan case AHCI_P_SCTL: 2051279965Smav p->sctl = value; 2052256056Sgrehan if (!(p->cmd & AHCI_P_CMD_ST)) { 2053256056Sgrehan if (value & ATA_SC_DET_RESET) 2054256056Sgrehan ahci_port_reset(p); 2055256056Sgrehan } 2056256056Sgrehan break; 2057256056Sgrehan case AHCI_P_SERR: 2058256056Sgrehan p->serr &= ~value; 2059256056Sgrehan break; 2060256056Sgrehan case AHCI_P_SACT: 2061256056Sgrehan p->sact |= value; 2062256056Sgrehan break; 2063256056Sgrehan case AHCI_P_CI: 2064256056Sgrehan p->ci |= value; 2065256056Sgrehan ahci_handle_port(p); 2066256056Sgrehan break; 2067256056Sgrehan case AHCI_P_SNTF: 2068256056Sgrehan case AHCI_P_FBS: 2069256056Sgrehan default: 2070256056Sgrehan break; 2071256056Sgrehan } 2072256056Sgrehan} 2073256056Sgrehan 2074256056Sgrehanstatic void 2075256056Sgrehanpci_ahci_host_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value) 2076256056Sgrehan{ 2077256056Sgrehan DPRINTF("pci_ahci_host: write offset 0x%"PRIx64" value 0x%"PRIx64"\n", 2078256056Sgrehan offset, value); 2079256056Sgrehan 2080256056Sgrehan switch (offset) { 2081256056Sgrehan case AHCI_CAP: 2082256056Sgrehan case AHCI_PI: 2083256056Sgrehan case AHCI_VS: 2084256056Sgrehan case AHCI_CAP2: 2085256709Sgrehan DPRINTF("pci_ahci_host: read only registers 0x%"PRIx64"\n", offset); 2086256056Sgrehan break; 2087256056Sgrehan case AHCI_GHC: 2088256056Sgrehan if (value & AHCI_GHC_HR) 2089256056Sgrehan ahci_reset(sc); 2090256056Sgrehan else if (value & AHCI_GHC_IE) { 2091256056Sgrehan sc->ghc |= AHCI_GHC_IE; 2092256056Sgrehan ahci_generate_intr(sc); 2093256056Sgrehan } 2094256056Sgrehan break; 2095256056Sgrehan case AHCI_IS: 2096256056Sgrehan sc->is &= ~value; 2097256056Sgrehan ahci_generate_intr(sc); 2098256056Sgrehan break; 2099256056Sgrehan default: 2100256056Sgrehan break; 2101256056Sgrehan } 2102256056Sgrehan} 2103256056Sgrehan 2104256056Sgrehanstatic void 2105256056Sgrehanpci_ahci_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 2106256056Sgrehan int baridx, uint64_t offset, int size, uint64_t value) 2107256056Sgrehan{ 2108256056Sgrehan struct pci_ahci_softc *sc = pi->pi_arg; 2109256056Sgrehan 2110256056Sgrehan assert(baridx == 5); 2111282595Sneel assert((offset % 4) == 0 && size == 4); 2112256056Sgrehan 2113256056Sgrehan pthread_mutex_lock(&sc->mtx); 2114256056Sgrehan 2115256056Sgrehan if (offset < AHCI_OFFSET) 2116256056Sgrehan pci_ahci_host_write(sc, offset, value); 2117256056Sgrehan else if (offset < AHCI_OFFSET + sc->ports * AHCI_STEP) 2118256056Sgrehan pci_ahci_port_write(sc, offset, value); 2119256056Sgrehan else 2120256056Sgrehan WPRINTF("pci_ahci: unknown i/o write offset 0x%"PRIx64"\n", offset); 2121256056Sgrehan 2122256056Sgrehan pthread_mutex_unlock(&sc->mtx); 2123256056Sgrehan} 2124256056Sgrehan 2125256056Sgrehanstatic uint64_t 2126256056Sgrehanpci_ahci_host_read(struct pci_ahci_softc *sc, uint64_t offset) 2127256056Sgrehan{ 2128256056Sgrehan uint32_t value; 2129256056Sgrehan 2130256056Sgrehan switch (offset) { 2131256056Sgrehan case AHCI_CAP: 2132256056Sgrehan case AHCI_GHC: 2133256056Sgrehan case AHCI_IS: 2134256056Sgrehan case AHCI_PI: 2135256056Sgrehan case AHCI_VS: 2136256056Sgrehan case AHCI_CCCC: 2137256056Sgrehan case AHCI_CCCP: 2138256056Sgrehan case AHCI_EM_LOC: 2139256056Sgrehan case AHCI_EM_CTL: 2140256056Sgrehan case AHCI_CAP2: 2141256056Sgrehan { 2142256056Sgrehan uint32_t *p = &sc->cap; 2143256056Sgrehan p += (offset - AHCI_CAP) / sizeof(uint32_t); 2144256056Sgrehan value = *p; 2145256056Sgrehan break; 2146256056Sgrehan } 2147256056Sgrehan default: 2148256056Sgrehan value = 0; 2149256056Sgrehan break; 2150256056Sgrehan } 2151256056Sgrehan DPRINTF("pci_ahci_host: read offset 0x%"PRIx64" value 0x%x\n", 2152256056Sgrehan offset, value); 2153256056Sgrehan 2154256056Sgrehan return (value); 2155256056Sgrehan} 2156256056Sgrehan 2157256056Sgrehanstatic uint64_t 2158256056Sgrehanpci_ahci_port_read(struct pci_ahci_softc *sc, uint64_t offset) 2159256056Sgrehan{ 2160256056Sgrehan uint32_t value; 2161256056Sgrehan int port = (offset - AHCI_OFFSET) / AHCI_STEP; 2162256056Sgrehan offset = (offset - AHCI_OFFSET) % AHCI_STEP; 2163256056Sgrehan 2164256056Sgrehan switch (offset) { 2165256056Sgrehan case AHCI_P_CLB: 2166256056Sgrehan case AHCI_P_CLBU: 2167256056Sgrehan case AHCI_P_FB: 2168256056Sgrehan case AHCI_P_FBU: 2169256056Sgrehan case AHCI_P_IS: 2170256056Sgrehan case AHCI_P_IE: 2171256056Sgrehan case AHCI_P_CMD: 2172256056Sgrehan case AHCI_P_TFD: 2173256056Sgrehan case AHCI_P_SIG: 2174256056Sgrehan case AHCI_P_SSTS: 2175256056Sgrehan case AHCI_P_SCTL: 2176256056Sgrehan case AHCI_P_SERR: 2177256056Sgrehan case AHCI_P_SACT: 2178256056Sgrehan case AHCI_P_CI: 2179256056Sgrehan case AHCI_P_SNTF: 2180256056Sgrehan case AHCI_P_FBS: 2181256056Sgrehan { 2182256056Sgrehan uint32_t *p= &sc->port[port].clb; 2183256056Sgrehan p += (offset - AHCI_P_CLB) / sizeof(uint32_t); 2184256056Sgrehan value = *p; 2185256056Sgrehan break; 2186256056Sgrehan } 2187256056Sgrehan default: 2188256056Sgrehan value = 0; 2189256056Sgrehan break; 2190256056Sgrehan } 2191256056Sgrehan 2192256056Sgrehan DPRINTF("pci_ahci_port %d: read offset 0x%"PRIx64" value 0x%x\n", 2193256056Sgrehan port, offset, value); 2194256056Sgrehan 2195256056Sgrehan return value; 2196256056Sgrehan} 2197256056Sgrehan 2198256056Sgrehanstatic uint64_t 2199256056Sgrehanpci_ahci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, 2200282595Sneel uint64_t regoff, int size) 2201256056Sgrehan{ 2202256056Sgrehan struct pci_ahci_softc *sc = pi->pi_arg; 2203282595Sneel uint64_t offset; 2204256056Sgrehan uint32_t value; 2205256056Sgrehan 2206256056Sgrehan assert(baridx == 5); 2207282595Sneel assert(size == 1 || size == 2 || size == 4); 2208282595Sneel assert((regoff & (size - 1)) == 0); 2209256056Sgrehan 2210256056Sgrehan pthread_mutex_lock(&sc->mtx); 2211256056Sgrehan 2212282595Sneel offset = regoff & ~0x3; /* round down to a multiple of 4 bytes */ 2213256056Sgrehan if (offset < AHCI_OFFSET) 2214256056Sgrehan value = pci_ahci_host_read(sc, offset); 2215256056Sgrehan else if (offset < AHCI_OFFSET + sc->ports * AHCI_STEP) 2216256056Sgrehan value = pci_ahci_port_read(sc, offset); 2217256056Sgrehan else { 2218256056Sgrehan value = 0; 2219282595Sneel WPRINTF("pci_ahci: unknown i/o read offset 0x%"PRIx64"\n", 2220282595Sneel regoff); 2221256056Sgrehan } 2222282595Sneel value >>= 8 * (regoff & 0x3); 2223256056Sgrehan 2224256056Sgrehan pthread_mutex_unlock(&sc->mtx); 2225256056Sgrehan 2226256056Sgrehan return (value); 2227256056Sgrehan} 2228256056Sgrehan 2229256056Sgrehanstatic int 2230256056Sgrehanpci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) 2231256056Sgrehan{ 2232256056Sgrehan char bident[sizeof("XX:X:X")]; 2233256056Sgrehan struct blockif_ctxt *bctxt; 2234256056Sgrehan struct pci_ahci_softc *sc; 2235256056Sgrehan int ret, slots; 2236280040Smav MD5_CTX mdctx; 2237280040Smav u_char digest[16]; 2238256056Sgrehan 2239256056Sgrehan ret = 0; 2240256056Sgrehan 2241256056Sgrehan if (opts == NULL) { 2242256056Sgrehan fprintf(stderr, "pci_ahci: backing device required\n"); 2243256056Sgrehan return (1); 2244256056Sgrehan } 2245256056Sgrehan 2246256056Sgrehan#ifdef AHCI_DEBUG 2247256056Sgrehan dbg = fopen("/tmp/log", "w+"); 2248256056Sgrehan#endif 2249256056Sgrehan 2250264770Sdelphij sc = calloc(1, sizeof(struct pci_ahci_softc)); 2251256056Sgrehan pi->pi_arg = sc; 2252256056Sgrehan sc->asc_pi = pi; 2253256056Sgrehan sc->ports = MAX_PORTS; 2254256056Sgrehan 2255256056Sgrehan /* 2256256056Sgrehan * Only use port 0 for a backing device. All other ports will be 2257256056Sgrehan * marked as unused 2258256056Sgrehan */ 2259256056Sgrehan sc->port[0].atapi = atapi; 2260256056Sgrehan 2261256056Sgrehan /* 2262256056Sgrehan * Attempt to open the backing image. Use the PCI 2263257729Sgrehan * slot/func for the identifier string. 2264256056Sgrehan */ 2265257729Sgrehan snprintf(bident, sizeof(bident), "%d:%d", pi->pi_slot, pi->pi_func); 2266256056Sgrehan bctxt = blockif_open(opts, bident); 2267256056Sgrehan if (bctxt == NULL) { 2268256056Sgrehan ret = 1; 2269256056Sgrehan goto open_fail; 2270256056Sgrehan } 2271256056Sgrehan sc->port[0].bctx = bctxt; 2272256056Sgrehan sc->port[0].pr_sc = sc; 2273256056Sgrehan 2274256056Sgrehan /* 2275280040Smav * Create an identifier for the backing file. Use parts of the 2276280040Smav * md5 sum of the filename 2277280040Smav */ 2278280040Smav MD5Init(&mdctx); 2279280040Smav MD5Update(&mdctx, opts, strlen(opts)); 2280280040Smav MD5Final(digest, &mdctx); 2281280040Smav sprintf(sc->port[0].ident, "BHYVE-%02X%02X-%02X%02X-%02X%02X", 2282280040Smav digest[0], digest[1], digest[2], digest[3], digest[4], digest[5]); 2283280040Smav 2284280040Smav /* 2285256056Sgrehan * Allocate blockif request structures and add them 2286256056Sgrehan * to the free list 2287256056Sgrehan */ 2288256056Sgrehan pci_ahci_ioreq_init(&sc->port[0]); 2289256056Sgrehan 2290256056Sgrehan pthread_mutex_init(&sc->mtx, NULL); 2291256056Sgrehan 2292256056Sgrehan /* Intel ICH8 AHCI */ 2293256056Sgrehan slots = sc->port[0].ioqsz; 2294256056Sgrehan if (slots > 32) 2295256056Sgrehan slots = 32; 2296256056Sgrehan --slots; 2297256056Sgrehan sc->cap = AHCI_CAP_64BIT | AHCI_CAP_SNCQ | AHCI_CAP_SSNTF | 2298256056Sgrehan AHCI_CAP_SMPS | AHCI_CAP_SSS | AHCI_CAP_SALP | 2299256056Sgrehan AHCI_CAP_SAL | AHCI_CAP_SCLO | (0x3 << AHCI_CAP_ISS_SHIFT)| 2300256056Sgrehan AHCI_CAP_PMD | AHCI_CAP_SSC | AHCI_CAP_PSC | 2301256056Sgrehan (slots << AHCI_CAP_NCS_SHIFT) | AHCI_CAP_SXS | (sc->ports - 1); 2302256056Sgrehan 2303256056Sgrehan /* Only port 0 implemented */ 2304256056Sgrehan sc->pi = 1; 2305256056Sgrehan sc->vs = 0x10300; 2306256056Sgrehan sc->cap2 = AHCI_CAP2_APST; 2307256056Sgrehan ahci_reset(sc); 2308256056Sgrehan 2309256056Sgrehan pci_set_cfgdata16(pi, PCIR_DEVICE, 0x2821); 2310256056Sgrehan pci_set_cfgdata16(pi, PCIR_VENDOR, 0x8086); 2311256056Sgrehan pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE); 2312256056Sgrehan pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_STORAGE_SATA); 2313256056Sgrehan pci_set_cfgdata8(pi, PCIR_PROGIF, PCIP_STORAGE_SATA_AHCI_1_0); 2314256056Sgrehan pci_emul_add_msicap(pi, 1); 2315256056Sgrehan pci_emul_alloc_bar(pi, 5, PCIBAR_MEM32, 2316256056Sgrehan AHCI_OFFSET + sc->ports * AHCI_STEP); 2317256056Sgrehan 2318265058Sgrehan pci_lintr_request(pi); 2319265058Sgrehan 2320256056Sgrehanopen_fail: 2321256056Sgrehan if (ret) { 2322279220Sgrehan if (sc->port[0].bctx != NULL) 2323279220Sgrehan blockif_close(sc->port[0].bctx); 2324256056Sgrehan free(sc); 2325256056Sgrehan } 2326256056Sgrehan 2327256056Sgrehan return (ret); 2328256056Sgrehan} 2329256056Sgrehan 2330256056Sgrehanstatic int 2331256056Sgrehanpci_ahci_hd_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) 2332256056Sgrehan{ 2333256056Sgrehan 2334256056Sgrehan return (pci_ahci_init(ctx, pi, opts, 0)); 2335256056Sgrehan} 2336256056Sgrehan 2337256056Sgrehanstatic int 2338256056Sgrehanpci_ahci_atapi_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) 2339256056Sgrehan{ 2340256056Sgrehan 2341256056Sgrehan return (pci_ahci_init(ctx, pi, opts, 1)); 2342256056Sgrehan} 2343256056Sgrehan 2344256056Sgrehan/* 2345256056Sgrehan * Use separate emulation names to distinguish drive and atapi devices 2346256056Sgrehan */ 2347256056Sgrehanstruct pci_devemu pci_de_ahci_hd = { 2348256056Sgrehan .pe_emu = "ahci-hd", 2349256056Sgrehan .pe_init = pci_ahci_hd_init, 2350256056Sgrehan .pe_barwrite = pci_ahci_write, 2351256056Sgrehan .pe_barread = pci_ahci_read 2352256056Sgrehan}; 2353256056SgrehanPCI_EMUL_SET(pci_de_ahci_hd); 2354256056Sgrehan 2355256056Sgrehanstruct pci_devemu pci_de_ahci_cd = { 2356256056Sgrehan .pe_emu = "ahci-cd", 2357256056Sgrehan .pe_init = pci_ahci_atapi_init, 2358256056Sgrehan .pe_barwrite = pci_ahci_write, 2359256056Sgrehan .pe_barread = pci_ahci_read 2360256056Sgrehan}; 2361256056SgrehanPCI_EMUL_SET(pci_de_ahci_cd); 2362