diff --git a/repos/os/src/drivers/ahci/README b/repos/os/src/drivers/ahci/README index 3ab8e528f..01447b37d 100644 --- a/repos/os/src/drivers/ahci/README +++ b/repos/os/src/drivers/ahci/README @@ -18,10 +18,13 @@ which client can access a certain device: ! ! ! -! +! +! +! ! ! ! -In the example above, a session request labeled with "test-ahci" -gains access to device 0, while "bench" gains access to device 1. +In the example above, a session request labeled with "test-ahci" gains access to +a device with certain model and serial numbers, while "bench" gains access to +device at port 1. diff --git a/repos/os/src/drivers/ahci/ahci.cc b/repos/os/src/drivers/ahci/ahci.cc index 191696c3c..5d88180a0 100644 --- a/repos/os/src/drivers/ahci/ahci.cc +++ b/repos/os/src/drivers/ahci/ahci.cc @@ -185,6 +185,19 @@ struct Ahci return port_num < MAX_PORTS && ports[port_num] && !port_claimed[port_num] && ports[port_num]->ready(); } + + long device_number(const char *model_num, const char *serial_num) + { + for (long port_num = 0; port_num < MAX_PORTS; port_num++) { + Ata_driver* drv = dynamic_cast(ports[port_num]); + if (!drv) + continue; + + if (*drv->model == model_num && *drv->serial == serial_num) + return port_num; + } + return -1; + } }; @@ -220,4 +233,9 @@ bool Ahci_driver::is_avail(long device_num) } +long Ahci_driver::device_number(char const *model_num, char const *serial_num) +{ + return sata_ahci()->device_number(model_num, serial_num); +} + diff --git a/repos/os/src/drivers/ahci/ahci.h b/repos/os/src/drivers/ahci/ahci.h index b63fc0ace..13f3fdfc5 100644 --- a/repos/os/src/drivers/ahci/ahci.h +++ b/repos/os/src/drivers/ahci/ahci.h @@ -39,6 +39,7 @@ namespace Ahci_driver { void init(Ahci_root &ep); bool is_avail(long device_num); + long device_number(char const *model_num, char const *serial_num); Block::Driver *claim_port(long device_num); void free_port(long device_num); diff --git a/repos/os/src/drivers/ahci/ata_driver.h b/repos/os/src/drivers/ahci/ata_driver.h index 6a042f797..587705c66 100644 --- a/repos/os/src/drivers/ahci/ata_driver.h +++ b/repos/os/src/drivers/ahci/ata_driver.h @@ -26,6 +26,9 @@ struct Identity : Genode::Mmio { Identity(Genode::addr_t base) : Mmio(base) { } + struct Serial_number : Register_array<0x14, 8, 20, 8> { }; + struct Model_number : Register_array<0x36, 8, 40, 8> { }; + struct Queue_depth : Register<0x96, 16> { struct Max_depth : Bitfield<0, 5> { }; @@ -71,6 +74,40 @@ struct Identity : Genode::Mmio } }; + +/** + * 16-bit word big endian device ASCII characters + */ +template +struct String +{ + char buf[DEVICE_STRING::ITEMS + 1]; + + String(Identity & info) + { + long j = 0; + for (unsigned long i = 0; i < DEVICE_STRING::ITEMS; i++) { + /* read and swap even and uneven characters */ + char c = (char)info.read(i ^ 1); + if (Genode::is_whitespace(c) && j == 0) + continue; + buf[j++] = c; + } + + buf[j] = 0; + + /* remove trailing white spaces */ + while ((j > 0) && (buf[--j] == ' ')) + buf[j] = 0; + } + + bool operator == (char const *other) const + { + return strcmp(buf, other) == 0; + } +}; + + /** * Commands to distinguish between ncq and non-ncq operation */ @@ -135,9 +172,15 @@ struct Dma_ext_command : Io_command */ struct Ata_driver : Port_driver { - Genode::Lazy_volatile_object info; - Io_command *io_cmd = nullptr; - Block::Packet_descriptor pending[32]; + typedef ::String Serial_string; + typedef ::String Model_string; + + Genode::Lazy_volatile_object info; + Genode::Lazy_volatile_object serial; + Genode::Lazy_volatile_object model; + + Io_command *io_cmd = nullptr; + Block::Packet_descriptor pending[32]; Ata_driver(Port &port, Signal_context_capability state_change) : Port_driver(port, state_change) @@ -242,8 +285,14 @@ struct Ata_driver : Port_driver if (Port::Is::Dss::get(status) || Port::Is::Pss::get(status)) { info.construct(device_info); - if (verbose) + serial.construct(*info); + model.construct(*info); + + if (verbose) { + PLOG("\t\tmodel number: %s", model->buf); + PLOG("\t\tserial number: %s", serial->buf); info->info(); + } check_device(); if (ncq_support()) diff --git a/repos/os/src/drivers/ahci/main.cc b/repos/os/src/drivers/ahci/main.cc index 02c411a61..95a817feb 100644 --- a/repos/os/src/drivers/ahci/main.cc +++ b/repos/os/src/drivers/ahci/main.cc @@ -61,27 +61,32 @@ class Block::Root_multiple_clients : public Root_component< ::Session_component> Server::Entrypoint &_ep; - long _device_num(const char *session_label) + long _device_num(const char *session_label, char *model, char *sn, size_t bufs_len) { long num = -1; - try { - using namespace Genode; + Xml_node policy = config()->xml_node().sub_node("policy"); - Xml_node policy = Genode::config()->xml_node().sub_node("policy"); + for (;; policy = policy.next("policy")) { + char label_buf[64]; + policy.attribute("label").value(label_buf, sizeof(label_buf)); - for (;; policy = policy.next("policy")) { - char label_buf[64]; - policy.attribute("label").value(label_buf, sizeof(label_buf)); + if (Genode::strcmp(session_label, label_buf)) + continue; - if (Genode::strcmp(session_label, label_buf)) - continue; - - /* read device attribute */ + /* try read device port number attribute */ + try { policy.attribute("device").value(&num); - break; - } - } catch (...) {} + } catch (...) { } + + /* try read device model and serial number attributes */ + try { + model[0] = sn[0] = 0; + policy.attribute("model").value(model, bufs_len); + policy.attribute("serial").value(sn, bufs_len); + } catch (...) { } + break; + } return num; } @@ -96,12 +101,16 @@ class Block::Root_multiple_clients : public Root_component< ::Session_component> /* TODO: build quota check */ /* Search for configured device */ - char label_buf[64]; + char label_buf[64], model_buf[64], sn_buf[64]; Genode::Arg_string::find_arg(args, "label").string(label_buf, sizeof(label_buf), ""); - long num = _device_num(label_buf); + long num = _device_num(label_buf, model_buf, sn_buf, sizeof(model_buf)); + /* prefer model/serial routing */ + if ((model_buf[0] != 0) && (sn_buf[0] != 0)) + num = Ahci_driver::device_number(model_buf, sn_buf); + if (num < 0) { PERR("No confguration found for client: %s", label_buf); throw Root::Invalid_args();