提交 54d268b2 编写于 作者: J John Snow

libqos/ahci: ATAPI support

Add pathways to tolerate ATAPI commands.

Notably, unlike ATA, each SCSI command's layout is a little different,
so support will have to be patched in for each command as we want to
test them in e.g. ahci_command_set_sizes and ahci_command_set_offset.

For now, I'm adding support for 0x28, READ (10).

[Maintainer edit: replaced type-punning with stl_be_p(). --js]
Signed-off-by: NJohn Snow <jsnow@redhat.com>
Message-id: 1452282920-21550-3-git-send-email-jsnow@redhat.com
上级 248de4a8
...@@ -74,7 +74,11 @@ AHCICommandProp ahci_command_properties[] = { ...@@ -74,7 +74,11 @@ AHCICommandProp ahci_command_properties[] = {
.lba48 = true, .write = true, .ncq = true }, .lba48 = true, .write = true, .ncq = true },
{ .cmd = CMD_READ_MAX, .lba28 = true }, { .cmd = CMD_READ_MAX, .lba28 = true },
{ .cmd = CMD_READ_MAX_EXT, .lba48 = 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, },
{ .cmd = CMD_PACKET_ID, .data = true, .pio = true,
.size = 512, .read = true }
}; };
struct AHCICommand { struct AHCICommand {
...@@ -90,7 +94,7 @@ struct AHCICommand { ...@@ -90,7 +94,7 @@ struct AHCICommand {
/* Data to be transferred to the guest */ /* Data to be transferred to the guest */
AHCICommandHeader header; AHCICommandHeader header;
RegH2DFIS fis; RegH2DFIS fis;
void *atapi_cmd; unsigned char *atapi_cmd;
}; };
/** /**
...@@ -731,6 +735,13 @@ static void command_table_init(AHCICommand *cmd) ...@@ -731,6 +735,13 @@ static void command_table_init(AHCICommand *cmd)
memset(fis->aux, 0x00, ARRAY_SIZE(fis->aux)); 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;
}
AHCICommand *ahci_command_create(uint8_t command_name) AHCICommand *ahci_command_create(uint8_t command_name)
{ {
AHCICommandProp *props = ahci_command_find(command_name); AHCICommandProp *props = ahci_command_find(command_name);
...@@ -767,8 +778,22 @@ AHCICommand *ahci_command_create(uint8_t command_name) ...@@ -767,8 +778,22 @@ AHCICommand *ahci_command_create(uint8_t command_name)
return cmd; 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) void ahci_command_free(AHCICommand *cmd)
{ {
g_free(cmd->atapi_cmd);
g_free(cmd); g_free(cmd);
} }
...@@ -782,10 +807,31 @@ void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags) ...@@ -782,10 +807,31 @@ void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags)
cmd->header.flags &= ~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) void ahci_command_set_offset(AHCICommand *cmd, uint64_t lba_sect)
{ {
RegH2DFIS *fis = &(cmd->fis); 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->lba28) {
g_assert_cmphex(lba_sect, <=, 0xFFFFFFF); g_assert_cmphex(lba_sect, <=, 0xFFFFFFF);
} else if (cmd->props->lba48 || cmd->props->ncq) { } else if (cmd->props->lba48 || cmd->props->ncq) {
g_assert_cmphex(lba_sect, <=, 0xFFFFFFFFFFFF); g_assert_cmphex(lba_sect, <=, 0xFFFFFFFFFFFF);
...@@ -811,6 +857,24 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer) ...@@ -811,6 +857,24 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer)
cmd->buffer = 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, void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
unsigned prd_size) unsigned prd_size)
{ {
...@@ -829,6 +893,8 @@ void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes, ...@@ -829,6 +893,8 @@ void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
NCQFIS *nfis = (NCQFIS *)&(cmd->fis); NCQFIS *nfis = (NCQFIS *)&(cmd->fis);
nfis->sector_low = sect_count & 0xFF; nfis->sector_low = sect_count & 0xFF;
nfis->sector_hi = (sect_count >> 8) & 0xFF; nfis->sector_hi = (sect_count >> 8) & 0xFF;
} else if (cmd->props->atapi) {
ahci_atapi_set_size(cmd, xbytes);
} else { } else {
cmd->fis.count = sect_count; cmd->fis.count = sect_count;
} }
...@@ -877,9 +943,14 @@ void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port) ...@@ -877,9 +943,14 @@ void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port)
g_assert((table_ptr & 0x7F) == 0x00); g_assert((table_ptr & 0x7F) == 0x00);
cmd->header.ctba = table_ptr; 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)); 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); 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 */ /* Construct and write the PRDs to the command table */
g_assert_cmphex(prdtl, ==, cmd->header.prdtl); g_assert_cmphex(prdtl, ==, cmd->header.prdtl);
......
...@@ -244,6 +244,10 @@ ...@@ -244,6 +244,10 @@
#define AHCI_VERSION_1_3 (0x00010300) #define AHCI_VERSION_1_3 (0x00010300)
#define AHCI_SECTOR_SIZE (512) #define AHCI_SECTOR_SIZE (512)
#define ATAPI_SECTOR_SIZE (2048)
#define AHCI_SIGNATURE_CDROM (0xeb140101)
#define AHCI_SIGNATURE_DISK (0x00000101)
/* FIS types */ /* FIS types */
enum { enum {
...@@ -277,11 +281,18 @@ enum { ...@@ -277,11 +281,18 @@ enum {
CMD_READ_MAX_EXT = 0x27, CMD_READ_MAX_EXT = 0x27,
CMD_FLUSH_CACHE = 0xE7, CMD_FLUSH_CACHE = 0xE7,
CMD_IDENTIFY = 0xEC, CMD_IDENTIFY = 0xEC,
CMD_PACKET = 0xA0,
CMD_PACKET_ID = 0xA1,
/* NCQ */ /* NCQ */
READ_FPDMA_QUEUED = 0x60, READ_FPDMA_QUEUED = 0x60,
WRITE_FPDMA_QUEUED = 0x61, WRITE_FPDMA_QUEUED = 0x61,
}; };
/* ATAPI Commands */
enum {
CMD_ATAPI_READ_10 = 0x28,
};
/* AHCI Command Header Flags & Masks*/ /* AHCI Command Header Flags & Masks*/
#define CMDH_CFL (0x1F) #define CMDH_CFL (0x1F)
#define CMDH_ATAPI (0x20) #define CMDH_ATAPI (0x20)
...@@ -561,6 +572,7 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, ...@@ -561,6 +572,7 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
/* Command Lifecycle */ /* Command Lifecycle */
AHCICommand *ahci_command_create(uint8_t command_name); 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_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port);
void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd); void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd);
void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd); void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd);
...@@ -577,6 +589,8 @@ void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes); ...@@ -577,6 +589,8 @@ 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_prd_size(AHCICommand *cmd, unsigned prd_size);
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);
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, void ahci_command_adjust(AHCICommand *cmd, uint64_t lba_sect, uint64_t gbuffer,
uint64_t xbytes, unsigned prd_size); uint64_t xbytes, unsigned prd_size);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册