usb_block: switch to Request_stream API

- remove old 'Driver' interface
- implement Request stream front end
- fix some namespacing

issue #3661
This commit is contained in:
Sebastian Sumpf 2020-02-21 08:37:08 +01:00 committed by Christian Helmuth
parent 96c93dae49
commit e97524ba7d
1 changed files with 256 additions and 151 deletions

View File

@ -1,11 +1,12 @@
/* /*
* \brief Usb session to Block session translator * \brief Usb session to Block session translator
* \author Josef Soentgen * \author Josef Soentgen
* \author Sebastian Sumpf
* \date 2016-02-08 * \date 2016-02-08
*/ */
/* /*
* Copyright (C) 2016-2017 Genode Labs GmbH * Copyright (C) 2016-2020 Genode Labs GmbH
* *
* This file is part of the Genode OS framework, which is distributed * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3. * under the terms of the GNU Affero General Public License version 3.
@ -13,14 +14,13 @@
/* Genode includes */ /* Genode includes */
#include <base/allocator_avl.h> #include <base/allocator_avl.h>
#include <base/attached_ram_dataspace.h>
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
#include <base/component.h> #include <base/component.h>
#include <base/log.h> #include <base/log.h>
#include <base/heap.h> #include <base/heap.h>
#include <base/sleep.h> #include <base/sleep.h>
#include <block/component.h> #include <block/request_stream.h>
#include <block/driver.h>
#include <block_session/connection.h>
#include <os/reporter.h> #include <os/reporter.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <usb/usb.h> #include <usb/usb.h>
@ -34,8 +34,11 @@ static bool verbose_scsi = false;
namespace Usb { namespace Usb {
using namespace Genode; using namespace Genode;
using namespace Block;
using Response = Block::Request_stream::Response;
struct Block_driver; struct Block_driver;
struct Block_session_component;
struct Main; struct Main;
} }
@ -44,8 +47,7 @@ namespace Usb {
** USB Mass Storage (BBB) Block::Driver implementation ** ** USB Mass Storage (BBB) Block::Driver implementation **
*********************************************************/ *********************************************************/
struct Usb::Block_driver : Usb::Completion, struct Usb::Block_driver : Usb::Completion
Block::Driver
{ {
Env &env; Env &env;
Entrypoint &ep; Entrypoint &ep;
@ -57,13 +59,34 @@ struct Usb::Block_driver : Usb::Completion,
*/ */
struct Block_request struct Block_request
{ {
Block::Packet_descriptor packet { }; Request block_request;
Block::sector_t lba { 0 }; addr_t address { 0 };
char *buffer { nullptr }; size_t size { 0 };
size_t size { 0 }; bool completed { false };
bool read { false };
bool pending { false }; Block_request(Request &request, Request_stream::Payload const &payload)
} req { }; : block_request(request)
{
payload.with_content(request, [&](void *addr, size_t sz) {
address = addr_t(addr);
size = sz;
});
}
bool read() const
{
return block_request.operation.type == Operation::Type::READ;
}
bool write() const
{
return block_request.operation.type == Operation::Type::WRITE;
}
};
Constructible<Block_request> request { };
bool request_pending() const { return request.constructed(); }
bool initialized = false; bool initialized = false;
bool device_plugged = false; bool device_plugged = false;
@ -74,21 +97,21 @@ struct Usb::Block_driver : Usb::Completion,
void handle_state_change() void handle_state_change()
{ {
if (!usb.plugged()) { if (!usb.plugged()) {
Genode::log("Device unplugged"); log("Device unplugged");
device_plugged = false; device_plugged = false;
return; return;
} }
if (initialized) { if (initialized) {
Genode::error("Device was already initialized"); error("Device was already initialized");
return; return;
} }
Genode::log("Device plugged"); log("Device plugged");
if (!initialize()) { if (!initialize()) {
env.parent().exit(-1); env.parent().exit(-1);
Genode::sleep_forever(); sleep_forever();
return; return;
} }
@ -107,23 +130,26 @@ struct Usb::Block_driver : Usb::Completion,
/* /*
* Read Usb session label from the configuration * Read Usb session label from the configuration
*/ */
static char const *get_label(Xml_node node) template <unsigned SIZE>
static Genode::String<SIZE> get_label(Xml_node node)
{ {
static Genode::String<256> usb_label; Genode::String<SIZE> usb_label { "usb_storage" };
try { try {
node.attribute("label").value(usb_label); node.attribute("label").value(usb_label);
return usb_label.string(); return usb_label.string();
} catch (...) { } } catch (...) { }
return "usb_storage"; return usb_label;
} }
/* /*
* USB session * USB session
*/ */
Allocator_avl alloc; Allocator_avl alloc;
Usb::Connection usb { env, &alloc, get_label(config.xml()), 2 * (1<<20), state_change_dispatcher }; Usb::Connection usb { env, &alloc,
Usb::Device device; get_label<128>(config.xml()).string(), 2 * (1<<20), state_change_dispatcher };
Usb::Device device;
Signal_handler<Main> &wake_up_handler;
/* /*
* Reporter * Reporter
@ -188,13 +214,13 @@ struct Usb::Block_driver : Usb::Completion,
Usb::Interface iface = device.interface(interface); Usb::Interface iface = device.interface(interface);
if (p.type != Packet_descriptor::BULK) { if (p.type != Packet_descriptor::BULK) {
Genode::error("Can only handle BULK packets"); error("Can only handle BULK packets");
iface.release(p); iface.release(p);
return; return;
} }
if (!p.succeded) { if (!p.succeded) {
Genode::error("init complete error: packet not succeeded"); error("init complete error: packet not succeeded");
iface.release(p); iface.release(p);
return; return;
} }
@ -217,7 +243,7 @@ struct Usb::Block_driver : Usb::Completion,
if (verbose_scsi) r.dump(); if (verbose_scsi) r.dump();
if (!r.sbc()) { if (!r.sbc()) {
Genode::warning("Device does not use SCSI Block Commands and may not work"); warning("Device does not use SCSI Block Commands and may not work");
} }
r.get_id<Inquiry_response::Vid>(vendor, sizeof(vendor)); r.get_id<Inquiry_response::Vid>(vendor, sizeof(vendor));
@ -265,7 +291,7 @@ struct Usb::Block_driver : Usb::Completion,
case NOT_READY_TO_READY_CHANGE: /* asq == 0x00 */ case NOT_READY_TO_READY_CHANGE: /* asq == 0x00 */
case POWER_ON_OR_RESET_OCCURRED: /* asq == 0x00 */ case POWER_ON_OR_RESET_OCCURRED: /* asq == 0x00 */
Genode::warning("Not ready - try again"); warning("Not ready - try again");
try_again = true; try_again = true;
break; break;
@ -294,7 +320,7 @@ struct Usb::Block_driver : Usb::Completion,
uint32_t const sig = csw.sig(); uint32_t const sig = csw.sig();
if (sig != Csw::SIG) { if (sig != Csw::SIG) {
Genode::error("CSW signature does not match: ", error("CSW signature does not match: ",
Hex(sig, Hex::PREFIX, Hex::PAD)); Hex(sig, Hex::PREFIX, Hex::PAD));
break; break;
} }
@ -302,7 +328,7 @@ struct Usb::Block_driver : Usb::Completion,
uint32_t const tag = csw.tag(); uint32_t const tag = csw.tag();
uint8_t const status = csw.sts(); uint8_t const status = csw.sts();
if (status != Csw::PASSED) { if (status != Csw::PASSED) {
Genode::error("CSW failed: ", Hex(status, Hex::PREFIX, Hex::PAD), error("CSW failed: ", Hex(status, Hex::PREFIX, Hex::PAD),
" tag: ", tag); " tag: ", tag);
break; break;
} }
@ -363,7 +389,7 @@ struct Usb::Block_driver : Usb::Completion,
Block::sector_t count, size_t size) Block::sector_t count, size_t size)
{ {
try { try {
Genode::Reporter::Xml_generator xml(reporter, [&] () { Reporter::Xml_generator xml(reporter, [&] () {
xml.node("device", [&] () { xml.node("device", [&] () {
xml.attribute("vendor", vendor); xml.attribute("vendor", vendor);
xml.attribute("product", product); xml.attribute("product", product);
@ -372,7 +398,7 @@ struct Usb::Block_driver : Usb::Completion,
xml.attribute("writeable", _writeable); xml.attribute("writeable", _writeable);
}); });
}); });
} catch (...) { Genode::warning("Could not report block device"); } } catch (...) { warning("Could not report block device"); }
} }
/** /**
@ -392,10 +418,10 @@ struct Usb::Block_driver : Usb::Completion,
Usb::Interface &iface = device.interface(active_interface); Usb::Interface &iface = device.interface(active_interface);
try { iface.claim(); } try { iface.claim(); }
catch (Usb::Session::Interface_already_claimed) { catch (Usb::Session::Interface_already_claimed) {
Genode::error("Device already claimed"); error("Device already claimed");
return false; return false;
} catch (Usb::Session::Interface_not_found) { } catch (Usb::Session::Interface_not_found) {
Genode::error("Interface not found"); error("Interface not found");
return false; return false;
} }
@ -410,7 +436,7 @@ struct Usb::Block_driver : Usb::Completion,
if (alt_iface.iclass != ICLASS_MASS_STORAGE if (alt_iface.iclass != ICLASS_MASS_STORAGE
|| alt_iface.isubclass != ISUBCLASS_SCSI || alt_iface.isubclass != ISUBCLASS_SCSI
|| alt_iface.iprotocol != IPROTO_BULK_ONLY) { || alt_iface.iprotocol != IPROTO_BULK_ONLY) {
Genode::error("No mass storage SCSI bulk-only device"); error("No mass storage SCSI bulk-only device");
return false; return false;
} }
@ -437,7 +463,7 @@ struct Usb::Block_driver : Usb::Completion,
Usb::Packet_descriptor p = iface.alloc(0); Usb::Packet_descriptor p = iface.alloc(0);
iface.control_transfer(p, 0x21, 0xff, 0, active_interface, 100); iface.control_transfer(p, 0x21, 0xff, 0, active_interface, 100);
if (!p.succeded) { if (!p.succeded) {
Genode::error("Could not reset device"); error("Could not reset device");
iface.release(p); iface.release(p);
throw -1; throw -1;
} }
@ -475,7 +501,7 @@ struct Usb::Block_driver : Usb::Completion,
csw(init, true); csw(init, true);
if (!init.inquiry) { if (!init.inquiry) {
Genode::warning("Inquiry_cmd failed"); warning("Inquiry_cmd failed");
throw -1; throw -1;
} }
@ -502,7 +528,7 @@ struct Usb::Block_driver : Usb::Completion,
resp(Scsi::Request_sense_response::LENGTH, init, true); resp(Scsi::Request_sense_response::LENGTH, init, true);
csw(init, true); csw(init, true);
if (!init.request_sense) { if (!init.request_sense) {
Genode::warning("Request_sense failed"); warning("Request_sense failed");
throw -1; throw -1;
} }
@ -524,7 +550,7 @@ struct Usb::Block_driver : Usb::Completion,
timer.msleep(1000); timer.msleep(1000);
} }
if (retries == MAX_RETRIES) { if (retries == MAX_RETRIES) {
Genode::warning("Test_unit_ready_cmd failed"); warning("Test_unit_ready_cmd failed");
throw -1; throw -1;
} }
} }
@ -547,7 +573,7 @@ struct Usb::Block_driver : Usb::Completion,
csw(init, true); csw(init, true);
if (!init.read_capacity) { if (!init.read_capacity) {
Genode::warning("Read_capacity_cmd failed"); warning("Read_capacity_cmd failed");
throw -1; throw -1;
} }
@ -563,7 +589,7 @@ struct Usb::Block_driver : Usb::Completion,
csw(init, true); csw(init, true);
if (!init.read_capacity) { if (!init.read_capacity) {
Genode::warning("Read_capacity_cmd failed"); warning("Read_capacity_cmd failed");
throw -1; throw -1;
} }
@ -582,7 +608,7 @@ struct Usb::Block_driver : Usb::Completion,
device.manufactorer_string.to_char(vendor, sizeof(vendor)); device.manufactorer_string.to_char(vendor, sizeof(vendor));
device.product_string.to_char(product, sizeof(product)); device.product_string.to_char(product, sizeof(product));
Genode::log("Found USB device: ", (char const*)vendor, " (", log("Found USB device: ", (char const*)vendor, " (",
(char const*)product, ") block size: ", _block_size, (char const*)product, ") block size: ", _block_size,
" count: ", _block_count); " count: ", _block_count);
@ -592,10 +618,10 @@ struct Usb::Block_driver : Usb::Completion,
return true; return true;
} catch (int) { } catch (int) {
/* handle command failures */ /* handle command failures */
Genode::error("Could not initialize storage device"); error("Could not initialize storage device");
} catch (...) { } catch (...) {
/* handle Usb::Session failures */ /* handle Usb::Session failures */
Genode::error("Could not initialize storage device"); error("Could not initialize storage device");
} }
return false; return false;
} }
@ -609,31 +635,23 @@ struct Usb::Block_driver : Usb::Completion,
bool execute_pending_request() bool execute_pending_request()
{ {
Usb::Interface &iface = device.interface(active_interface); Usb::Interface &iface = device.interface(active_interface);
Usb::Endpoint ep = iface.endpoint(req.read ? ep_in : ep_out); Usb::Endpoint ep = iface.endpoint(request->read() ? ep_in : ep_out);
Usb::Packet_descriptor p = iface.alloc(req.size); Usb::Packet_descriptor p = iface.alloc(request->size);
if (!req.read) memcpy(iface.content(p), req.buffer, req.size); if (request->write())
memcpy(iface.content(p), (void *)request->address, request->size);
iface.bulk_transfer(p, ep, false, this); iface.bulk_transfer(p, ep, false, this);
return true; return true;
} }
/** void wakeup_client(bool success)
* Acknowledge currently pending request
*
* After receiving the CSW ack the request at the Block session.
*/
void ack_pending_request(bool success = true)
{ {
/* request->block_request.success = success;
* Needs to be reset bevor calling ack_packet to prevent getting a new request->completed = true;
* request imediately and throwing Request_congestion() in io() again.
*/
req.pending = false;
Block::Packet_descriptor p = req.packet; wake_up_handler.dispatch(0);
ack_packet(p, success);
} }
/** /**
@ -648,18 +666,19 @@ struct Usb::Block_driver : Usb::Completion,
Usb::Interface iface = device.interface(active_interface); Usb::Interface iface = device.interface(active_interface);
if (p.type != Packet_descriptor::BULK) { if (p.type != Packet_descriptor::BULK) {
Genode::error("No BULK packet"); error("No BULK packet");
iface.release(p); iface.release(p);
return; return;
} }
if (!p.succeded) { if (!p.succeded) {
Genode::error("complete error: packet not succeded"); error("complete error: packet not succeded");
if (req.pending) { if (request_pending()) {
Genode::error("request pending: tag: ", active_tag, " read: ", error("request pending: tag: ", active_tag, " read: ",
(int)req.read, " buffer: ", (void *)req.buffer, " lba: ", request->read(), " buffer: ", Hex(request->address),
req.lba, " size: ", req.size); " lba: ", request->block_request.operation.block_number,
ack_pending_request(false); " size: ", request->size);
wakeup_client(false);
} }
iface.release(p); iface.release(p);
return; return;
@ -668,7 +687,7 @@ struct Usb::Block_driver : Usb::Completion,
static bool request_executed = false; static bool request_executed = false;
if (!p.read_transfer()) { if (!p.read_transfer()) {
/* send read/write request */ /* send read/write request */
if (req.pending) { if (request_pending()) {
/* /*
* The CBW was successfully sent to the device, now read/write the * The CBW was successfully sent to the device, now read/write the
@ -688,16 +707,16 @@ struct Usb::Block_driver : Usb::Completion,
int actual_size = p.transfer.actual_size; int actual_size = p.transfer.actual_size;
if (actual_size < 0) { if (actual_size < 0) {
Genode::error("Transfer actual size: ", actual_size); error("Transfer actual size: ", actual_size);
actual_size = 0; actual_size = 0;
} }
/* the size indicates an IN I/O packet */ /* the size indicates an IN I/O packet */
if ((uint32_t)actual_size >= _block_size) { if ((uint32_t)actual_size >= _block_size) {
if (req.pending) { if (request_pending()) {
/* the content was successfully read, get the CSW */ /* the content was successfully read, get the CSW */
memcpy(req.buffer, iface.content(p), actual_size); memcpy((void *)request->address, iface.content(p), actual_size);
csw(*this); csw(*this);
} }
@ -707,41 +726,42 @@ struct Usb::Block_driver : Usb::Completion,
/* when ending up here, we should have gotten an CSW packet */ /* when ending up here, we should have gotten an CSW packet */
if (actual_size != Csw::LENGTH) if (actual_size != Csw::LENGTH)
Genode::warning("This is not the actual size you are looking for"); warning("This is not the actual size you are looking for");
do { do {
Csw csw((addr_t)iface.content(p)); Csw csw((addr_t)iface.content(p));
uint32_t const sig = csw.sig(); uint32_t const sig = csw.sig();
if (sig != Csw::SIG) { if (sig != Csw::SIG) {
Genode::error("CSW signature does not match: ", error("CSW signature does not match: ",
Hex(sig, Hex::PREFIX, Hex::PAD)); Hex(sig, Hex::PREFIX, Hex::PAD));
break; break;
} }
uint32_t const tag = csw.tag(); uint32_t const tag = csw.tag();
if (tag != active_tag) { if (tag != active_tag) {
Genode::error("CSW tag mismatch. Got ", tag, " expected: ", error("CSW tag mismatch. Got ", tag, " expected: ",
active_tag); active_tag);
break; break;
} }
uint8_t const status = csw.sts(); uint8_t const status = csw.sts();
if (status != Csw::PASSED) { if (status != Csw::PASSED) {
Genode::error("CSW failed: ", Hex(status, Hex::PREFIX, Hex::PAD), error("CSW failed: ", Hex(status, Hex::PREFIX, Hex::PAD),
" read: ", (int)req.read, " buffer: ", (void *)req.buffer, " read: ", request->read(), " buffer: ", (void *)request->address,
" lba: ", req.lba, " size: ", req.size); " lba: ", request->block_request.operation.block_number,
" size: ", request->size);
break; break;
} }
uint32_t const dr = csw.dr(); uint32_t const dr = csw.dr();
if (dr) { if (dr) {
Genode::warning("CSW data residue: ", dr, " not considered"); warning("CSW data residue: ", dr, " not considered");
} }
/* ack Block::Packet_descriptor */ /* ack Block::Packet_descriptor */
request_executed = false; request_executed = false;
ack_pending_request(); wakeup_client(true);
} while (0); } while (0);
iface.release(p); iface.release(p);
@ -767,12 +787,12 @@ struct Usb::Block_driver : Usb::Completion,
* \param ep Server::Endpoint * \param ep Server::Endpoint
* \param sigh signal context used for annoucing Block service * \param sigh signal context used for annoucing Block service
*/ */
Block_driver(Env &env, Genode::Allocator &alloc, Block_driver(Env &env, Allocator &alloc,
Genode::Signal_context_capability sigh) Genode::Signal_context_capability sigh,
Signal_handler<Main> &wake_up_handler)
: :
Block::Driver(env.ram()),
env(env), ep(env.ep()), announce_sigh(sigh), alloc(&alloc), env(env), ep(env.ep()), announce_sigh(sigh), alloc(&alloc),
device(&alloc, usb, ep) device(&alloc, usb, ep), wake_up_handler(wake_up_handler)
{ {
parse_config(config.xml()); parse_config(config.xml());
reporter.enabled(true); reporter.enabled(true);
@ -789,111 +809,196 @@ struct Usb::Block_driver : Usb::Completion,
/** /**
* Send CBW * Send CBW
*/ */
void send_cbw(Block::sector_t lba, size_t len, bool read) void send_cbw(block_number_t lba, block_count_t count, bool read)
{ {
uint32_t const t = new_tag(); uint32_t const t = new_tag();
char cb[Cbw::LENGTH]; char cb[Cbw::LENGTH];
if (read) { if (read) {
if (force_cmd_16) Read_16 r((addr_t)cb, t, active_lun, lba, len, _block_size); if (force_cmd_16) Read_16 r((addr_t)cb, t, active_lun, lba, count, _block_size);
else Read_10 r((addr_t)cb, t, active_lun, lba, len, _block_size); else Read_10 r((addr_t)cb, t, active_lun, lba, count, _block_size);
} else { } else {
if (force_cmd_16) Write_16 w((addr_t)cb, t, active_lun, lba, len, _block_size); if (force_cmd_16) Write_16 w((addr_t)cb, t, active_lun, lba, count, _block_size);
else Write_10 w((addr_t)cb, t, active_lun, lba, len, _block_size); else Write_10 w((addr_t)cb, t, active_lun, lba, count, _block_size);
} }
cbw(cb, *this); cbw(cb, *this);
} }
/** /*******************************************
* Perform IO/ request ** interface to Block_session_component **
* *******************************************/
* \param read set to true when reading, false when writting
* \param lba address of the starting block
* \param buffer source/destination buffer
* \param p Block::Packet_descriptor
*/
void io(bool read, Block::sector_t lba, size_t count,
char *buffer, Block::Packet_descriptor &p)
{
if (!device_plugged) throw Io_error();
if (lba+count > _block_count) throw Io_error();
if (req.pending) throw Request_congestion();
req.pending = true; Block::Session::Info info() const
req.packet = p;
req.lba = lba;
req.size = count * _block_size;
req.buffer = buffer;
req.read = read;
send_cbw(lba, count, read);
}
/*******************************
** Block::Driver interface **
*******************************/
Block::Session::Info info() const override
{ {
return { .block_size = _block_size, return { .block_size = _block_size,
.block_count = _block_count, .block_count = _block_count,
.align_log2 = Genode::log2(_block_size), .align_log2 = log2(_block_size),
.writeable = _writeable }; .writeable = _writeable };
} }
void read(Block::sector_t lba, size_t count, Response submit(Request &block_request,
char *buffer, Block::Packet_descriptor &p) override { Request_stream::Payload const &payload)
io(true, lba, count, buffer, p); } {
if (device_plugged == false)
return Response::REJECTED;
void write(Block::sector_t lba, size_t count, Operation const &op = block_request.operation;
char const *buffer, Block::Packet_descriptor &p) override {
io(false, lba, count, const_cast<char*>(buffer), p); }
void sync() override { /* maybe implement SYNCHRONIZE_CACHE_10/16? */ } /* read only */
if (info().writeable == false &&
op.type == Operation::Type::WRITE)
return Response::REJECTED;
/* range check */
block_number_t const last = op.block_number + op.count;
if (last >= info().block_count)
return Response::REJECTED;
/* check if request is pending */
if (request_pending())
return Response::RETRY;
request.construct(block_request, payload);
/* execute */
send_cbw(op.block_number, op.count, request->read());
return Response::ACCEPTED;
}
template <typename FUNC>
void with_completed(FUNC const &fn)
{
if (request_pending() == false || request->completed == false) return;
fn(request->block_request);
request.destruct();
}
}; };
struct Usb::Main struct Usb::Block_session_component : Rpc_object<Block::Session>,
Block::Request_stream
{
Env &_env;
Block_session_component(Env &env, Dataspace_capability ds,
Signal_context_capability sigh,
Block::Session::Info info)
:
Request_stream(env.rm(), ds, env.ep(), sigh, info),
_env(env)
{
_env.ep().manage(*this);
}
~Block_session_component() { _env.ep().dissolve(*this); }
Info info() const override { return Request_stream::info(); }
Capability<Tx> tx_cap() override { return Request_stream::tx_cap(); }
};
struct Usb::Main : Rpc_object<Typed_root<Block::Session>>
{ {
Env &env; Env &env;
Heap heap { env.ram(), env.rm() }; Heap heap { env.ram(), env.rm() };
void announce() Constructible<Attached_ram_dataspace> block_ds { };
{ Constructible<Block_session_component> block_session { };
env.parent().announce(env.ep().manage(root));
}
Signal_handler<Main> announce_dispatcher { Signal_handler<Main> announce_dispatcher {
env.ep(), *this, &Usb::Main::announce }; env.ep(), *this, &Usb::Main::announce };
struct Factory : Block::Driver_factory Io_signal_handler<Main> request_handler {
env.ep(), *this, &Main::handle_requests };
Block_driver driver { env, heap, announce_dispatcher, request_handler };
void announce()
{ {
Env &env; env.parent().announce(env.ep().manage(*this));
Allocator &alloc; }
Signal_context_capability sigh;
Usb::Block_driver driver;
Factory(Env &env, Allocator &alloc, /**
Signal_context_capability sigh) * There can only be one request in flight for this driver, so keep it simple
: env(env), alloc(alloc), sigh(sigh), */
driver(env, alloc, sigh) { } void handle_requests()
{
if (!block_session.constructed()) return;
Block::Driver *create() override { return &driver; } /* ack and release possibly pending packet */
block_session->try_acknowledge([&] (Block_session_component::Ack &ack) {
driver.with_completed([&] (Block::Request &request) {
ack.submit(request);
});
});
void destroy(Block::Driver *) override { } block_session->with_requests([&] (Request request) {
private: /* only read/write for now */
if (Operation::has_payload(request.operation.type) == false) {
request.success = true;
return Response::REJECTED;
}
/* Response response = Response::RETRY;
* Noncopyable
*/
Factory(Factory const &);
Factory &operator = (Factory const &);
};
Factory factory { env, heap, announce_dispatcher }; block_session->with_payload([&] (Request_stream::Payload const &payload) {
Block::Root root { env.ep(), heap, env.rm(), factory, true }; response = driver.submit(request, payload);
});
return response;
});
block_session->wakeup_client_if_needed();
}
/*****************************
** Block session interface **
*****************************/
Genode::Session_capability session(Root::Session_args const &args,
Affinity const &) override
{
log("new block session: ", args.string());
if (block_session.constructed()) {
error("device is already in use");
throw Service_denied();
}
size_t const ds_size =
Arg_string::find_arg(args.string(), "tx_buf_size").ulong_value(0);
Ram_quota const ram_quota = ram_quota_from_args(args.string());
if (ds_size >= ram_quota.value) {
warning("communication buffer size exceeds session quota");
throw Insufficient_ram_quota();
}
block_ds.construct(env.ram(), env.rm(), ds_size);
block_session.construct(env, block_ds->cap(), request_handler,
driver.info());
return block_session->cap();
}
void upgrade(Genode::Session_capability, Root::Upgrade_args const&) override { }
void close(Genode::Session_capability cap) override
{
if (!block_session.constructed() || !(block_session->cap() == cap))
return;
block_session.destruct();
block_ds.destruct();
}
Main(Env &env) : env(env) { } Main(Env &env) : env(env) { }
}; };