static void mptsas_expander_delete(MPT_ADAPTER *ioc,
struct mptsas_portinfo *port_info, u8 force);
static void mptsas_send_expander_event(struct fw_event_work *fw_event);
+static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
+static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
}
+static void
+mptsas_queue_rescan(MPT_ADAPTER *ioc)
+{
+ struct fw_event_work *fw_event;
+ int sz;
+
+ sz = offsetof(struct fw_event_work, event_data);
+ fw_event = kzalloc(sz, GFP_ATOMIC);
+ if (!fw_event) {
+ printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
+ ioc->name, __func__, __LINE__);
+ return;
+ }
+ fw_event->event = -1;
+ fw_event->ioc = ioc;
+ mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
+}
+
/**
* mptsas_target_reset
complete(&ioc->sas_mgmt.done);
}
mptsas_cleanup_fw_event_q(ioc);
+ mptsas_queue_rescan(ioc);
mptsas_fw_event_on(ioc);
break;
default:
container_of(work, struct fw_event_work, work.work);
MPT_ADAPTER *ioc = fw_event->ioc;
+ /* special rescan topology handling */
+ if (fw_event->event == -1) {
+ if (ioc->in_rescan) {
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: rescan ignored as it is in progress\n",
+ ioc->name, __func__));
+ return;
+ }
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
+ "reset\n", ioc->name, __func__));
+ ioc->in_rescan = 1;
+ mptsas_not_responding_devices(ioc);
+ mptsas_scan_sas_topology(ioc);
+ ioc->in_rescan = 0;
+ mptsas_free_fw_event(ioc, fw_event);
+ return;
+ }
/* events handling turned off during host reset */
if (ioc->fw_events_off) {
if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
- if (!port_info)
+ if (!port_info) {
+ if (ioc->old_sas_discovery_protocal) {
+ port_info = mptsas_expander_add(ioc,
+ le16_to_cpu(link_data->DevHandle));
+ if (port_info)
+ goto out;
+ }
goto out;
+ }
if (port_info == ioc->hba_port_info)
mptsas_probe_hba_phys(ioc);
mptsas_free_fw_event(ioc, fw_event);
}
+static void
+mptsas_not_responding_devices(MPT_ADAPTER *ioc)
+{
+ struct mptsas_portinfo buffer, *port_info;
+ struct mptsas_device_info *sas_info;
+ struct mptsas_devinfo sas_device;
+ u32 handle;
+ VirtTarget *vtarget = NULL;
+ struct mptsas_phyinfo *phy_info;
+ u8 found_expander;
+ int retval, retry_count;
+ unsigned long flags;
+
+ mpt_findImVolumes(ioc);
+
+ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ if (ioc->ioc_reset_in_progress) {
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: exiting due to a parallel reset \n", ioc->name,
+ __func__));
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+ /* devices, logical volumes */
+ mutex_lock(&ioc->sas_device_info_mutex);
+ redo_device_scan:
+ list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
+ sas_device.handle = 0;
+ retry_count = 0;
+retry_page:
+ retval = mptsas_sas_device_pg0(ioc, &sas_device,
+ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
+ << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+ (sas_info->fw.channel << 8) +
+ sas_info->fw.id);
+
+ if (sas_device.handle)
+ continue;
+ if (retval == -EBUSY) {
+ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ if (ioc->ioc_reset_in_progress) {
+ dfailprintk(ioc,
+ printk(MYIOC_s_DEBUG_FMT
+ "%s: exiting due to reset\n",
+ ioc->name, __func__));
+ spin_unlock_irqrestore
+ (&ioc->taskmgmt_lock, flags);
+ mutex_unlock(&ioc->sas_device_info_mutex);
+ return;
+ }
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock,
+ flags);
+ }
+
+ if (retval && (retval != -ENODEV)) {
+ if (retry_count < 10) {
+ retry_count++;
+ goto retry_page;
+ } else {
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: Config page retry exceeded retry "
+ "count deleting device 0x%llx\n",
+ ioc->name, __func__,
+ sas_info->sas_address));
+ }
+ }
+
+ /* delete device */
+ vtarget = mptsas_find_vtarget(ioc,
+ sas_info->fw.channel, sas_info->fw.id);
+ if (vtarget)
+ vtarget->deleted = 1;
+ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+ sas_info->sas_address);
+ if (phy_info) {
+ mptsas_del_end_device(ioc, phy_info);
+ goto redo_device_scan;
+ }
+ }
+ mutex_unlock(&ioc->sas_device_info_mutex);
+
+ /* expanders */
+ mutex_lock(&ioc->sas_topology_mutex);
+ redo_expander_scan:
+ list_for_each_entry(port_info, &ioc->sas_topology, list) {
+
+ if (port_info->phy_info &&
+ (!(port_info->phy_info[0].identify.device_info &
+ MPI_SAS_DEVICE_INFO_SMP_TARGET)))
+ continue;
+ found_expander = 0;
+ handle = 0xFFFF;
+ while (!mptsas_sas_expander_pg0(ioc, &buffer,
+ (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
+ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
+ !found_expander) {
+
+ handle = buffer.phy_info[0].handle;
+ if (buffer.phy_info[0].identify.sas_address ==
+ port_info->phy_info[0].identify.sas_address) {
+ found_expander = 1;
+ }
+ kfree(buffer.phy_info);
+ }
+
+ if (!found_expander) {
+ mptsas_expander_delete(ioc, port_info, 0);
+ goto redo_expander_scan;
+ }
+ }
+ mutex_lock(&ioc->sas_topology_mutex);
+}
+
/**
* mptsas_probe_expanders - adding expanders
* @ioc: Pointer to MPT_ADAPTER structure
MpiEventDataSasExpanderStatusChange_t *expander_data =
(MpiEventDataSasExpanderStatusChange_t *)reply->Data;
+ if (ioc->old_sas_discovery_protocal)
+ return 0;
if (expander_data->ReasonCode ==
MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
+ if (ioc->old_sas_discovery_protocal && !discovery_status)
+ mptsas_queue_rescan(ioc);
return 0;
}
case MPI_EVENT_INTEGRATED_RAID:
goto out_mptsas_probe;
}
+ /* older firmware doesn't support expander events */
+ if ((ioc->facts.HeaderVersion >> 8) < 0xE)
+ ioc->old_sas_discovery_protocal = 1;
mptsas_scan_sas_topology(ioc);
mptsas_fw_event_on(ioc);
return 0;