Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_ahci.c
Show First 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | struct ahci_ioreq { | ||||
uint8_t *cfis; | uint8_t *cfis; | ||||
uint32_t len; | uint32_t len; | ||||
uint32_t done; | uint32_t done; | ||||
int slot; | int slot; | ||||
int more; | int more; | ||||
}; | }; | ||||
struct ahci_port { | struct ahci_port { | ||||
block_backend_t *be; | |||||
struct blockif_ctxt *bctx; | struct blockif_ctxt *bctx; | ||||
freqlabs: You shouldn't need both `be` and `bctx` here. Most of the changes in this file will go away if… | |||||
Done Inline ActionsThey are not the same as I previously explained. Problem of hanging everthing off a blockif_ctxt structure, is that that struct is very much tailored to the current properties of a physical disk. And other backing-stores might need other data. wjw_digiware.nl: They are not the same as I previously explained.
But perhaps `struct blockif_ctxt *bctx`… | |||||
struct pci_ahci_softc *pr_sc; | struct pci_ahci_softc *pr_sc; | ||||
uint8_t *cmd_lst; | uint8_t *cmd_lst; | ||||
uint8_t *rfis; | uint8_t *rfis; | ||||
char ident[AHCI_PORT_IDENT]; | char ident[AHCI_PORT_IDENT]; | ||||
int port; | int port; | ||||
int atapi; | int atapi; | ||||
int reset; | int reset; | ||||
int waitforclear; | int waitforclear; | ||||
▲ Show 20 Lines • Show All 341 Lines • ▼ Show 20 Lines | ahci_port_stop(struct ahci_port *p) | ||||
int error; | int error; | ||||
assert(pthread_mutex_isowned_np(&p->pr_sc->mtx)); | assert(pthread_mutex_isowned_np(&p->pr_sc->mtx)); | ||||
TAILQ_FOREACH(aior, &p->iobhd, io_blist) { | TAILQ_FOREACH(aior, &p->iobhd, io_blist) { | ||||
/* | /* | ||||
* Try to cancel the outstanding blockif request. | * Try to cancel the outstanding blockif request. | ||||
*/ | */ | ||||
error = blockif_cancel(p->bctx, &aior->io_req); | error = blockbe_cancel(p->be, &aior->io_req); | ||||
if (error != 0) | if (error != 0) | ||||
continue; | continue; | ||||
slot = aior->slot; | slot = aior->slot; | ||||
cfis = aior->cfis; | cfis = aior->cfis; | ||||
if (cfis[2] == ATA_WRITE_FPDMA_QUEUED || | if (cfis[2] == ATA_WRITE_FPDMA_QUEUED || | ||||
cfis[2] == ATA_READ_FPDMA_QUEUED || | cfis[2] == ATA_READ_FPDMA_QUEUED || | ||||
cfis[2] == ATA_SEND_FPDMA_QUEUED) | cfis[2] == ATA_SEND_FPDMA_QUEUED) | ||||
▲ Show 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | for (i = 0, j = 0; i < prdtl && j < BLOCKIF_IOV_MAX && left > 0; | ||||
todo += dbcsz; | todo += dbcsz; | ||||
left -= dbcsz; | left -= dbcsz; | ||||
skip = 0; | skip = 0; | ||||
j++; | j++; | ||||
} | } | ||||
/* If we got limited by IOV length, round I/O down to sector size. */ | /* If we got limited by IOV length, round I/O down to sector size. */ | ||||
if (j == BLOCKIF_IOV_MAX) { | if (j == BLOCKIF_IOV_MAX) { | ||||
extra = todo % blockif_sectsz(p->bctx); | extra = todo % blockbe_sectsz(p->be); | ||||
todo -= extra; | todo -= extra; | ||||
assert(todo > 0); | assert(todo > 0); | ||||
while (extra > 0) { | while (extra > 0) { | ||||
if (breq->br_iov[j - 1].iov_len > extra) { | if (breq->br_iov[j - 1].iov_len > extra) { | ||||
breq->br_iov[j - 1].iov_len -= extra; | breq->br_iov[j - 1].iov_len -= extra; | ||||
break; | break; | ||||
} | } | ||||
extra -= breq->br_iov[j - 1].iov_len; | extra -= breq->br_iov[j - 1].iov_len; | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | if (!len) | ||||
len = 65536; | len = 65536; | ||||
} else { | } else { | ||||
lba = ((cfis[7] & 0xf) << 24) | (cfis[6] << 16) | | lba = ((cfis[7] & 0xf) << 24) | (cfis[6] << 16) | | ||||
(cfis[5] << 8) | cfis[4]; | (cfis[5] << 8) | cfis[4]; | ||||
len = cfis[12]; | len = cfis[12]; | ||||
if (!len) | if (!len) | ||||
len = 256; | len = 256; | ||||
} | } | ||||
lba *= blockif_sectsz(p->bctx); | lba *= blockbe_sectsz(p->be); | ||||
len *= blockif_sectsz(p->bctx); | len *= blockbe_sectsz(p->be); | ||||
/* Pull request off free list */ | /* Pull request off free list */ | ||||
aior = STAILQ_FIRST(&p->iofhd); | aior = STAILQ_FIRST(&p->iofhd); | ||||
assert(aior != NULL); | assert(aior != NULL); | ||||
STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); | STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); | ||||
aior->cfis = cfis; | aior->cfis = cfis; | ||||
aior->slot = slot; | aior->slot = slot; | ||||
aior->len = len; | aior->len = len; | ||||
aior->done = done; | aior->done = done; | ||||
breq = &aior->io_req; | breq = &aior->io_req; | ||||
breq->br_offset = lba + done; | breq->br_offset = lba + done; | ||||
ahci_build_iov(p, aior, prdt, hdr->prdtl); | ahci_build_iov(p, aior, prdt, hdr->prdtl); | ||||
/* Mark this command in-flight. */ | /* Mark this command in-flight. */ | ||||
p->pending |= 1 << slot; | p->pending |= 1 << slot; | ||||
/* Stuff request onto busy list. */ | /* Stuff request onto busy list. */ | ||||
TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); | TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); | ||||
if (ncq && first) | if (ncq && first) | ||||
ahci_write_fis_d2h_ncq(p, slot); | ahci_write_fis_d2h_ncq(p, slot); | ||||
if (readop) | if (readop) | ||||
err = blockif_read(p->bctx, breq); | err = blockbe_read(p->be, breq); | ||||
else | else | ||||
err = blockif_write(p->bctx, breq); | err = blockbe_write(p->be, breq); | ||||
assert(err == 0); | assert(err == 0); | ||||
} | } | ||||
static void | static void | ||||
ahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis) | ahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis) | ||||
{ | { | ||||
struct ahci_ioreq *aior; | struct ahci_ioreq *aior; | ||||
struct blockif_req *breq; | struct blockif_req *breq; | ||||
Show All 17 Lines | ahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis) | ||||
*/ | */ | ||||
p->pending |= 1 << slot; | p->pending |= 1 << slot; | ||||
/* | /* | ||||
* Stuff request onto busy list | * Stuff request onto busy list | ||||
*/ | */ | ||||
TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); | TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); | ||||
err = blockif_flush(p->bctx, breq); | err = blockbe_flush(p->be, breq); | ||||
assert(err == 0); | assert(err == 0); | ||||
} | } | ||||
static inline void | static inline void | ||||
read_prdt(struct ahci_port *p, int slot, uint8_t *cfis, | read_prdt(struct ahci_port *p, int slot, uint8_t *cfis, | ||||
void *buf, int size) | void *buf, int size) | ||||
{ | { | ||||
struct ahci_cmd_hdr *hdr; | struct ahci_cmd_hdr *hdr; | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | next: | ||||
STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); | STAILQ_REMOVE_HEAD(&p->iofhd, io_flist); | ||||
aior->cfis = cfis; | aior->cfis = cfis; | ||||
aior->slot = slot; | aior->slot = slot; | ||||
aior->len = len; | aior->len = len; | ||||
aior->done = done; | aior->done = done; | ||||
aior->more = (len != done); | aior->more = (len != done); | ||||
breq = &aior->io_req; | breq = &aior->io_req; | ||||
breq->br_offset = elba * blockif_sectsz(p->bctx); | breq->br_offset = elba * blockbe_sectsz(p->be); | ||||
breq->br_resid = elen * blockif_sectsz(p->bctx); | breq->br_resid = elen * blockbe_sectsz(p->be); | ||||
/* | /* | ||||
* Mark this command in-flight. | * Mark this command in-flight. | ||||
*/ | */ | ||||
p->pending |= 1 << slot; | p->pending |= 1 << slot; | ||||
/* | /* | ||||
* Stuff request onto busy list | * Stuff request onto busy list | ||||
*/ | */ | ||||
TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); | TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); | ||||
if (ncq && first) | if (ncq && first) | ||||
ahci_write_fis_d2h_ncq(p, slot); | ahci_write_fis_d2h_ncq(p, slot); | ||||
err = blockif_delete(p->bctx, breq); | err = blockbe_delete(p->be, breq); | ||||
assert(err == 0); | assert(err == 0); | ||||
} | } | ||||
static inline void | static inline void | ||||
write_prdt(struct ahci_port *p, int slot, uint8_t *cfis, | write_prdt(struct ahci_port *p, int slot, uint8_t *cfis, | ||||
void *buf, int size) | void *buf, int size) | ||||
{ | { | ||||
struct ahci_cmd_hdr *hdr; | struct ahci_cmd_hdr *hdr; | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | ahci_handle_read_log(struct ahci_port *p, int slot, uint8_t *cfis) | ||||
if (cfis[4] == 0x00) { /* Log directory */ | if (cfis[4] == 0x00) { /* Log directory */ | ||||
buf16[0x00] = 1; /* Version -- 1 */ | buf16[0x00] = 1; /* Version -- 1 */ | ||||
buf16[0x10] = 1; /* NCQ Command Error Log -- 1 page */ | buf16[0x10] = 1; /* NCQ Command Error Log -- 1 page */ | ||||
buf16[0x13] = 1; /* SATA NCQ Send and Receive Log -- 1 page */ | buf16[0x13] = 1; /* SATA NCQ Send and Receive Log -- 1 page */ | ||||
} else if (cfis[4] == 0x10) { /* NCQ Command Error Log */ | } else if (cfis[4] == 0x10) { /* NCQ Command Error Log */ | ||||
memcpy(buf8, p->err_cfis, sizeof(p->err_cfis)); | memcpy(buf8, p->err_cfis, sizeof(p->err_cfis)); | ||||
ahci_checksum(buf8, sizeof(buf)); | ahci_checksum(buf8, sizeof(buf)); | ||||
} else if (cfis[4] == 0x13) { /* SATA NCQ Send and Receive Log */ | } else if (cfis[4] == 0x13) { /* SATA NCQ Send and Receive Log */ | ||||
if (blockif_candelete(p->bctx) && !blockif_is_ro(p->bctx)) { | if (blockbe_candelete(p->be) && !blockbe_is_ro(p->be)) { | ||||
buf[0x00] = 1; /* SFQ DSM supported */ | buf[0x00] = 1; /* SFQ DSM supported */ | ||||
buf[0x01] = 1; /* SFQ DSM TRIM supported */ | buf[0x01] = 1; /* SFQ DSM TRIM supported */ | ||||
} | } | ||||
} else { | } else { | ||||
ahci_write_fis_d2h(p, slot, cfis, | ahci_write_fis_d2h(p, slot, cfis, | ||||
(ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); | (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); | ||||
return; | return; | ||||
} | } | ||||
Show All 15 Lines | ahci_write_fis_d2h(p, slot, cfis, | ||||
(ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); | (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); | ||||
} else { | } else { | ||||
uint16_t buf[256]; | uint16_t buf[256]; | ||||
uint64_t sectors; | uint64_t sectors; | ||||
int sectsz, psectsz, psectoff, candelete, ro; | int sectsz, psectsz, psectoff, candelete, ro; | ||||
uint16_t cyl; | uint16_t cyl; | ||||
uint8_t sech, heads; | uint8_t sech, heads; | ||||
ro = blockif_is_ro(p->bctx); | ro = blockbe_is_ro(p->be); | ||||
candelete = blockif_candelete(p->bctx); | candelete = blockbe_candelete(p->be); | ||||
sectsz = blockif_sectsz(p->bctx); | sectsz = blockbe_sectsz(p->be); | ||||
sectors = blockif_size(p->bctx) / sectsz; | sectors = blockbe_size(p->be) / sectsz; | ||||
blockif_chs(p->bctx, &cyl, &heads, &sech); | blockbe_chs(p->be, &cyl, &heads, &sech); | ||||
blockif_psectsz(p->bctx, &psectsz, &psectoff); | blockbe_psectsz(p->be, &psectsz, &psectoff); | ||||
memset(buf, 0, sizeof(buf)); | memset(buf, 0, sizeof(buf)); | ||||
buf[0] = 0x0040; | buf[0] = 0x0040; | ||||
buf[1] = cyl; | buf[1] = cyl; | ||||
buf[3] = heads; | buf[3] = heads; | ||||
buf[6] = sech; | buf[6] = sech; | ||||
ata_string((uint8_t *)(buf+10), p->ident, 20); | ata_string((uint8_t *)(buf+10), p->ident, 20); | ||||
ata_string((uint8_t *)(buf+23), "001", 8); | ata_string((uint8_t *)(buf+23), "001", 8); | ||||
ata_string((uint8_t *)(buf+27), "BHYVE SATA DISK", 40); | ata_string((uint8_t *)(buf+27), "BHYVE SATA DISK", 40); | ||||
▲ Show 20 Lines • Show All 170 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
atapi_read_capacity(struct ahci_port *p, int slot, uint8_t *cfis) | atapi_read_capacity(struct ahci_port *p, int slot, uint8_t *cfis) | ||||
{ | { | ||||
uint8_t buf[8]; | uint8_t buf[8]; | ||||
uint64_t sectors; | uint64_t sectors; | ||||
sectors = blockif_size(p->bctx) / 2048; | sectors = blockbe_size(p->be) / 2048; | ||||
be32enc(buf, sectors - 1); | be32enc(buf, sectors - 1); | ||||
be32enc(buf + 4, 2048); | be32enc(buf + 4, 2048); | ||||
cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; | cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN; | ||||
write_prdt(p, slot, cfis, buf, sizeof(buf)); | write_prdt(p, slot, cfis, buf, sizeof(buf)); | ||||
ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); | ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC); | ||||
} | } | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (start_track <= 1) { | ||||
*bp++ = 0; | *bp++ = 0; | ||||
*bp++ = 0; | *bp++ = 0; | ||||
} | } | ||||
} | } | ||||
*bp++ = 0; | *bp++ = 0; | ||||
*bp++ = 0x14; | *bp++ = 0x14; | ||||
*bp++ = 0xaa; | *bp++ = 0xaa; | ||||
*bp++ = 0; | *bp++ = 0; | ||||
sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx); | sectors = blockbe_size(p->be) / blockbe_sectsz(p->be); | ||||
sectors >>= 2; | sectors >>= 2; | ||||
if (msf) { | if (msf) { | ||||
*bp++ = 0; | *bp++ = 0; | ||||
lba_to_msf(bp, sectors); | lba_to_msf(bp, sectors); | ||||
bp += 3; | bp += 3; | ||||
} else { | } else { | ||||
be32enc(bp, sectors); | be32enc(bp, sectors); | ||||
bp += 4; | bp += 4; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | case 2: | ||||
*bp++ = 1; | *bp++ = 1; | ||||
*bp++ = 0x14; | *bp++ = 0x14; | ||||
*bp++ = 0; | *bp++ = 0; | ||||
*bp++ = 0xa2; | *bp++ = 0xa2; | ||||
*bp++ = 0; | *bp++ = 0; | ||||
*bp++ = 0; | *bp++ = 0; | ||||
*bp++ = 0; | *bp++ = 0; | ||||
sectors = blockif_size(p->bctx) / blockif_sectsz(p->bctx); | sectors = blockbe_size(p->be) / blockbe_sectsz(p->be); | ||||
sectors >>= 2; | sectors >>= 2; | ||||
if (msf) { | if (msf) { | ||||
*bp++ = 0; | *bp++ = 0; | ||||
lba_to_msf(bp, sectors); | lba_to_msf(bp, sectors); | ||||
bp += 3; | bp += 3; | ||||
} else { | } else { | ||||
be32enc(bp, sectors); | be32enc(bp, sectors); | ||||
bp += 4; | bp += 4; | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | atapi_read(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done) | ||||
ahci_build_iov(p, aior, prdt, hdr->prdtl); | ahci_build_iov(p, aior, prdt, hdr->prdtl); | ||||
/* Mark this command in-flight. */ | /* Mark this command in-flight. */ | ||||
p->pending |= 1 << slot; | p->pending |= 1 << slot; | ||||
/* Stuff request onto busy list. */ | /* Stuff request onto busy list. */ | ||||
TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); | TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist); | ||||
err = blockif_read(p->bctx, breq); | err = blockbe_read(p->be, breq); | ||||
assert(err == 0); | assert(err == 0); | ||||
} | } | ||||
static void | static void | ||||
atapi_request_sense(struct ahci_port *p, int slot, uint8_t *cfis) | atapi_request_sense(struct ahci_port *p, int slot, uint8_t *cfis) | ||||
{ | { | ||||
uint8_t buf[64]; | uint8_t buf[64]; | ||||
uint8_t *acmd; | uint8_t *acmd; | ||||
▲ Show 20 Lines • Show All 573 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
pci_ahci_ioreq_init(struct ahci_port *pr) | pci_ahci_ioreq_init(struct ahci_port *pr) | ||||
{ | { | ||||
struct ahci_ioreq *vr; | struct ahci_ioreq *vr; | ||||
int i; | int i; | ||||
pr->ioqsz = blockif_queuesz(pr->bctx); | pr->ioqsz = blockbe_queuesz(pr->be); | ||||
pr->ioreq = calloc(pr->ioqsz, sizeof(struct ahci_ioreq)); | pr->ioreq = calloc(pr->ioqsz, sizeof(struct ahci_ioreq)); | ||||
STAILQ_INIT(&pr->iofhd); | STAILQ_INIT(&pr->iofhd); | ||||
/* | /* | ||||
* Add all i/o request entries to the free queue | * Add all i/o request entries to the free queue | ||||
*/ | */ | ||||
for (i = 0; i < pr->ioqsz; i++) { | for (i = 0; i < pr->ioqsz; i++) { | ||||
vr = &pr->ioreq[i]; | vr = &pr->ioreq[i]; | ||||
▲ Show 20 Lines • Show All 321 Lines • ▼ Show 20 Lines | if (opts[0] == 0) | ||||
continue; | continue; | ||||
/* | /* | ||||
* 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(opts, bident); | |||||
if (bctxt == NULL) { | ret = blockbe_open(&(sc->port[p].be),opts, bident); | ||||
if (ret != 0) { | |||||
sc->ports = p; | sc->ports = p; | ||||
ret = 1; | ret = 1; | ||||
goto open_fail; | goto open_fail; | ||||
} | } | ||||
bctxt = calloc(1, sizeof(struct locblk_ctxt)); | |||||
if (bctxt == NULL) { | |||||
perror("calloc"); | |||||
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 | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | pci_emul_alloc_bar(pi, 5, PCIBAR_MEM32, | ||||
AHCI_OFFSET + sc->ports * AHCI_STEP); | AHCI_OFFSET + sc->ports * AHCI_STEP); | ||||
pci_lintr_request(pi); | pci_lintr_request(pi); | ||||
open_fail: | open_fail: | ||||
if (ret) { | if (ret) { | ||||
for (p = 0; p < sc->ports; p++) { | for (p = 0; p < sc->ports; p++) { | ||||
if (sc->port[p].bctx != NULL) | if (sc->port[p].bctx != NULL) | ||||
blockif_close(sc->port[p].bctx); | blockbe_close(sc->port[p].be); | ||||
} | } | ||||
free(sc); | free(sc); | ||||
} | } | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
Show All 39 Lines |
You shouldn't need both be and bctx here. Most of the changes in this file will go away if you keep the existing blockif function and struct names.