Allow AHCI controller to support up to 32 arbitrary devices.

While old syntax is still supported, new syntax looks like this:

-s 3,ahci,hd:/dev/zvol/XXX,hd:/dev/zvol/YYY,cd:/storage/ZZZ.iso

Sponsored by:	iXsystems, Inc.
This commit is contained in:
Alexander Motin 2016-07-08 21:25:37 +00:00
parent dcc88911a9
commit 098f5155d1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=302459
2 changed files with 93 additions and 62 deletions

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd June 24, 2016
.Dd July 8, 2016
.Dt BHYVE 8
.Os
.Sh NAME
@ -171,6 +171,8 @@ Virtio network interface.
Virtio block storage interface.
.It Li virtio-rnd
Virtio RNG interface.
.It Li ahci
AHCI controller attached to arbitraty devices.
.It Li ahci-cd
AHCI controller attached to an ATAPI CD/DVD.
.It Li ahci-hd
@ -347,15 +349,11 @@ null-modem device.
.Bd -literal -offset indent
bhyve -c 4 \\
-s 0,amd_hostbridge -s 1,lpc \\
-s 1:0,ahci-hd,/images/disk.1 \\
-s 1:1,ahci-hd,/images/disk.2 \\
-s 1:2,ahci-hd,/images/disk.3 \\
-s 1:3,ahci-hd,/images/disk.4 \\
-s 1:4,ahci-hd,/images/disk.5 \\
-s 1:5,ahci-hd,/images/disk.6 \\
-s 1:6,ahci-hd,/images/disk.7 \\
-s 1:7,ahci-hd,/images/disk.8 \\
-s 2,ahci-cd,/images/install.iso \\
-s 1:0,ahci,hd:/images/disk.1,hd:/images/disk.2,\\
hd:/images/disk.3,hd:/images/disk.4,\\
hd:/images/disk.5,hd:/images/disk.6,\\
hd:/images/disk.7,hd:/images/disk.8,\\
cd:/images/install.iso \\
-s 3,virtio-net,tap0 \\
-l com1,/dev/nmdm0A \\
-A -H -P -m 8G

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2013 Zhixiang Yu <zcore@freebsd.org>
* Copyright (c) 2015-2016 Alexander Motin <mav@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -57,7 +58,8 @@ __FBSDID("$FreeBSD$");
#include "ahci.h"
#include "block_if.h"
#define MAX_PORTS 6 /* Intel ICH8 AHCI supports 6 ports */
#define DEF_PORTS 6 /* Intel ICH8 AHCI supports 6 ports */
#define MAX_PORTS 32 /* AHCI supports 32 ports */
#define PxSIG_ATA 0x00000101 /* ATA drive */
#define PxSIG_ATAPI 0xeb140101 /* ATAPI drive */
@ -2221,20 +2223,16 @@ pci_ahci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
static int
pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi)
{
char bident[sizeof("XX:X:X")];
char bident[sizeof("XX:XX:XX")];
struct blockif_ctxt *bctxt;
struct pci_ahci_softc *sc;
int ret, slots;
int ret, slots, p;
MD5_CTX mdctx;
u_char digest[16];
char *next, *next2;
ret = 0;
if (opts == NULL) {
fprintf(stderr, "pci_ahci: backing device required\n");
return (1);
}
#ifdef AHCI_DEBUG
dbg = fopen("/tmp/log", "w+");
#endif
@ -2242,58 +2240,83 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi)
sc = calloc(1, sizeof(struct pci_ahci_softc));
pi->pi_arg = sc;
sc->asc_pi = pi;
sc->ports = MAX_PORTS;
/*
* Only use port 0 for a backing device. All other ports will be
* marked as unused
*/
sc->port[0].atapi = atapi;
/*
* Attempt to open the backing image. Use the PCI
* slot/func for the identifier string.
*/
snprintf(bident, sizeof(bident), "%d:%d", pi->pi_slot, pi->pi_func);
bctxt = blockif_open(opts, bident);
if (bctxt == NULL) {
ret = 1;
goto open_fail;
}
sc->port[0].bctx = bctxt;
sc->port[0].pr_sc = sc;
/*
* Create an identifier for the backing file. Use parts of the
* md5 sum of the filename
*/
MD5Init(&mdctx);
MD5Update(&mdctx, opts, strlen(opts));
MD5Final(digest, &mdctx);
sprintf(sc->port[0].ident, "BHYVE-%02X%02X-%02X%02X-%02X%02X",
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5]);
/*
* Allocate blockif request structures and add them
* to the free list
*/
pci_ahci_ioreq_init(&sc->port[0]);
pthread_mutex_init(&sc->mtx, NULL);
sc->ports = 0;
sc->pi = 0;
slots = 32;
for (p = 0; p < MAX_PORTS && opts != NULL; p++, opts = next) {
/* 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;
}
/* 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)
continue;
/*
* Attempt to open the backing image. Use the PCI slot/func
* and the port number for the identifier string.
*/
snprintf(bident, sizeof(bident), "%d:%d:%d", pi->pi_slot,
pi->pi_func, p);
bctxt = blockif_open(opts, bident);
if (bctxt == NULL) {
sc->ports = p;
ret = 1;
goto open_fail;
}
sc->port[p].bctx = bctxt;
sc->port[p].pr_sc = sc;
sc->port[p].atapi = atapi;
/*
* Create an identifier for the backing file.
* Use parts of the md5 sum of the filename
*/
MD5Init(&mdctx);
MD5Update(&mdctx, opts, strlen(opts));
MD5Final(digest, &mdctx);
sprintf(sc->port[p].ident, "BHYVE-%02X%02X-%02X%02X-%02X%02X",
digest[0], digest[1], digest[2], digest[3], digest[4],
digest[5]);
/*
* Allocate blockif request structures and add them
* to the free list
*/
pci_ahci_ioreq_init(&sc->port[p]);
sc->pi |= (1 << p);
if (sc->port[p].ioqsz < slots)
slots = sc->port[p].ioqsz;
}
sc->ports = p;
/* Intel ICH8 AHCI */
slots = sc->port[0].ioqsz;
if (slots > 32)
slots = 32;
--slots;
if (sc->ports < DEF_PORTS)
sc->ports = DEF_PORTS;
sc->cap = AHCI_CAP_64BIT | AHCI_CAP_SNCQ | AHCI_CAP_SSNTF |
AHCI_CAP_SMPS | AHCI_CAP_SSS | AHCI_CAP_SALP |
AHCI_CAP_SAL | AHCI_CAP_SCLO | (0x3 << AHCI_CAP_ISS_SHIFT)|
AHCI_CAP_PMD | AHCI_CAP_SSC | AHCI_CAP_PSC |
(slots << AHCI_CAP_NCS_SHIFT) | AHCI_CAP_SXS | (sc->ports - 1);
/* Only port 0 implemented */
sc->pi = 1;
sc->vs = 0x10300;
sc->cap2 = AHCI_CAP2_APST;
ahci_reset(sc);
@ -2311,8 +2334,10 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi)
open_fail:
if (ret) {
if (sc->port[0].bctx != NULL)
blockif_close(sc->port[0].bctx);
for (p = 0; p < sc->ports; p++) {
if (sc->port[p].bctx != NULL)
blockif_close(sc->port[p].bctx);
}
free(sc);
}
@ -2336,6 +2361,14 @@ pci_ahci_atapi_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
/*
* Use separate emulation names to distinguish drive and atapi devices
*/
struct pci_devemu pci_de_ahci = {
.pe_emu = "ahci",
.pe_init = pci_ahci_hd_init,
.pe_barwrite = pci_ahci_write,
.pe_barread = pci_ahci_read
};
PCI_EMUL_SET(pci_de_ahci);
struct pci_devemu pci_de_ahci_hd = {
.pe_emu = "ahci-hd",
.pe_init = pci_ahci_hd_init,