diff options
| -rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.c | 135 | ||||
| -rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.h | 36 |
2 files changed, 171 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; |
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 057f3c01ed61..6a48e5bb94e7 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h | |||
| @@ -119,6 +119,7 @@ enum ibmvfc_mad_types { | |||
| 119 | IBMVFC_PROCESS_LOGIN = 0x0008, | 119 | IBMVFC_PROCESS_LOGIN = 0x0008, |
| 120 | IBMVFC_QUERY_TARGET = 0x0010, | 120 | IBMVFC_QUERY_TARGET = 0x0010, |
| 121 | IBMVFC_IMPLICIT_LOGOUT = 0x0040, | 121 | IBMVFC_IMPLICIT_LOGOUT = 0x0040, |
| 122 | IBMVFC_PASSTHRU = 0x0200, | ||
| 122 | IBMVFC_TMF_MAD = 0x0100, | 123 | IBMVFC_TMF_MAD = 0x0100, |
| 123 | }; | 124 | }; |
| 124 | 125 | ||
| @@ -439,6 +440,37 @@ struct ibmvfc_cmd { | |||
| 439 | struct ibmvfc_fcp_rsp rsp; | 440 | struct ibmvfc_fcp_rsp rsp; |
| 440 | }__attribute__((packed, aligned (8))); | 441 | }__attribute__((packed, aligned (8))); |
| 441 | 442 | ||
| 443 | struct ibmvfc_passthru_fc_iu { | ||
| 444 | u32 payload[7]; | ||
| 445 | #define IBMVFC_ADISC 0x52000000 | ||
| 446 | u32 response[7]; | ||
| 447 | }; | ||
| 448 | |||
| 449 | struct ibmvfc_passthru_iu { | ||
| 450 | u64 task_tag; | ||
| 451 | u32 cmd_len; | ||
| 452 | u32 rsp_len; | ||
| 453 | u16 status; | ||
| 454 | u16 error; | ||
| 455 | u32 flags; | ||
| 456 | #define IBMVFC_FC_ELS 0x01 | ||
| 457 | u32 cancel_key; | ||
| 458 | u32 reserved; | ||
| 459 | struct srp_direct_buf cmd; | ||
| 460 | struct srp_direct_buf rsp; | ||
| 461 | u64 correlation; | ||
| 462 | u64 scsi_id; | ||
| 463 | u64 tag; | ||
| 464 | u64 reserved2[2]; | ||
| 465 | }__attribute__((packed, aligned (8))); | ||
| 466 | |||
| 467 | struct ibmvfc_passthru_mad { | ||
| 468 | struct ibmvfc_mad_common common; | ||
| 469 | struct srp_direct_buf cmd_ioba; | ||
| 470 | struct ibmvfc_passthru_iu iu; | ||
| 471 | struct ibmvfc_passthru_fc_iu fc_iu; | ||
| 472 | }__attribute__((packed, aligned (8))); | ||
| 473 | |||
| 442 | struct ibmvfc_trace_start_entry { | 474 | struct ibmvfc_trace_start_entry { |
| 443 | u32 xfer_len; | 475 | u32 xfer_len; |
| 444 | }__attribute__((packed)); | 476 | }__attribute__((packed)); |
| @@ -531,6 +563,7 @@ union ibmvfc_iu { | |||
| 531 | struct ibmvfc_implicit_logout implicit_logout; | 563 | struct ibmvfc_implicit_logout implicit_logout; |
| 532 | struct ibmvfc_tmf tmf; | 564 | struct ibmvfc_tmf tmf; |
| 533 | struct ibmvfc_cmd cmd; | 565 | struct ibmvfc_cmd cmd; |
| 566 | struct ibmvfc_passthru_mad passthru; | ||
| 534 | }__attribute__((packed, aligned (8))); | 567 | }__attribute__((packed, aligned (8))); |
| 535 | 568 | ||
| 536 | enum ibmvfc_target_action { | 569 | enum ibmvfc_target_action { |
| @@ -656,6 +689,9 @@ struct ibmvfc_host { | |||
| 656 | #define tgt_dbg(t, fmt, ...) \ | 689 | #define tgt_dbg(t, fmt, ...) \ |
| 657 | DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)) | 690 | DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)) |
| 658 | 691 | ||
| 692 | #define tgt_info(t, fmt, ...) \ | ||
| 693 | dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__) | ||
| 694 | |||
| 659 | #define tgt_err(t, fmt, ...) \ | 695 | #define tgt_err(t, fmt, ...) \ |
| 660 | dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__) | 696 | dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__) |
| 661 | 697 | ||
