Commit cf57c2f1 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/jnsnow/tags/ide-pull-request' into staging



# gpg: Signature made Mon 11 Jan 2016 19:16:27 GMT using RSA key ID AAFC390E
# gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>"

* remotes/jnsnow/tags/ide-pull-request:
  libqos/ahci: organize header
  qtest/ahci: ATAPI data tests
  libqos/ahci: add ahci_exec
  libqos/ahci: allow nondata commands for ahci_io variants
  libqos: allow zero-size allocations
  libqos/ahci: Switch to mutable properties
  libqos/ahci: ATAPI identify
  libqos/ahci: ATAPI support
  ahci-test: fix memory leak
  ide: ahci: reset ncq object to unused on error
  macio: fix overflow in lba to offset conversion for ATAPI devices

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 7b8a354d c5620e65
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -910,6 +910,7 @@ static void ncq_err(NCQTransferState *ncq_tfs)
    ide_state->error = ABRT_ERR;
    ide_state->status = READY_STAT | ERR_STAT;
    ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
    ncq_tfs->used = 0;
}

static void ncq_finish(NCQTransferState *ncq_tfs)
+1 −1
Original line number Diff line number Diff line
@@ -280,7 +280,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
    }

    /* Calculate current offset */
    offset = (int64_t)(s->lba << 11) + s->io_buffer_index;
    offset = ((int64_t)s->lba << 11) + s->io_buffer_index;

    pmac_dma_read(s->blk, offset, io->len, pmac_ide_atapi_transfer_cb, io);
    return;
+109 −22
Original line number Diff line number Diff line
@@ -215,6 +215,7 @@ static AHCIQState *ahci_boot_and_enable(const char *cli, ...)
    va_list ap;
    uint16_t buff[256];
    uint8_t port;
    uint8_t hello;

    if (cli) {
        va_start(ap, cli);
@@ -229,7 +230,12 @@ static AHCIQState *ahci_boot_and_enable(const char *cli, ...)
    /* Initialize test device */
    port = ahci_port_select(ahci);
    ahci_port_clear(ahci, port);
    ahci_io(ahci, port, CMD_IDENTIFY, &buff, sizeof(buff), 0);
    if (is_atapi(ahci, port)) {
        hello = CMD_PACKET_ID;
    } else {
        hello = CMD_IDENTIFY;
    }
    ahci_io(ahci, port, hello, &buff, sizeof(buff), 0);

    return ahci;
}
@@ -884,18 +890,12 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize,
static uint8_t ahci_test_nondata(AHCIQState *ahci, uint8_t ide_cmd)
{
    uint8_t port;
    AHCICommand *cmd;

    /* Sanitize */
    port = ahci_port_select(ahci);
    ahci_port_clear(ahci, port);

    /* Issue Command */
    cmd = ahci_command_create(ide_cmd);
    ahci_command_commit(ahci, cmd, port);
    ahci_command_issue(ahci, cmd);
    ahci_command_verify(ahci, cmd);
    ahci_command_free(cmd);
    ahci_io(ahci, port, ide_cmd, NULL, 0, 0);

    return port;
}
@@ -1045,14 +1045,14 @@ static void test_dma_fragmented(void)
    ahci_command_commit(ahci, cmd, px);
    ahci_command_issue(ahci, cmd);
    ahci_command_verify(ahci, cmd);
    g_free(cmd);
    ahci_command_free(cmd);

    cmd = ahci_command_create(CMD_READ_DMA);
    ahci_command_adjust(cmd, 0, ptr, bufsize, 32);
    ahci_command_commit(ahci, cmd, px);
    ahci_command_issue(ahci, cmd);
    ahci_command_verify(ahci, cmd);
    g_free(cmd);
    ahci_command_free(cmd);

    /* Read back the guest's receive buffer into local memory */
    bufread(ptr, rx, bufsize);
@@ -1080,7 +1080,6 @@ static void test_flush_retry(void)
    AHCIQState *ahci;
    AHCICommand *cmd;
    uint8_t port;
    const char *s;

    prepare_blkdebug_script(debug_path, "flush_to_disk");
    ahci = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0,"
@@ -1094,19 +1093,10 @@ static void test_flush_retry(void)
    /* Issue Flush Command and wait for error */
    port = ahci_port_select(ahci);
    ahci_port_clear(ahci, port);
    cmd = ahci_command_create(CMD_FLUSH_CACHE);
    ahci_command_commit(ahci, cmd, port);
    ahci_command_issue_async(ahci, cmd);
    qmp_eventwait("STOP");

    /* Complete the command */
    s = "{'execute':'cont' }";
    qmp_async(s);
    qmp_eventwait("RESUME");
    ahci_command_wait(ahci, cmd);
    ahci_command_verify(ahci, cmd);
    cmd = ahci_guest_io_halt(ahci, port, CMD_FLUSH_CACHE, 0, 0, 0);
    ahci_guest_io_resume(ahci, cmd);

    ahci_command_free(cmd);
    ahci_shutdown(ahci);
}

@@ -1423,6 +1413,98 @@ static void test_ncq_simple(void)
    ahci_shutdown(ahci);
}

static int prepare_iso(size_t size, unsigned char **buf, char **name)
{
    char cdrom_path[] = "/tmp/qtest.iso.XXXXXX";
    unsigned char *patt;
    ssize_t ret;
    int fd = mkstemp(cdrom_path);

    g_assert(buf);
    g_assert(name);
    patt = g_malloc(size);

    /* Generate a pattern and build a CDROM image to read from */
    generate_pattern(patt, size, ATAPI_SECTOR_SIZE);
    ret = write(fd, patt, size);
    g_assert(ret == size);

    *name = g_strdup(cdrom_path);
    *buf = patt;
    return fd;
}

static void remove_iso(int fd, char *name)
{
    unlink(name);
    g_free(name);
    close(fd);
}

static int ahci_cb_cmp_buff(AHCIQState *ahci, AHCICommand *cmd,
                            const AHCIOpts *opts)
{
    unsigned char *tx = opts->opaque;
    unsigned char *rx = g_malloc0(opts->size);

    bufread(opts->buffer, rx, opts->size);
    g_assert_cmphex(memcmp(tx, rx, opts->size), ==, 0);
    g_free(rx);

    return 0;
}

static void ahci_test_cdrom(int nsectors, bool dma)
{
    AHCIQState *ahci;
    unsigned char *tx;
    char *iso;
    int fd;
    AHCIOpts opts = {
        .size = (ATAPI_SECTOR_SIZE * nsectors),
        .atapi = true,
        .atapi_dma = dma,
        .post_cb = ahci_cb_cmp_buff,
    };

    /* Prepare ISO and fill 'tx' buffer */
    fd = prepare_iso(1024 * 1024, &tx, &iso);
    opts.opaque = tx;

    /* Standard startup wonkery, but use ide-cd and our special iso file */
    ahci = ahci_boot_and_enable("-drive if=none,id=drive0,file=%s,format=raw "
                                "-M q35 "
                                "-device ide-cd,drive=drive0 ", iso);

    /* Build & Send AHCI command */
    ahci_exec(ahci, ahci_port_select(ahci), CMD_ATAPI_READ_10, &opts);

    /* Cleanup */
    g_free(tx);
    ahci_shutdown(ahci);
    remove_iso(fd, iso);
}

static void test_cdrom_dma(void)
{
    ahci_test_cdrom(1, true);
}

static void test_cdrom_dma_multi(void)
{
    ahci_test_cdrom(3, true);
}

static void test_cdrom_pio(void)
{
    ahci_test_cdrom(1, false);
}

static void test_cdrom_pio_multi(void)
{
    ahci_test_cdrom(3, false);
}

/******************************************************************************/
/* AHCI I/O Test Matrix Definitions                                           */

@@ -1707,6 +1789,11 @@ int main(int argc, char **argv)
    qtest_add_func("/ahci/io/ncq/retry", test_halted_ncq);
    qtest_add_func("/ahci/migrate/ncq/halted", test_migrate_halted_ncq);

    qtest_add_func("/ahci/cdrom/dma/single", test_cdrom_dma);
    qtest_add_func("/ahci/cdrom/dma/multi", test_cdrom_dma_multi);
    qtest_add_func("/ahci/cdrom/pio/single", test_cdrom_pio);
    qtest_add_func("/ahci/cdrom/pio/multi", test_cdrom_pio_multi);

    ret = g_test_run();

    /* Cleanup */
+169 −8
Original line number Diff line number Diff line
@@ -74,7 +74,11 @@ AHCICommandProp ahci_command_properties[] = {
                                 .lba48 = true, .write = true, .ncq = true },
    { .cmd = CMD_READ_MAX,       .lba28 = true },
    { .cmd = CMD_READ_MAX_EXT,   .lba48 = true },
    { .cmd = CMD_FLUSH_CACHE,    .data = false }
    { .cmd = CMD_FLUSH_CACHE,    .data = false },
    { .cmd = CMD_PACKET,         .data = true,  .size = 16,
                                 .atapi = true, .pio = true },
    { .cmd = CMD_PACKET_ID,      .data = true,  .pio = true,
                                 .size = 512,   .read = true }
};

struct AHCICommand {
@@ -90,7 +94,7 @@ struct AHCICommand {
    /* Data to be transferred to the guest */
    AHCICommandHeader header;
    RegH2DFIS fis;
    void *atapi_cmd;
    unsigned char *atapi_cmd;
};

/**
@@ -110,6 +114,11 @@ void ahci_free(AHCIQState *ahci, uint64_t addr)
    qfree(ahci->parent, addr);
}

bool is_atapi(AHCIQState *ahci, uint8_t port)
{
    return ahci_px_rreg(ahci, port, AHCI_PX_SIG) == AHCI_SIGNATURE_CDROM;
}

/**
 * Locate, verify, and return a handle to the AHCI device.
 */
@@ -592,6 +601,82 @@ inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd)
    return (bytes + bytes_per_prd - 1) / bytes_per_prd;
}

const AHCIOpts default_opts = { .size = 0 };

/**
 * ahci_exec: execute a given command on a specific
 * AHCI port.
 *
 * @ahci: The device to send the command to
 * @port: The port number of the SATA device we wish
 *        to have execute this command
 * @op:   The S/ATA command to execute, or if opts.atapi
 *        is true, the SCSI command code.
 * @opts: Optional arguments to modify execution behavior.
 */
void ahci_exec(AHCIQState *ahci, uint8_t port,
               uint8_t op, const AHCIOpts *opts_in)
{
    AHCICommand *cmd;
    int rc;
    AHCIOpts *opts;

    opts = g_memdup((opts_in == NULL ? &default_opts : opts_in),
                    sizeof(AHCIOpts));

    /* No guest buffer provided, create one. */
    if (opts->size && !opts->buffer) {
        opts->buffer = ahci_alloc(ahci, opts->size);
        g_assert(opts->buffer);
        qmemset(opts->buffer, 0x00, opts->size);
    }

    /* Command creation */
    if (opts->atapi) {
        cmd = ahci_atapi_command_create(op);
        if (opts->atapi_dma) {
            ahci_command_enable_atapi_dma(cmd);
        }
    } else {
        cmd = ahci_command_create(op);
    }
    ahci_command_adjust(cmd, opts->lba, opts->buffer,
                        opts->size, opts->prd_size);

    if (opts->pre_cb) {
        rc = opts->pre_cb(ahci, cmd, opts);
        g_assert_cmpint(rc, ==, 0);
    }

    /* Write command to memory and issue it */
    ahci_command_commit(ahci, cmd, port);
    ahci_command_issue_async(ahci, cmd);
    if (opts->error) {
        qmp_eventwait("STOP");
    }
    if (opts->mid_cb) {
        rc = opts->mid_cb(ahci, cmd, opts);
        g_assert_cmpint(rc, ==, 0);
    }
    if (opts->error) {
        qmp_async("{'execute':'cont' }");
        qmp_eventwait("RESUME");
    }

    /* Wait for command to complete and verify sanity */
    ahci_command_wait(ahci, cmd);
    ahci_command_verify(ahci, cmd);
    if (opts->post_cb) {
        rc = opts->post_cb(ahci, cmd, opts);
        g_assert_cmpint(rc, ==, 0);
    }
    ahci_command_free(cmd);
    if (opts->buffer != opts_in->buffer) {
        ahci_free(ahci, opts->buffer);
    }
    g_free(opts);
}

/* Issue a command, expecting it to fail and STOP the VM */
AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port,
                                uint8_t ide_cmd, uint64_t buffer,
@@ -659,16 +744,16 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
    props = ahci_command_find(ide_cmd);
    g_assert(props);
    ptr = ahci_alloc(ahci, bufsize);
    g_assert(ptr);
    g_assert(!bufsize || ptr);
    qmemset(ptr, 0x00, bufsize);

    if (props->write) {
    if (bufsize && props->write) {
        bufwrite(ptr, buffer, bufsize);
    }

    ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize, sector);

    if (props->read) {
    if (bufsize && props->read) {
        bufread(ptr, buffer, bufsize);
    }

@@ -731,6 +816,18 @@ static void command_table_init(AHCICommand *cmd)
    memset(fis->aux, 0x00, ARRAY_SIZE(fis->aux));
}

void ahci_command_enable_atapi_dma(AHCICommand *cmd)
{
    RegH2DFIS *fis = &(cmd->fis);
    g_assert(cmd->props->atapi);
    fis->feature_low |= 0x01;
    cmd->interrupts &= ~AHCI_PX_IS_PSS;
    cmd->props->dma = true;
    cmd->props->pio = false;
    /* BUG: We expect the DMA Setup interrupt for DMA commands */
    /* cmd->interrupts |= AHCI_PX_IS_DSS; */
}

AHCICommand *ahci_command_create(uint8_t command_name)
{
    AHCICommandProp *props = ahci_command_find(command_name);
@@ -745,7 +842,7 @@ AHCICommand *ahci_command_create(uint8_t command_name)
    g_assert(!props->ncq || props->lba48);

    /* Defaults and book-keeping */
    cmd->props = props;
    cmd->props = g_memdup(props, sizeof(AHCICommandProp));
    cmd->name = command_name;
    cmd->xbytes = props->size;
    cmd->prd_size = 4096;
@@ -767,8 +864,23 @@ AHCICommand *ahci_command_create(uint8_t command_name)
    return cmd;
}

AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd)
{
    AHCICommand *cmd = ahci_command_create(CMD_PACKET);
    cmd->atapi_cmd = g_malloc0(16);
    cmd->atapi_cmd[0] = scsi_cmd;
    /* ATAPI needs a PIO transfer chunk size set inside of the LBA registers.
     * The block/sector size is a natural default. */
    cmd->fis.lba_lo[1] = ATAPI_SECTOR_SIZE >> 8 & 0xFF;
    cmd->fis.lba_lo[2] = ATAPI_SECTOR_SIZE & 0xFF;

    return cmd;
}

void ahci_command_free(AHCICommand *cmd)
{
    g_free(cmd->atapi_cmd);
    g_free(cmd->props);
    g_free(cmd);
}

@@ -782,10 +894,34 @@ void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags)
    cmd->header.flags &= ~cmdh_flags;
}

static void ahci_atapi_command_set_offset(AHCICommand *cmd, uint64_t lba)
{
    unsigned char *cbd = cmd->atapi_cmd;
    g_assert(cbd);

    switch (cbd[0]) {
    case CMD_ATAPI_READ_10:
        g_assert_cmpuint(lba, <=, UINT32_MAX);
        stl_be_p(&cbd[2], lba);
        break;
    default:
        /* SCSI doesn't have uniform packet formats,
         * so you have to add support for it manually. Sorry! */
        g_assert_not_reached();
    }
}

void ahci_command_set_offset(AHCICommand *cmd, uint64_t lba_sect)
{
    RegH2DFIS *fis = &(cmd->fis);
    if (cmd->props->lba28) {

    if (cmd->props->atapi) {
        ahci_atapi_command_set_offset(cmd, lba_sect);
        return;
    } else if (!cmd->props->data && !lba_sect) {
        /* Not meaningful, ignore. */
        return;
    } else if (cmd->props->lba28) {
        g_assert_cmphex(lba_sect, <=, 0xFFFFFFF);
    } else if (cmd->props->lba48 || cmd->props->ncq) {
        g_assert_cmphex(lba_sect, <=, 0xFFFFFFFFFFFF);
@@ -811,6 +947,24 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer)
    cmd->buffer = buffer;
}

static void ahci_atapi_set_size(AHCICommand *cmd, uint64_t xbytes)
{
    unsigned char *cbd = cmd->atapi_cmd;
    uint64_t nsectors = xbytes / 2048;
    g_assert(cbd);

    switch (cbd[0]) {
    case CMD_ATAPI_READ_10:
        g_assert_cmpuint(nsectors, <=, UINT16_MAX);
        stw_be_p(&cbd[7], nsectors);
        break;
    default:
        /* SCSI doesn't have uniform packet formats,
         * so you have to add support for it manually. Sorry! */
        g_assert_not_reached();
    }
}

void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
                            unsigned prd_size)
{
@@ -829,6 +983,8 @@ void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
        NCQFIS *nfis = (NCQFIS *)&(cmd->fis);
        nfis->sector_low = sect_count & 0xFF;
        nfis->sector_hi = (sect_count >> 8) & 0xFF;
    } else if (cmd->props->atapi) {
        ahci_atapi_set_size(cmd, xbytes);
    } else {
        cmd->fis.count = sect_count;
    }
@@ -877,9 +1033,14 @@ void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port)
    g_assert((table_ptr & 0x7F) == 0x00);
    cmd->header.ctba = table_ptr;

    /* Commit the command header and command FIS */
    /* Commit the command header (part of the Command List Buffer) */
    ahci_set_command_header(ahci, port, cmd->slot, &(cmd->header));
    /* Now, write the command table (FIS, ACMD, and PRDT) -- FIS first, */
    ahci_write_fis(ahci, cmd);
    /* Then ATAPI CMD, if needed */
    if (cmd->props->atapi) {
        memwrite(table_ptr + 0x40, cmd->atapi_cmd, 16);
    }

    /* Construct and write the PRDs to the command table */
    g_assert_cmphex(prdtl, ==, cmd->header.prdtl);
+55 −11
Original line number Diff line number Diff line
@@ -244,6 +244,10 @@
#define AHCI_VERSION_1_3         (0x00010300)

#define AHCI_SECTOR_SIZE                (512)
#define ATAPI_SECTOR_SIZE              (2048)

#define AHCI_SIGNATURE_CDROM     (0xeb140101)
#define AHCI_SIGNATURE_DISK      (0x00000101)

/* FIS types */
enum {
@@ -277,11 +281,18 @@ enum {
    CMD_READ_MAX_EXT   = 0x27,
    CMD_FLUSH_CACHE    = 0xE7,
    CMD_IDENTIFY       = 0xEC,
    CMD_PACKET         = 0xA0,
    CMD_PACKET_ID      = 0xA1,
    /* NCQ */
    READ_FPDMA_QUEUED  = 0x60,
    WRITE_FPDMA_QUEUED = 0x61,
};

/* ATAPI Commands */
enum {
    CMD_ATAPI_READ_10 = 0x28,
};

/* AHCI Command Header Flags & Masks*/
#define CMDH_CFL        (0x1F)
#define CMDH_ATAPI      (0x20)
@@ -451,6 +462,21 @@ typedef struct PRD {
/* Opaque, defined within ahci.c */
typedef struct AHCICommand AHCICommand;

/* Options to ahci_exec */
typedef struct AHCIOpts {
    size_t size;
    unsigned prd_size;
    uint64_t lba;
    uint64_t buffer;
    bool atapi;
    bool atapi_dma;
    bool error;
    int (*pre_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *);
    int (*mid_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *);
    int (*post_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *);
    void *opaque;
} AHCIOpts;

/*** Macro Utilities ***/
#define BITANY(data, mask) (((data) & (mask)) != 0)
#define BITSET(data, mask) (((data) & (mask)) == (mask))
@@ -527,14 +553,28 @@ static inline void ahci_px_clr(AHCIQState *ahci, uint8_t port,
/*** Prototypes ***/
uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes);
void ahci_free(AHCIQState *ahci, uint64_t addr);
void ahci_clean_mem(AHCIQState *ahci);

/* Device management */
QPCIDevice *get_ahci_device(uint32_t *fingerprint);
void free_ahci_device(QPCIDevice *dev);
void ahci_clean_mem(AHCIQState *ahci);
void ahci_pci_enable(AHCIQState *ahci);
void start_ahci_device(AHCIQState *ahci);
void ahci_hba_enable(AHCIQState *ahci);

/* Port Management */
unsigned ahci_port_select(AHCIQState *ahci);
void ahci_port_clear(AHCIQState *ahci, uint8_t port);

/* Command header / table management */
unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port);
void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
                             uint8_t slot, AHCICommandHeader *cmd);
void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
                             uint8_t slot, AHCICommandHeader *cmd);
void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot);

/* AHCI sanity check routines */
void ahci_port_check_error(AHCIQState *ahci, uint8_t port);
void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port,
                                uint32_t intr_mask);
@@ -543,14 +583,12 @@ void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot);
void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port,
                                uint8_t slot, size_t buffsize);
void ahci_port_check_cmd_sanity(AHCIQState *ahci, AHCICommand *cmd);
void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
                             uint8_t slot, AHCICommandHeader *cmd);
void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
                             uint8_t slot, AHCICommandHeader *cmd);
void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot);
void ahci_write_fis(AHCIQState *ahci, AHCICommand *cmd);
unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port);

/* Misc */
bool is_atapi(AHCIQState *ahci, uint8_t port);
unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd);

/* Command: Macro level execution */
void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
                   uint64_t gbuffer, size_t size, uint64_t sector);
AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
@@ -558,9 +596,12 @@ AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
void ahci_guest_io_resume(AHCIQState *ahci, AHCICommand *cmd);
void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
             void *buffer, size_t bufsize, uint64_t sector);
void ahci_exec(AHCIQState *ahci, uint8_t port,
               uint8_t op, const AHCIOpts *opts);

/* Command Lifecycle */
/* Command: Fine-grained lifecycle */
AHCICommand *ahci_command_create(uint8_t command_name);
AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd);
void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port);
void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd);
void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd);
@@ -568,7 +609,7 @@ void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd);
void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd);
void ahci_command_free(AHCICommand *cmd);

/* Command adjustments */
/* Command: adjustments */
void ahci_command_set_flags(AHCICommand *cmd, uint16_t cmdh_flags);
void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags);
void ahci_command_set_offset(AHCICommand *cmd, uint64_t lba_sect);
@@ -577,10 +618,13 @@ void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes);
void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size);
void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
                            unsigned prd_size);
void ahci_command_set_acmd(AHCICommand *cmd, void *acmd);
void ahci_command_enable_atapi_dma(AHCICommand *cmd);
void ahci_command_adjust(AHCICommand *cmd, uint64_t lba_sect, uint64_t gbuffer,
                         uint64_t xbytes, unsigned prd_size);

/* Command Misc */
/* Command: Misc */
uint8_t ahci_command_slot(AHCICommand *cmd);
void ahci_write_fis(AHCIQState *ahci, AHCICommand *cmd);

#endif
Loading