ahci: add sync operation support

- implemement 'flush cache ext' for ATA
- enable sync operation for request stream

issue #3636
This commit is contained in:
Sebastian Sumpf 2020-02-19 14:10:17 +01:00 committed by Norman Feske
parent e096202b1f
commit 5225d12381
4 changed files with 42 additions and 19 deletions

View File

@ -250,6 +250,13 @@ namespace Ahci {
write<Sector0_7::Tag>(slot);
}
void flush_cache_ext()
{
write<Bits::C>(1);
write<Device::Lba>(0);
write<Command>(0xea);
}
void atapi()
{
write<Bits::C>(1);

View File

@ -171,10 +171,14 @@ class Ata::Protocol : public Ahci::Protocol, Noncopyable
(pending_start >= block_number && pending_start <= end) ||
(pending_end >= block_number && pending_end <= end)) {
warning("overlap: "
warning("overlap: ",
"pending ", pending_start,
" + ", req.operation.count, ", "
"request: ", block_number, " + ", request.operation.count);
" + ", req.operation.count,
" (", req.operation.type == Block::Operation::Type::WRITE ?
"write" : "read", "), ",
"request: ", block_number, " + ", request.operation.count,
" (", request.operation.type == Block::Operation::Type::WRITE ?
"write" : "read", ")");
return true;
}
@ -248,10 +252,14 @@ class Ata::Protocol : public Ahci::Protocol, Noncopyable
void handle_irq(Port &port) override
{
unsigned is = port.read<Port::Is>();
/* ncg */
if (_ncq_support(port))
while (Port::Is::Sdbs::get(port.read<Port::Is>()))
if (_ncq_support(port) && Port::Is::Fpdma_irq::get(is))
do {
port.ack_irq();
}
while (Port::Is::Sdbs::get(port.read<Port::Is>()));
/* normal dma */
else if (Port::Is::Dma_ext_irq::get(port.read<Port::Is>()))
port.ack_irq();
@ -272,14 +280,16 @@ class Ata::Protocol : public Ahci::Protocol, Noncopyable
Response submit(Port &port, Block::Request const request) override
{
if (port.sanity_check(request) == false || port.dma_base == 0)
return Response::REJECTED;
if (_writeable == false && request.operation.type == Block::Operation::Type::WRITE)
return Response::REJECTED;
if (_overlap_check(request))
return Response::RETRY;
if (Block::Operation::has_payload(request.operation.type)) {
if (port.sanity_check(request) == false || port.dma_base == 0)
return Response::REJECTED;
if (_overlap_check(request))
return Response::RETRY;
}
Request *r = _slots.get();
@ -298,21 +308,26 @@ class Ata::Protocol : public Ahci::Protocol, Noncopyable
op.count * _block_size());
/* setup ATA command */
bool read = op.type == Block::Operation::Type::READ;
if (_ncq_support(port)) {
table.fis.fpdma(read, op.block_number, op.count, slot);
/* write bit for command header + read/write ATA requests */
bool const write = (op.type == Block::Operation::Type::WRITE);
bool const sync = (op.type == Block::Operation::Type::SYNC);
if (sync) {
table.fis.flush_cache_ext();
} else if (_ncq_support(port)) {
table.fis.fpdma(write == false, op.block_number, op.count, slot);
/* ensure that 'Cmd::St' is 1 before writing 'Sact' */
port.start();
/* set pending */
port.write<Port::Sact>(1U << slot);
} else {
table.fis.dma_ext(read, op.block_number, op.count);
table.fis.dma_ext(write == false, op.block_number, op.count);
}
/* set or clear write flag in command header */
Command_header header(port.command_header_addr(slot));
header.write<Command_header::Bits::W>(read ? 0 : 1);
header.write<Command_header::Bits::W>(write ? 1 : 0);
header.clear_byte_count();
port.execute(slot);

View File

@ -148,8 +148,8 @@ class Atapi::Protocol : public Ahci::Protocol, Noncopyable
Response submit(Port &port, Block::Request const request) override
{
if (port.sanity_check(request) == false || port.dma_base == 0 ||
request.operation.type != Block::Operation::Type::READ)
if (request.operation.type != Block::Operation::Type::READ ||
port.sanity_check(request) == false || port.dma_base == 0)
return Response::REJECTED;
if (_pending.operation.valid())

View File

@ -275,8 +275,9 @@ struct Ahci::Block_session_component : Rpc_object<Block::Session>,
Response response = Response::RETRY;
/* only READ/WRITE requests, others are noops for now */
if (Block::Operation::has_payload(request.operation.type) == false) {
/* ignored operations */
if (request.operation.type == Block::Operation::Type::TRIM ||
request.operation.type == Block::Operation::Type::INVALID) {
request.success = true;
progress = true;
return Response::REJECTED;