aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/bhyve/pci_ahci.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bhyve/pci_ahci.c')
-rw-r--r--usr.sbin/bhyve/pci_ahci.c283
1 files changed, 156 insertions, 127 deletions
diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c
index 64c1fe0b90ca..38ec87c34eed 100644
--- a/usr.sbin/bhyve/pci_ahci.c
+++ b/usr.sbin/bhyve/pci_ahci.c
@@ -58,6 +58,8 @@ __FBSDID("$FreeBSD$");
#include <md5.h>
#include "bhyverun.h"
+#include "config.h"
+#include "debug.h"
#include "pci_emul.h"
#include "ahci.h"
#include "block_if.h"
@@ -2313,20 +2315,115 @@ pci_ahci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
return (value);
}
+/*
+ * Each AHCI controller has a "port" node which contains nodes for
+ * each port named after the decimal number of the port (no leading
+ * zeroes). Port nodes contain a "type" ("hd" or "cd"), as well as
+ * options for blockif. For example:
+ *
+ * pci.0.1.0
+ * .device="ahci"
+ * .port
+ * .0
+ * .type="hd"
+ * .path="/path/to/image"
+ */
+static int
+pci_ahci_legacy_config_port(nvlist_t *nvl, int port, const char *type,
+ const char *opts)
+{
+ char node_name[sizeof("XX")];
+ nvlist_t *port_nvl;
+
+ snprintf(node_name, sizeof(node_name), "%d", port);
+ port_nvl = create_relative_config_node(nvl, node_name);
+ set_config_value_node(port_nvl, "type", type);
+ return (blockif_legacy_config(port_nvl, opts));
+}
+
static int
-pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi)
+pci_ahci_legacy_config(nvlist_t *nvl, const char *opts)
+{
+ nvlist_t *ports_nvl;
+ const char *type;
+ char *next, *next2, *str, *tofree;
+ int p, ret;
+
+ if (opts == NULL)
+ return (0);
+
+ ports_nvl = create_relative_config_node(nvl, "port");
+ ret = 1;
+ tofree = str = strdup(opts);
+ for (p = 0; p < MAX_PORTS && str != NULL; p++, str = next) {
+ /* Identify and cut off type of present port. */
+ if (strncmp(str, "hd:", 3) == 0) {
+ type = "hd";
+ str += 3;
+ } else if (strncmp(str, "cd:", 3) == 0) {
+ type = "cd";
+ str += 3;
+ } else
+ type = NULL;
+
+ /* Find and cut off the next port options. */
+ next = strstr(str, ",hd:");
+ next2 = strstr(str, ",cd:");
+ if (next == NULL || (next2 != NULL && next2 < next))
+ next = next2;
+ if (next != NULL) {
+ next[0] = 0;
+ next++;
+ }
+
+ if (str[0] == 0)
+ continue;
+
+ if (type == NULL) {
+ EPRINTLN("Missing or invalid type for port %d: \"%s\"",
+ p, str);
+ goto out;
+ }
+
+ if (pci_ahci_legacy_config_port(ports_nvl, p, type, str) != 0)
+ goto out;
+ }
+ ret = 0;
+out:
+ free(tofree);
+ return (ret);
+}
+
+static int
+pci_ahci_cd_legacy_config(nvlist_t *nvl, const char *opts)
+{
+ nvlist_t *ports_nvl;
+
+ ports_nvl = create_relative_config_node(nvl, "port");
+ return (pci_ahci_legacy_config_port(ports_nvl, 0, "cd", opts));
+}
+
+static int
+pci_ahci_hd_legacy_config(nvlist_t *nvl, const char *opts)
+{
+ nvlist_t *ports_nvl;
+
+ ports_nvl = create_relative_config_node(nvl, "port");
+ return (pci_ahci_legacy_config_port(ports_nvl, 0, "hd", opts));
+}
+
+static int
+pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
{
char bident[sizeof("XX:XX:XX")];
+ char node_name[sizeof("XX")];
struct blockif_ctxt *bctxt;
struct pci_ahci_softc *sc;
- int ret, slots, p;
+ int atapi, ret, slots, p;
MD5_CTX mdctx;
u_char digest[16];
- char *next, *next2;
- char *bopt, *uopt, *xopts, *config;
- FILE* fp;
- size_t block_len;
- int comma, optpos;
+ const char *path, *type, *value;
+ nvlist_t *ports_nvl, *port_nvl;
ret = 0;
@@ -2342,98 +2439,24 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi)
sc->pi = 0;
slots = 32;
- for (p = 0; p < MAX_PORTS && opts != NULL; p++, opts = next) {
+ ports_nvl = find_relative_config_node(nvl, "port");
+ for (p = 0; p < MAX_PORTS; p++) {
struct ata_params *ata_ident = &sc->port[p].ata_ident;
- memset(ata_ident, 0, sizeof(struct ata_params));
-
- /* Identify and cut off type of present port. */
- if (strncmp(opts, "hd:", 3) == 0) {
- atapi = 0;
- opts += 3;
- } else if (strncmp(opts, "cd:", 3) == 0) {
- atapi = 1;
- opts += 3;
- }
+ char ident[AHCI_PORT_IDENT];
- /* Find and cut off the next port options. */
- next = strstr(opts, ",hd:");
- next2 = strstr(opts, ",cd:");
- if (next == NULL || (next2 != NULL && next2 < next))
- next = next2;
- if (next != NULL) {
- next[0] = 0;
- next++;
- }
-
- if (opts[0] == 0)
+ snprintf(node_name, sizeof(node_name), "%d", p);
+ port_nvl = find_relative_config_node(ports_nvl, node_name);
+ if (port_nvl == NULL)
continue;
- uopt = strdup(opts);
- bopt = NULL;
- fp = open_memstream(&bopt, &block_len);
- comma = 0;
- optpos = 0;
-
- for (xopts = strtok(uopt, ",");
- xopts != NULL;
- xopts = strtok(NULL, ",")) {
-
- /* First option assume as block filename. */
- if (optpos == 0) {
- /*
- * Create an identifier for the backing file.
- * Use parts of the md5 sum of the filename
- */
- char ident[AHCI_PORT_IDENT];
- MD5Init(&mdctx);
- MD5Update(&mdctx, opts, strlen(opts));
- MD5Final(digest, &mdctx);
- snprintf(ident, AHCI_PORT_IDENT,
- "BHYVE-%02X%02X-%02X%02X-%02X%02X",
- digest[0], digest[1], digest[2], digest[3], digest[4],
- digest[5]);
- ata_string((uint8_t*)&ata_ident->serial, ident, 20);
- ata_string((uint8_t*)&ata_ident->revision, "001", 8);
- if (atapi) {
- ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DVD ROM", 40);
- }
- else {
- ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DISK", 40);
- }
- }
-
- if ((config = strchr(xopts, '=')) != NULL) {
- *config++ = '\0';
- if (!strcmp("nmrr", xopts)) {
- ata_ident->media_rotation_rate = atoi(config);
- }
- else if (!strcmp("ser", xopts)) {
- ata_string((uint8_t*)(&ata_ident->serial), config, 20);
- }
- else if (!strcmp("rev", xopts)) {
- ata_string((uint8_t*)(&ata_ident->revision), config, 8);
- }
- else if (!strcmp("model", xopts)) {
- ata_string((uint8_t*)(&ata_ident->model), config, 40);
- }
- else {
- /* Pass all other options to blockif_open. */
- *--config = '=';
- fprintf(fp, "%s%s", comma ? "," : "", xopts);
- comma = 1;
- }
- }
- else {
- /* Pass all other options to blockif_open. */
- fprintf(fp, "%s%s", comma ? "," : "", xopts);
- comma = 1;
- }
- optpos++;
- }
- free(uopt);
- fclose(fp);
+ type = get_config_value_node(port_nvl, "type");
+ if (type == NULL)
+ continue;
- DPRINTF("%s\n", bopt);
+ if (strcmp(type, "hd") == 0)
+ atapi = 0;
+ else
+ atapi = 1;
/*
* Attempt to open the backing image. Use the PCI slot/func
@@ -2441,9 +2464,8 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi)
*/
snprintf(bident, sizeof(bident), "%d:%d:%d", pi->pi_slot,
pi->pi_func, p);
- bctxt = blockif_open(bopt, bident);
- free(bopt);
+ bctxt = blockif_open(port_nvl, bident);
if (bctxt == NULL) {
sc->ports = p;
ret = 1;
@@ -2454,6 +2476,38 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi)
sc->port[p].port = p;
sc->port[p].atapi = atapi;
+ /*
+ * Create an identifier for the backing file.
+ * Use parts of the md5 sum of the filename
+ */
+ path = get_config_value_node(port_nvl, "path");
+ MD5Init(&mdctx);
+ MD5Update(&mdctx, path, strlen(path));
+ MD5Final(digest, &mdctx);
+ snprintf(ident, AHCI_PORT_IDENT,
+ "BHYVE-%02X%02X-%02X%02X-%02X%02X",
+ digest[0], digest[1], digest[2], digest[3], digest[4],
+ digest[5]);
+
+ memset(ata_ident, 0, sizeof(struct ata_params));
+ ata_string((uint8_t*)&ata_ident->serial, ident, 20);
+ ata_string((uint8_t*)&ata_ident->revision, "001", 8);
+ if (atapi)
+ ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DVD ROM", 40);
+ else
+ ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DISK", 40);
+ value = get_config_value_node(port_nvl, "nmrr");
+ if (value != NULL)
+ ata_ident->media_rotation_rate = atoi(value);
+ value = get_config_value_node(port_nvl, "ser");
+ if (value != NULL)
+ ata_string((uint8_t*)(&ata_ident->serial), value, 20);
+ value = get_config_value_node(port_nvl, "rev");
+ if (value != NULL)
+ ata_string((uint8_t*)(&ata_ident->revision), value, 8);
+ value = get_config_value_node(port_nvl, "model");
+ if (value != NULL)
+ ata_string((uint8_t*)(&ata_ident->model), value, 40);
ata_identify_init(&sc->port[p], atapi);
/*
@@ -2507,20 +2561,6 @@ open_fail:
return (ret);
}
-static int
-pci_ahci_hd_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
-{
-
- return (pci_ahci_init(ctx, pi, opts, 0));
-}
-
-static int
-pci_ahci_atapi_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
-{
-
- return (pci_ahci_init(ctx, pi, opts, 1));
-}
-
#ifdef BHYVE_SNAPSHOT
static int
pci_ahci_snapshot_save_queues(struct ahci_port *port,
@@ -2802,7 +2842,8 @@ pci_ahci_resume(struct vmctx *ctx, struct pci_devinst *pi)
*/
struct pci_devemu pci_de_ahci = {
.pe_emu = "ahci",
- .pe_init = pci_ahci_hd_init,
+ .pe_init = pci_ahci_init,
+ .pe_legacy_config = pci_ahci_legacy_config,
.pe_barwrite = pci_ahci_write,
.pe_barread = pci_ahci_read,
#ifdef BHYVE_SNAPSHOT
@@ -2815,26 +2856,14 @@ PCI_EMUL_SET(pci_de_ahci);
struct pci_devemu pci_de_ahci_hd = {
.pe_emu = "ahci-hd",
- .pe_init = pci_ahci_hd_init,
- .pe_barwrite = pci_ahci_write,
- .pe_barread = pci_ahci_read,
-#ifdef BHYVE_SNAPSHOT
- .pe_snapshot = pci_ahci_snapshot,
- .pe_pause = pci_ahci_pause,
- .pe_resume = pci_ahci_resume,
-#endif
+ .pe_legacy_config = pci_ahci_hd_legacy_config,
+ .pe_alias = "ahci",
};
PCI_EMUL_SET(pci_de_ahci_hd);
struct pci_devemu pci_de_ahci_cd = {
.pe_emu = "ahci-cd",
- .pe_init = pci_ahci_atapi_init,
- .pe_barwrite = pci_ahci_write,
- .pe_barread = pci_ahci_read,
-#ifdef BHYVE_SNAPSHOT
- .pe_snapshot = pci_ahci_snapshot,
- .pe_pause = pci_ahci_pause,
- .pe_resume = pci_ahci_resume,
-#endif
+ .pe_legacy_config = pci_ahci_cd_legacy_config,
+ .pe_alias = "ahci",
};
PCI_EMUL_SET(pci_de_ahci_cd);