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();