diff options
author | Brian King <brking@linux.vnet.ibm.com> | 2008-07-22 09:31:47 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-07-26 15:14:58 -0400 |
commit | 989b854579875b38d45fffa7f8c89177f7698cd3 (patch) | |
tree | dfd8ea7a20edac28c0fb803e06bf30301fe69cce /drivers/scsi/ibmvscsi/ibmvfc.c | |
parent | 52d7e861cc071688f5fa3ee1b6e94785adeff8db (diff) |
[SCSI] ibmvfc: Add ADISC support
Add an ADISC to the target discovery job in order to sanity check whether or
not we need to re-login to the target.
Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/ibmvscsi/ibmvfc.c')
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 1917acb9102e..a33fa133f75b 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c | |||
@@ -2914,6 +2914,139 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) | |||
2914 | } | 2914 | } |
2915 | 2915 | ||
2916 | /** | 2916 | /** |
2917 | * ibmvfc_adisc_needs_plogi - Does device need PLOGI? | ||
2918 | * @mad: ibmvfc passthru mad struct | ||
2919 | * @tgt: ibmvfc target struct | ||
2920 | * | ||
2921 | * Returns: | ||
2922 | * 1 if PLOGI needed / 0 if PLOGI not needed | ||
2923 | **/ | ||
2924 | static int ibmvfc_adisc_needs_plogi(struct ibmvfc_passthru_mad *mad, | ||
2925 | struct ibmvfc_target *tgt) | ||
2926 | { | ||
2927 | if (memcmp(&mad->fc_iu.response[2], &tgt->ids.port_name, | ||
2928 | sizeof(tgt->ids.port_name))) | ||
2929 | return 1; | ||
2930 | if (memcmp(&mad->fc_iu.response[4], &tgt->ids.node_name, | ||
2931 | sizeof(tgt->ids.node_name))) | ||
2932 | return 1; | ||
2933 | if (mad->fc_iu.response[6] != tgt->scsi_id) | ||
2934 | return 1; | ||
2935 | return 0; | ||
2936 | } | ||
2937 | |||
2938 | /** | ||
2939 | * ibmvfc_tgt_adisc_done - Completion handler for ADISC | ||
2940 | * @evt: ibmvfc event struct | ||
2941 | * | ||
2942 | **/ | ||
2943 | static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt) | ||
2944 | { | ||
2945 | struct ibmvfc_target *tgt = evt->tgt; | ||
2946 | struct ibmvfc_host *vhost = evt->vhost; | ||
2947 | struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru; | ||
2948 | u32 status = mad->common.status; | ||
2949 | u8 fc_reason, fc_explain; | ||
2950 | |||
2951 | vhost->discovery_threads--; | ||
2952 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2953 | |||
2954 | switch (status) { | ||
2955 | case IBMVFC_MAD_SUCCESS: | ||
2956 | tgt_dbg(tgt, "ADISC succeeded\n"); | ||
2957 | if (ibmvfc_adisc_needs_plogi(mad, tgt)) | ||
2958 | tgt->need_login = 1; | ||
2959 | break; | ||
2960 | case IBMVFC_MAD_DRIVER_FAILED: | ||
2961 | break; | ||
2962 | case IBMVFC_MAD_FAILED: | ||
2963 | default: | ||
2964 | tgt->need_login = 1; | ||
2965 | fc_reason = (mad->fc_iu.response[1] & 0x00ff0000) >> 16; | ||
2966 | fc_explain = (mad->fc_iu.response[1] & 0x0000ff00) >> 8; | ||
2967 | tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", | ||
2968 | ibmvfc_get_cmd_error(mad->iu.status, mad->iu.error), | ||
2969 | mad->iu.status, mad->iu.error, | ||
2970 | ibmvfc_get_fc_type(fc_reason), fc_reason, | ||
2971 | ibmvfc_get_ls_explain(fc_explain), fc_explain, status); | ||
2972 | break; | ||
2973 | }; | ||
2974 | |||
2975 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2976 | ibmvfc_free_event(evt); | ||
2977 | wake_up(&vhost->work_wait_q); | ||
2978 | } | ||
2979 | |||
2980 | /** | ||
2981 | * ibmvfc_init_passthru - Initialize an event struct for FC passthru | ||
2982 | * @evt: ibmvfc event struct | ||
2983 | * | ||
2984 | **/ | ||
2985 | static void ibmvfc_init_passthru(struct ibmvfc_event *evt) | ||
2986 | { | ||
2987 | struct ibmvfc_passthru_mad *mad = &evt->iu.passthru; | ||
2988 | |||
2989 | memset(mad, 0, sizeof(*mad)); | ||
2990 | mad->common.version = 1; | ||
2991 | mad->common.opcode = IBMVFC_PASSTHRU; | ||
2992 | mad->common.length = sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu); | ||
2993 | mad->cmd_ioba.va = (u64)evt->crq.ioba + | ||
2994 | offsetof(struct ibmvfc_passthru_mad, iu); | ||
2995 | mad->cmd_ioba.len = sizeof(mad->iu); | ||
2996 | mad->iu.cmd_len = sizeof(mad->fc_iu.payload); | ||
2997 | mad->iu.rsp_len = sizeof(mad->fc_iu.response); | ||
2998 | mad->iu.cmd.va = (u64)evt->crq.ioba + | ||
2999 | offsetof(struct ibmvfc_passthru_mad, fc_iu) + | ||
3000 | offsetof(struct ibmvfc_passthru_fc_iu, payload); | ||
3001 | mad->iu.cmd.len = sizeof(mad->fc_iu.payload); | ||
3002 | mad->iu.rsp.va = (u64)evt->crq.ioba + | ||
3003 | offsetof(struct ibmvfc_passthru_mad, fc_iu) + | ||
3004 | offsetof(struct ibmvfc_passthru_fc_iu, response); | ||
3005 | mad->iu.rsp.len = sizeof(mad->fc_iu.response); | ||
3006 | } | ||
3007 | |||
3008 | /** | ||
3009 | * ibmvfc_tgt_adisc - Initiate an ADISC for specified target | ||
3010 | * @tgt: ibmvfc target struct | ||
3011 | * | ||
3012 | **/ | ||
3013 | static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) | ||
3014 | { | ||
3015 | struct ibmvfc_passthru_mad *mad; | ||
3016 | struct ibmvfc_host *vhost = tgt->vhost; | ||
3017 | struct ibmvfc_event *evt; | ||
3018 | |||
3019 | if (vhost->discovery_threads >= disc_threads) | ||
3020 | return; | ||
3021 | |||
3022 | kref_get(&tgt->kref); | ||
3023 | evt = ibmvfc_get_event(vhost); | ||
3024 | vhost->discovery_threads++; | ||
3025 | ibmvfc_init_event(evt, ibmvfc_tgt_adisc_done, IBMVFC_MAD_FORMAT); | ||
3026 | evt->tgt = tgt; | ||
3027 | |||
3028 | ibmvfc_init_passthru(evt); | ||
3029 | mad = &evt->iu.passthru; | ||
3030 | mad->iu.flags = IBMVFC_FC_ELS; | ||
3031 | mad->iu.scsi_id = tgt->scsi_id; | ||
3032 | |||
3033 | mad->fc_iu.payload[0] = IBMVFC_ADISC; | ||
3034 | memcpy(&mad->fc_iu.payload[2], &vhost->login_buf->resp.port_name, | ||
3035 | sizeof(vhost->login_buf->resp.port_name)); | ||
3036 | memcpy(&mad->fc_iu.payload[4], &vhost->login_buf->resp.node_name, | ||
3037 | sizeof(vhost->login_buf->resp.node_name)); | ||
3038 | mad->fc_iu.payload[6] = vhost->login_buf->resp.scsi_id & 0x00ffffff; | ||
3039 | |||
3040 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); | ||
3041 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { | ||
3042 | vhost->discovery_threads--; | ||
3043 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
3044 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
3045 | } else | ||
3046 | tgt_dbg(tgt, "Sent ADISC\n"); | ||
3047 | } | ||
3048 | |||
3049 | /** | ||
2917 | * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD | 3050 | * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD |
2918 | * @evt: ibmvfc event struct | 3051 | * @evt: ibmvfc event struct |
2919 | * | 3052 | * |
@@ -2933,6 +3066,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) | |||
2933 | tgt->new_scsi_id = rsp->scsi_id; | 3066 | tgt->new_scsi_id = rsp->scsi_id; |
2934 | if (rsp->scsi_id != tgt->scsi_id) | 3067 | if (rsp->scsi_id != tgt->scsi_id) |
2935 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); | 3068 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); |
3069 | else | ||
3070 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc); | ||
2936 | break; | 3071 | break; |
2937 | case IBMVFC_MAD_DRIVER_FAILED: | 3072 | case IBMVFC_MAD_DRIVER_FAILED: |
2938 | break; | 3073 | break; |