static int mpssas_volume_add(struct mps_softc *sc, u16 handle) { struct mpssas_softc *sassc; struct mpssas_target *targ; u64 wwid; unsigned int id; int error = 0; struct mpssas_lun *lun; sassc = sc->sassc; mpssas_startup_increment(sassc); /* wwid is endian safe */ mps_config_get_volume_wwid(sc, handle, &wwid); if (!wwid) { printf("%s: invalid WWID; cannot add volume to mapping table\n", __func__); error = ENXIO; goto out; } id = mps_mapping_get_raid_id(sc, wwid, handle); if (id == MPS_MAP_BAD_ID) { printf("%s: could not get ID for volume with handle 0x%04x and " "WWID 0x%016llx\n", __func__, handle, (unsigned long long)wwid); error = ENXIO; goto out; } targ = &sassc->targets[id]; targ->tid = id; targ->handle = handle; targ->devname = wwid; 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_MPT2); } SLIST_INIT(&targ->luns); #if __FreeBSD_version < 1000039 if ((sassc->flags & MPSSAS_IN_STARTUP) == 0) #endif mpssas_rescan_target(sc, targ); mps_dprint(sc, MPS_MAPPING, "RAID target id %d added (WWID = 0x%jx)\n", targ->tid, wwid); out: mpssas_startup_decrement(sassc); return (error); }
static int mpssas_volume_add(struct mps_softc *sc, Mpi2EventIrConfigElement_t *element) { struct mpssas_softc *sassc; struct mpssas_target *targ; u64 wwid; u16 handle = le16toh(element->VolDevHandle); unsigned int id; int error = 0; sassc = sc->sassc; mpssas_startup_increment(sassc); mps_config_get_volume_wwid(sc, handle, &wwid); if (!wwid) { kprintf("%s: invalid WWID; cannot add volume to mapping table\n", __func__); error = ENXIO; goto out; } id = mps_mapping_get_raid_id(sc, wwid, handle); if (id == MPS_MAP_BAD_ID) { kprintf("%s: could not get ID for volume with handle 0x%04x and " "WWID 0x%016llx\n", __func__, handle, (unsigned long long)wwid); error = ENXIO; goto out; } targ = &sassc->targets[id]; targ->tid = id; targ->handle = handle; targ->devname = wwid; TAILQ_INIT(&targ->commands); TAILQ_INIT(&targ->timedout_commands); SLIST_INIT(&targ->luns); if ((sassc->flags & MPSSAS_IN_STARTUP) == 0) mpssas_rescan_target(sc, targ); mps_dprint(sc, MPS_INFO, "RAID target id %d added (WWID = 0x%jx)\n", targ->tid, wwid); out: mpssas_startup_decrement(sassc); return (error); }
static int mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){ char devstring[80]; struct mpssas_softc *sassc; struct mpssas_target *targ; Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t config_page; uint64_t sas_address, sata_sas_address; uint64_t parent_sas_address = 0; u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); u32 device_info, parent_devinfo = 0; unsigned int id; int ret; int error = 0; sassc = sc->sassc; mpssas_startup_increment(sassc); if ((mps_config_get_sas_device_pg0(sc, &mpi_reply, &config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { kprintf("%s: error reading SAS device page0\n", __func__); error = ENXIO; goto out; } device_info = le32toh(config_page.DeviceInfo); if (((device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) && (config_page.ParentDevHandle != 0)) { Mpi2ConfigReply_t tmp_mpi_reply; Mpi2SasDevicePage0_t parent_config_page; if ((mps_config_get_sas_device_pg0(sc, &tmp_mpi_reply, &parent_config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, le16toh(config_page.ParentDevHandle)))) { kprintf("%s: error reading SAS device %#x page0\n", __func__, le16toh(config_page.ParentDevHandle)); } else { parent_sas_address = parent_config_page.SASAddress.High; parent_sas_address = (parent_sas_address << 32) | parent_config_page.SASAddress.Low; parent_devinfo = le32toh(parent_config_page.DeviceInfo); } } /* TODO Check proper endianess */ sas_address = config_page.SASAddress.High; sas_address = (sas_address << 32) | config_page.SASAddress.Low; if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) { ret = mpssas_get_sas_address_for_sata_disk(sc, &sata_sas_address, handle, device_info); if (!ret) id = mps_mapping_get_sas_id(sc, sata_sas_address, handle); else id = mps_mapping_get_sas_id(sc, sas_address, handle); } else id = mps_mapping_get_sas_id(sc, sas_address, handle); } else id = mps_mapping_get_sas_id(sc, sas_address, handle); if (id == MPS_MAP_BAD_ID) { kprintf("failure at %s:%d/%s()! Could not get ID for device " "with handle 0x%04x\n", __FILE__, __LINE__, __func__, handle); error = ENXIO; goto out; } mps_vprintf(sc, "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) | le32toh(config_page.DeviceName.Low); targ->encl_handle = le16toh(config_page.EnclosureHandle); targ->encl_slot = le16toh(config_page.Slot); targ->handle = handle; targ->parent_handle = le16toh(config_page.ParentDevHandle); targ->sasaddr = mps_to_u64(&config_page.SASAddress); targ->parent_sasaddr = le64toh(parent_sas_address); targ->parent_devinfo = parent_devinfo; targ->tid = id; targ->linkrate = (linkrate>>4); targ->flags = 0; TAILQ_INIT(&targ->commands); TAILQ_INIT(&targ->timedout_commands); SLIST_INIT(&targ->luns); mps_describe_devinfo(targ->devinfo, devstring, 80); mps_vprintf(sc, "Found device <%s> <%s> <0x%04x> <%d/%d>\n", devstring, mps_describe_table(mps_linkrate_names, targ->linkrate), targ->handle, targ->encl_handle, targ->encl_slot); if ((sassc->flags & MPSSAS_IN_STARTUP) == 0) mpssas_rescan_target(sc, targ); mps_vprintf(sc, "Target id 0x%x added\n", targ->tid); out: mpssas_startup_decrement(sassc); return (error); }
/** * _mps_fw_work - delayed task for processing firmware events * @sc: per adapter object * @fw_event: The fw_event_work object * Context: user. * * Return nothing. */ static void mpssas_fw_work(struct mps_softc *sc, struct mps_fw_event_work *fw_event) { struct mpssas_softc *sassc; sassc = sc->sassc; switch (fw_event->event) { case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: { MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data; MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy; int i; data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *) fw_event->event_data; mps_mapping_topology_change_event(sc, fw_event->event_data); for (i = 0; i < data->NumEntries; i++) { phy = &data->PHY[i]; switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) { case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: if (mpssas_add_device(sc, phy->AttachedDevHandle, phy->LinkRate)){ kprintf("%s: failed to add device with " "handle 0x%x\n", __func__, phy->AttachedDevHandle); mpssas_prepare_remove(sassc, phy-> AttachedDevHandle); } break; case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: mpssas_prepare_remove(sassc, phy-> AttachedDevHandle); break; case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: default: break; } } /* * refcount was incremented for this event in * mpssas_evt_handler. Decrement it here because the event has * been processed. */ mpssas_startup_decrement(sassc); break; } case MPI2_EVENT_SAS_DISCOVERY: { MPI2_EVENT_DATA_SAS_DISCOVERY *data; data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)fw_event->event_data; if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED) mps_dprint(sc, MPS_TRACE,"SAS discovery start event\n"); if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) { mps_dprint(sc, MPS_TRACE,"SAS discovery stop event\n"); sassc->flags &= ~MPSSAS_IN_DISCOVERY; mpssas_discovery_end(sassc); } break; } case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: { Mpi2EventDataSasEnclDevStatusChange_t *data; data = (Mpi2EventDataSasEnclDevStatusChange_t *) fw_event->event_data; mps_mapping_enclosure_dev_status_change_event(sc, fw_event->event_data); break; } case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: { Mpi2EventIrConfigElement_t *element; int i; u8 foreign_config; Mpi2EventDataIrConfigChangeList_t *event_data; struct mpssas_target *targ; unsigned int id; event_data = fw_event->event_data; foreign_config = (le32toh(event_data->Flags) & MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; id = mps_mapping_get_raid_id_from_handle (sc, element->VolDevHandle); mps_mapping_ir_config_change_event(sc, event_data); for (i = 0; i < event_data->NumElements; i++, element++) { switch (element->ReasonCode) { case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: case MPI2_EVENT_IR_CHANGE_RC_ADDED: if (!foreign_config) { if (mpssas_volume_add(sc, element)) { kprintf("%s: failed to add RAID " "volume with handle 0x%x\n", __func__, le16toh(element-> VolDevHandle)); } } break; case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: case MPI2_EVENT_IR_CHANGE_RC_REMOVED: /* * Rescan after volume is deleted or removed. */ if (!foreign_config) { if (id == MPS_MAP_BAD_ID) { kprintf("%s: could not get ID " "for volume with handle " "0x%04x\n", __func__, element->VolDevHandle); break; } targ = &sassc->targets[id]; targ->handle = 0x0; targ->encl_slot = 0x0; targ->encl_handle = 0x0; targ->exp_dev_handle = 0x0; targ->phy_num = 0x0; targ->linkrate = 0x0; mpssas_rescan_target(sc, targ); kprintf("RAID target id 0x%x removed\n", targ->tid); } break; case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: /* * Phys Disk of a volume has been created. Hide * it from the OS. */ mpssas_prepare_remove(sassc, element-> PhysDiskDevHandle); break; case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: /* * Phys Disk of a volume has been deleted. * Expose it to the OS. */ if (mpssas_add_device(sc, element->PhysDiskDevHandle, 0)){ kprintf("%s: failed to add device with " "handle 0x%x\n", __func__, element->PhysDiskDevHandle); mpssas_prepare_remove(sassc, element-> PhysDiskDevHandle); } break; } } /* * refcount was incremented for this event in * mpssas_evt_handler. Decrement it here because the event has * been processed. */ mpssas_startup_decrement(sassc); break; } case MPI2_EVENT_IR_VOLUME: { Mpi2EventDataIrVolume_t *event_data = fw_event->event_data; /* * Informational only. */ mps_dprint(sc, MPS_INFO, "Received IR Volume event:\n"); switch (event_data->ReasonCode) { case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED: mps_dprint(sc, MPS_INFO, " Volume Settings " "changed from 0x%x to 0x%x for Volome with " "handle 0x%x", event_data->PreviousValue, event_data->NewValue, event_data->VolDevHandle); break; case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED: mps_dprint(sc, MPS_INFO, " Volume Status " "changed from 0x%x to 0x%x for Volome with " "handle 0x%x", event_data->PreviousValue, event_data->NewValue, event_data->VolDevHandle); break; case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED: mps_dprint(sc, MPS_INFO, " Volume State " "changed from 0x%x to 0x%x for Volome with " "handle 0x%x", event_data->PreviousValue, event_data->NewValue, event_data->VolDevHandle); break; default: break; } break; } case MPI2_EVENT_IR_PHYSICAL_DISK: { Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data; /* * Informational only. */ mps_dprint(sc, MPS_INFO, "Received IR Phys Disk event:\n"); switch (event_data->ReasonCode) { case MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED: mps_dprint(sc, MPS_INFO, " Phys Disk Settings " "changed from 0x%x to 0x%x for Phys Disk Number " "%d and handle 0x%x at Enclosure handle 0x%x, Slot " "%d", event_data->PreviousValue, event_data->NewValue, event_data->PhysDiskNum, event_data->PhysDiskDevHandle, event_data->EnclosureHandle, event_data->Slot); break; case MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED: mps_dprint(sc, MPS_INFO, " Phys Disk Status changed " "from 0x%x to 0x%x for Phys Disk Number %d and " "handle 0x%x at Enclosure handle 0x%x, Slot %d", event_data->PreviousValue, event_data->NewValue, event_data->PhysDiskNum, event_data->PhysDiskDevHandle, event_data->EnclosureHandle, event_data->Slot); break; case MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED: mps_dprint(sc, MPS_INFO, " Phys Disk State changed " "from 0x%x to 0x%x for Phys Disk Number %d and " "handle 0x%x at Enclosure handle 0x%x, Slot %d", event_data->PreviousValue, event_data->NewValue, event_data->PhysDiskNum, event_data->PhysDiskDevHandle, event_data->EnclosureHandle, event_data->Slot); break; default: break; } break; } case MPI2_EVENT_IR_OPERATION_STATUS: { Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data; /* * Informational only. */ mps_dprint(sc, MPS_INFO, "Received IR Op Status event:\n"); mps_dprint(sc, MPS_INFO, " RAID Operation of %d is %d " "percent complete for Volume with handle 0x%x", event_data->RAIDOperation, event_data->PercentComplete, event_data->VolDevHandle); break; } case MPI2_EVENT_LOG_ENTRY_ADDED: { pMpi2EventDataLogEntryAdded_t logEntry; uint16_t logQualifier; uint8_t logCode; logEntry = (pMpi2EventDataLogEntryAdded_t)fw_event->event_data; logQualifier = logEntry->LogEntryQualifier; if (logQualifier == MPI2_WD_LOG_ENTRY) { logCode = logEntry->LogData[0]; switch (logCode) { case MPI2_WD_SSD_THROTTLING: kprintf("WarpDrive Warning: IO Throttling has " "occurred in the WarpDrive subsystem. " "Check WarpDrive documentation for " "additional details\n"); break; case MPI2_WD_DRIVE_LIFE_WARN: kprintf("WarpDrive Warning: Program/Erase " "Cycles for the WarpDrive subsystem in " "degraded range. Check WarpDrive " "documentation for additional details\n"); break; case MPI2_WD_DRIVE_LIFE_DEAD: kprintf("WarpDrive Fatal Error: There are no " "Program/Erase Cycles for the WarpDrive " "subsystem. The storage device will be in " "read-only mode. Check WarpDrive " "documentation for additional details\n"); break; case MPI2_WD_RAIL_MON_FAIL: kprintf("WarpDrive Fatal Error: The Backup Rail " "Monitor has failed on the WarpDrive " "subsystem. Check WarpDrive documentation " "for additional details\n"); break; default: break; } } break; } case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: default: mps_dprint(sc, MPS_TRACE,"Unhandled event 0x%0X\n", fw_event->event); break; } mpssas_fw_event_free(sc, fw_event); }
static int mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){ char devstring[80]; struct mpssas_softc *sassc; struct mpssas_target *targ; Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t config_page; uint64_t sas_address; uint64_t parent_sas_address = 0; u32 device_info, parent_devinfo = 0; unsigned int id; int ret = 1, error = 0, i; struct mpssas_lun *lun; u8 is_SATA_SSD = 0; struct mps_command *cm; sassc = sc->sassc; mpssas_startup_increment(sassc); if ((mps_config_get_sas_device_pg0(sc, &mpi_reply, &config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { printf("%s: error reading SAS device page0\n", __func__); error = ENXIO; goto out; } device_info = le32toh(config_page.DeviceInfo); if (((device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) && (le16toh(config_page.ParentDevHandle) != 0)) { Mpi2ConfigReply_t tmp_mpi_reply; Mpi2SasDevicePage0_t parent_config_page; if ((mps_config_get_sas_device_pg0(sc, &tmp_mpi_reply, &parent_config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, le16toh(config_page.ParentDevHandle)))) { printf("%s: error reading SAS device %#x page0\n", __func__, le16toh(config_page.ParentDevHandle)); } else { parent_sas_address = parent_config_page.SASAddress.High; parent_sas_address = (parent_sas_address << 32) | parent_config_page.SASAddress.Low; parent_devinfo = le32toh(parent_config_page.DeviceInfo); } } /* TODO Check proper endianess */ sas_address = config_page.SASAddress.High; sas_address = (sas_address << 32) | config_page.SASAddress.Low; /* * Always get SATA Identify information because this is used to * determine if Start/Stop Unit should be sent to the drive when the * system is shutdown. */ if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) { ret = mpssas_get_sas_address_for_sata_disk(sc, &sas_address, handle, device_info, &is_SATA_SSD); if (ret) { mps_dprint(sc, MPS_INFO, "%s: failed to get disk type " "(SSD or HDD) for SATA device with handle 0x%04x\n", __func__, handle); } else { mps_dprint(sc, MPS_INFO, "SAS Address from SATA " "device = %jx\n", sas_address); } } id = mps_mapping_get_sas_id(sc, sas_address, handle); if (id == MPS_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 (mpssas_check_id(sassc, id) != 0) { device_printf(sc->mps_dev, "Excluding target id %d\n", id); error = ENXIO; goto out; } mps_dprint(sc, MPS_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) | le32toh(config_page.DeviceName.Low); targ->encl_handle = le16toh(config_page.EnclosureHandle); targ->encl_slot = le16toh(config_page.Slot); targ->handle = handle; targ->parent_handle = le16toh(config_page.ParentDevHandle); targ->sasaddr = mps_to_u64(&config_page.SASAddress); targ->parent_sasaddr = le64toh(parent_sas_address); targ->parent_devinfo = parent_devinfo; targ->tid = id; targ->linkrate = (linkrate>>4); targ->flags = 0; if (is_SATA_SSD) { targ->flags = MPS_TARGET_IS_SATA_SSD; } 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_MPT2); } SLIST_INIT(&targ->luns); mps_describe_devinfo(targ->devinfo, devstring, 80); mps_dprint(sc, MPS_MAPPING, "Found device <%s> <%s> <0x%04x> <%d/%d>\n", devstring, mps_describe_table(mps_linkrate_names, targ->linkrate), targ->handle, targ->encl_handle, targ->encl_slot); #if __FreeBSD_version < 1000039 if ((sassc->flags & MPSSAS_IN_STARTUP) == 0) #endif mpssas_rescan_target(sc, targ); mps_dprint(sc, MPS_MAPPING, "Target id 0x%x added\n", targ->tid); /* * Check all commands to see if the SATA_ID_TIMEOUT flag has been set. * If so, send a Target Reset TM to the target that was just created. * An Abort Task TM should be used instead of a Target Reset, but that * would be much more difficult because targets have not been fully * discovered yet, and LUN's haven't been setup. So, just reset the * target instead of the LUN. */ for (i = 1; i < sc->num_reqs; i++) { cm = &sc->commands[i]; if (cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) { targ->timeouts++; cm->cm_state = MPS_CM_STATE_TIMEDOUT; if ((targ->tm = mpssas_alloc_tm(sc)) != NULL) { mps_dprint(sc, MPS_INFO, "%s: sending Target " "Reset for stuck SATA identify command " "(cm = %p)\n", __func__, cm); targ->tm->cm_targ = targ; mpssas_send_reset(sc, targ->tm, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); } else { mps_dprint(sc, MPS_ERROR, "Failed to allocate " "tm for Target Reset after SATA ID command " "timed out (cm %p)\n", cm); } /* * No need to check for more since the target is * already being reset. */ break; } } out: /* * Free the commands that may not have been freed from the SATA ID call */ for (i = 1; i < sc->num_reqs; i++) { cm = &sc->commands[i]; if (cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) { mps_free_command(sc, cm); } } mpssas_startup_decrement(sassc); return (error); }