Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_ahci.c
Show First 20 Lines • Show All 2,323 Lines • ▼ Show 20 Lines | |||||
* pci.0.1.0 | * pci.0.1.0 | ||||
* .device="ahci" | * .device="ahci" | ||||
* .port | * .port | ||||
* .0 | * .0 | ||||
* .type="hd" | * .type="hd" | ||||
* .path="/path/to/image" | * .path="/path/to/image" | ||||
*/ | */ | ||||
static int | static int | ||||
pci_ahci_legacy_config_port(nvlist_t *nvl, int port, const char *type, | pci_ahci_legacy_config_port(config_node_t *node, int port, const char *type, | ||||
const char *opts) | const char *opts) | ||||
{ | { | ||||
char node_name[sizeof("XX")]; | char node_name[sizeof("XX")]; | ||||
nvlist_t *port_nvl; | config_node_t *port_node; | ||||
snprintf(node_name, sizeof(node_name), "%d", port); | snprintf(node_name, sizeof(node_name), "%d", port); | ||||
port_nvl = create_relative_config_node(nvl, node_name); | port_node = create_relative_config_node(node, node_name); | ||||
set_config_value_node(port_nvl, "type", type); | set_config_value_node(port_node, "type", type); | ||||
return (blockif_legacy_config(port_nvl, opts)); | return (blockif_legacy_config(port_node, opts)); | ||||
} | } | ||||
static int | static int | ||||
pci_ahci_legacy_config(nvlist_t *nvl, const char *opts) | pci_ahci_legacy_config(config_node_t *node, const char *opts) | ||||
{ | { | ||||
nvlist_t *ports_nvl; | config_node_t *ports_node; | ||||
const char *type; | const char *type; | ||||
char *next, *next2, *str, *tofree; | char *next, *next2, *str, *tofree; | ||||
int p, ret; | int p, ret; | ||||
if (opts == NULL) | if (opts == NULL) | ||||
return (0); | return (0); | ||||
ports_nvl = create_relative_config_node(nvl, "port"); | ports_node = create_relative_config_node(node, "port"); | ||||
ret = 1; | ret = 1; | ||||
tofree = str = strdup(opts); | tofree = str = strdup(opts); | ||||
for (p = 0; p < MAX_PORTS && str != NULL; p++, str = next) { | for (p = 0; p < MAX_PORTS && str != NULL; p++, str = next) { | ||||
/* Identify and cut off type of present port. */ | /* Identify and cut off type of present port. */ | ||||
if (strncmp(str, "hd:", 3) == 0) { | if (strncmp(str, "hd:", 3) == 0) { | ||||
type = "hd"; | type = "hd"; | ||||
str += 3; | str += 3; | ||||
} else if (strncmp(str, "cd:", 3) == 0) { | } else if (strncmp(str, "cd:", 3) == 0) { | ||||
Show All 16 Lines | if (str[0] == 0) | ||||
continue; | continue; | ||||
if (type == NULL) { | if (type == NULL) { | ||||
EPRINTLN("Missing or invalid type for port %d: \"%s\"", | EPRINTLN("Missing or invalid type for port %d: \"%s\"", | ||||
p, str); | p, str); | ||||
goto out; | goto out; | ||||
} | } | ||||
if (pci_ahci_legacy_config_port(ports_nvl, p, type, str) != 0) | if (pci_ahci_legacy_config_port(ports_node, p, type, str) != 0) | ||||
goto out; | goto out; | ||||
} | } | ||||
ret = 0; | ret = 0; | ||||
out: | out: | ||||
free(tofree); | free(tofree); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
pci_ahci_cd_legacy_config(nvlist_t *nvl, const char *opts) | pci_ahci_cd_legacy_config(config_node_t *node, const char *opts) | ||||
{ | { | ||||
nvlist_t *ports_nvl; | config_node_t *ports_node; | ||||
ports_nvl = create_relative_config_node(nvl, "port"); | ports_node = create_relative_config_node(node, "port"); | ||||
return (pci_ahci_legacy_config_port(ports_nvl, 0, "cd", opts)); | return (pci_ahci_legacy_config_port(ports_node, 0, "cd", opts)); | ||||
} | } | ||||
static int | static int | ||||
pci_ahci_hd_legacy_config(nvlist_t *nvl, const char *opts) | pci_ahci_hd_legacy_config(config_node_t *node, const char *opts) | ||||
{ | { | ||||
nvlist_t *ports_nvl; | config_node_t *ports_node; | ||||
ports_nvl = create_relative_config_node(nvl, "port"); | ports_node = create_relative_config_node(node, "port"); | ||||
return (pci_ahci_legacy_config_port(ports_nvl, 0, "hd", opts)); | return (pci_ahci_legacy_config_port(ports_node, 0, "hd", opts)); | ||||
} | } | ||||
static int | static int | ||||
pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) | pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, config_node_t *node) | ||||
{ | { | ||||
char bident[sizeof("XX:XX:XX")]; | char bident[sizeof("XX:XX:XX")]; | ||||
char node_name[sizeof("XX")]; | char node_name[sizeof("XX")]; | ||||
struct blockif_ctxt *bctxt; | struct blockif_ctxt *bctxt; | ||||
struct pci_ahci_softc *sc; | struct pci_ahci_softc *sc; | ||||
int atapi, ret, slots, p; | int atapi, ret, slots, p; | ||||
MD5_CTX mdctx; | MD5_CTX mdctx; | ||||
u_char digest[16]; | u_char digest[16]; | ||||
const char *path, *type, *value; | const char *path, *type, *value; | ||||
nvlist_t *ports_nvl, *port_nvl; | config_node_t *ports_node, *port_node; | ||||
ret = 0; | ret = 0; | ||||
#ifdef AHCI_DEBUG | #ifdef AHCI_DEBUG | ||||
dbg = fopen("/tmp/log", "w+"); | dbg = fopen("/tmp/log", "w+"); | ||||
#endif | #endif | ||||
sc = calloc(1, sizeof(struct pci_ahci_softc)); | sc = calloc(1, sizeof(struct pci_ahci_softc)); | ||||
pi->pi_arg = sc; | pi->pi_arg = sc; | ||||
sc->asc_pi = pi; | sc->asc_pi = pi; | ||||
pthread_mutex_init(&sc->mtx, NULL); | pthread_mutex_init(&sc->mtx, NULL); | ||||
sc->ports = 0; | sc->ports = 0; | ||||
sc->pi = 0; | sc->pi = 0; | ||||
slots = 32; | slots = 32; | ||||
ports_nvl = find_relative_config_node(nvl, "port"); | ports_node = find_relative_config_node(node, "port"); | ||||
for (p = 0; p < MAX_PORTS; p++) { | for (p = 0; p < MAX_PORTS; p++) { | ||||
struct ata_params *ata_ident = &sc->port[p].ata_ident; | struct ata_params *ata_ident = &sc->port[p].ata_ident; | ||||
char ident[AHCI_PORT_IDENT]; | char ident[AHCI_PORT_IDENT]; | ||||
snprintf(node_name, sizeof(node_name), "%d", p); | snprintf(node_name, sizeof(node_name), "%d", p); | ||||
port_nvl = find_relative_config_node(ports_nvl, node_name); | port_node = find_relative_config_node(ports_node, node_name); | ||||
if (port_nvl == NULL) | if (port_node == NULL) | ||||
continue; | continue; | ||||
type = get_config_value_node(port_nvl, "type"); | type = get_config_value_node(port_node, "type"); | ||||
if (type == NULL) | if (type == NULL) | ||||
continue; | continue; | ||||
if (strcmp(type, "hd") == 0) | if (strcmp(type, "hd") == 0) | ||||
atapi = 0; | atapi = 0; | ||||
else | else | ||||
atapi = 1; | atapi = 1; | ||||
/* | /* | ||||
* Attempt to open the backing image. Use the PCI slot/func | * Attempt to open the backing image. Use the PCI slot/func | ||||
* and the port number for the identifier string. | * and the port number for the identifier string. | ||||
*/ | */ | ||||
snprintf(bident, sizeof(bident), "%d:%d:%d", pi->pi_slot, | snprintf(bident, sizeof(bident), "%d:%d:%d", pi->pi_slot, | ||||
pi->pi_func, p); | pi->pi_func, p); | ||||
bctxt = blockif_open(port_nvl, bident); | bctxt = blockif_open(port_node, bident); | ||||
if (bctxt == NULL) { | if (bctxt == NULL) { | ||||
sc->ports = p; | sc->ports = p; | ||||
ret = 1; | ret = 1; | ||||
goto open_fail; | goto open_fail; | ||||
} | } | ||||
sc->port[p].bctx = bctxt; | sc->port[p].bctx = bctxt; | ||||
sc->port[p].pr_sc = sc; | sc->port[p].pr_sc = sc; | ||||
sc->port[p].port = p; | sc->port[p].port = p; | ||||
sc->port[p].atapi = atapi; | sc->port[p].atapi = atapi; | ||||
/* | /* | ||||
* Create an identifier for the backing file. | * Create an identifier for the backing file. | ||||
* Use parts of the md5 sum of the filename | * Use parts of the md5 sum of the filename | ||||
*/ | */ | ||||
path = get_config_value_node(port_nvl, "path"); | path = get_config_value_node(port_node, "path"); | ||||
MD5Init(&mdctx); | MD5Init(&mdctx); | ||||
MD5Update(&mdctx, path, strlen(path)); | MD5Update(&mdctx, path, strlen(path)); | ||||
MD5Final(digest, &mdctx); | MD5Final(digest, &mdctx); | ||||
snprintf(ident, AHCI_PORT_IDENT, | snprintf(ident, AHCI_PORT_IDENT, | ||||
"BHYVE-%02X%02X-%02X%02X-%02X%02X", | "BHYVE-%02X%02X-%02X%02X-%02X%02X", | ||||
digest[0], digest[1], digest[2], digest[3], digest[4], | digest[0], digest[1], digest[2], digest[3], digest[4], | ||||
digest[5]); | digest[5]); | ||||
memset(ata_ident, 0, sizeof(struct ata_params)); | memset(ata_ident, 0, sizeof(struct ata_params)); | ||||
ata_string((uint8_t*)&ata_ident->serial, ident, 20); | ata_string((uint8_t*)&ata_ident->serial, ident, 20); | ||||
ata_string((uint8_t*)&ata_ident->revision, "001", 8); | ata_string((uint8_t*)&ata_ident->revision, "001", 8); | ||||
if (atapi) | if (atapi) | ||||
ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DVD ROM", 40); | ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DVD ROM", 40); | ||||
else | else | ||||
ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DISK", 40); | ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DISK", 40); | ||||
value = get_config_value_node(port_nvl, "nmrr"); | value = get_config_value_node(port_node, "nmrr"); | ||||
if (value != NULL) | if (value != NULL) | ||||
ata_ident->media_rotation_rate = atoi(value); | ata_ident->media_rotation_rate = atoi(value); | ||||
value = get_config_value_node(port_nvl, "ser"); | value = get_config_value_node(port_node, "ser"); | ||||
if (value != NULL) | if (value != NULL) | ||||
ata_string((uint8_t*)(&ata_ident->serial), value, 20); | ata_string((uint8_t*)(&ata_ident->serial), value, 20); | ||||
value = get_config_value_node(port_nvl, "rev"); | value = get_config_value_node(port_node, "rev"); | ||||
if (value != NULL) | if (value != NULL) | ||||
ata_string((uint8_t*)(&ata_ident->revision), value, 8); | ata_string((uint8_t*)(&ata_ident->revision), value, 8); | ||||
value = get_config_value_node(port_nvl, "model"); | value = get_config_value_node(port_node, "model"); | ||||
if (value != NULL) | if (value != NULL) | ||||
ata_string((uint8_t*)(&ata_ident->model), value, 40); | ata_string((uint8_t*)(&ata_ident->model), value, 40); | ||||
ata_identify_init(&sc->port[p], atapi); | ata_identify_init(&sc->port[p], atapi); | ||||
/* | /* | ||||
* Allocate blockif request structures and add them | * Allocate blockif request structures and add them | ||||
* to the free list | * to the free list | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 353 Lines • Show Last 20 Lines |