diff options
Diffstat (limited to 'sys/dev/mpr/mpr_sas_lsi.c')
-rw-r--r-- | sys/dev/mpr/mpr_sas_lsi.c | 244 |
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; } |