Provide link speed data in XPT_GET_TRAN_SETTINGS. Provide full version

information for that and XPT_PATH_INQ. Provide macros to encode/decode
major/minor versions.  Read the link speed and lane count to compute
the base_transfer_speed for XPT_PATH_INQ.

Sponsored by: Netflix
This commit is contained in:
Warner Losh 2017-11-14 05:05:16 +00:00
parent d505913c91
commit 4e3b274457
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=325794
5 changed files with 51 additions and 18 deletions

View file

@ -1016,11 +1016,14 @@ struct ccb_trans_settings_nvme
u_int valid; /* Which fields to honor */
#define CTS_NVME_VALID_SPEC 0x01
#define CTS_NVME_VALID_CAPS 0x02
u_int spec_major; /* Major version of spec supported */
u_int spec_minor; /* Minor verison of spec supported */
u_int spec_tiny; /* Tiny version of spec supported */
u_int max_xfer; /* Max transfer size (0 -> unlimited */
u_int caps;
#define CTS_NVME_VALID_LINK 0x04
uint32_t spec; /* NVMe spec implemented -- same as vs register */
uint32_t max_xfer; /* Max transfer size (0 -> unlimited */
uint32_t caps;
uint8_t lanes; /* Number of PCIe lanes */
uint8_t speed; /* PCIe generation for each lane */
uint8_t max_lanes; /* Number of PCIe lanes */
uint8_t max_speed; /* PCIe generation for each lane */
};
#include <cam/mmc/mmc_bus.h>

View file

@ -33,8 +33,6 @@
struct ccb_nvmeio;
#define NVME_REV_1 1 /* Supports NVMe 1.2 or earlier */
void nvme_ns_cmd(struct ccb_nvmeio *nvmeio, uint8_t cmd, uint32_t nsid,
uint32_t cdw10, uint32_t cdw11, uint32_t cdw12, uint32_t cdw13,
uint32_t cdw14, uint32_t cdw15);

View file

@ -639,12 +639,14 @@ nvme_announce_periph(struct cam_periph *periph)
static void
nvme_proto_announce(struct cam_ed *device)
{
nvme_print_ident(device->nvme_cdata, device->nvme_data);
}
static void
nvme_proto_denounce(struct cam_ed *device)
{
nvme_print_ident(device->nvme_cdata, device->nvme_data);
}

View file

@ -41,6 +41,13 @@
#define NVME_IO_TEST _IOWR('n', 100, struct nvme_io_test)
#define NVME_BIO_TEST _IOWR('n', 101, struct nvme_io_test)
/*
* Macros to deal with NVME revisions, as defined VS register
*/
#define NVME_REV(x, y) (((x) << 16) | ((y) << 8))
#define NVME_MAJOR(r) (((r) >> 16) & 0xffff)
#define NVME_MINOR(r) (((r) >> 8) & 0xff)
/*
* Use to mark a command to apply to all namespaces, or to retrieve global
* log pages.

View file

@ -44,6 +44,9 @@ __FBSDID("$FreeBSD$");
#include <cam/cam_xpt_internal.h> // Yes, this is wrong.
#include <cam/cam_debug.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include "nvme_private.h"
#define ccb_accb_ptr spriv_ptr0
@ -122,6 +125,22 @@ nvme_sim_nvmeio(struct cam_sim *sim, union ccb *ccb)
ccb->ccb_h.status |= CAM_SIM_QUEUED;
}
static uint32_t
nvme_link_kBps(struct nvme_controller *ctrlr)
{
uint32_t speed, lanes, link[] = { 1, 250000, 500000, 985000, 1970000 };
speed = pcie_link_status(ctrlr->dev) & PCIEM_LINK_STA_SPEED;
lanes = (pcie_link_status(ctrlr->dev) & PCIEM_LINK_STA_WIDTH) >> 4;
/*
* Failsafe on link speed indicator. If it is insane report the number of
* lanes as the speed. Not 100% accurate, but may be diagnostic.
*/
if (speed >= nitems(link))
speed = 0;
return link[speed] * lanes;
}
static void
nvme_sim_action(struct cam_sim *sim, union ccb *ccb)
{
@ -179,15 +198,15 @@ nvme_sim_action(struct cam_sim *sim, union ccb *ccb)
cpi->maxio = nvme_ns_get_max_io_xfer_size(ns);
cpi->initiator_id = 0;
cpi->bus_id = cam_sim_bus(sim);
cpi->base_transfer_speed = 4000000; /* 4 GB/s 4 lanes pcie 3 */
cpi->base_transfer_speed = nvme_link_kBps(ctrlr);
strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
strlcpy(cpi->hba_vid, "NVMe", HBA_IDLEN);
strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
cpi->unit_number = cam_sim_unit(sim);
cpi->transport = XPORT_NVME; /* XXX XPORT_PCIE ? */
cpi->transport_version = 1; /* XXX Get PCIe spec ? */
cpi->transport_version = nvme_mmio_read_4(ctrlr, vs);
cpi->protocol = PROTO_NVME;
cpi->protocol_version = NVME_REV_1; /* Groks all 1.x NVMe cards */
cpi->protocol_version = nvme_mmio_read_4(ctrlr, vs);
cpi->xport_specific.nvme.nsid = ns->id;
cpi->ccb_h.status = CAM_REQ_CMP;
break;
@ -197,20 +216,24 @@ nvme_sim_action(struct cam_sim *sim, union ccb *ccb)
struct ccb_trans_settings *cts;
struct ccb_trans_settings_nvme *nvmep;
struct ccb_trans_settings_nvme *nvmex;
device_t dev;
dev = ctrlr->dev;
cts = &ccb->cts;
nvmex = &cts->xport_specific.nvme;
nvmep = &cts->proto_specific.nvme;
nvmex->valid = CTS_NVME_VALID_SPEC;
nvmex->spec_major = 1; /* XXX read from card */
nvmex->spec_minor = 2;
nvmex->spec_tiny = 0;
nvmex->valid = CTS_NVME_VALID_SPEC | CTS_NVME_VALID_LINK;
nvmex->spec = nvme_mmio_read_4(ctrlr, vs);
nvmex->speed = pcie_link_status(dev) & PCIEM_LINK_STA_SPEED;
nvmex->lanes = (pcie_link_status(dev) & PCIEM_LINK_STA_WIDTH) >> 4;
nvmex->max_speed = pcie_link_caps(dev) & PCIEM_LINK_CAP_MAX_SPEED;
nvmex->max_lanes = (pcie_link_caps(dev) & PCIEM_LINK_CAP_MAX_WIDTH) >> 4;
/* XXX these should be something else maybe ? */
nvmep->valid = 1;
nvmep->spec = nvmex->spec;
nvmep->valid = CTS_NVME_VALID_SPEC;
nvmep->spec_major = 1; /* XXX read from card */
nvmep->spec_minor = 2;
nvmep->spec_tiny = 0;
cts->transport = XPORT_NVME;
cts->protocol = PROTO_NVME;
cts->ccb_h.status = CAM_REQ_CMP;