summaryrefslogtreecommitdiffstats
path: root/sys/dev/mpr/mpr_sas_lsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mpr/mpr_sas_lsi.c')
-rw-r--r--sys/dev/mpr/mpr_sas_lsi.c244
1 files changed, 229 insertions, 15 deletions
diff --git a/sys/dev/mpr/mpr_sas_lsi.c b/sys/dev/mpr/mpr_sas_lsi.c
index f773df2..2f3b360 100644
--- a/sys/dev/mpr/mpr_sas_lsi.c
+++ b/sys/dev/mpr/mpr_sas_lsi.c
@@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$");
#include <dev/mpr/mpi/mpi2.h>
#include <dev/mpr/mpi/mpi2_ioc.h>
#include <dev/mpr/mpi/mpi2_sas.h>
+#include <dev/mpr/mpi/mpi2_pci.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_raid.h>
@@ -116,6 +117,8 @@ static void mprsas_fw_work(struct mpr_softc *sc,
static void mprsas_fw_event_free(struct mpr_softc *,
struct mpr_fw_event_work *);
static int mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate);
+static int mprsas_add_pcie_device(struct mpr_softc *sc, u16 handle,
+ u8 linkrate);
static int mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle,
Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz,
u32 devinfo);
@@ -156,6 +159,7 @@ mprsas_evt_handler(struct mpr_softc *sc, uintptr_t data,
bcopy(event->EventData, fw_event->event_data, sz);
fw_event->event = event->Event;
if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
+ event->Event == MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST ||
event->Event == MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE ||
event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
sc->track_mapping_events)
@@ -167,13 +171,13 @@ mprsas_evt_handler(struct mpr_softc *sc, uintptr_t data,
* events are processed.
*/
if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
+ event->Event == MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST ||
event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
sc->wait_for_port_enable)
mprsas_startup_increment(sc->sassc);
TAILQ_INSERT_TAIL(&sc->sassc->ev_queue, fw_event, ev_link);
taskqueue_enqueue(sc->sassc->ev_tq, &sc->sassc->ev_task);
-
}
static void
@@ -205,7 +209,7 @@ mprsas_fw_work(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event)
{
MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy;
- int i;
+ uint8_t i;
data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
fw_event->event_data;
@@ -674,6 +678,60 @@ skip_fp_send:
}
break;
}
+ case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
+ {
+ MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST *data;
+ MPI26_EVENT_PCIE_TOPO_PORT_ENTRY *port_entry;
+ uint8_t i, link_rate;
+ uint16_t handle;
+
+ data = (MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST *)
+ fw_event->event_data;
+
+ mpr_mapping_pcie_topology_change_event(sc,
+ fw_event->event_data);
+
+ for (i = 0; i < data->NumEntries; i++) {
+ port_entry = &data->PortEntry[i];
+ handle = le16toh(port_entry->AttachedDevHandle);
+ link_rate = port_entry->CurrentPortInfo &
+ MPI26_EVENT_PCIE_TOPO_PI_RATE_MASK;
+ switch (port_entry->PortStatus) {
+ case MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED:
+ if (link_rate <
+ MPI26_EVENT_PCIE_TOPO_PI_RATE_2_5) {
+ mpr_dprint(sc, MPR_ERROR, "%s: Cannot "
+ "add PCIe device with handle 0x%x "
+ "with unknown link rate.\n",
+ __func__, handle);
+ break;
+ }
+ if (mprsas_add_pcie_device(sc, handle,
+ link_rate)) {
+ mpr_dprint(sc, MPR_ERROR, "%s: failed "
+ "to add PCIe device with handle "
+ "0x%x\n", __func__, handle);
+ mprsas_prepare_remove(sassc, handle);
+ }
+ break;
+ case MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
+ mprsas_prepare_remove(sassc, handle);
+ break;
+ case MPI26_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
+ case MPI26_EVENT_PCIE_TOPO_PS_NO_CHANGE:
+ case MPI26_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
+ default:
+ break;
+ }
+ }
+ /*
+ * refcount was incremented for this event in
+ * mprsas_evt_handler. Decrement it here because the event has
+ * been processed.
+ */
+ mprsas_startup_decrement(sassc);
+ break;
+ }
case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
default:
@@ -703,7 +761,8 @@ mprsas_firmware_event_work(void *arg, int pending)
}
static int
-mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){
+mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate)
+{
char devstring[80];
struct mprsas_softc *sassc;
struct mprsas_target *targ;
@@ -769,13 +828,24 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){
}
}
- id = mpr_mapping_get_sas_id(sc, sas_address, handle);
+ /*
+ * use_phynum:
+ * 1 - use the PhyNum field as a fallback to the mapping logic
+ * 0 - never use the PhyNum field
+ * -1 - only use the PhyNum field
+ */
+ id = MPR_MAP_BAD_ID;
+ if (sc->use_phynum != -1)
+ id = mpr_mapping_get_sas_id(sc, sas_address, handle);
if (id == MPR_MAP_BAD_ID) {
- printf("failure at %s:%d/%s()! Could not get ID for device "
- "with handle 0x%04x\n", __FILE__, __LINE__, __func__,
- handle);
- error = ENXIO;
- goto out;
+ if ((sc->use_phynum == 0) ||
+ ((id = config_page.PhyNum) > sassc->maxtargets)) {
+ mpr_dprint(sc, MPR_INFO, "failure at %s:%d/%s()! "
+ "Could not get ID for device with handle 0x%04x\n",
+ __FILE__, __LINE__, __func__, handle);
+ error = ENXIO;
+ goto out;
+ }
}
if (mprsas_check_id(sassc, id) != 0) {
@@ -784,9 +854,16 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){
goto out;
}
+ targ = &sassc->targets[id];
+ if (targ->handle != 0x0) {
+ mpr_dprint(sc, MPR_MAPPING, "Attempting to reuse target id "
+ "%d handle 0x%04x\n", id, targ->handle);
+ error = ENXIO;
+ goto out;
+ }
+
mpr_dprint(sc, MPR_MAPPING, "SAS Address from SAS device page0 = %jx\n",
sas_address);
- targ = &sassc->targets[id];
targ->devinfo = device_info;
targ->devname = le32toh(config_page.DeviceName.High);
targ->devname = (targ->devname << 32) |
@@ -809,8 +886,10 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){
if (is_SATA_SSD) {
targ->flags = MPR_TARGET_IS_SATA_SSD;
}
- if (le16toh(config_page.Flags) &
- MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
+ if ((le16toh(config_page.Flags) &
+ MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) &&
+ (le16toh(config_page.Flags) &
+ MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE)) {
targ->scsi_req_desc_type =
MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
}
@@ -890,7 +969,7 @@ out:
mprsas_startup_decrement(sassc);
return (error);
}
-
+
int
mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc,
u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD)
@@ -1122,6 +1201,141 @@ mprsas_ata_id_timeout(void *data)
}
static int
+mprsas_add_pcie_device(struct mpr_softc *sc, u16 handle, u8 linkrate)
+{
+ char devstring[80];
+ struct mprsas_softc *sassc;
+ struct mprsas_target *targ;
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi26PCIeDevicePage0_t config_page;
+ Mpi26PCIeDevicePage2_t config_page2;
+ uint64_t pcie_wwid, parent_wwid = 0;
+ u32 device_info, parent_devinfo = 0;
+ unsigned int id;
+ int error = 0;
+ struct mprsas_lun *lun;
+
+ sassc = sc->sassc;
+ mprsas_startup_increment(sassc);
+ if ((mpr_config_get_pcie_device_pg0(sc, &mpi_reply, &config_page,
+ MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) {
+ printf("%s: error reading PCIe device page0\n", __func__);
+ error = ENXIO;
+ goto out;
+ }
+
+ device_info = le32toh(config_page.DeviceInfo);
+
+ if (((device_info & MPI26_PCIE_DEVINFO_PCI_SWITCH) == 0)
+ && (le16toh(config_page.ParentDevHandle) != 0)) {
+ Mpi2ConfigReply_t tmp_mpi_reply;
+ Mpi26PCIeDevicePage0_t parent_config_page;
+
+ if ((mpr_config_get_pcie_device_pg0(sc, &tmp_mpi_reply,
+ &parent_config_page, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE,
+ le16toh(config_page.ParentDevHandle)))) {
+ printf("%s: error reading PCIe device %#x page0\n",
+ __func__, le16toh(config_page.ParentDevHandle));
+ } else {
+ parent_wwid = parent_config_page.WWID.High;
+ parent_wwid = (parent_wwid << 32) |
+ parent_config_page.WWID.Low;
+ parent_devinfo = le32toh(parent_config_page.DeviceInfo);
+ }
+ }
+ /* TODO Check proper endianness */
+ pcie_wwid = config_page.WWID.High;
+ pcie_wwid = (pcie_wwid << 32) | config_page.WWID.Low;
+ mpr_dprint(sc, MPR_INFO, "PCIe WWID from PCIe device page0 = %jx\n",
+ pcie_wwid);
+
+ if ((mpr_config_get_pcie_device_pg2(sc, &mpi_reply, &config_page2,
+ MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) {
+ printf("%s: error reading PCIe device page2\n", __func__);
+ error = ENXIO;
+ goto out;
+ }
+
+ id = mpr_mapping_get_sas_id(sc, pcie_wwid, handle);
+ if (id == MPR_MAP_BAD_ID) {
+ printf("failure at %s:%d/%s()! Could not get ID for device "
+ "with handle 0x%04x\n", __FILE__, __LINE__, __func__,
+ handle);
+ error = ENXIO;
+ goto out;
+ }
+
+ if (mprsas_check_id(sassc, id) != 0) {
+ device_printf(sc->mpr_dev, "Excluding target id %d\n", id);
+ error = ENXIO;
+ goto out;
+ }
+
+ mpr_dprint(sc, MPR_MAPPING, "WWID from PCIe device page0 = %jx\n",
+ pcie_wwid);
+ targ = &sassc->targets[id];
+ targ->devinfo = device_info;
+ targ->encl_handle = le16toh(config_page.EnclosureHandle);
+ targ->encl_slot = le16toh(config_page.Slot);
+ targ->encl_level = config_page.EnclosureLevel;
+ targ->connector_name[0] = ((char *)&config_page.ConnectorName)[0];
+ targ->connector_name[1] = ((char *)&config_page.ConnectorName)[1];
+ targ->connector_name[2] = ((char *)&config_page.ConnectorName)[2];
+ targ->connector_name[3] = ((char *)&config_page.ConnectorName)[3];
+ targ->is_nvme = device_info & MPI26_PCIE_DEVINFO_NVME;
+ targ->MDTS = config_page2.MaximumDataTransferSize;
+ /*
+ * Assume always TRUE for encl_level_valid because there is no valid
+ * flag for PCIe.
+ */
+ targ->encl_level_valid = TRUE;
+ targ->handle = handle;
+ targ->parent_handle = le16toh(config_page.ParentDevHandle);
+ targ->sasaddr = mpr_to_u64(&config_page.WWID);
+ targ->parent_sasaddr = le64toh(parent_wwid);
+ targ->parent_devinfo = parent_devinfo;
+ targ->tid = id;
+ targ->linkrate = linkrate;
+ targ->flags = 0;
+ if ((le16toh(config_page.Flags) &
+ MPI26_PCIEDEV0_FLAGS_ENABLED_FAST_PATH) &&
+ (le16toh(config_page.Flags) &
+ MPI26_PCIEDEV0_FLAGS_FAST_PATH_CAPABLE)) {
+ targ->scsi_req_desc_type =
+ MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
+ }
+ TAILQ_INIT(&targ->commands);
+ TAILQ_INIT(&targ->timedout_commands);
+ while (!SLIST_EMPTY(&targ->luns)) {
+ lun = SLIST_FIRST(&targ->luns);
+ SLIST_REMOVE_HEAD(&targ->luns, lun_link);
+ free(lun, M_MPR);
+ }
+ SLIST_INIT(&targ->luns);
+
+ mpr_describe_devinfo(targ->devinfo, devstring, 80);
+ mpr_dprint(sc, (MPR_INFO|MPR_MAPPING), "Found PCIe device <%s> <%s> "
+ "handle<0x%04x> enclosureHandle<0x%04x> slot %d\n", devstring,
+ mpr_describe_table(mpr_pcie_linkrate_names, targ->linkrate),
+ targ->handle, targ->encl_handle, targ->encl_slot);
+ if (targ->encl_level_valid) {
+ mpr_dprint(sc, (MPR_INFO|MPR_MAPPING), "At enclosure level %d "
+ "and connector name (%4s)\n", targ->encl_level,
+ targ->connector_name);
+ }
+#if ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000039)) || \
+ (__FreeBSD_version < 902502)
+ if ((sassc->flags & MPRSAS_IN_STARTUP) == 0)
+#endif
+ mprsas_rescan_target(sc, targ);
+ mpr_dprint(sc, MPR_MAPPING, "Target id 0x%x added\n", targ->tid);
+
+out:
+ mprsas_startup_decrement(sassc);
+ return (error);
+}
+
+static int
mprsas_volume_add(struct mpr_softc *sc, u16 handle)
{
struct mprsas_softc *sassc;
@@ -1217,8 +1431,8 @@ mprsas_SSU_to_SATA_devices(struct mpr_softc *sc)
if (target->stop_at_shutdown) {
ccb = xpt_alloc_ccb_nowait();
if (ccb == NULL) {
- mpr_dprint(sc, MPR_FAULT, "Unable to alloc CCB to stop "
- "unit.\n");
+ mpr_dprint(sc, MPR_FAULT, "Unable to alloc CCB "
+ "to stop unit.\n");
return;
}
OpenPOWER on IntegriCloud