diff options
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
-rw-r--r-- | drivers/message/fusion/mptsas.c | 211 |
1 files changed, 206 insertions, 5 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 83873e3d0ce7..c20bbe45da82 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
@@ -1075,6 +1075,19 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
1075 | return 0; | 1075 | return 0; |
1076 | } | 1076 | } |
1077 | 1077 | ||
1078 | static void | ||
1079 | mptsas_block_io_sdev(struct scsi_device *sdev, void *data) | ||
1080 | { | ||
1081 | scsi_device_set_state(sdev, SDEV_BLOCK); | ||
1082 | } | ||
1083 | |||
1084 | static void | ||
1085 | mptsas_block_io_starget(struct scsi_target *starget) | ||
1086 | { | ||
1087 | if (starget) | ||
1088 | starget_for_each_device(starget, NULL, mptsas_block_io_sdev); | ||
1089 | } | ||
1090 | |||
1078 | /** | 1091 | /** |
1079 | * mptsas_target_reset_queue | 1092 | * mptsas_target_reset_queue |
1080 | * | 1093 | * |
@@ -1098,10 +1111,11 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, | |||
1098 | id = sas_event_data->TargetID; | 1111 | id = sas_event_data->TargetID; |
1099 | channel = sas_event_data->Bus; | 1112 | channel = sas_event_data->Bus; |
1100 | 1113 | ||
1101 | if (!(vtarget = mptsas_find_vtarget(ioc, channel, id))) | 1114 | vtarget = mptsas_find_vtarget(ioc, channel, id); |
1102 | return; | 1115 | if (vtarget) { |
1103 | 1116 | mptsas_block_io_starget(vtarget->starget); | |
1104 | vtarget->deleted = 1; /* block IO */ | 1117 | vtarget->deleted = 1; /* block IO */ |
1118 | } | ||
1105 | 1119 | ||
1106 | target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), | 1120 | target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), |
1107 | GFP_ATOMIC); | 1121 | GFP_ATOMIC); |
@@ -1868,7 +1882,8 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | |||
1868 | if (ioc->sas_discovery_quiesce_io) | 1882 | if (ioc->sas_discovery_quiesce_io) |
1869 | return SCSI_MLQUEUE_HOST_BUSY; | 1883 | return SCSI_MLQUEUE_HOST_BUSY; |
1870 | 1884 | ||
1871 | // scsi_print_command(SCpnt); | 1885 | if (ioc->debug_level & MPT_DEBUG_SCSI) |
1886 | scsi_print_command(SCpnt); | ||
1872 | 1887 | ||
1873 | return mptscsih_qcmd(SCpnt,done); | 1888 | return mptscsih_qcmd(SCpnt,done); |
1874 | } | 1889 | } |
@@ -2686,6 +2701,187 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, | |||
2686 | return error; | 2701 | return error; |
2687 | } | 2702 | } |
2688 | 2703 | ||
2704 | struct rep_manu_request{ | ||
2705 | u8 smp_frame_type; | ||
2706 | u8 function; | ||
2707 | u8 reserved; | ||
2708 | u8 request_length; | ||
2709 | }; | ||
2710 | |||
2711 | struct rep_manu_reply{ | ||
2712 | u8 smp_frame_type; /* 0x41 */ | ||
2713 | u8 function; /* 0x01 */ | ||
2714 | u8 function_result; | ||
2715 | u8 response_length; | ||
2716 | u16 expander_change_count; | ||
2717 | u8 reserved0[2]; | ||
2718 | u8 sas_format:1; | ||
2719 | u8 reserved1:7; | ||
2720 | u8 reserved2[3]; | ||
2721 | u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; | ||
2722 | u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; | ||
2723 | u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; | ||
2724 | u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; | ||
2725 | u16 component_id; | ||
2726 | u8 component_revision_id; | ||
2727 | u8 reserved3; | ||
2728 | u8 vendor_specific[8]; | ||
2729 | }; | ||
2730 | |||
2731 | /** | ||
2732 | * mptsas_exp_repmanufacture_info - | ||
2733 | * @ioc: per adapter object | ||
2734 | * @sas_address: expander sas address | ||
2735 | * @edev: the sas_expander_device object | ||
2736 | * | ||
2737 | * Fills in the sas_expander_device object when SMP port is created. | ||
2738 | * | ||
2739 | * Returns 0 for success, non-zero for failure. | ||
2740 | */ | ||
2741 | static int | ||
2742 | mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc, | ||
2743 | u64 sas_address, struct sas_expander_device *edev) | ||
2744 | { | ||
2745 | MPT_FRAME_HDR *mf; | ||
2746 | SmpPassthroughRequest_t *smpreq; | ||
2747 | SmpPassthroughReply_t *smprep; | ||
2748 | struct rep_manu_reply *manufacture_reply; | ||
2749 | struct rep_manu_request *manufacture_request; | ||
2750 | int ret; | ||
2751 | int flagsLength; | ||
2752 | unsigned long timeleft; | ||
2753 | char *psge; | ||
2754 | unsigned long flags; | ||
2755 | void *data_out = NULL; | ||
2756 | dma_addr_t data_out_dma = 0; | ||
2757 | u32 sz; | ||
2758 | |||
2759 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | ||
2760 | if (ioc->ioc_reset_in_progress) { | ||
2761 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | ||
2762 | printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n", | ||
2763 | __func__, ioc->name); | ||
2764 | return -EFAULT; | ||
2765 | } | ||
2766 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | ||
2767 | |||
2768 | ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); | ||
2769 | if (ret) | ||
2770 | goto out; | ||
2771 | |||
2772 | mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); | ||
2773 | if (!mf) { | ||
2774 | ret = -ENOMEM; | ||
2775 | goto out_unlock; | ||
2776 | } | ||
2777 | |||
2778 | smpreq = (SmpPassthroughRequest_t *)mf; | ||
2779 | memset(smpreq, 0, sizeof(*smpreq)); | ||
2780 | |||
2781 | sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); | ||
2782 | |||
2783 | data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma); | ||
2784 | if (!data_out) { | ||
2785 | printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n", | ||
2786 | __FILE__, __LINE__, __func__); | ||
2787 | ret = -ENOMEM; | ||
2788 | goto put_mf; | ||
2789 | } | ||
2790 | |||
2791 | manufacture_request = data_out; | ||
2792 | manufacture_request->smp_frame_type = 0x40; | ||
2793 | manufacture_request->function = 1; | ||
2794 | manufacture_request->reserved = 0; | ||
2795 | manufacture_request->request_length = 0; | ||
2796 | |||
2797 | smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; | ||
2798 | smpreq->PhysicalPort = 0xFF; | ||
2799 | *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); | ||
2800 | smpreq->RequestDataLength = sizeof(struct rep_manu_request); | ||
2801 | |||
2802 | psge = (char *) | ||
2803 | (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); | ||
2804 | |||
2805 | flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | | ||
2806 | MPI_SGE_FLAGS_SYSTEM_ADDRESS | | ||
2807 | MPI_SGE_FLAGS_HOST_TO_IOC | | ||
2808 | MPI_SGE_FLAGS_END_OF_BUFFER; | ||
2809 | flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; | ||
2810 | flagsLength |= sizeof(struct rep_manu_request); | ||
2811 | |||
2812 | ioc->add_sge(psge, flagsLength, data_out_dma); | ||
2813 | psge += ioc->SGE_size; | ||
2814 | |||
2815 | flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | | ||
2816 | MPI_SGE_FLAGS_SYSTEM_ADDRESS | | ||
2817 | MPI_SGE_FLAGS_IOC_TO_HOST | | ||
2818 | MPI_SGE_FLAGS_END_OF_BUFFER; | ||
2819 | flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; | ||
2820 | flagsLength |= sizeof(struct rep_manu_reply); | ||
2821 | ioc->add_sge(psge, flagsLength, data_out_dma + | ||
2822 | sizeof(struct rep_manu_request)); | ||
2823 | |||
2824 | INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) | ||
2825 | mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); | ||
2826 | |||
2827 | timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); | ||
2828 | if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { | ||
2829 | ret = -ETIME; | ||
2830 | mpt_free_msg_frame(ioc, mf); | ||
2831 | mf = NULL; | ||
2832 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) | ||
2833 | goto out_free; | ||
2834 | if (!timeleft) | ||
2835 | mpt_HardResetHandler(ioc, CAN_SLEEP); | ||
2836 | goto out_free; | ||
2837 | } | ||
2838 | |||
2839 | mf = NULL; | ||
2840 | |||
2841 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { | ||
2842 | u8 *tmp; | ||
2843 | |||
2844 | smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; | ||
2845 | if (le16_to_cpu(smprep->ResponseDataLength) != | ||
2846 | sizeof(struct rep_manu_reply)) | ||
2847 | goto out_free; | ||
2848 | |||
2849 | manufacture_reply = data_out + sizeof(struct rep_manu_request); | ||
2850 | strncpy(edev->vendor_id, manufacture_reply->vendor_id, | ||
2851 | SAS_EXPANDER_VENDOR_ID_LEN); | ||
2852 | strncpy(edev->product_id, manufacture_reply->product_id, | ||
2853 | SAS_EXPANDER_PRODUCT_ID_LEN); | ||
2854 | strncpy(edev->product_rev, manufacture_reply->product_rev, | ||
2855 | SAS_EXPANDER_PRODUCT_REV_LEN); | ||
2856 | edev->level = manufacture_reply->sas_format; | ||
2857 | if (manufacture_reply->sas_format) { | ||
2858 | strncpy(edev->component_vendor_id, | ||
2859 | manufacture_reply->component_vendor_id, | ||
2860 | SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); | ||
2861 | tmp = (u8 *)&manufacture_reply->component_id; | ||
2862 | edev->component_id = tmp[0] << 8 | tmp[1]; | ||
2863 | edev->component_revision_id = | ||
2864 | manufacture_reply->component_revision_id; | ||
2865 | } | ||
2866 | } else { | ||
2867 | printk(MYIOC_s_ERR_FMT | ||
2868 | "%s: smp passthru reply failed to be returned\n", | ||
2869 | ioc->name, __func__); | ||
2870 | ret = -ENXIO; | ||
2871 | } | ||
2872 | out_free: | ||
2873 | if (data_out_dma) | ||
2874 | pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma); | ||
2875 | put_mf: | ||
2876 | if (mf) | ||
2877 | mpt_free_msg_frame(ioc, mf); | ||
2878 | out_unlock: | ||
2879 | CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) | ||
2880 | mutex_unlock(&ioc->sas_mgmt.mutex); | ||
2881 | out: | ||
2882 | return ret; | ||
2883 | } | ||
2884 | |||
2689 | static void | 2885 | static void |
2690 | mptsas_parse_device_info(struct sas_identify *identify, | 2886 | mptsas_parse_device_info(struct sas_identify *identify, |
2691 | struct mptsas_devinfo *device_info) | 2887 | struct mptsas_devinfo *device_info) |
@@ -2967,6 +3163,11 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
2967 | goto out; | 3163 | goto out; |
2968 | } | 3164 | } |
2969 | mptsas_set_rphy(ioc, phy_info, rphy); | 3165 | mptsas_set_rphy(ioc, phy_info, rphy); |
3166 | if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE || | ||
3167 | identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) | ||
3168 | mptsas_exp_repmanufacture_info(ioc, | ||
3169 | identify.sas_address, | ||
3170 | rphy_to_expander_device(rphy)); | ||
2970 | } | 3171 | } |
2971 | 3172 | ||
2972 | out: | 3173 | out: |