Annotation of qemu/hw/ide/ahci.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * QEMU AHCI Emulation
        !             3:  *
        !             4:  * Copyright (c) 2010 [email protected]
        !             5:  * Copyright (c) 2010 Roland Elek <[email protected]>
        !             6:  * Copyright (c) 2010 Sebastian Herbszt <[email protected]>
        !             7:  * Copyright (c) 2010 Alexander Graf <[email protected]>
        !             8:  *
        !             9:  * This library is free software; you can redistribute it and/or
        !            10:  * modify it under the terms of the GNU Lesser General Public
        !            11:  * License as published by the Free Software Foundation; either
        !            12:  * version 2 of the License, or (at your option) any later version.
        !            13:  *
        !            14:  * This library is distributed in the hope that it will be useful,
        !            15:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            17:  * Lesser General Public License for more details.
        !            18:  *
        !            19:  * You should have received a copy of the GNU Lesser General Public
        !            20:  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
        !            21:  *
        !            22:  */
        !            23: 
        !            24: #include <hw/hw.h>
        !            25: #include <hw/msi.h>
        !            26: #include <hw/pc.h>
        !            27: #include <hw/pci.h>
        !            28: 
        !            29: #include "monitor.h"
        !            30: #include "dma.h"
        !            31: #include "cpu-common.h"
        !            32: #include "internal.h"
        !            33: #include <hw/ide/pci.h>
        !            34: #include <hw/ide/ahci.h>
        !            35: 
        !            36: /* #define DEBUG_AHCI */
        !            37: 
        !            38: #ifdef DEBUG_AHCI
        !            39: #define DPRINTF(port, fmt, ...) \
        !            40: do { fprintf(stderr, "ahci: %s: [%d] ", __FUNCTION__, port); \
        !            41:      fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
        !            42: #else
        !            43: #define DPRINTF(port, fmt, ...) do {} while(0)
        !            44: #endif
        !            45: 
        !            46: static void check_cmd(AHCIState *s, int port);
        !            47: static int handle_cmd(AHCIState *s,int port,int slot);
        !            48: static void ahci_reset_port(AHCIState *s, int port);
        !            49: static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
        !            50: static void ahci_init_d2h(AHCIDevice *ad);
        !            51: 
        !            52: static uint32_t  ahci_port_read(AHCIState *s, int port, int offset)
        !            53: {
        !            54:     uint32_t val;
        !            55:     AHCIPortRegs *pr;
        !            56:     pr = &s->dev[port].port_regs;
        !            57: 
        !            58:     switch (offset) {
        !            59:     case PORT_LST_ADDR:
        !            60:         val = pr->lst_addr;
        !            61:         break;
        !            62:     case PORT_LST_ADDR_HI:
        !            63:         val = pr->lst_addr_hi;
        !            64:         break;
        !            65:     case PORT_FIS_ADDR:
        !            66:         val = pr->fis_addr;
        !            67:         break;
        !            68:     case PORT_FIS_ADDR_HI:
        !            69:         val = pr->fis_addr_hi;
        !            70:         break;
        !            71:     case PORT_IRQ_STAT:
        !            72:         val = pr->irq_stat;
        !            73:         break;
        !            74:     case PORT_IRQ_MASK:
        !            75:         val = pr->irq_mask;
        !            76:         break;
        !            77:     case PORT_CMD:
        !            78:         val = pr->cmd;
        !            79:         break;
        !            80:     case PORT_TFDATA:
        !            81:         val = ((uint16_t)s->dev[port].port.ifs[0].error << 8) |
        !            82:               s->dev[port].port.ifs[0].status;
        !            83:         break;
        !            84:     case PORT_SIG:
        !            85:         val = pr->sig;
        !            86:         break;
        !            87:     case PORT_SCR_STAT:
        !            88:         if (s->dev[port].port.ifs[0].bs) {
        !            89:             val = SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP |
        !            90:                   SATA_SCR_SSTATUS_SPD_GEN1 | SATA_SCR_SSTATUS_IPM_ACTIVE;
        !            91:         } else {
        !            92:             val = SATA_SCR_SSTATUS_DET_NODEV;
        !            93:         }
        !            94:         break;
        !            95:     case PORT_SCR_CTL:
        !            96:         val = pr->scr_ctl;
        !            97:         break;
        !            98:     case PORT_SCR_ERR:
        !            99:         val = pr->scr_err;
        !           100:         break;
        !           101:     case PORT_SCR_ACT:
        !           102:         pr->scr_act &= ~s->dev[port].finished;
        !           103:         s->dev[port].finished = 0;
        !           104:         val = pr->scr_act;
        !           105:         break;
        !           106:     case PORT_CMD_ISSUE:
        !           107:         val = pr->cmd_issue;
        !           108:         break;
        !           109:     case PORT_RESERVED:
        !           110:     default:
        !           111:         val = 0;
        !           112:     }
        !           113:     DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
        !           114:     return val;
        !           115: 
        !           116: }
        !           117: 
        !           118: static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
        !           119: {
        !           120:     struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
        !           121: 
        !           122:     DPRINTF(0, "raise irq\n");
        !           123: 
        !           124:     if (msi_enabled(&d->card)) {
        !           125:         msi_notify(&d->card, 0);
        !           126:     } else {
        !           127:         qemu_irq_raise(s->irq);
        !           128:     }
        !           129: }
        !           130: 
        !           131: static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
        !           132: {
        !           133:     struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
        !           134: 
        !           135:     DPRINTF(0, "lower irq\n");
        !           136: 
        !           137:     if (!msi_enabled(&d->card)) {
        !           138:         qemu_irq_lower(s->irq);
        !           139:     }
        !           140: }
        !           141: 
        !           142: static void ahci_check_irq(AHCIState *s)
        !           143: {
        !           144:     int i;
        !           145: 
        !           146:     DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus);
        !           147: 
        !           148:     for (i = 0; i < s->ports; i++) {
        !           149:         AHCIPortRegs *pr = &s->dev[i].port_regs;
        !           150:         if (pr->irq_stat & pr->irq_mask) {
        !           151:             s->control_regs.irqstatus |= (1 << i);
        !           152:         }
        !           153:     }
        !           154: 
        !           155:     if (s->control_regs.irqstatus &&
        !           156:         (s->control_regs.ghc & HOST_CTL_IRQ_EN)) {
        !           157:             ahci_irq_raise(s, NULL);
        !           158:     } else {
        !           159:         ahci_irq_lower(s, NULL);
        !           160:     }
        !           161: }
        !           162: 
        !           163: static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d,
        !           164:                              int irq_type)
        !           165: {
        !           166:     DPRINTF(d->port_no, "trigger irq %#x -> %x\n",
        !           167:             irq_type, d->port_regs.irq_mask & irq_type);
        !           168: 
        !           169:     d->port_regs.irq_stat |= irq_type;
        !           170:     ahci_check_irq(s);
        !           171: }
        !           172: 
        !           173: static void map_page(uint8_t **ptr, uint64_t addr, uint32_t wanted)
        !           174: {
        !           175:     target_phys_addr_t len = wanted;
        !           176: 
        !           177:     if (*ptr) {
        !           178:         cpu_physical_memory_unmap(*ptr, len, 1, len);
        !           179:     }
        !           180: 
        !           181:     *ptr = cpu_physical_memory_map(addr, &len, 1);
        !           182:     if (len < wanted) {
        !           183:         cpu_physical_memory_unmap(*ptr, len, 1, len);
        !           184:         *ptr = NULL;
        !           185:     }
        !           186: }
        !           187: 
        !           188: static void  ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
        !           189: {
        !           190:     AHCIPortRegs *pr = &s->dev[port].port_regs;
        !           191: 
        !           192:     DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
        !           193:     switch (offset) {
        !           194:         case PORT_LST_ADDR:
        !           195:             pr->lst_addr = val;
        !           196:             map_page(&s->dev[port].lst,
        !           197:                      ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
        !           198:             s->dev[port].cur_cmd = NULL;
        !           199:             break;
        !           200:         case PORT_LST_ADDR_HI:
        !           201:             pr->lst_addr_hi = val;
        !           202:             map_page(&s->dev[port].lst,
        !           203:                      ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
        !           204:             s->dev[port].cur_cmd = NULL;
        !           205:             break;
        !           206:         case PORT_FIS_ADDR:
        !           207:             pr->fis_addr = val;
        !           208:             map_page(&s->dev[port].res_fis,
        !           209:                      ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
        !           210:             break;
        !           211:         case PORT_FIS_ADDR_HI:
        !           212:             pr->fis_addr_hi = val;
        !           213:             map_page(&s->dev[port].res_fis,
        !           214:                      ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
        !           215:             break;
        !           216:         case PORT_IRQ_STAT:
        !           217:             pr->irq_stat &= ~val;
        !           218:             break;
        !           219:         case PORT_IRQ_MASK:
        !           220:             pr->irq_mask = val & 0xfdc000ff;
        !           221:             ahci_check_irq(s);
        !           222:             break;
        !           223:         case PORT_CMD:
        !           224:             pr->cmd = val & ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON);
        !           225: 
        !           226:             if (pr->cmd & PORT_CMD_START) {
        !           227:                 pr->cmd |= PORT_CMD_LIST_ON;
        !           228:             }
        !           229: 
        !           230:             if (pr->cmd & PORT_CMD_FIS_RX) {
        !           231:                 pr->cmd |= PORT_CMD_FIS_ON;
        !           232:             }
        !           233: 
        !           234:             /* XXX usually the FIS would be pending on the bus here and
        !           235:                    issuing deferred until the OS enables FIS receival.
        !           236:                    Instead, we only submit it once - which works in most
        !           237:                    cases, but is a hack. */
        !           238:             if ((pr->cmd & PORT_CMD_FIS_ON) &&
        !           239:                 !s->dev[port].init_d2h_sent) {
        !           240:                 ahci_init_d2h(&s->dev[port]);
        !           241:                 s->dev[port].init_d2h_sent = 1;
        !           242:             }
        !           243: 
        !           244:             check_cmd(s, port);
        !           245:             break;
        !           246:         case PORT_TFDATA:
        !           247:             s->dev[port].port.ifs[0].error = (val >> 8) & 0xff;
        !           248:             s->dev[port].port.ifs[0].status = val & 0xff;
        !           249:             break;
        !           250:         case PORT_SIG:
        !           251:             pr->sig = val;
        !           252:             break;
        !           253:         case PORT_SCR_STAT:
        !           254:             pr->scr_stat = val;
        !           255:             break;
        !           256:         case PORT_SCR_CTL:
        !           257:             if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) &&
        !           258:                 ((val & AHCI_SCR_SCTL_DET) == 0)) {
        !           259:                 ahci_reset_port(s, port);
        !           260:             }
        !           261:             pr->scr_ctl = val;
        !           262:             break;
        !           263:         case PORT_SCR_ERR:
        !           264:             pr->scr_err &= ~val;
        !           265:             break;
        !           266:         case PORT_SCR_ACT:
        !           267:             /* RW1 */
        !           268:             pr->scr_act |= val;
        !           269:             break;
        !           270:         case PORT_CMD_ISSUE:
        !           271:             pr->cmd_issue |= val;
        !           272:             check_cmd(s, port);
        !           273:             break;
        !           274:         default:
        !           275:             break;
        !           276:     }
        !           277: }
        !           278: 
        !           279: static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
        !           280: {
        !           281:     AHCIState *s = ptr;
        !           282:     uint32_t val = 0;
        !           283: 
        !           284:     addr = addr & 0xfff;
        !           285:     if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
        !           286:         switch (addr) {
        !           287:         case HOST_CAP:
        !           288:             val = s->control_regs.cap;
        !           289:             break;
        !           290:         case HOST_CTL:
        !           291:             val = s->control_regs.ghc;
        !           292:             break;
        !           293:         case HOST_IRQ_STAT:
        !           294:             val = s->control_regs.irqstatus;
        !           295:             break;
        !           296:         case HOST_PORTS_IMPL:
        !           297:             val = s->control_regs.impl;
        !           298:             break;
        !           299:         case HOST_VERSION:
        !           300:             val = s->control_regs.version;
        !           301:             break;
        !           302:         }
        !           303: 
        !           304:         DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
        !           305:     } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
        !           306:                (addr < (AHCI_PORT_REGS_START_ADDR +
        !           307:                 (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
        !           308:         val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
        !           309:                              addr & AHCI_PORT_ADDR_OFFSET_MASK);
        !           310:     }
        !           311: 
        !           312:     return val;
        !           313: }
        !           314: 
        !           315: 
        !           316: 
        !           317: static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
        !           318: {
        !           319:     AHCIState *s = ptr;
        !           320:     addr = addr & 0xfff;
        !           321: 
        !           322:     /* Only aligned reads are allowed on AHCI */
        !           323:     if (addr & 3) {
        !           324:         fprintf(stderr, "ahci: Mis-aligned write to addr 0x"
        !           325:                 TARGET_FMT_plx "\n", addr);
        !           326:         return;
        !           327:     }
        !           328: 
        !           329:     if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
        !           330:         DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
        !           331: 
        !           332:         switch (addr) {
        !           333:             case HOST_CAP: /* R/WO, RO */
        !           334:                 /* FIXME handle R/WO */
        !           335:                 break;
        !           336:             case HOST_CTL: /* R/W */
        !           337:                 if (val & HOST_CTL_RESET) {
        !           338:                     DPRINTF(-1, "HBA Reset\n");
        !           339:                     ahci_reset(container_of(s, AHCIPCIState, ahci));
        !           340:                 } else {
        !           341:                     s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
        !           342:                     ahci_check_irq(s);
        !           343:                 }
        !           344:                 break;
        !           345:             case HOST_IRQ_STAT: /* R/WC, RO */
        !           346:                 s->control_regs.irqstatus &= ~val;
        !           347:                 ahci_check_irq(s);
        !           348:                 break;
        !           349:             case HOST_PORTS_IMPL: /* R/WO, RO */
        !           350:                 /* FIXME handle R/WO */
        !           351:                 break;
        !           352:             case HOST_VERSION: /* RO */
        !           353:                 /* FIXME report write? */
        !           354:                 break;
        !           355:             default:
        !           356:                 DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr);
        !           357:         }
        !           358:     } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
        !           359:                (addr < (AHCI_PORT_REGS_START_ADDR +
        !           360:                 (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
        !           361:         ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
        !           362:                         addr & AHCI_PORT_ADDR_OFFSET_MASK, val);
        !           363:     }
        !           364: 
        !           365: }
        !           366: 
        !           367: static CPUReadMemoryFunc * const ahci_readfn[3]={
        !           368:     ahci_mem_readl,
        !           369:     ahci_mem_readl,
        !           370:     ahci_mem_readl
        !           371: };
        !           372: 
        !           373: static CPUWriteMemoryFunc * const ahci_writefn[3]={
        !           374:     ahci_mem_writel,
        !           375:     ahci_mem_writel,
        !           376:     ahci_mem_writel
        !           377: };
        !           378: 
        !           379: static void ahci_reg_init(AHCIState *s)
        !           380: {
        !           381:     int i;
        !           382: 
        !           383:     s->control_regs.cap = (s->ports - 1) |
        !           384:                           (AHCI_NUM_COMMAND_SLOTS << 8) |
        !           385:                           (AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) |
        !           386:                           HOST_CAP_NCQ | HOST_CAP_AHCI;
        !           387: 
        !           388:     s->control_regs.impl = (1 << s->ports) - 1;
        !           389: 
        !           390:     s->control_regs.version = AHCI_VERSION_1_0;
        !           391: 
        !           392:     for (i = 0; i < s->ports; i++) {
        !           393:         s->dev[i].port_state = STATE_RUN;
        !           394:     }
        !           395: }
        !           396: 
        !           397: static uint32_t read_from_sglist(uint8_t *buffer, uint32_t len,
        !           398:                                  QEMUSGList *sglist)
        !           399: {
        !           400:     uint32_t i = 0;
        !           401:     uint32_t total = 0, once;
        !           402:     ScatterGatherEntry *cur_prd;
        !           403:     uint32_t sgcount;
        !           404: 
        !           405:     cur_prd = sglist->sg;
        !           406:     sgcount = sglist->nsg;
        !           407:     for (i = 0; len && sgcount; i++) {
        !           408:         once = MIN(cur_prd->len, len);
        !           409:         cpu_physical_memory_read(cur_prd->base, buffer, once);
        !           410:         cur_prd++;
        !           411:         sgcount--;
        !           412:         len -= once;
        !           413:         buffer += once;
        !           414:         total += once;
        !           415:     }
        !           416: 
        !           417:     return total;
        !           418: }
        !           419: 
        !           420: static uint32_t write_to_sglist(uint8_t *buffer, uint32_t len,
        !           421:                                 QEMUSGList *sglist)
        !           422: {
        !           423:     uint32_t i = 0;
        !           424:     uint32_t total = 0, once;
        !           425:     ScatterGatherEntry *cur_prd;
        !           426:     uint32_t sgcount;
        !           427: 
        !           428:     DPRINTF(-1, "total: 0x%x bytes\n", len);
        !           429: 
        !           430:     cur_prd = sglist->sg;
        !           431:     sgcount = sglist->nsg;
        !           432:     for (i = 0; len && sgcount; i++) {
        !           433:         once = MIN(cur_prd->len, len);
        !           434:         DPRINTF(-1, "write 0x%x bytes to 0x%lx\n", once, (long)cur_prd->base);
        !           435:         cpu_physical_memory_write(cur_prd->base, buffer, once);
        !           436:         cur_prd++;
        !           437:         sgcount--;
        !           438:         len -= once;
        !           439:         buffer += once;
        !           440:         total += once;
        !           441:     }
        !           442: 
        !           443:     return total;
        !           444: }
        !           445: 
        !           446: static void check_cmd(AHCIState *s, int port)
        !           447: {
        !           448:     AHCIPortRegs *pr = &s->dev[port].port_regs;
        !           449:     int slot;
        !           450: 
        !           451:     if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
        !           452:         for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) {
        !           453:             if ((pr->cmd_issue & (1 << slot)) &&
        !           454:                 !handle_cmd(s, port, slot)) {
        !           455:                 pr->cmd_issue &= ~(1 << slot);
        !           456:             }
        !           457:         }
        !           458:     }
        !           459: }
        !           460: 
        !           461: static void ahci_check_cmd_bh(void *opaque)
        !           462: {
        !           463:     AHCIDevice *ad = opaque;
        !           464: 
        !           465:     qemu_bh_delete(ad->check_bh);
        !           466:     ad->check_bh = NULL;
        !           467: 
        !           468:     if ((ad->busy_slot != -1) &&
        !           469:         !(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
        !           470:         /* no longer busy */
        !           471:         ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
        !           472:         ad->busy_slot = -1;
        !           473:     }
        !           474: 
        !           475:     check_cmd(ad->hba, ad->port_no);
        !           476: }
        !           477: 
        !           478: static void ahci_init_d2h(AHCIDevice *ad)
        !           479: {
        !           480:     uint8_t init_fis[0x20];
        !           481:     IDEState *ide_state = &ad->port.ifs[0];
        !           482: 
        !           483:     memset(init_fis, 0, sizeof(init_fis));
        !           484: 
        !           485:     init_fis[4] = 1;
        !           486:     init_fis[12] = 1;
        !           487: 
        !           488:     if (ide_state->drive_kind == IDE_CD) {
        !           489:         init_fis[5] = ide_state->lcyl;
        !           490:         init_fis[6] = ide_state->hcyl;
        !           491:     }
        !           492: 
        !           493:     ahci_write_fis_d2h(ad, init_fis);
        !           494: }
        !           495: 
        !           496: static void ahci_reset_port(AHCIState *s, int port)
        !           497: {
        !           498:     AHCIDevice *d = &s->dev[port];
        !           499:     AHCIPortRegs *pr = &d->port_regs;
        !           500:     IDEState *ide_state = &d->port.ifs[0];
        !           501:     int i;
        !           502: 
        !           503:     DPRINTF(port, "reset port\n");
        !           504: 
        !           505:     ide_bus_reset(&d->port);
        !           506:     ide_state->ncq_queues = AHCI_MAX_CMDS;
        !           507: 
        !           508:     pr->irq_stat = 0;
        !           509:     pr->irq_mask = 0;
        !           510:     pr->scr_stat = 0;
        !           511:     pr->scr_ctl = 0;
        !           512:     pr->scr_err = 0;
        !           513:     pr->scr_act = 0;
        !           514:     d->busy_slot = -1;
        !           515:     d->init_d2h_sent = 0;
        !           516: 
        !           517:     ide_state = &s->dev[port].port.ifs[0];
        !           518:     if (!ide_state->bs) {
        !           519:         return;
        !           520:     }
        !           521: 
        !           522:     /* reset ncq queue */
        !           523:     for (i = 0; i < AHCI_MAX_CMDS; i++) {
        !           524:         NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[i];
        !           525:         if (!ncq_tfs->used) {
        !           526:             continue;
        !           527:         }
        !           528: 
        !           529:         if (ncq_tfs->aiocb) {
        !           530:             bdrv_aio_cancel(ncq_tfs->aiocb);
        !           531:             ncq_tfs->aiocb = NULL;
        !           532:         }
        !           533: 
        !           534:         qemu_sglist_destroy(&ncq_tfs->sglist);
        !           535:         ncq_tfs->used = 0;
        !           536:     }
        !           537: 
        !           538:     s->dev[port].port_state = STATE_RUN;
        !           539:     if (!ide_state->bs) {
        !           540:         s->dev[port].port_regs.sig = 0;
        !           541:         ide_state->status = SEEK_STAT | WRERR_STAT;
        !           542:     } else if (ide_state->drive_kind == IDE_CD) {
        !           543:         s->dev[port].port_regs.sig = SATA_SIGNATURE_CDROM;
        !           544:         ide_state->lcyl = 0x14;
        !           545:         ide_state->hcyl = 0xeb;
        !           546:         DPRINTF(port, "set lcyl = %d\n", ide_state->lcyl);
        !           547:         ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT;
        !           548:     } else {
        !           549:         s->dev[port].port_regs.sig = SATA_SIGNATURE_DISK;
        !           550:         ide_state->status = SEEK_STAT | WRERR_STAT;
        !           551:     }
        !           552: 
        !           553:     ide_state->error = 1;
        !           554:     ahci_init_d2h(d);
        !           555: }
        !           556: 
        !           557: static void debug_print_fis(uint8_t *fis, int cmd_len)
        !           558: {
        !           559: #ifdef DEBUG_AHCI
        !           560:     int i;
        !           561: 
        !           562:     fprintf(stderr, "fis:");
        !           563:     for (i = 0; i < cmd_len; i++) {
        !           564:         if ((i & 0xf) == 0) {
        !           565:             fprintf(stderr, "\n%02x:",i);
        !           566:         }
        !           567:         fprintf(stderr, "%02x ",fis[i]);
        !           568:     }
        !           569:     fprintf(stderr, "\n");
        !           570: #endif
        !           571: }
        !           572: 
        !           573: static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished)
        !           574: {
        !           575:     AHCIPortRegs *pr = &s->dev[port].port_regs;
        !           576:     IDEState *ide_state;
        !           577:     uint8_t *sdb_fis;
        !           578: 
        !           579:     if (!s->dev[port].res_fis ||
        !           580:         !(pr->cmd & PORT_CMD_FIS_RX)) {
        !           581:         return;
        !           582:     }
        !           583: 
        !           584:     sdb_fis = &s->dev[port].res_fis[RES_FIS_SDBFIS];
        !           585:     ide_state = &s->dev[port].port.ifs[0];
        !           586: 
        !           587:     /* clear memory */
        !           588:     *(uint32_t*)sdb_fis = 0;
        !           589: 
        !           590:     /* write values */
        !           591:     sdb_fis[0] = ide_state->error;
        !           592:     sdb_fis[2] = ide_state->status & 0x77;
        !           593:     s->dev[port].finished |= finished;
        !           594:     *(uint32_t*)(sdb_fis + 4) = cpu_to_le32(s->dev[port].finished);
        !           595: 
        !           596:     ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_STAT_SDBS);
        !           597: }
        !           598: 
        !           599: static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
        !           600: {
        !           601:     AHCIPortRegs *pr = &ad->port_regs;
        !           602:     uint8_t *d2h_fis;
        !           603:     int i;
        !           604:     target_phys_addr_t cmd_len = 0x80;
        !           605:     int cmd_mapped = 0;
        !           606: 
        !           607:     if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
        !           608:         return;
        !           609:     }
        !           610: 
        !           611:     if (!cmd_fis) {
        !           612:         /* map cmd_fis */
        !           613:         uint64_t tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr);
        !           614:         cmd_fis = cpu_physical_memory_map(tbl_addr, &cmd_len, 0);
        !           615:         cmd_mapped = 1;
        !           616:     }
        !           617: 
        !           618:     d2h_fis = &ad->res_fis[RES_FIS_RFIS];
        !           619: 
        !           620:     d2h_fis[0] = 0x34;
        !           621:     d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
        !           622:     d2h_fis[2] = ad->port.ifs[0].status;
        !           623:     d2h_fis[3] = ad->port.ifs[0].error;
        !           624: 
        !           625:     d2h_fis[4] = cmd_fis[4];
        !           626:     d2h_fis[5] = cmd_fis[5];
        !           627:     d2h_fis[6] = cmd_fis[6];
        !           628:     d2h_fis[7] = cmd_fis[7];
        !           629:     d2h_fis[8] = cmd_fis[8];
        !           630:     d2h_fis[9] = cmd_fis[9];
        !           631:     d2h_fis[10] = cmd_fis[10];
        !           632:     d2h_fis[11] = cmd_fis[11];
        !           633:     d2h_fis[12] = cmd_fis[12];
        !           634:     d2h_fis[13] = cmd_fis[13];
        !           635:     for (i = 14; i < 0x20; i++) {
        !           636:         d2h_fis[i] = 0;
        !           637:     }
        !           638: 
        !           639:     if (d2h_fis[2] & ERR_STAT) {
        !           640:         ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_TFES);
        !           641:     }
        !           642: 
        !           643:     ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
        !           644: 
        !           645:     if (cmd_mapped) {
        !           646:         cpu_physical_memory_unmap(cmd_fis, cmd_len, 0, cmd_len);
        !           647:     }
        !           648: }
        !           649: 
        !           650: static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
        !           651: {
        !           652:     AHCICmdHdr *cmd = ad->cur_cmd;
        !           653:     uint32_t opts = le32_to_cpu(cmd->opts);
        !           654:     uint64_t prdt_addr = le64_to_cpu(cmd->tbl_addr) + 0x80;
        !           655:     int sglist_alloc_hint = opts >> AHCI_CMD_HDR_PRDT_LEN;
        !           656:     target_phys_addr_t prdt_len = (sglist_alloc_hint * sizeof(AHCI_SG));
        !           657:     target_phys_addr_t real_prdt_len = prdt_len;
        !           658:     uint8_t *prdt;
        !           659:     int i;
        !           660:     int r = 0;
        !           661: 
        !           662:     if (!sglist_alloc_hint) {
        !           663:         DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
        !           664:         return -1;
        !           665:     }
        !           666: 
        !           667:     /* map PRDT */
        !           668:     if (!(prdt = cpu_physical_memory_map(prdt_addr, &prdt_len, 0))){
        !           669:         DPRINTF(ad->port_no, "map failed\n");
        !           670:         return -1;
        !           671:     }
        !           672: 
        !           673:     if (prdt_len < real_prdt_len) {
        !           674:         DPRINTF(ad->port_no, "mapped less than expected\n");
        !           675:         r = -1;
        !           676:         goto out;
        !           677:     }
        !           678: 
        !           679:     /* Get entries in the PRDT, init a qemu sglist accordingly */
        !           680:     if (sglist_alloc_hint > 0) {
        !           681:         AHCI_SG *tbl = (AHCI_SG *)prdt;
        !           682: 
        !           683:         qemu_sglist_init(sglist, sglist_alloc_hint);
        !           684:         for (i = 0; i < sglist_alloc_hint; i++) {
        !           685:             /* flags_size is zero-based */
        !           686:             qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
        !           687:                             le32_to_cpu(tbl[i].flags_size) + 1);
        !           688:         }
        !           689:     }
        !           690: 
        !           691: out:
        !           692:     cpu_physical_memory_unmap(prdt, prdt_len, 0, prdt_len);
        !           693:     return r;
        !           694: }
        !           695: 
        !           696: static void ncq_cb(void *opaque, int ret)
        !           697: {
        !           698:     NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
        !           699:     IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
        !           700: 
        !           701:     /* Clear bit for this tag in SActive */
        !           702:     ncq_tfs->drive->port_regs.scr_act &= ~(1 << ncq_tfs->tag);
        !           703: 
        !           704:     if (ret < 0) {
        !           705:         /* error */
        !           706:         ide_state->error = ABRT_ERR;
        !           707:         ide_state->status = READY_STAT | ERR_STAT;
        !           708:         ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
        !           709:     } else {
        !           710:         ide_state->status = READY_STAT | SEEK_STAT;
        !           711:     }
        !           712: 
        !           713:     ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs->drive->port_no,
        !           714:                        (1 << ncq_tfs->tag));
        !           715: 
        !           716:     DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
        !           717:             ncq_tfs->tag);
        !           718: 
        !           719:     qemu_sglist_destroy(&ncq_tfs->sglist);
        !           720:     ncq_tfs->used = 0;
        !           721: }
        !           722: 
        !           723: static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
        !           724:                                 int slot)
        !           725: {
        !           726:     NCQFrame *ncq_fis = (NCQFrame*)cmd_fis;
        !           727:     uint8_t tag = ncq_fis->tag >> 3;
        !           728:     NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[tag];
        !           729: 
        !           730:     if (ncq_tfs->used) {
        !           731:         /* error - already in use */
        !           732:         fprintf(stderr, "%s: tag %d already used\n", __FUNCTION__, tag);
        !           733:         return;
        !           734:     }
        !           735: 
        !           736:     ncq_tfs->used = 1;
        !           737:     ncq_tfs->drive = &s->dev[port];
        !           738:     ncq_tfs->slot = slot;
        !           739:     ncq_tfs->lba = ((uint64_t)ncq_fis->lba5 << 40) |
        !           740:                    ((uint64_t)ncq_fis->lba4 << 32) |
        !           741:                    ((uint64_t)ncq_fis->lba3 << 24) |
        !           742:                    ((uint64_t)ncq_fis->lba2 << 16) |
        !           743:                    ((uint64_t)ncq_fis->lba1 << 8) |
        !           744:                    (uint64_t)ncq_fis->lba0;
        !           745: 
        !           746:     /* Note: We calculate the sector count, but don't currently rely on it.
        !           747:      * The total size of the DMA buffer tells us the transfer size instead. */
        !           748:     ncq_tfs->sector_count = ((uint16_t)ncq_fis->sector_count_high << 8) |
        !           749:                                 ncq_fis->sector_count_low;
        !           750: 
        !           751:     DPRINTF(port, "NCQ transfer LBA from %ld to %ld, drive max %ld\n",
        !           752:             ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
        !           753:             s->dev[port].port.ifs[0].nb_sectors - 1);
        !           754: 
        !           755:     ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist);
        !           756:     ncq_tfs->tag = tag;
        !           757: 
        !           758:     switch(ncq_fis->command) {
        !           759:         case READ_FPDMA_QUEUED:
        !           760:             DPRINTF(port, "NCQ reading %d sectors from LBA %ld, tag %d\n",
        !           761:                     ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
        !           762:             ncq_tfs->is_read = 1;
        !           763: 
        !           764:             DPRINTF(port, "tag %d aio read %ld\n", ncq_tfs->tag, ncq_tfs->lba);
        !           765:             ncq_tfs->aiocb = dma_bdrv_read(ncq_tfs->drive->port.ifs[0].bs,
        !           766:                                            &ncq_tfs->sglist, ncq_tfs->lba,
        !           767:                                            ncq_cb, ncq_tfs);
        !           768:             break;
        !           769:         case WRITE_FPDMA_QUEUED:
        !           770:             DPRINTF(port, "NCQ writing %d sectors to LBA %ld, tag %d\n",
        !           771:                     ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
        !           772:             ncq_tfs->is_read = 0;
        !           773: 
        !           774:             DPRINTF(port, "tag %d aio write %ld\n", ncq_tfs->tag, ncq_tfs->lba);
        !           775:             ncq_tfs->aiocb = dma_bdrv_write(ncq_tfs->drive->port.ifs[0].bs,
        !           776:                                             &ncq_tfs->sglist, ncq_tfs->lba,
        !           777:                                             ncq_cb, ncq_tfs);
        !           778:             break;
        !           779:         default:
        !           780:             DPRINTF(port, "error: tried to process non-NCQ command as NCQ\n");
        !           781:             qemu_sglist_destroy(&ncq_tfs->sglist);
        !           782:             break;
        !           783:     }
        !           784: }
        !           785: 
        !           786: static int handle_cmd(AHCIState *s, int port, int slot)
        !           787: {
        !           788:     IDEState *ide_state;
        !           789:     uint32_t opts;
        !           790:     uint64_t tbl_addr;
        !           791:     AHCICmdHdr *cmd;
        !           792:     uint8_t *cmd_fis;
        !           793:     target_phys_addr_t cmd_len;
        !           794: 
        !           795:     if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
        !           796:         /* Engine currently busy, try again later */
        !           797:         DPRINTF(port, "engine busy\n");
        !           798:         return -1;
        !           799:     }
        !           800: 
        !           801:     cmd = &((AHCICmdHdr *)s->dev[port].lst)[slot];
        !           802: 
        !           803:     if (!s->dev[port].lst) {
        !           804:         DPRINTF(port, "error: lst not given but cmd handled");
        !           805:         return -1;
        !           806:     }
        !           807: 
        !           808:     /* remember current slot handle for later */
        !           809:     s->dev[port].cur_cmd = cmd;
        !           810: 
        !           811:     opts = le32_to_cpu(cmd->opts);
        !           812:     tbl_addr = le64_to_cpu(cmd->tbl_addr);
        !           813: 
        !           814:     cmd_len = 0x80;
        !           815:     cmd_fis = cpu_physical_memory_map(tbl_addr, &cmd_len, 1);
        !           816: 
        !           817:     if (!cmd_fis) {
        !           818:         DPRINTF(port, "error: guest passed us an invalid cmd fis\n");
        !           819:         return -1;
        !           820:     }
        !           821: 
        !           822:     /* The device we are working for */
        !           823:     ide_state = &s->dev[port].port.ifs[0];
        !           824: 
        !           825:     if (!ide_state->bs) {
        !           826:         DPRINTF(port, "error: guest accessed unused port");
        !           827:         goto out;
        !           828:     }
        !           829: 
        !           830:     debug_print_fis(cmd_fis, 0x90);
        !           831:     //debug_print_fis(cmd_fis, (opts & AHCI_CMD_HDR_CMD_FIS_LEN) * 4);
        !           832: 
        !           833:     switch (cmd_fis[0]) {
        !           834:         case SATA_FIS_TYPE_REGISTER_H2D:
        !           835:             break;
        !           836:         default:
        !           837:             DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
        !           838:                           "cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1],
        !           839:                           cmd_fis[2]);
        !           840:             goto out;
        !           841:             break;
        !           842:     }
        !           843: 
        !           844:     switch (cmd_fis[1]) {
        !           845:         case SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER:
        !           846:             break;
        !           847:         case 0:
        !           848:             break;
        !           849:         default:
        !           850:             DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
        !           851:                           "cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1],
        !           852:                           cmd_fis[2]);
        !           853:             goto out;
        !           854:             break;
        !           855:     }
        !           856: 
        !           857:     switch (s->dev[port].port_state) {
        !           858:         case STATE_RUN:
        !           859:             if (cmd_fis[15] & ATA_SRST) {
        !           860:                 s->dev[port].port_state = STATE_RESET;
        !           861:             }
        !           862:             break;
        !           863:         case STATE_RESET:
        !           864:             if (!(cmd_fis[15] & ATA_SRST)) {
        !           865:                 ahci_reset_port(s, port);
        !           866:             }
        !           867:             break;
        !           868:     }
        !           869: 
        !           870:     if (cmd_fis[1] == SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER) {
        !           871: 
        !           872:         /* Check for NCQ command */
        !           873:         if ((cmd_fis[2] == READ_FPDMA_QUEUED) ||
        !           874:             (cmd_fis[2] == WRITE_FPDMA_QUEUED)) {
        !           875:             process_ncq_command(s, port, cmd_fis, slot);
        !           876:             goto out;
        !           877:         }
        !           878: 
        !           879:         /* Decompose the FIS  */
        !           880:         ide_state->nsector = (int64_t)((cmd_fis[13] << 8) | cmd_fis[12]);
        !           881:         ide_state->feature = cmd_fis[3];
        !           882:         if (!ide_state->nsector) {
        !           883:             ide_state->nsector = 256;
        !           884:         }
        !           885: 
        !           886:         if (ide_state->drive_kind != IDE_CD) {
        !           887:             ide_set_sector(ide_state, (cmd_fis[6] << 16) | (cmd_fis[5] << 8) |
        !           888:                            cmd_fis[4]);
        !           889:         }
        !           890: 
        !           891:         /* Copy the ACMD field (ATAPI packet, if any) from the AHCI command
        !           892:          * table to ide_state->io_buffer
        !           893:          */
        !           894:         if (opts & AHCI_CMD_ATAPI) {
        !           895:             memcpy(ide_state->io_buffer, &cmd_fis[AHCI_COMMAND_TABLE_ACMD], 0x10);
        !           896:             ide_state->lcyl = 0x14;
        !           897:             ide_state->hcyl = 0xeb;
        !           898:             debug_print_fis(ide_state->io_buffer, 0x10);
        !           899:             ide_state->feature = IDE_FEATURE_DMA;
        !           900:             s->dev[port].done_atapi_packet = 0;
        !           901:             /* XXX send PIO setup FIS */
        !           902:         }
        !           903: 
        !           904:         ide_state->error = 0;
        !           905: 
        !           906:         /* Reset transferred byte counter */
        !           907:         cmd->status = 0;
        !           908: 
        !           909:         /* We're ready to process the command in FIS byte 2. */
        !           910:         ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
        !           911: 
        !           912:         if (s->dev[port].port.ifs[0].status & READY_STAT) {
        !           913:             ahci_write_fis_d2h(&s->dev[port], cmd_fis);
        !           914:         }
        !           915:     }
        !           916: 
        !           917: out:
        !           918:     cpu_physical_memory_unmap(cmd_fis, cmd_len, 1, cmd_len);
        !           919: 
        !           920:     if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
        !           921:         /* async command, complete later */
        !           922:         s->dev[port].busy_slot = slot;
        !           923:         return -1;
        !           924:     }
        !           925: 
        !           926:     /* done handling the command */
        !           927:     return 0;
        !           928: }
        !           929: 
        !           930: /* DMA dev <-> ram */
        !           931: static int ahci_start_transfer(IDEDMA *dma)
        !           932: {
        !           933:     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
        !           934:     IDEState *s = &ad->port.ifs[0];
        !           935:     uint32_t size = (uint32_t)(s->data_end - s->data_ptr);
        !           936:     /* write == ram -> device */
        !           937:     uint32_t opts = le32_to_cpu(ad->cur_cmd->opts);
        !           938:     int is_write = opts & AHCI_CMD_WRITE;
        !           939:     int is_atapi = opts & AHCI_CMD_ATAPI;
        !           940:     int has_sglist = 0;
        !           941: 
        !           942:     if (is_atapi && !ad->done_atapi_packet) {
        !           943:         /* already prepopulated iobuffer */
        !           944:         ad->done_atapi_packet = 1;
        !           945:         goto out;
        !           946:     }
        !           947: 
        !           948:     if (!ahci_populate_sglist(ad, &s->sg)) {
        !           949:         has_sglist = 1;
        !           950:     }
        !           951: 
        !           952:     DPRINTF(ad->port_no, "%sing %d bytes on %s w/%s sglist\n",
        !           953:             is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata",
        !           954:             has_sglist ? "" : "o");
        !           955: 
        !           956:     if (is_write && has_sglist && (s->data_ptr < s->data_end)) {
        !           957:         read_from_sglist(s->data_ptr, size, &s->sg);
        !           958:     }
        !           959: 
        !           960:     if (!is_write && has_sglist && (s->data_ptr < s->data_end)) {
        !           961:         write_to_sglist(s->data_ptr, size, &s->sg);
        !           962:     }
        !           963: 
        !           964:     /* update number of transferred bytes */
        !           965:     ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + size);
        !           966: 
        !           967: out:
        !           968:     /* declare that we processed everything */
        !           969:     s->data_ptr = s->data_end;
        !           970: 
        !           971:     if (has_sglist) {
        !           972:         qemu_sglist_destroy(&s->sg);
        !           973:     }
        !           974: 
        !           975:     s->end_transfer_func(s);
        !           976: 
        !           977:     if (!(s->status & DRQ_STAT)) {
        !           978:         /* done with DMA */
        !           979:         ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS);
        !           980:     }
        !           981: 
        !           982:     return 0;
        !           983: }
        !           984: 
        !           985: static void ahci_start_dma(IDEDMA *dma, IDEState *s,
        !           986:                            BlockDriverCompletionFunc *dma_cb)
        !           987: {
        !           988:     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
        !           989: 
        !           990:     DPRINTF(ad->port_no, "\n");
        !           991:     ad->dma_cb = dma_cb;
        !           992:     ad->dma_status |= BM_STATUS_DMAING;
        !           993:     dma_cb(s, 0);
        !           994: }
        !           995: 
        !           996: static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
        !           997: {
        !           998:     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
        !           999:     IDEState *s = &ad->port.ifs[0];
        !          1000:     int i;
        !          1001: 
        !          1002:     ahci_populate_sglist(ad, &s->sg);
        !          1003: 
        !          1004:     s->io_buffer_size = 0;
        !          1005:     for (i = 0; i < s->sg.nsg; i++) {
        !          1006:         s->io_buffer_size += s->sg.sg[i].len;
        !          1007:     }
        !          1008: 
        !          1009:     DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
        !          1010:     return s->io_buffer_size != 0;
        !          1011: }
        !          1012: 
        !          1013: static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
        !          1014: {
        !          1015:     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
        !          1016:     IDEState *s = &ad->port.ifs[0];
        !          1017:     uint8_t *p = s->io_buffer + s->io_buffer_index;
        !          1018:     int l = s->io_buffer_size - s->io_buffer_index;
        !          1019: 
        !          1020:     if (ahci_populate_sglist(ad, &s->sg)) {
        !          1021:         return 0;
        !          1022:     }
        !          1023: 
        !          1024:     if (is_write) {
        !          1025:         write_to_sglist(p, l, &s->sg);
        !          1026:     } else {
        !          1027:         read_from_sglist(p, l, &s->sg);
        !          1028:     }
        !          1029: 
        !          1030:     /* update number of transferred bytes */
        !          1031:     ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l);
        !          1032:     s->io_buffer_index += l;
        !          1033: 
        !          1034:     DPRINTF(ad->port_no, "len=%#x\n", l);
        !          1035: 
        !          1036:     return 1;
        !          1037: }
        !          1038: 
        !          1039: static int ahci_dma_set_unit(IDEDMA *dma, int unit)
        !          1040: {
        !          1041:     /* only a single unit per link */
        !          1042:     return 0;
        !          1043: }
        !          1044: 
        !          1045: static int ahci_dma_add_status(IDEDMA *dma, int status)
        !          1046: {
        !          1047:     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
        !          1048:     ad->dma_status |= status;
        !          1049:     DPRINTF(ad->port_no, "set status: %x\n", status);
        !          1050: 
        !          1051:     if (status & BM_STATUS_INT) {
        !          1052:         ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS);
        !          1053:     }
        !          1054: 
        !          1055:     return 0;
        !          1056: }
        !          1057: 
        !          1058: static int ahci_dma_set_inactive(IDEDMA *dma)
        !          1059: {
        !          1060:     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
        !          1061: 
        !          1062:     DPRINTF(ad->port_no, "dma done\n");
        !          1063: 
        !          1064:     /* update d2h status */
        !          1065:     ahci_write_fis_d2h(ad, NULL);
        !          1066: 
        !          1067:     ad->dma_cb = NULL;
        !          1068: 
        !          1069:     /* maybe we still have something to process, check later */
        !          1070:     ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad);
        !          1071:     qemu_bh_schedule(ad->check_bh);
        !          1072: 
        !          1073:     return 0;
        !          1074: }
        !          1075: 
        !          1076: static void ahci_irq_set(void *opaque, int n, int level)
        !          1077: {
        !          1078: }
        !          1079: 
        !          1080: static void ahci_dma_restart_cb(void *opaque, int running, int reason)
        !          1081: {
        !          1082: }
        !          1083: 
        !          1084: static int ahci_dma_reset(IDEDMA *dma)
        !          1085: {
        !          1086:     return 0;
        !          1087: }
        !          1088: 
        !          1089: static const IDEDMAOps ahci_dma_ops = {
        !          1090:     .start_dma = ahci_start_dma,
        !          1091:     .start_transfer = ahci_start_transfer,
        !          1092:     .prepare_buf = ahci_dma_prepare_buf,
        !          1093:     .rw_buf = ahci_dma_rw_buf,
        !          1094:     .set_unit = ahci_dma_set_unit,
        !          1095:     .add_status = ahci_dma_add_status,
        !          1096:     .set_inactive = ahci_dma_set_inactive,
        !          1097:     .restart_cb = ahci_dma_restart_cb,
        !          1098:     .reset = ahci_dma_reset,
        !          1099: };
        !          1100: 
        !          1101: void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
        !          1102: {
        !          1103:     qemu_irq *irqs;
        !          1104:     int i;
        !          1105: 
        !          1106:     s->ports = ports;
        !          1107:     s->dev = qemu_mallocz(sizeof(AHCIDevice) * ports);
        !          1108:     ahci_reg_init(s);
        !          1109:     s->mem = cpu_register_io_memory(ahci_readfn, ahci_writefn, s,
        !          1110:                                     DEVICE_LITTLE_ENDIAN);
        !          1111:     irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports);
        !          1112: 
        !          1113:     for (i = 0; i < s->ports; i++) {
        !          1114:         AHCIDevice *ad = &s->dev[i];
        !          1115: 
        !          1116:         ide_bus_new(&ad->port, qdev, i);
        !          1117:         ide_init2(&ad->port, irqs[i]);
        !          1118: 
        !          1119:         ad->hba = s;
        !          1120:         ad->port_no = i;
        !          1121:         ad->port.dma = &ad->dma;
        !          1122:         ad->port.dma->ops = &ahci_dma_ops;
        !          1123:         ad->port_regs.cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
        !          1124:     }
        !          1125: }
        !          1126: 
        !          1127: void ahci_uninit(AHCIState *s)
        !          1128: {
        !          1129:     qemu_free(s->dev);
        !          1130: }
        !          1131: 
        !          1132: void ahci_pci_map(PCIDevice *pci_dev, int region_num,
        !          1133:         pcibus_t addr, pcibus_t size, int type)
        !          1134: {
        !          1135:     struct AHCIPCIState *d = (struct AHCIPCIState *)pci_dev;
        !          1136:     AHCIState *s = &d->ahci;
        !          1137: 
        !          1138:     cpu_register_physical_memory(addr, size, s->mem);
        !          1139: }
        !          1140: 
        !          1141: void ahci_reset(void *opaque)
        !          1142: {
        !          1143:     struct AHCIPCIState *d = opaque;
        !          1144:     int i;
        !          1145: 
        !          1146:     d->ahci.control_regs.irqstatus = 0;
        !          1147:     d->ahci.control_regs.ghc = 0;
        !          1148: 
        !          1149:     for (i = 0; i < d->ahci.ports; i++) {
        !          1150:         ahci_reset_port(&d->ahci, i);
        !          1151:     }
        !          1152: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.