aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ibmvscsi/ibmvfc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/ibmvscsi/ibmvfc.c')
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c204
1 files changed, 177 insertions, 27 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 61f8fdea2d96..ae560bc04f9d 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -521,9 +521,10 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
521static void ibmvfc_reinit_host(struct ibmvfc_host *vhost) 521static void ibmvfc_reinit_host(struct ibmvfc_host *vhost)
522{ 522{
523 if (vhost->action == IBMVFC_HOST_ACTION_NONE) { 523 if (vhost->action == IBMVFC_HOST_ACTION_NONE) {
524 scsi_block_requests(vhost->host); 524 if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
525 ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING); 525 scsi_block_requests(vhost->host);
526 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); 526 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
527 }
527 } else 528 } else
528 vhost->reinit = 1; 529 vhost->reinit = 1;
529 530
@@ -854,39 +855,41 @@ static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost)
854} 855}
855 856
856/** 857/**
857 * __ibmvfc_find_target - Find the specified scsi_target (no locking) 858 * __ibmvfc_get_target - Find the specified scsi_target (no locking)
858 * @starget: scsi target struct 859 * @starget: scsi target struct
859 * 860 *
860 * Return value: 861 * Return value:
861 * ibmvfc_target struct / NULL if not found 862 * ibmvfc_target struct / NULL if not found
862 **/ 863 **/
863static struct ibmvfc_target *__ibmvfc_find_target(struct scsi_target *starget) 864static struct ibmvfc_target *__ibmvfc_get_target(struct scsi_target *starget)
864{ 865{
865 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 866 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
866 struct ibmvfc_host *vhost = shost_priv(shost); 867 struct ibmvfc_host *vhost = shost_priv(shost);
867 struct ibmvfc_target *tgt; 868 struct ibmvfc_target *tgt;
868 869
869 list_for_each_entry(tgt, &vhost->targets, queue) 870 list_for_each_entry(tgt, &vhost->targets, queue)
870 if (tgt->target_id == starget->id) 871 if (tgt->target_id == starget->id) {
872 kref_get(&tgt->kref);
871 return tgt; 873 return tgt;
874 }
872 return NULL; 875 return NULL;
873} 876}
874 877
875/** 878/**
876 * ibmvfc_find_target - Find the specified scsi_target 879 * ibmvfc_get_target - Find the specified scsi_target
877 * @starget: scsi target struct 880 * @starget: scsi target struct
878 * 881 *
879 * Return value: 882 * Return value:
880 * ibmvfc_target struct / NULL if not found 883 * ibmvfc_target struct / NULL if not found
881 **/ 884 **/
882static struct ibmvfc_target *ibmvfc_find_target(struct scsi_target *starget) 885static struct ibmvfc_target *ibmvfc_get_target(struct scsi_target *starget)
883{ 886{
884 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 887 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
885 struct ibmvfc_target *tgt; 888 struct ibmvfc_target *tgt;
886 unsigned long flags; 889 unsigned long flags;
887 890
888 spin_lock_irqsave(shost->host_lock, flags); 891 spin_lock_irqsave(shost->host_lock, flags);
889 tgt = __ibmvfc_find_target(starget); 892 tgt = __ibmvfc_get_target(starget);
890 spin_unlock_irqrestore(shost->host_lock, flags); 893 spin_unlock_irqrestore(shost->host_lock, flags);
891 return tgt; 894 return tgt;
892} 895}
@@ -963,6 +966,9 @@ static void ibmvfc_get_host_port_state(struct Scsi_Host *shost)
963 case IBMVFC_HALTED: 966 case IBMVFC_HALTED:
964 fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED; 967 fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED;
965 break; 968 break;
969 case IBMVFC_NO_CRQ:
970 fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
971 break;
966 default: 972 default:
967 ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state); 973 ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state);
968 fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; 974 fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
@@ -988,6 +994,17 @@ static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
988} 994}
989 995
990/** 996/**
997 * ibmvfc_release_tgt - Free memory allocated for a target
998 * @kref: kref struct
999 *
1000 **/
1001static void ibmvfc_release_tgt(struct kref *kref)
1002{
1003 struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref);
1004 kfree(tgt);
1005}
1006
1007/**
991 * ibmvfc_get_starget_node_name - Get SCSI target's node name 1008 * ibmvfc_get_starget_node_name - Get SCSI target's node name
992 * @starget: scsi target struct 1009 * @starget: scsi target struct
993 * 1010 *
@@ -996,8 +1013,10 @@ static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
996 **/ 1013 **/
997static void ibmvfc_get_starget_node_name(struct scsi_target *starget) 1014static void ibmvfc_get_starget_node_name(struct scsi_target *starget)
998{ 1015{
999 struct ibmvfc_target *tgt = ibmvfc_find_target(starget); 1016 struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
1000 fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0; 1017 fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0;
1018 if (tgt)
1019 kref_put(&tgt->kref, ibmvfc_release_tgt);
1001} 1020}
1002 1021
1003/** 1022/**
@@ -1009,8 +1028,10 @@ static void ibmvfc_get_starget_node_name(struct scsi_target *starget)
1009 **/ 1028 **/
1010static void ibmvfc_get_starget_port_name(struct scsi_target *starget) 1029static void ibmvfc_get_starget_port_name(struct scsi_target *starget)
1011{ 1030{
1012 struct ibmvfc_target *tgt = ibmvfc_find_target(starget); 1031 struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
1013 fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0; 1032 fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0;
1033 if (tgt)
1034 kref_put(&tgt->kref, ibmvfc_release_tgt);
1014} 1035}
1015 1036
1016/** 1037/**
@@ -1022,8 +1043,10 @@ static void ibmvfc_get_starget_port_name(struct scsi_target *starget)
1022 **/ 1043 **/
1023static void ibmvfc_get_starget_port_id(struct scsi_target *starget) 1044static void ibmvfc_get_starget_port_id(struct scsi_target *starget)
1024{ 1045{
1025 struct ibmvfc_target *tgt = ibmvfc_find_target(starget); 1046 struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
1026 fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1; 1047 fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1;
1048 if (tgt)
1049 kref_put(&tgt->kref, ibmvfc_release_tgt);
1027} 1050}
1028 1051
1029/** 1052/**
@@ -1113,7 +1136,7 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
1113 login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ; 1136 login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ;
1114 login_info->capabilities = IBMVFC_CAN_MIGRATE; 1137 login_info->capabilities = IBMVFC_CAN_MIGRATE;
1115 login_info->async.va = vhost->async_crq.msg_token; 1138 login_info->async.va = vhost->async_crq.msg_token;
1116 login_info->async.len = vhost->async_crq.size; 1139 login_info->async.len = vhost->async_crq.size * sizeof(*vhost->async_crq.msgs);
1117 strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME); 1140 strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME);
1118 strncpy(login_info->device_name, 1141 strncpy(login_info->device_name,
1119 vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME); 1142 vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME);
@@ -1404,7 +1427,7 @@ static void ibmvfc_log_error(struct ibmvfc_event *evt)
1404 err = cmd_status[index].name; 1427 err = cmd_status[index].name;
1405 } 1428 }
1406 1429
1407 if (!logerr && (vhost->log_level <= IBMVFC_DEFAULT_LOG_LEVEL)) 1430 if (!logerr && (vhost->log_level <= (IBMVFC_DEFAULT_LOG_LEVEL + 1)))
1408 return; 1431 return;
1409 1432
1410 if (rsp->flags & FCP_RSP_LEN_VALID) 1433 if (rsp->flags & FCP_RSP_LEN_VALID)
@@ -2054,7 +2077,7 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
2054{ 2077{
2055 const char *desc = ibmvfc_get_ae_desc(crq->event); 2078 const char *desc = ibmvfc_get_ae_desc(crq->event);
2056 2079
2057 ibmvfc_log(vhost, 2, "%s event received\n", desc); 2080 ibmvfc_log(vhost, 3, "%s event received\n", desc);
2058 2081
2059 switch (crq->event) { 2082 switch (crq->event) {
2060 case IBMVFC_AE_LINK_UP: 2083 case IBMVFC_AE_LINK_UP:
@@ -2648,17 +2671,6 @@ static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
2648} 2671}
2649 2672
2650/** 2673/**
2651 * ibmvfc_release_tgt - Free memory allocated for a target
2652 * @kref: kref struct
2653 *
2654 **/
2655static void ibmvfc_release_tgt(struct kref *kref)
2656{
2657 struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref);
2658 kfree(tgt);
2659}
2660
2661/**
2662 * ibmvfc_tgt_prli_done - Completion handler for Process Login 2674 * ibmvfc_tgt_prli_done - Completion handler for Process Login
2663 * @evt: ibmvfc event struct 2675 * @evt: ibmvfc event struct
2664 * 2676 *
@@ -2902,6 +2914,139 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt)
2902} 2914}
2903 2915
2904/** 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 **/
2924static 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 **/
2943static 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 **/
2985static 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 **/
3013static 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/**
2905 * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD 3050 * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD
2906 * @evt: ibmvfc event struct 3051 * @evt: ibmvfc event struct
2907 * 3052 *
@@ -2921,6 +3066,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)
2921 tgt->new_scsi_id = rsp->scsi_id; 3066 tgt->new_scsi_id = rsp->scsi_id;
2922 if (rsp->scsi_id != tgt->scsi_id) 3067 if (rsp->scsi_id != tgt->scsi_id)
2923 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);
2924 break; 3071 break;
2925 case IBMVFC_MAD_DRIVER_FAILED: 3072 case IBMVFC_MAD_DRIVER_FAILED:
2926 break; 3073 break;
@@ -3336,6 +3483,7 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
3336 tgt_dbg(tgt, "rport add succeeded\n"); 3483 tgt_dbg(tgt, "rport add succeeded\n");
3337 rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff; 3484 rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff;
3338 rport->supported_classes = 0; 3485 rport->supported_classes = 0;
3486 tgt->target_id = rport->scsi_target_id;
3339 if (tgt->service_parms.class1_parms[0] & 0x80000000) 3487 if (tgt->service_parms.class1_parms[0] & 0x80000000)
3340 rport->supported_classes |= FC_COS_CLASS1; 3488 rport->supported_classes |= FC_COS_CLASS1;
3341 if (tgt->service_parms.class2_parms[0] & 0x80000000) 3489 if (tgt->service_parms.class2_parms[0] & 0x80000000)
@@ -3800,10 +3948,12 @@ static int ibmvfc_remove(struct vio_dev *vdev)
3800 3948
3801 ENTER; 3949 ENTER;
3802 ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr); 3950 ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr);
3951 ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
3952 ibmvfc_wait_while_resetting(vhost);
3953 ibmvfc_release_crq_queue(vhost);
3803 kthread_stop(vhost->work_thread); 3954 kthread_stop(vhost->work_thread);
3804 fc_remove_host(vhost->host); 3955 fc_remove_host(vhost->host);
3805 scsi_remove_host(vhost->host); 3956 scsi_remove_host(vhost->host);
3806 ibmvfc_release_crq_queue(vhost);
3807 3957
3808 spin_lock_irqsave(vhost->host->host_lock, flags); 3958 spin_lock_irqsave(vhost->host->host_lock, flags);
3809 ibmvfc_purge_requests(vhost, DID_ERROR); 3959 ibmvfc_purge_requests(vhost, DID_ERROR);