mirror of https://github.com/xemu-project/xemu.git
libqos/ahci: add NCQ frame support
NCQ frames are generated a little differently than their non-NCQ cousins. Add support for them. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 1435016308-6150-11-git-send-email-jsnow@redhat.com
This commit is contained in:
parent
40d29928ca
commit
cb45304108
|
@ -695,19 +695,34 @@ static void command_header_init(AHCICommand *cmd)
|
||||||
static void command_table_init(AHCICommand *cmd)
|
static void command_table_init(AHCICommand *cmd)
|
||||||
{
|
{
|
||||||
RegH2DFIS *fis = &(cmd->fis);
|
RegH2DFIS *fis = &(cmd->fis);
|
||||||
|
uint16_t sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE);
|
||||||
|
|
||||||
fis->fis_type = REG_H2D_FIS;
|
fis->fis_type = REG_H2D_FIS;
|
||||||
fis->flags = REG_H2D_FIS_CMD; /* "Command" bit */
|
fis->flags = REG_H2D_FIS_CMD; /* "Command" bit */
|
||||||
fis->command = cmd->name;
|
fis->command = cmd->name;
|
||||||
cmd->fis.feature_low = 0x00;
|
|
||||||
cmd->fis.feature_high = 0x00;
|
if (cmd->props->ncq) {
|
||||||
|
NCQFIS *ncqfis = (NCQFIS *)fis;
|
||||||
|
/* NCQ is weird and re-uses FIS frames for unrelated data.
|
||||||
|
* See SATA 3.2, 13.6.4.1 READ FPDMA QUEUED for an example. */
|
||||||
|
ncqfis->sector_low = sect_count & 0xFF;
|
||||||
|
ncqfis->sector_hi = (sect_count >> 8) & 0xFF;
|
||||||
|
ncqfis->device = NCQ_DEVICE_MAGIC;
|
||||||
|
/* Force Unit Access is bit 7 in the device register */
|
||||||
|
ncqfis->tag = 0; /* bits 3-7 are the NCQ tag */
|
||||||
|
ncqfis->prio = 0; /* bits 6,7 are a prio tag */
|
||||||
|
/* RARC bit is bit 0 of TAG field */
|
||||||
|
} else {
|
||||||
|
fis->feature_low = 0x00;
|
||||||
|
fis->feature_high = 0x00;
|
||||||
if (cmd->props->lba28 || cmd->props->lba48) {
|
if (cmd->props->lba28 || cmd->props->lba48) {
|
||||||
cmd->fis.device = ATA_DEVICE_LBA;
|
fis->device = ATA_DEVICE_LBA;
|
||||||
}
|
}
|
||||||
cmd->fis.count = (cmd->xbytes / AHCI_SECTOR_SIZE);
|
fis->count = (cmd->xbytes / AHCI_SECTOR_SIZE);
|
||||||
cmd->fis.icc = 0x00;
|
}
|
||||||
cmd->fis.control = 0x00;
|
fis->icc = 0x00;
|
||||||
memset(cmd->fis.aux, 0x00, ARRAY_SIZE(cmd->fis.aux));
|
fis->control = 0x00;
|
||||||
|
memset(fis->aux, 0x00, ARRAY_SIZE(fis->aux));
|
||||||
}
|
}
|
||||||
|
|
||||||
AHCICommand *ahci_command_create(uint8_t command_name)
|
AHCICommand *ahci_command_create(uint8_t command_name)
|
||||||
|
@ -721,6 +736,7 @@ AHCICommand *ahci_command_create(uint8_t command_name)
|
||||||
g_assert(!(props->lba28 && props->lba48));
|
g_assert(!(props->lba28 && props->lba48));
|
||||||
g_assert(!(props->read && props->write));
|
g_assert(!(props->read && props->write));
|
||||||
g_assert(!props->size || props->data);
|
g_assert(!props->size || props->data);
|
||||||
|
g_assert(!props->ncq || (props->ncq && props->lba48));
|
||||||
|
|
||||||
/* Defaults and book-keeping */
|
/* Defaults and book-keeping */
|
||||||
cmd->props = props;
|
cmd->props = props;
|
||||||
|
@ -789,6 +805,8 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer)
|
||||||
void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
|
void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
|
||||||
unsigned prd_size)
|
unsigned prd_size)
|
||||||
{
|
{
|
||||||
|
uint16_t sect_count;
|
||||||
|
|
||||||
/* Each PRD can describe up to 4MiB, and must not be odd. */
|
/* Each PRD can describe up to 4MiB, and must not be odd. */
|
||||||
g_assert_cmphex(prd_size, <=, 4096 * 1024);
|
g_assert_cmphex(prd_size, <=, 4096 * 1024);
|
||||||
g_assert_cmphex(prd_size & 0x01, ==, 0x00);
|
g_assert_cmphex(prd_size & 0x01, ==, 0x00);
|
||||||
|
@ -796,7 +814,15 @@ void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
|
||||||
cmd->prd_size = prd_size;
|
cmd->prd_size = prd_size;
|
||||||
}
|
}
|
||||||
cmd->xbytes = xbytes;
|
cmd->xbytes = xbytes;
|
||||||
cmd->fis.count = (cmd->xbytes / AHCI_SECTOR_SIZE);
|
sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE);
|
||||||
|
|
||||||
|
if (cmd->props->ncq) {
|
||||||
|
NCQFIS *nfis = (NCQFIS *)&(cmd->fis);
|
||||||
|
nfis->sector_low = sect_count & 0xFF;
|
||||||
|
nfis->sector_hi = (sect_count >> 8) & 0xFF;
|
||||||
|
} else {
|
||||||
|
cmd->fis.count = sect_count;
|
||||||
|
}
|
||||||
cmd->header.prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size);
|
cmd->header.prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -291,8 +291,9 @@ enum {
|
||||||
#define CMDH_PMP (0xF000)
|
#define CMDH_PMP (0xF000)
|
||||||
|
|
||||||
/* ATA device register masks */
|
/* ATA device register masks */
|
||||||
#define ATA_DEVICE_MAGIC 0xA0
|
#define ATA_DEVICE_MAGIC 0xA0 /* used in ata1-3 */
|
||||||
#define ATA_DEVICE_LBA 0x40
|
#define ATA_DEVICE_LBA 0x40
|
||||||
|
#define NCQ_DEVICE_MAGIC 0x40 /* for ncq device registers */
|
||||||
#define ATA_DEVICE_DRIVE 0x10
|
#define ATA_DEVICE_DRIVE 0x10
|
||||||
#define ATA_DEVICE_HEAD 0x0F
|
#define ATA_DEVICE_HEAD 0x0F
|
||||||
|
|
||||||
|
@ -396,6 +397,32 @@ typedef struct RegH2DFIS {
|
||||||
uint8_t aux[4];
|
uint8_t aux[4];
|
||||||
} __attribute__((__packed__)) RegH2DFIS;
|
} __attribute__((__packed__)) RegH2DFIS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register host-to-device FIS structure, for NCQ commands.
|
||||||
|
* Actually just a RegH2DFIS, but with fields repurposed.
|
||||||
|
* Repurposed fields are annotated below.
|
||||||
|
*/
|
||||||
|
typedef struct NCQFIS {
|
||||||
|
/* DW0 */
|
||||||
|
uint8_t fis_type;
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t command;
|
||||||
|
uint8_t sector_low; /* H2D: Feature 7:0 */
|
||||||
|
/* DW1 */
|
||||||
|
uint8_t lba_lo[3];
|
||||||
|
uint8_t device;
|
||||||
|
/* DW2 */
|
||||||
|
uint8_t lba_hi[3];
|
||||||
|
uint8_t sector_hi; /* H2D: Feature 15:8 */
|
||||||
|
/* DW3 */
|
||||||
|
uint8_t tag; /* H2D: Count 0:7 */
|
||||||
|
uint8_t prio; /* H2D: Count 15:8 */
|
||||||
|
uint8_t icc;
|
||||||
|
uint8_t control;
|
||||||
|
/* DW4 */
|
||||||
|
uint8_t aux[4];
|
||||||
|
} __attribute__((__packed__)) NCQFIS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command List entry structure.
|
* Command List entry structure.
|
||||||
* The command list contains between 1-32 of these structures.
|
* The command list contains between 1-32 of these structures.
|
||||||
|
|
Loading…
Reference in New Issue