diff --git a/repos/os/src/drivers/usb_block/main.cc b/repos/os/src/drivers/usb_block/main.cc index 1b7c5f8020..5f4f4f2572 100644 --- a/repos/os/src/drivers/usb_block/main.cc +++ b/repos/os/src/drivers/usb_block/main.cc @@ -64,7 +64,7 @@ struct Usb::Block_driver : Usb::Completion size_t size { 0 }; bool completed { false }; - Block_request(Request &request, Request_stream::Payload const &payload) + Block_request(Request const &request, Request_stream::Payload const &payload) : block_request(request) { payload.with_content(request, [&](void *addr, size_t sz) { @@ -902,12 +902,20 @@ struct Usb::Block_driver : Usb::Completion .writeable = _writeable }; } - Response submit(Request &block_request, + Response submit(Request const &block_request, Request_stream::Payload const &payload) { if (device_plugged == false) return Response::REJECTED; + /* + * Check if there is already a request pending and wait + * until it has finished. We do this check here to implement + * 'SYNC' as barrier that waits for out-standing requests. + */ + if (request_pending()) + return Response::RETRY; + Operation const &op = block_request.operation; /* read only */ @@ -924,12 +932,16 @@ struct Usb::Block_driver : Usb::Completion if (!force_cmd_16 && last >= ~0U) return Response::REJECTED; - /* check if request is pending */ - if (request_pending()) - return Response::RETRY; - request.construct(block_request, payload); + /* operations currently handled as successful NOP */ + if (request->block_request.operation.type == Operation::Type::TRIM + || request->block_request.operation.type == Operation::Type::SYNC) { + request->block_request.success = true; + request->completed = true; + return Response::ACCEPTED; + } + /* execute */ send_cbw(op.block_number, op.count, request->read()); @@ -1000,28 +1012,31 @@ struct Usb::Main : Rpc_object> { if (!block_session.constructed()) return; - /* ack and release possibly pending packet */ - block_session->try_acknowledge([&] (Block_session_component::Ack &ack) { - driver.with_completed([&] (Block::Request &request) { - ack.submit(request); + bool progress; + do { + progress = false; + + /* ack and release possibly pending packet */ + block_session->try_acknowledge([&] (Block_session_component::Ack &ack) { + driver.with_completed([&] (Block::Request const &request) { + ack.submit(request); + progress = true; + }); }); - }); - block_session->with_requests([&] (Request request) { + block_session->with_requests([&] (Request const request) { - /* only read/write for now */ - if (Operation::has_payload(request.operation.type) == false) { - request.success = true; - return Response::REJECTED; - } + Response response = Response::RETRY; - Response response = Response::RETRY; + block_session->with_payload([&] (Request_stream::Payload const &payload) { + response = driver.submit(request, payload); + }); + if (response != Response::RETRY) + progress = true; - block_session->with_payload([&] (Request_stream::Payload const &payload) { - response = driver.submit(request, payload); + return response; }); - return response; - }); + } while (progress); block_session->wakeup_client_if_needed(); }