diff options
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
-rw-r--r-- | drivers/message/fusion/mptsas.c | 746 |
1 files changed, 510 insertions, 236 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 22a027ec9e5d..7f2f76f0db3f 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
@@ -113,6 +113,12 @@ static int mptsas_add_end_device(MPT_ADAPTER *ioc, | |||
113 | struct mptsas_phyinfo *phy_info); | 113 | struct mptsas_phyinfo *phy_info); |
114 | static void mptsas_del_end_device(MPT_ADAPTER *ioc, | 114 | static void mptsas_del_end_device(MPT_ADAPTER *ioc, |
115 | struct mptsas_phyinfo *phy_info); | 115 | struct mptsas_phyinfo *phy_info); |
116 | static void mptsas_send_link_status_event(struct fw_event_work *fw_event); | ||
117 | static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address | ||
118 | (MPT_ADAPTER *ioc, u64 sas_address); | ||
119 | static void mptsas_expander_delete(MPT_ADAPTER *ioc, | ||
120 | struct mptsas_portinfo *port_info, u8 force); | ||
121 | static void mptsas_send_expander_event(struct fw_event_work *fw_event); | ||
116 | 122 | ||
117 | static void mptsas_print_phy_data(MPT_ADAPTER *ioc, | 123 | static void mptsas_print_phy_data(MPT_ADAPTER *ioc, |
118 | MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) | 124 | MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) |
@@ -342,20 +348,6 @@ static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) | |||
342 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | 348 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; |
343 | } | 349 | } |
344 | 350 | ||
345 | static struct mptsas_portinfo * | ||
346 | mptsas_get_hba_portinfo(MPT_ADAPTER *ioc) | ||
347 | { | ||
348 | struct list_head *head = &ioc->sas_topology; | ||
349 | struct mptsas_portinfo *pi = NULL; | ||
350 | |||
351 | /* always the first entry on sas_topology list */ | ||
352 | |||
353 | if (!list_empty(head)) | ||
354 | pi = list_entry(head->next, struct mptsas_portinfo, list); | ||
355 | |||
356 | return pi; | ||
357 | } | ||
358 | |||
359 | /* | 351 | /* |
360 | * mptsas_find_portinfo_by_handle | 352 | * mptsas_find_portinfo_by_handle |
361 | * | 353 | * |
@@ -377,6 +369,38 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) | |||
377 | return rc; | 369 | return rc; |
378 | } | 370 | } |
379 | 371 | ||
372 | /** | ||
373 | * mptsas_find_portinfo_by_sas_address - | ||
374 | * @ioc: Pointer to MPT_ADAPTER structure | ||
375 | * @handle: | ||
376 | * | ||
377 | * This function should be called with the sas_topology_mutex already held | ||
378 | * | ||
379 | **/ | ||
380 | static struct mptsas_portinfo * | ||
381 | mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) | ||
382 | { | ||
383 | struct mptsas_portinfo *port_info, *rc = NULL; | ||
384 | int i; | ||
385 | |||
386 | if (sas_address >= ioc->hba_port_sas_addr && | ||
387 | sas_address < (ioc->hba_port_sas_addr + | ||
388 | ioc->hba_port_num_phy)) | ||
389 | return ioc->hba_port_info; | ||
390 | |||
391 | mutex_lock(&ioc->sas_topology_mutex); | ||
392 | list_for_each_entry(port_info, &ioc->sas_topology, list) | ||
393 | for (i = 0; i < port_info->num_phys; i++) | ||
394 | if (port_info->phy_info[i].identify.sas_address == | ||
395 | sas_address) { | ||
396 | rc = port_info; | ||
397 | goto out; | ||
398 | } | ||
399 | out: | ||
400 | mutex_unlock(&ioc->sas_topology_mutex); | ||
401 | return rc; | ||
402 | } | ||
403 | |||
380 | /* | 404 | /* |
381 | * Returns true if there is a scsi end device | 405 | * Returns true if there is a scsi end device |
382 | */ | 406 | */ |
@@ -940,7 +964,6 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) | |||
940 | { | 964 | { |
941 | MPT_SCSI_HOST *hd = shost_priv(ioc->sh); | 965 | MPT_SCSI_HOST *hd = shost_priv(ioc->sh); |
942 | struct list_head *head = &hd->target_reset_list; | 966 | struct list_head *head = &hd->target_reset_list; |
943 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; | ||
944 | u8 id, channel; | 967 | u8 id, channel; |
945 | struct mptsas_target_reset_event *target_reset_list; | 968 | struct mptsas_target_reset_event *target_reset_list; |
946 | SCSITaskMgmtReply_t *pScsiTmReply; | 969 | SCSITaskMgmtReply_t *pScsiTmReply; |
@@ -995,7 +1018,6 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) | |||
995 | ioc->name, jiffies_to_msecs(jiffies - | 1018 | ioc->name, jiffies_to_msecs(jiffies - |
996 | target_reset_list->time_count)/1000)); | 1019 | target_reset_list->time_count)/1000)); |
997 | 1020 | ||
998 | sas_event_data = &target_reset_list->sas_event_data; | ||
999 | id = pScsiTmReply->TargetID; | 1021 | id = pScsiTmReply->TargetID; |
1000 | channel = pScsiTmReply->Bus; | 1022 | channel = pScsiTmReply->Bus; |
1001 | target_reset_list->time_count = jiffies; | 1023 | target_reset_list->time_count = jiffies; |
@@ -1410,6 +1432,12 @@ mptsas_firmware_event_work(struct work_struct *work) | |||
1410 | MPI_SAS_OP_CLEAR_NOT_PRESENT); | 1432 | MPI_SAS_OP_CLEAR_NOT_PRESENT); |
1411 | mptsas_free_fw_event(ioc, fw_event); | 1433 | mptsas_free_fw_event(ioc, fw_event); |
1412 | break; | 1434 | break; |
1435 | case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: | ||
1436 | mptsas_send_expander_event(fw_event); | ||
1437 | break; | ||
1438 | case MPI_EVENT_SAS_PHY_LINK_STATUS: | ||
1439 | mptsas_send_link_status_event(fw_event); | ||
1440 | break; | ||
1413 | } | 1441 | } |
1414 | } | 1442 | } |
1415 | 1443 | ||
@@ -1909,7 +1937,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
1909 | struct mptsas_portinfo *port_info; | 1937 | struct mptsas_portinfo *port_info; |
1910 | 1938 | ||
1911 | mutex_lock(&ioc->sas_topology_mutex); | 1939 | mutex_lock(&ioc->sas_topology_mutex); |
1912 | port_info = mptsas_get_hba_portinfo(ioc); | 1940 | port_info = ioc->hba_port_info; |
1913 | if (port_info && port_info->phy_info) | 1941 | if (port_info && port_info->phy_info) |
1914 | sas_address = | 1942 | sas_address = |
1915 | port_info->phy_info[0].phy->identify.sas_address; | 1943 | port_info->phy_info[0].phy->identify.sas_address; |
@@ -2646,9 +2674,7 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
2646 | struct mptsas_portinfo *port_info; | 2674 | struct mptsas_portinfo *port_info; |
2647 | int i; | 2675 | int i; |
2648 | 2676 | ||
2649 | mutex_lock(&ioc->sas_topology_mutex); | 2677 | port_info = ioc->hba_port_info; |
2650 | port_info = mptsas_get_hba_portinfo(ioc); | ||
2651 | mutex_unlock(&ioc->sas_topology_mutex); | ||
2652 | 2678 | ||
2653 | for (i = 0; i < port_info->num_phys; i++) | 2679 | for (i = 0; i < port_info->num_phys; i++) |
2654 | if (port_info->phy_info[i].identify.sas_address == | 2680 | if (port_info->phy_info[i].identify.sas_address == |
@@ -2707,7 +2733,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) | |||
2707 | struct mptsas_portinfo *port_info, *hba; | 2733 | struct mptsas_portinfo *port_info, *hba; |
2708 | int error = -ENOMEM, i; | 2734 | int error = -ENOMEM, i; |
2709 | 2735 | ||
2710 | hba = kzalloc(sizeof(*port_info), GFP_KERNEL); | 2736 | hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); |
2711 | if (! hba) | 2737 | if (! hba) |
2712 | goto out; | 2738 | goto out; |
2713 | 2739 | ||
@@ -2717,9 +2743,10 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) | |||
2717 | 2743 | ||
2718 | mptsas_sas_io_unit_pg1(ioc); | 2744 | mptsas_sas_io_unit_pg1(ioc); |
2719 | mutex_lock(&ioc->sas_topology_mutex); | 2745 | mutex_lock(&ioc->sas_topology_mutex); |
2720 | port_info = mptsas_get_hba_portinfo(ioc); | 2746 | port_info = ioc->hba_port_info; |
2721 | if (!port_info) { | 2747 | if (!port_info) { |
2722 | port_info = hba; | 2748 | ioc->hba_port_info = port_info = hba; |
2749 | ioc->hba_port_num_phy = port_info->num_phys; | ||
2723 | list_add_tail(&port_info->list, &ioc->sas_topology); | 2750 | list_add_tail(&port_info->list, &ioc->sas_topology); |
2724 | } else { | 2751 | } else { |
2725 | for (i = 0; i < hba->num_phys; i++) { | 2752 | for (i = 0; i < hba->num_phys; i++) { |
@@ -2735,15 +2762,22 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) | |||
2735 | hba = NULL; | 2762 | hba = NULL; |
2736 | } | 2763 | } |
2737 | mutex_unlock(&ioc->sas_topology_mutex); | 2764 | mutex_unlock(&ioc->sas_topology_mutex); |
2765 | #if defined(CPQ_CIM) | ||
2766 | ioc->num_ports = port_info->num_phys; | ||
2767 | #endif | ||
2738 | for (i = 0; i < port_info->num_phys; i++) { | 2768 | for (i = 0; i < port_info->num_phys; i++) { |
2739 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], | 2769 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], |
2740 | (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << | 2770 | (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << |
2741 | MPI_SAS_PHY_PGAD_FORM_SHIFT), i); | 2771 | MPI_SAS_PHY_PGAD_FORM_SHIFT), i); |
2742 | 2772 | port_info->phy_info[i].identify.handle = | |
2773 | port_info->phy_info[i].handle; | ||
2743 | mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, | 2774 | mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, |
2744 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | 2775 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
2745 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 2776 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
2746 | port_info->phy_info[i].handle); | 2777 | port_info->phy_info[i].identify.handle); |
2778 | if (!ioc->hba_port_sas_addr) | ||
2779 | ioc->hba_port_sas_addr = | ||
2780 | port_info->phy_info[i].identify.sas_address; | ||
2747 | port_info->phy_info[i].identify.phy_id = | 2781 | port_info->phy_info[i].identify.phy_id = |
2748 | port_info->phy_info[i].phy_id = i; | 2782 | port_info->phy_info[i].phy_id = i; |
2749 | if (port_info->phy_info[i].attached.handle) | 2783 | if (port_info->phy_info[i].attached.handle) |
@@ -2768,248 +2802,497 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) | |||
2768 | return error; | 2802 | return error; |
2769 | } | 2803 | } |
2770 | 2804 | ||
2771 | static int | 2805 | static void |
2772 | mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) | 2806 | mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) |
2773 | { | 2807 | { |
2774 | struct mptsas_portinfo *port_info, *p, *ex; | 2808 | struct mptsas_portinfo *parent; |
2775 | struct device *parent; | 2809 | struct device *parent_dev; |
2776 | struct sas_rphy *rphy; | 2810 | struct sas_rphy *rphy; |
2777 | int error = -ENOMEM, i, j; | 2811 | int i; |
2778 | 2812 | u64 sas_address; /* expander sas address */ | |
2779 | ex = kzalloc(sizeof(*port_info), GFP_KERNEL); | 2813 | u32 handle; |
2780 | if (!ex) | ||
2781 | goto out; | ||
2782 | |||
2783 | error = mptsas_sas_expander_pg0(ioc, ex, | ||
2784 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << | ||
2785 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); | ||
2786 | if (error) | ||
2787 | goto out_free_port_info; | ||
2788 | |||
2789 | *handle = ex->phy_info[0].handle; | ||
2790 | |||
2791 | mutex_lock(&ioc->sas_topology_mutex); | ||
2792 | port_info = mptsas_find_portinfo_by_handle(ioc, *handle); | ||
2793 | if (!port_info) { | ||
2794 | port_info = ex; | ||
2795 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
2796 | } else { | ||
2797 | for (i = 0; i < ex->num_phys; i++) { | ||
2798 | port_info->phy_info[i].handle = | ||
2799 | ex->phy_info[i].handle; | ||
2800 | port_info->phy_info[i].port_id = | ||
2801 | ex->phy_info[i].port_id; | ||
2802 | } | ||
2803 | kfree(ex->phy_info); | ||
2804 | kfree(ex); | ||
2805 | ex = NULL; | ||
2806 | } | ||
2807 | mutex_unlock(&ioc->sas_topology_mutex); | ||
2808 | 2814 | ||
2815 | handle = port_info->phy_info[0].handle; | ||
2816 | sas_address = port_info->phy_info[0].identify.sas_address; | ||
2809 | for (i = 0; i < port_info->num_phys; i++) { | 2817 | for (i = 0; i < port_info->num_phys; i++) { |
2810 | mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], | 2818 | mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], |
2811 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << | 2819 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << |
2812 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle); | 2820 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle); |
2813 | 2821 | ||
2814 | if (port_info->phy_info[i].identify.handle) { | 2822 | mptsas_sas_device_pg0(ioc, |
2815 | mptsas_sas_device_pg0(ioc, | 2823 | &port_info->phy_info[i].identify, |
2816 | &port_info->phy_info[i].identify, | 2824 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
2817 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | 2825 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
2818 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 2826 | port_info->phy_info[i].identify.handle); |
2819 | port_info->phy_info[i].identify.handle); | 2827 | port_info->phy_info[i].identify.phy_id = |
2820 | port_info->phy_info[i].identify.phy_id = | 2828 | port_info->phy_info[i].phy_id; |
2821 | port_info->phy_info[i].phy_id; | ||
2822 | } | ||
2823 | 2829 | ||
2824 | if (port_info->phy_info[i].attached.handle) { | 2830 | if (port_info->phy_info[i].attached.handle) { |
2825 | mptsas_sas_device_pg0(ioc, | 2831 | mptsas_sas_device_pg0(ioc, |
2826 | &port_info->phy_info[i].attached, | 2832 | &port_info->phy_info[i].attached, |
2827 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | 2833 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
2828 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 2834 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
2829 | port_info->phy_info[i].attached.handle); | 2835 | port_info->phy_info[i].attached.handle); |
2830 | port_info->phy_info[i].attached.phy_id = | 2836 | port_info->phy_info[i].attached.phy_id = |
2831 | port_info->phy_info[i].phy_id; | 2837 | port_info->phy_info[i].phy_id; |
2832 | } | 2838 | } |
2833 | } | 2839 | } |
2834 | 2840 | ||
2835 | parent = &ioc->sh->shost_gendev; | 2841 | mutex_lock(&ioc->sas_topology_mutex); |
2836 | for (i = 0; i < port_info->num_phys; i++) { | 2842 | parent = mptsas_find_portinfo_by_handle(ioc, |
2837 | mutex_lock(&ioc->sas_topology_mutex); | 2843 | port_info->phy_info[0].identify.handle_parent); |
2838 | list_for_each_entry(p, &ioc->sas_topology, list) { | 2844 | if (!parent) { |
2839 | for (j = 0; j < p->num_phys; j++) { | ||
2840 | if (port_info->phy_info[i].identify.handle != | ||
2841 | p->phy_info[j].attached.handle) | ||
2842 | continue; | ||
2843 | rphy = mptsas_get_rphy(&p->phy_info[j]); | ||
2844 | parent = &rphy->dev; | ||
2845 | } | ||
2846 | } | ||
2847 | mutex_unlock(&ioc->sas_topology_mutex); | 2845 | mutex_unlock(&ioc->sas_topology_mutex); |
2846 | return; | ||
2847 | } | ||
2848 | for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev; | ||
2849 | i++) { | ||
2850 | if (parent->phy_info[i].attached.sas_address == sas_address) { | ||
2851 | rphy = mptsas_get_rphy(&parent->phy_info[i]); | ||
2852 | parent_dev = &rphy->dev; | ||
2853 | } | ||
2848 | } | 2854 | } |
2855 | mutex_unlock(&ioc->sas_topology_mutex); | ||
2849 | 2856 | ||
2850 | mptsas_setup_wide_ports(ioc, port_info); | 2857 | mptsas_setup_wide_ports(ioc, port_info); |
2851 | |||
2852 | for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) | 2858 | for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) |
2853 | mptsas_probe_one_phy(parent, &port_info->phy_info[i], | 2859 | mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i], |
2854 | ioc->sas_index, 0); | 2860 | ioc->sas_index, 0); |
2861 | } | ||
2855 | 2862 | ||
2856 | return 0; | 2863 | static void |
2864 | mptsas_expander_event_add(MPT_ADAPTER *ioc, | ||
2865 | MpiEventDataSasExpanderStatusChange_t *expander_data) | ||
2866 | { | ||
2867 | struct mptsas_portinfo *port_info; | ||
2868 | int i; | ||
2869 | __le64 sas_address; | ||
2857 | 2870 | ||
2858 | out_free_port_info: | 2871 | port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); |
2859 | if (ex) { | 2872 | if (!port_info) |
2860 | kfree(ex->phy_info); | 2873 | BUG(); |
2861 | kfree(ex); | 2874 | port_info->num_phys = (expander_data->NumPhys) ? |
2875 | expander_data->NumPhys : 1; | ||
2876 | port_info->phy_info = kcalloc(port_info->num_phys, | ||
2877 | sizeof(struct mptsas_phyinfo), GFP_KERNEL); | ||
2878 | if (!port_info->phy_info) | ||
2879 | BUG(); | ||
2880 | memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); | ||
2881 | for (i = 0; i < port_info->num_phys; i++) { | ||
2882 | port_info->phy_info[i].portinfo = port_info; | ||
2883 | port_info->phy_info[i].handle = | ||
2884 | le16_to_cpu(expander_data->DevHandle); | ||
2885 | port_info->phy_info[i].identify.sas_address = | ||
2886 | le64_to_cpu(sas_address); | ||
2887 | port_info->phy_info[i].identify.handle_parent = | ||
2888 | le16_to_cpu(expander_data->ParentDevHandle); | ||
2862 | } | 2889 | } |
2863 | out: | 2890 | |
2864 | return error; | 2891 | mutex_lock(&ioc->sas_topology_mutex); |
2892 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
2893 | mutex_unlock(&ioc->sas_topology_mutex); | ||
2894 | |||
2895 | printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " | ||
2896 | "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, | ||
2897 | (unsigned long long)sas_address); | ||
2898 | |||
2899 | mptsas_expander_refresh(ioc, port_info); | ||
2865 | } | 2900 | } |
2866 | 2901 | ||
2867 | /* | 2902 | /** |
2868 | * mptsas_delete_expander_phys | 2903 | * mptsas_delete_expander_siblings - remove siblings attached to expander |
2869 | * | 2904 | * @ioc: Pointer to MPT_ADAPTER structure |
2870 | * | 2905 | * @parent: the parent port_info object |
2871 | * This will traverse topology, and remove expanders | 2906 | * @expander: the expander port_info object |
2872 | * that are no longer present | 2907 | **/ |
2873 | */ | ||
2874 | static void | 2908 | static void |
2875 | mptsas_delete_expander_phys(MPT_ADAPTER *ioc) | 2909 | mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo |
2910 | *parent, struct mptsas_portinfo *expander) | ||
2876 | { | 2911 | { |
2877 | struct mptsas_portinfo buffer; | ||
2878 | struct mptsas_portinfo *port_info, *n, *parent; | ||
2879 | struct mptsas_phyinfo *phy_info; | 2912 | struct mptsas_phyinfo *phy_info; |
2880 | struct sas_port * port; | 2913 | struct mptsas_portinfo *port_info; |
2914 | struct sas_rphy *rphy; | ||
2881 | int i; | 2915 | int i; |
2882 | u64 expander_sas_address; | ||
2883 | 2916 | ||
2884 | mutex_lock(&ioc->sas_topology_mutex); | 2917 | phy_info = expander->phy_info; |
2885 | list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { | 2918 | for (i = 0; i < expander->num_phys; i++, phy_info++) { |
2919 | rphy = mptsas_get_rphy(phy_info); | ||
2920 | if (!rphy) | ||
2921 | continue; | ||
2922 | if (rphy->identify.device_type == SAS_END_DEVICE) | ||
2923 | mptsas_del_end_device(ioc, phy_info); | ||
2924 | } | ||
2886 | 2925 | ||
2887 | if (!(port_info->phy_info[0].identify.device_info & | 2926 | phy_info = expander->phy_info; |
2888 | MPI_SAS_DEVICE_INFO_SMP_TARGET)) | 2927 | for (i = 0; i < expander->num_phys; i++, phy_info++) { |
2928 | rphy = mptsas_get_rphy(phy_info); | ||
2929 | if (!rphy) | ||
2889 | continue; | 2930 | continue; |
2931 | if (rphy->identify.device_type == | ||
2932 | MPI_SAS_DEVICE_INFO_EDGE_EXPANDER || | ||
2933 | rphy->identify.device_type == | ||
2934 | MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) { | ||
2935 | port_info = mptsas_find_portinfo_by_sas_address(ioc, | ||
2936 | rphy->identify.sas_address); | ||
2937 | if (!port_info) | ||
2938 | continue; | ||
2939 | if (port_info == parent) /* backlink rphy */ | ||
2940 | continue; | ||
2941 | /* | ||
2942 | Delete this expander even if the expdevpage is exists | ||
2943 | because the parent expander is already deleted | ||
2944 | */ | ||
2945 | mptsas_expander_delete(ioc, port_info, 1); | ||
2946 | } | ||
2947 | } | ||
2948 | } | ||
2890 | 2949 | ||
2891 | if (mptsas_sas_expander_pg0(ioc, &buffer, | ||
2892 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << | ||
2893 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), | ||
2894 | port_info->phy_info[0].handle)) { | ||
2895 | 2950 | ||
2896 | /* | 2951 | /** |
2897 | * Obtain the port_info instance to the parent port | 2952 | * mptsas_expander_delete - remove this expander |
2898 | */ | 2953 | * @ioc: Pointer to MPT_ADAPTER structure |
2899 | parent = mptsas_find_portinfo_by_handle(ioc, | 2954 | * @port_info: expander port_info struct |
2900 | port_info->phy_info[0].identify.handle_parent); | 2955 | * @force: Flag to forcefully delete the expander |
2956 | * | ||
2957 | **/ | ||
2901 | 2958 | ||
2902 | if (!parent) | 2959 | static void mptsas_expander_delete(MPT_ADAPTER *ioc, |
2903 | goto next_port; | 2960 | struct mptsas_portinfo *port_info, u8 force) |
2961 | { | ||
2904 | 2962 | ||
2905 | expander_sas_address = | 2963 | struct mptsas_portinfo *parent; |
2906 | port_info->phy_info[0].identify.sas_address; | 2964 | int i; |
2965 | u64 expander_sas_address; | ||
2966 | struct mptsas_phyinfo *phy_info; | ||
2967 | struct mptsas_portinfo buffer; | ||
2968 | struct mptsas_portinfo_details *port_details; | ||
2969 | struct sas_port *port; | ||
2907 | 2970 | ||
2908 | /* | 2971 | if (!port_info) |
2909 | * Delete rphys in the parent that point | 2972 | return; |
2910 | * to this expander. The transport layer will | ||
2911 | * cleanup all the children. | ||
2912 | */ | ||
2913 | phy_info = parent->phy_info; | ||
2914 | for (i = 0; i < parent->num_phys; i++, phy_info++) { | ||
2915 | port = mptsas_get_port(phy_info); | ||
2916 | if (!port) | ||
2917 | continue; | ||
2918 | if (phy_info->attached.sas_address != | ||
2919 | expander_sas_address) | ||
2920 | continue; | ||
2921 | dsaswideprintk(ioc, | ||
2922 | dev_printk(KERN_DEBUG, &port->dev, | ||
2923 | MYIOC_s_FMT "delete port (%d)\n", ioc->name, | ||
2924 | port->port_identifier)); | ||
2925 | sas_port_delete(port); | ||
2926 | mptsas_port_delete(ioc, phy_info->port_details); | ||
2927 | } | ||
2928 | next_port: | ||
2929 | 2973 | ||
2930 | phy_info = port_info->phy_info; | 2974 | /* see if expander is still there before deleting */ |
2931 | for (i = 0; i < port_info->num_phys; i++, phy_info++) | 2975 | mptsas_sas_expander_pg0(ioc, &buffer, |
2932 | mptsas_port_delete(ioc, phy_info->port_details); | 2976 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << |
2977 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), | ||
2978 | port_info->phy_info[0].identify.handle); | ||
2933 | 2979 | ||
2934 | list_del(&port_info->list); | 2980 | if (buffer.num_phys) { |
2935 | kfree(port_info->phy_info); | ||
2936 | kfree(port_info); | ||
2937 | } | ||
2938 | /* | ||
2939 | * Free this memory allocated from inside | ||
2940 | * mptsas_sas_expander_pg0 | ||
2941 | */ | ||
2942 | kfree(buffer.phy_info); | 2981 | kfree(buffer.phy_info); |
2982 | if (!force) | ||
2983 | return; | ||
2943 | } | 2984 | } |
2944 | mutex_unlock(&ioc->sas_topology_mutex); | 2985 | |
2986 | |||
2987 | /* | ||
2988 | * Obtain the port_info instance to the parent port | ||
2989 | */ | ||
2990 | port_details = NULL; | ||
2991 | expander_sas_address = | ||
2992 | port_info->phy_info[0].identify.sas_address; | ||
2993 | parent = mptsas_find_portinfo_by_handle(ioc, | ||
2994 | port_info->phy_info[0].identify.handle_parent); | ||
2995 | mptsas_delete_expander_siblings(ioc, parent, port_info); | ||
2996 | if (!parent) | ||
2997 | goto out; | ||
2998 | |||
2999 | /* | ||
3000 | * Delete rphys in the parent that point | ||
3001 | * to this expander. | ||
3002 | */ | ||
3003 | phy_info = parent->phy_info; | ||
3004 | port = NULL; | ||
3005 | for (i = 0; i < parent->num_phys; i++, phy_info++) { | ||
3006 | if (!phy_info->phy) | ||
3007 | continue; | ||
3008 | if (phy_info->attached.sas_address != | ||
3009 | expander_sas_address) | ||
3010 | continue; | ||
3011 | if (!port) { | ||
3012 | port = mptsas_get_port(phy_info); | ||
3013 | port_details = phy_info->port_details; | ||
3014 | } | ||
3015 | dev_printk(KERN_DEBUG, &phy_info->phy->dev, | ||
3016 | MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, | ||
3017 | phy_info->phy_id, phy_info->phy); | ||
3018 | sas_port_delete_phy(port, phy_info->phy); | ||
3019 | } | ||
3020 | if (port) { | ||
3021 | dev_printk(KERN_DEBUG, &port->dev, | ||
3022 | MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n", | ||
3023 | ioc->name, port->port_identifier, | ||
3024 | (unsigned long long)expander_sas_address); | ||
3025 | sas_port_delete(port); | ||
3026 | mptsas_port_delete(ioc, port_details); | ||
3027 | } | ||
3028 | out: | ||
3029 | |||
3030 | printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, " | ||
3031 | "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, | ||
3032 | (unsigned long long)expander_sas_address); | ||
3033 | |||
3034 | /* | ||
3035 | * free link | ||
3036 | */ | ||
3037 | list_del(&port_info->list); | ||
3038 | kfree(port_info->phy_info); | ||
3039 | kfree(port_info); | ||
2945 | } | 3040 | } |
2946 | 3041 | ||
2947 | /* | 3042 | |
2948 | * Start of day discovery | 3043 | /** |
3044 | * mptsas_send_expander_event - expanders events | ||
3045 | * @ioc: Pointer to MPT_ADAPTER structure | ||
3046 | * @expander_data: event data | ||
3047 | * | ||
3048 | * | ||
3049 | * This function handles adding, removing, and refreshing | ||
3050 | * device handles within the expander objects. | ||
2949 | */ | 3051 | */ |
2950 | static void | 3052 | static void |
2951 | mptsas_scan_sas_topology(MPT_ADAPTER *ioc) | 3053 | mptsas_send_expander_event(struct fw_event_work *fw_event) |
2952 | { | 3054 | { |
2953 | u32 handle = 0xFFFF; | 3055 | MPT_ADAPTER *ioc; |
3056 | MpiEventDataSasExpanderStatusChange_t *expander_data; | ||
3057 | struct mptsas_portinfo *port_info; | ||
3058 | __le64 sas_address; | ||
2954 | int i; | 3059 | int i; |
2955 | 3060 | ||
2956 | mutex_lock(&ioc->sas_discovery_mutex); | 3061 | ioc = fw_event->ioc; |
2957 | mptsas_probe_hba_phys(ioc); | 3062 | expander_data = (MpiEventDataSasExpanderStatusChange_t *) |
2958 | while (!mptsas_probe_expander_phys(ioc, &handle)) | 3063 | fw_event->event_data; |
2959 | ; | 3064 | memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); |
2960 | /* | 3065 | port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); |
2961 | Reporting RAID volumes. | 3066 | |
2962 | */ | 3067 | if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { |
2963 | if (!ioc->ir_firmware) | 3068 | if (port_info) { |
2964 | goto out; | 3069 | for (i = 0; i < port_info->num_phys; i++) { |
2965 | if (!ioc->raid_data.pIocPg2) | 3070 | port_info->phy_info[i].portinfo = port_info; |
2966 | goto out; | 3071 | port_info->phy_info[i].handle = |
2967 | if (!ioc->raid_data.pIocPg2->NumActiveVolumes) | 3072 | le16_to_cpu(expander_data->DevHandle); |
2968 | goto out; | 3073 | port_info->phy_info[i].identify.sas_address = |
2969 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { | 3074 | le64_to_cpu(sas_address); |
2970 | scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, | 3075 | port_info->phy_info[i].identify.handle_parent = |
2971 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); | 3076 | le16_to_cpu(expander_data->ParentDevHandle); |
3077 | } | ||
3078 | mptsas_expander_refresh(ioc, port_info); | ||
3079 | } else if (!port_info && expander_data->NumPhys) | ||
3080 | mptsas_expander_event_add(ioc, expander_data); | ||
3081 | } else if (expander_data->ReasonCode == | ||
3082 | MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) | ||
3083 | mptsas_expander_delete(ioc, port_info, 0); | ||
3084 | |||
3085 | mptsas_free_fw_event(ioc, fw_event); | ||
3086 | } | ||
3087 | |||
3088 | |||
3089 | /** | ||
3090 | * mptsas_expander_add - | ||
3091 | * @ioc: Pointer to MPT_ADAPTER structure | ||
3092 | * @handle: | ||
3093 | * | ||
3094 | */ | ||
3095 | struct mptsas_portinfo * | ||
3096 | mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle) | ||
3097 | { | ||
3098 | struct mptsas_portinfo buffer, *port_info; | ||
3099 | int i; | ||
3100 | |||
3101 | if ((mptsas_sas_expander_pg0(ioc, &buffer, | ||
3102 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << | ||
3103 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle))) | ||
3104 | return NULL; | ||
3105 | |||
3106 | port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC); | ||
3107 | if (!port_info) { | ||
3108 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
3109 | "%s: exit at line=%d\n", ioc->name, | ||
3110 | __func__, __LINE__)); | ||
3111 | return NULL; | ||
3112 | } | ||
3113 | port_info->num_phys = buffer.num_phys; | ||
3114 | port_info->phy_info = buffer.phy_info; | ||
3115 | for (i = 0; i < port_info->num_phys; i++) | ||
3116 | port_info->phy_info[i].portinfo = port_info; | ||
3117 | mutex_lock(&ioc->sas_topology_mutex); | ||
3118 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
3119 | mutex_unlock(&ioc->sas_topology_mutex); | ||
3120 | printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " | ||
3121 | "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, | ||
3122 | (unsigned long long)buffer.phy_info[0].identify.sas_address); | ||
3123 | mptsas_expander_refresh(ioc, port_info); | ||
3124 | return port_info; | ||
3125 | } | ||
3126 | |||
3127 | static void | ||
3128 | mptsas_send_link_status_event(struct fw_event_work *fw_event) | ||
3129 | { | ||
3130 | MPT_ADAPTER *ioc; | ||
3131 | MpiEventDataSasPhyLinkStatus_t *link_data; | ||
3132 | struct mptsas_portinfo *port_info; | ||
3133 | struct mptsas_phyinfo *phy_info = NULL; | ||
3134 | __le64 sas_address; | ||
3135 | u8 phy_num; | ||
3136 | u8 link_rate; | ||
3137 | |||
3138 | ioc = fw_event->ioc; | ||
3139 | link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data; | ||
3140 | |||
3141 | memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64)); | ||
3142 | sas_address = le64_to_cpu(sas_address); | ||
3143 | link_rate = link_data->LinkRates >> 4; | ||
3144 | phy_num = link_data->PhyNum; | ||
3145 | |||
3146 | port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); | ||
3147 | if (port_info) { | ||
3148 | phy_info = &port_info->phy_info[phy_num]; | ||
3149 | if (phy_info) | ||
3150 | phy_info->negotiated_link_rate = link_rate; | ||
3151 | } | ||
3152 | |||
3153 | if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 || | ||
3154 | link_rate == MPI_SAS_IOUNIT0_RATE_3_0) { | ||
3155 | |||
3156 | if (!port_info) | ||
3157 | goto out; | ||
3158 | |||
3159 | if (port_info == ioc->hba_port_info) | ||
3160 | mptsas_probe_hba_phys(ioc); | ||
3161 | else | ||
3162 | mptsas_expander_refresh(ioc, port_info); | ||
3163 | } else if (phy_info && phy_info->phy) { | ||
3164 | if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED) | ||
3165 | phy_info->phy->negotiated_linkrate = | ||
3166 | SAS_PHY_DISABLED; | ||
3167 | else if (link_rate == | ||
3168 | MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION) | ||
3169 | phy_info->phy->negotiated_linkrate = | ||
3170 | SAS_LINK_RATE_FAILED; | ||
3171 | else | ||
3172 | phy_info->phy->negotiated_linkrate = | ||
3173 | SAS_LINK_RATE_UNKNOWN; | ||
2972 | } | 3174 | } |
2973 | out: | 3175 | out: |
2974 | mutex_unlock(&ioc->sas_discovery_mutex); | 3176 | mptsas_free_fw_event(ioc, fw_event); |
2975 | } | 3177 | } |
2976 | 3178 | ||
2977 | /* | 3179 | /** |
2978 | * Work queue thread to handle Runtime discovery | 3180 | * mptsas_probe_expanders - adding expanders |
2979 | * Mere purpose is the hot add/delete of expanders | 3181 | * @ioc: Pointer to MPT_ADAPTER structure |
2980 | *(Mutex UNLOCKED) | 3182 | * |
2981 | */ | 3183 | **/ |
2982 | static void | 3184 | static void |
2983 | __mptsas_discovery_work(MPT_ADAPTER *ioc) | 3185 | mptsas_probe_expanders(MPT_ADAPTER *ioc) |
2984 | { | 3186 | { |
2985 | u32 handle = 0xFFFF; | 3187 | struct mptsas_portinfo buffer, *port_info; |
3188 | u32 handle; | ||
3189 | int i; | ||
2986 | 3190 | ||
2987 | ioc->sas_discovery_runtime=1; | 3191 | handle = 0xFFFF; |
2988 | mptsas_delete_expander_phys(ioc); | 3192 | while (!mptsas_sas_expander_pg0(ioc, &buffer, |
2989 | mptsas_probe_hba_phys(ioc); | 3193 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << |
2990 | while (!mptsas_probe_expander_phys(ioc, &handle)) | 3194 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) { |
2991 | ; | 3195 | |
2992 | ioc->sas_discovery_runtime=0; | 3196 | handle = buffer.phy_info[0].handle; |
3197 | port_info = mptsas_find_portinfo_by_sas_address(ioc, | ||
3198 | buffer.phy_info[0].identify.sas_address); | ||
3199 | |||
3200 | if (port_info) { | ||
3201 | /* refreshing handles */ | ||
3202 | for (i = 0; i < buffer.num_phys; i++) { | ||
3203 | port_info->phy_info[i].handle = handle; | ||
3204 | port_info->phy_info[i].identify.handle_parent = | ||
3205 | buffer.phy_info[0].identify.handle_parent; | ||
3206 | } | ||
3207 | mptsas_expander_refresh(ioc, port_info); | ||
3208 | kfree(buffer.phy_info); | ||
3209 | continue; | ||
3210 | } | ||
3211 | |||
3212 | port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); | ||
3213 | if (!port_info) { | ||
3214 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
3215 | "%s: exit at line=%d\n", ioc->name, | ||
3216 | __func__, __LINE__)); | ||
3217 | return; | ||
3218 | } | ||
3219 | port_info->num_phys = buffer.num_phys; | ||
3220 | port_info->phy_info = buffer.phy_info; | ||
3221 | for (i = 0; i < port_info->num_phys; i++) | ||
3222 | port_info->phy_info[i].portinfo = port_info; | ||
3223 | mutex_lock(&ioc->sas_topology_mutex); | ||
3224 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
3225 | mutex_unlock(&ioc->sas_topology_mutex); | ||
3226 | printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " | ||
3227 | "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, | ||
3228 | (unsigned long long)buffer.phy_info[0].identify.sas_address); | ||
3229 | mptsas_expander_refresh(ioc, port_info); | ||
3230 | } | ||
3231 | } | ||
3232 | |||
3233 | static void | ||
3234 | mptsas_probe_devices(MPT_ADAPTER *ioc) | ||
3235 | { | ||
3236 | u16 handle; | ||
3237 | struct mptsas_devinfo sas_device; | ||
3238 | struct mptsas_phyinfo *phy_info; | ||
3239 | |||
3240 | handle = 0xFFFF; | ||
3241 | while (!(mptsas_sas_device_pg0(ioc, &sas_device, | ||
3242 | MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) { | ||
3243 | |||
3244 | handle = sas_device.handle; | ||
3245 | |||
3246 | if ((sas_device.device_info & | ||
3247 | (MPI_SAS_DEVICE_INFO_SSP_TARGET | | ||
3248 | MPI_SAS_DEVICE_INFO_STP_TARGET | | ||
3249 | MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) | ||
3250 | continue; | ||
3251 | |||
3252 | phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); | ||
3253 | if (!phy_info) | ||
3254 | continue; | ||
3255 | |||
3256 | if (mptsas_get_rphy(phy_info)) | ||
3257 | continue; | ||
3258 | |||
3259 | mptsas_add_end_device(ioc, phy_info); | ||
3260 | } | ||
2993 | } | 3261 | } |
2994 | 3262 | ||
2995 | /* | 3263 | /* |
2996 | * Work queue thread to handle Runtime discovery | 3264 | * Start of day discovery |
2997 | * Mere purpose is the hot add/delete of expanders | ||
2998 | *(Mutex LOCKED) | ||
2999 | */ | 3265 | */ |
3000 | static void | 3266 | static void |
3001 | mptsas_discovery_work(struct work_struct *work) | 3267 | mptsas_scan_sas_topology(MPT_ADAPTER *ioc) |
3002 | { | 3268 | { |
3003 | struct mptsas_discovery_event *ev = | 3269 | struct scsi_device *sdev; |
3004 | container_of(work, struct mptsas_discovery_event, work); | 3270 | int i; |
3005 | MPT_ADAPTER *ioc = ev->ioc; | ||
3006 | 3271 | ||
3007 | mutex_lock(&ioc->sas_discovery_mutex); | 3272 | mptsas_probe_hba_phys(ioc); |
3008 | __mptsas_discovery_work(ioc); | 3273 | mptsas_probe_expanders(ioc); |
3009 | mutex_unlock(&ioc->sas_discovery_mutex); | 3274 | mptsas_probe_devices(ioc); |
3010 | kfree(ev); | ||
3011 | } | ||
3012 | 3275 | ||
3276 | /* | ||
3277 | Reporting RAID volumes. | ||
3278 | */ | ||
3279 | if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 || | ||
3280 | !ioc->raid_data.pIocPg2->NumActiveVolumes) | ||
3281 | return; | ||
3282 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { | ||
3283 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, | ||
3284 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); | ||
3285 | if (sdev) { | ||
3286 | scsi_device_put(sdev); | ||
3287 | continue; | ||
3288 | } | ||
3289 | printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " | ||
3290 | "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, | ||
3291 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID); | ||
3292 | scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, | ||
3293 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); | ||
3294 | } | ||
3295 | } | ||
3013 | 3296 | ||
3014 | static struct mptsas_phyinfo * | 3297 | static struct mptsas_phyinfo * |
3015 | mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) | 3298 | mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) |
@@ -3544,33 +3827,6 @@ mptsas_send_raid_event(struct fw_event_work *fw_event) | |||
3544 | mptsas_free_fw_event(ioc, fw_event); | 3827 | mptsas_free_fw_event(ioc, fw_event); |
3545 | } | 3828 | } |
3546 | 3829 | ||
3547 | static void | ||
3548 | mptsas_send_discovery_event(MPT_ADAPTER *ioc, | ||
3549 | EVENT_DATA_SAS_DISCOVERY *discovery_data) | ||
3550 | { | ||
3551 | struct mptsas_discovery_event *ev; | ||
3552 | u32 discovery_status; | ||
3553 | |||
3554 | /* | ||
3555 | * DiscoveryStatus | ||
3556 | * | ||
3557 | * This flag will be non-zero when firmware | ||
3558 | * kicks off discovery, and return to zero | ||
3559 | * once its completed. | ||
3560 | */ | ||
3561 | discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus); | ||
3562 | ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0; | ||
3563 | if (discovery_status) | ||
3564 | return; | ||
3565 | |||
3566 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | ||
3567 | if (!ev) | ||
3568 | return; | ||
3569 | INIT_WORK(&ev->work, mptsas_discovery_work); | ||
3570 | ev->ioc = ioc; | ||
3571 | schedule_work(&ev->work); | ||
3572 | }; | ||
3573 | |||
3574 | /* | 3830 | /* |
3575 | * mptsas_send_ir2_event - handle exposing hidden disk when | 3831 | * mptsas_send_ir2_event - handle exposing hidden disk when |
3576 | * an inactive raid volume is added | 3832 | * an inactive raid volume is added |
@@ -3634,10 +3890,28 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | |||
3634 | } | 3890 | } |
3635 | break; | 3891 | break; |
3636 | } | 3892 | } |
3637 | case MPI_EVENT_SAS_DISCOVERY: | 3893 | case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: |
3638 | mptsas_send_discovery_event(ioc, | 3894 | { |
3639 | (EVENT_DATA_SAS_DISCOVERY *)reply->Data); | 3895 | MpiEventDataSasExpanderStatusChange_t *expander_data = |
3896 | (MpiEventDataSasExpanderStatusChange_t *)reply->Data; | ||
3897 | |||
3898 | |||
3899 | if (expander_data->ReasonCode == | ||
3900 | MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING && | ||
3901 | ioc->device_missing_delay) | ||
3902 | delay = HZ * ioc->device_missing_delay; | ||
3640 | break; | 3903 | break; |
3904 | } | ||
3905 | case MPI_EVENT_SAS_DISCOVERY: | ||
3906 | { | ||
3907 | u32 discovery_status; | ||
3908 | EventDataSasDiscovery_t *discovery_data = | ||
3909 | (EventDataSasDiscovery_t *)reply->Data; | ||
3910 | |||
3911 | discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus); | ||
3912 | ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0; | ||
3913 | return 0; | ||
3914 | } | ||
3641 | case MPI_EVENT_INTEGRATED_RAID: | 3915 | case MPI_EVENT_INTEGRATED_RAID: |
3642 | case MPI_EVENT_PERSISTENT_TABLE_FULL: | 3916 | case MPI_EVENT_PERSISTENT_TABLE_FULL: |
3643 | case MPI_EVENT_IR2: | 3917 | case MPI_EVENT_IR2: |
@@ -3885,7 +4159,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) | |||
3885 | kfree(p); | 4159 | kfree(p); |
3886 | } | 4160 | } |
3887 | mutex_unlock(&ioc->sas_topology_mutex); | 4161 | mutex_unlock(&ioc->sas_topology_mutex); |
3888 | 4162 | ioc->hba_port_info = NULL; | |
3889 | mptscsih_remove(pdev); | 4163 | mptscsih_remove(pdev); |
3890 | } | 4164 | } |
3891 | 4165 | ||