提交 cb453041 编写于 作者: J John Snow

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: NJohn Snow <jsnow@redhat.com>
Reviewed-by: NStefan Hajnoczi <stefanha@redhat.com>
Message-id: 1435016308-6150-11-git-send-email-jsnow@redhat.com
上级 40d29928
...@@ -695,19 +695,34 @@ static void command_header_init(AHCICommand *cmd) ...@@ -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) {
if (cmd->props->lba28 || cmd->props->lba48) { NCQFIS *ncqfis = (NCQFIS *)fis;
cmd->fis.device = ATA_DEVICE_LBA; /* 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) {
fis->device = ATA_DEVICE_LBA;
}
fis->count = (cmd->xbytes / AHCI_SECTOR_SIZE);
} }
cmd->fis.count = (cmd->xbytes / AHCI_SECTOR_SIZE); fis->icc = 0x00;
cmd->fis.icc = 0x00; fis->control = 0x00;
cmd->fis.control = 0x00; memset(fis->aux, 0x00, ARRAY_SIZE(fis->aux));
memset(cmd->fis.aux, 0x00, ARRAY_SIZE(cmd->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) ...@@ -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) ...@@ -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, ...@@ -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 { ...@@ -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 { ...@@ -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.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册