[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>

authored by

Brian King and committed by
James Bottomley
989b8545 52d7e861

+171
+135
drivers/scsi/ibmvscsi/ibmvfc.c
··· 2914 } 2915 2916 /** 2917 * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD 2918 * @evt: ibmvfc event struct 2919 * ··· 3066 tgt->new_scsi_id = rsp->scsi_id; 3067 if (rsp->scsi_id != tgt->scsi_id) 3068 ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); 3069 break; 3070 case IBMVFC_MAD_DRIVER_FAILED: 3071 break;
··· 2914 } 2915 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 + /** 3050 * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD 3051 * @evt: ibmvfc event struct 3052 * ··· 2933 tgt->new_scsi_id = rsp->scsi_id; 2934 if (rsp->scsi_id != tgt->scsi_id) 2935 ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); 2936 + else 2937 + ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc); 2938 break; 2939 case IBMVFC_MAD_DRIVER_FAILED: 2940 break;
+36
drivers/scsi/ibmvscsi/ibmvfc.h
··· 119 IBMVFC_PROCESS_LOGIN = 0x0008, 120 IBMVFC_QUERY_TARGET = 0x0010, 121 IBMVFC_IMPLICIT_LOGOUT = 0x0040, 122 IBMVFC_TMF_MAD = 0x0100, 123 }; 124 ··· 440 struct ibmvfc_fcp_rsp rsp; 441 }__attribute__((packed, aligned (8))); 442 443 struct ibmvfc_trace_start_entry { 444 u32 xfer_len; 445 }__attribute__((packed)); ··· 563 struct ibmvfc_implicit_logout implicit_logout; 564 struct ibmvfc_tmf tmf; 565 struct ibmvfc_cmd cmd; 566 }__attribute__((packed, aligned (8))); 567 568 enum ibmvfc_target_action { ··· 688 689 #define tgt_dbg(t, fmt, ...) \ 690 DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)) 691 692 #define tgt_err(t, fmt, ...) \ 693 dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
··· 119 IBMVFC_PROCESS_LOGIN = 0x0008, 120 IBMVFC_QUERY_TARGET = 0x0010, 121 IBMVFC_IMPLICIT_LOGOUT = 0x0040, 122 + IBMVFC_PASSTHRU = 0x0200, 123 IBMVFC_TMF_MAD = 0x0100, 124 }; 125 ··· 439 struct ibmvfc_fcp_rsp rsp; 440 }__attribute__((packed, aligned (8))); 441 442 + struct ibmvfc_passthru_fc_iu { 443 + u32 payload[7]; 444 + #define IBMVFC_ADISC 0x52000000 445 + u32 response[7]; 446 + }; 447 + 448 + struct ibmvfc_passthru_iu { 449 + u64 task_tag; 450 + u32 cmd_len; 451 + u32 rsp_len; 452 + u16 status; 453 + u16 error; 454 + u32 flags; 455 + #define IBMVFC_FC_ELS 0x01 456 + u32 cancel_key; 457 + u32 reserved; 458 + struct srp_direct_buf cmd; 459 + struct srp_direct_buf rsp; 460 + u64 correlation; 461 + u64 scsi_id; 462 + u64 tag; 463 + u64 reserved2[2]; 464 + }__attribute__((packed, aligned (8))); 465 + 466 + struct ibmvfc_passthru_mad { 467 + struct ibmvfc_mad_common common; 468 + struct srp_direct_buf cmd_ioba; 469 + struct ibmvfc_passthru_iu iu; 470 + struct ibmvfc_passthru_fc_iu fc_iu; 471 + }__attribute__((packed, aligned (8))); 472 + 473 struct ibmvfc_trace_start_entry { 474 u32 xfer_len; 475 }__attribute__((packed)); ··· 531 struct ibmvfc_implicit_logout implicit_logout; 532 struct ibmvfc_tmf tmf; 533 struct ibmvfc_cmd cmd; 534 + struct ibmvfc_passthru_mad passthru; 535 }__attribute__((packed, aligned (8))); 536 537 enum ibmvfc_target_action { ··· 655 656 #define tgt_dbg(t, fmt, ...) \ 657 DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)) 658 + 659 + #define tgt_info(t, fmt, ...) \ 660 + dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__) 661 662 #define tgt_err(t, fmt, ...) \ 663 dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)