Changeset View
Changeset View
Standalone View
Standalone View
head/usr.sbin/bhyve/pci_nvme.c
Show First 20 Lines • Show All 2,092 Lines • ▼ Show 20 Lines | |||||
static bool | static bool | ||||
nvme_opc_dataset_mgmt(struct pci_nvme_softc *sc, | nvme_opc_dataset_mgmt(struct pci_nvme_softc *sc, | ||||
struct nvme_command *cmd, | struct nvme_command *cmd, | ||||
struct pci_nvme_blockstore *nvstore, | struct pci_nvme_blockstore *nvstore, | ||||
struct pci_nvme_ioreq *req, | struct pci_nvme_ioreq *req, | ||||
uint16_t *status) | uint16_t *status) | ||||
{ | { | ||||
struct nvme_dsm_range *range; | |||||
uint32_t nr, r, non_zero, dr; | |||||
int err; | int err; | ||||
bool pending = false; | bool pending = false; | ||||
if ((sc->ctrldata.oncs & NVME_ONCS_DSM) == 0) { | if ((sc->ctrldata.oncs & NVME_ONCS_DSM) == 0) { | ||||
pci_nvme_status_genc(status, NVME_SC_INVALID_OPCODE); | pci_nvme_status_genc(status, NVME_SC_INVALID_OPCODE); | ||||
goto out; | goto out; | ||||
} | } | ||||
nr = cmd->cdw10 & 0xff; | |||||
/* copy locally because a range entry could straddle PRPs */ | |||||
range = calloc(1, NVME_MAX_DSM_TRIM); | |||||
if (range == NULL) { | |||||
pci_nvme_status_genc(status, NVME_SC_INTERNAL_DEVICE_ERROR); | |||||
goto out; | |||||
} | |||||
nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, cmd->prp1, cmd->prp2, | |||||
(uint8_t *)range, NVME_MAX_DSM_TRIM, NVME_COPY_FROM_PRP); | |||||
/* Check for invalid ranges and the number of non-zero lengths */ | |||||
non_zero = 0; | |||||
for (r = 0; r <= nr; r++) { | |||||
if (pci_nvme_out_of_range(nvstore, | |||||
range[r].starting_lba, range[r].length)) { | |||||
pci_nvme_status_genc(status, NVME_SC_LBA_OUT_OF_RANGE); | |||||
goto out; | |||||
} | |||||
if (range[r].length != 0) | |||||
non_zero++; | |||||
} | |||||
if (cmd->cdw11 & NVME_DSM_ATTR_DEALLOCATE) { | if (cmd->cdw11 & NVME_DSM_ATTR_DEALLOCATE) { | ||||
struct nvme_dsm_range *range; | |||||
size_t offset, bytes; | size_t offset, bytes; | ||||
uint32_t nr, r; | |||||
int sectsz_bits = sc->nvstore.sectsz_bits; | int sectsz_bits = sc->nvstore.sectsz_bits; | ||||
/* | /* | ||||
* DSM calls are advisory only, and compliant controllers | * DSM calls are advisory only, and compliant controllers | ||||
* may choose to take no actions (i.e. return Success). | * may choose to take no actions (i.e. return Success). | ||||
*/ | */ | ||||
if (!nvstore->deallocate) { | if (!nvstore->deallocate) { | ||||
pci_nvme_status_genc(status, NVME_SC_SUCCESS); | pci_nvme_status_genc(status, NVME_SC_SUCCESS); | ||||
goto out; | goto out; | ||||
} | } | ||||
if (req == NULL) { | /* If all ranges have a zero length, return Success */ | ||||
pci_nvme_status_genc(status, NVME_SC_INTERNAL_DEVICE_ERROR); | if (non_zero == 0) { | ||||
pci_nvme_status_genc(status, NVME_SC_SUCCESS); | |||||
goto out; | goto out; | ||||
} | } | ||||
/* copy locally because a range entry could straddle PRPs */ | if (req == NULL) { | ||||
range = calloc(1, NVME_MAX_DSM_TRIM); | |||||
if (range == NULL) { | |||||
pci_nvme_status_genc(status, NVME_SC_INTERNAL_DEVICE_ERROR); | pci_nvme_status_genc(status, NVME_SC_INTERNAL_DEVICE_ERROR); | ||||
goto out; | goto out; | ||||
} | } | ||||
nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, cmd->prp1, cmd->prp2, | |||||
(uint8_t *)range, NVME_MAX_DSM_TRIM, NVME_COPY_FROM_PRP); | |||||
if (pci_nvme_out_of_range(nvstore, range[0].starting_lba, | |||||
range[0].length)) { | |||||
pci_nvme_status_genc(status, NVME_SC_LBA_OUT_OF_RANGE); | |||||
goto out; | |||||
} | |||||
offset = range[0].starting_lba << sectsz_bits; | offset = range[0].starting_lba << sectsz_bits; | ||||
bytes = range[0].length << sectsz_bits; | bytes = range[0].length << sectsz_bits; | ||||
/* | /* | ||||
* If the request is for more than a single range, store | * If the request is for more than a single range, store | ||||
* the ranges in the br_iov. Optimize for the common case | * the ranges in the br_iov. Optimize for the common case | ||||
* of a single range. | * of a single range. | ||||
* | * | ||||
* Note that NVMe Number of Ranges is a zero based value | * Note that NVMe Number of Ranges is a zero based value | ||||
*/ | */ | ||||
nr = cmd->cdw10 & 0xff; | |||||
req->io_req.br_iovcnt = 0; | req->io_req.br_iovcnt = 0; | ||||
req->io_req.br_offset = offset; | req->io_req.br_offset = offset; | ||||
req->io_req.br_resid = bytes; | req->io_req.br_resid = bytes; | ||||
if (nr == 0) { | if (nr == 0) { | ||||
req->io_req.br_callback = pci_nvme_io_done; | req->io_req.br_callback = pci_nvme_io_done; | ||||
} else { | } else { | ||||
struct iovec *iov = req->io_req.br_iov; | struct iovec *iov = req->io_req.br_iov; | ||||
for (r = 0; r <= nr; r++) { | for (r = 0, dr = 0; r <= nr; r++) { | ||||
if (pci_nvme_out_of_range(nvstore, range[r].starting_lba, | |||||
range[r].length)) { | |||||
pci_nvme_status_genc(status, NVME_SC_LBA_OUT_OF_RANGE); | |||||
goto out; | |||||
} | |||||
offset = range[r].starting_lba << sectsz_bits; | offset = range[r].starting_lba << sectsz_bits; | ||||
bytes = range[r].length << sectsz_bits; | bytes = range[r].length << sectsz_bits; | ||||
if (bytes == 0) | |||||
continue; | |||||
if ((nvstore->size - offset) < bytes) { | if ((nvstore->size - offset) < bytes) { | ||||
pci_nvme_status_genc(status, NVME_SC_LBA_OUT_OF_RANGE); | pci_nvme_status_genc(status, | ||||
NVME_SC_LBA_OUT_OF_RANGE); | |||||
goto out; | goto out; | ||||
} | } | ||||
iov[r].iov_base = (void *)offset; | iov[dr].iov_base = (void *)offset; | ||||
iov[r].iov_len = bytes; | iov[dr].iov_len = bytes; | ||||
dr++; | |||||
} | } | ||||
req->io_req.br_callback = pci_nvme_dealloc_sm; | req->io_req.br_callback = pci_nvme_dealloc_sm; | ||||
/* | /* | ||||
* Use prev_gpaddr to track the current entry and | * Use prev_gpaddr to track the current entry and | ||||
* prev_size to track the number of entries | * prev_size to track the number of entries | ||||
*/ | */ | ||||
req->prev_gpaddr = 0; | req->prev_gpaddr = 0; | ||||
req->prev_size = r; | req->prev_size = dr; | ||||
} | } | ||||
err = blockif_delete(nvstore->ctx, &req->io_req); | err = blockif_delete(nvstore->ctx, &req->io_req); | ||||
if (err) | if (err) | ||||
pci_nvme_status_genc(status, NVME_SC_INTERNAL_DEVICE_ERROR); | pci_nvme_status_genc(status, NVME_SC_INTERNAL_DEVICE_ERROR); | ||||
else | else | ||||
pending = true; | pending = true; | ||||
free(range); | |||||
} | } | ||||
out: | out: | ||||
free(range); | |||||
return (pending); | return (pending); | ||||
} | } | ||||
static void | static void | ||||
pci_nvme_handle_io_cmd(struct pci_nvme_softc* sc, uint16_t idx) | pci_nvme_handle_io_cmd(struct pci_nvme_softc* sc, uint16_t idx) | ||||
{ | { | ||||
struct nvme_submission_queue *sq; | struct nvme_submission_queue *sq; | ||||
uint16_t status; | uint16_t status; | ||||
▲ Show 20 Lines • Show All 594 Lines • Show Last 20 Lines |