diff options
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_init.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_init.c | 239 |
1 files changed, 200 insertions, 39 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 3075fbaef55..0497873a1dd 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c | |||
@@ -773,14 +773,14 @@ int qla4xxx_start_firmware(struct scsi_qla_host *ha) | |||
773 | * be freed so that when login happens from user space there are free DDB | 773 | * be freed so that when login happens from user space there are free DDB |
774 | * indices available. | 774 | * indices available. |
775 | **/ | 775 | **/ |
776 | static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) | 776 | void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) |
777 | { | 777 | { |
778 | int max_ddbs; | 778 | int max_ddbs; |
779 | int ret; | 779 | int ret; |
780 | uint32_t idx = 0, next_idx = 0; | 780 | uint32_t idx = 0, next_idx = 0; |
781 | uint32_t state = 0, conn_err = 0; | 781 | uint32_t state = 0, conn_err = 0; |
782 | 782 | ||
783 | max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES : | 783 | max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : |
784 | MAX_DEV_DB_ENTRIES; | 784 | MAX_DEV_DB_ENTRIES; |
785 | 785 | ||
786 | for (idx = 0; idx < max_ddbs; idx = next_idx) { | 786 | for (idx = 0; idx < max_ddbs; idx = next_idx) { |
@@ -804,7 +804,6 @@ static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) | |||
804 | } | 804 | } |
805 | } | 805 | } |
806 | 806 | ||
807 | |||
808 | /** | 807 | /** |
809 | * qla4xxx_initialize_adapter - initiailizes hba | 808 | * qla4xxx_initialize_adapter - initiailizes hba |
810 | * @ha: Pointer to host adapter structure. | 809 | * @ha: Pointer to host adapter structure. |
@@ -812,7 +811,7 @@ static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) | |||
812 | * This routine parforms all of the steps necessary to initialize the adapter. | 811 | * This routine parforms all of the steps necessary to initialize the adapter. |
813 | * | 812 | * |
814 | **/ | 813 | **/ |
815 | int qla4xxx_initialize_adapter(struct scsi_qla_host *ha) | 814 | int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset) |
816 | { | 815 | { |
817 | int status = QLA_ERROR; | 816 | int status = QLA_ERROR; |
818 | 817 | ||
@@ -840,7 +839,8 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha) | |||
840 | if (status == QLA_ERROR) | 839 | if (status == QLA_ERROR) |
841 | goto exit_init_hba; | 840 | goto exit_init_hba; |
842 | 841 | ||
843 | qla4xxx_free_ddb_index(ha); | 842 | if (is_reset == RESET_ADAPTER) |
843 | qla4xxx_build_ddb_list(ha, is_reset); | ||
844 | 844 | ||
845 | set_bit(AF_ONLINE, &ha->flags); | 845 | set_bit(AF_ONLINE, &ha->flags); |
846 | exit_init_hba: | 846 | exit_init_hba: |
@@ -855,38 +855,12 @@ exit_init_hba: | |||
855 | return status; | 855 | return status; |
856 | } | 856 | } |
857 | 857 | ||
858 | /** | 858 | int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, |
859 | * qla4xxx_process_ddb_changed - process ddb state change | 859 | struct ddb_entry *ddb_entry, uint32_t state) |
860 | * @ha - Pointer to host adapter structure. | ||
861 | * @fw_ddb_index - Firmware's device database index | ||
862 | * @state - Device state | ||
863 | * | ||
864 | * This routine processes a Decive Database Changed AEN Event. | ||
865 | **/ | ||
866 | int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | ||
867 | uint32_t state, uint32_t conn_err) | ||
868 | { | 860 | { |
869 | struct ddb_entry * ddb_entry; | ||
870 | uint32_t old_fw_ddb_device_state; | 861 | uint32_t old_fw_ddb_device_state; |
871 | int status = QLA_ERROR; | 862 | int status = QLA_ERROR; |
872 | 863 | ||
873 | /* check for out of range index */ | ||
874 | if (fw_ddb_index >= MAX_DDB_ENTRIES) | ||
875 | goto exit_ddb_event; | ||
876 | |||
877 | /* Get the corresponging ddb entry */ | ||
878 | ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); | ||
879 | /* Device does not currently exist in our database. */ | ||
880 | if (ddb_entry == NULL) { | ||
881 | ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n", | ||
882 | __func__, fw_ddb_index); | ||
883 | |||
884 | if (state == DDB_DS_NO_CONNECTION_ACTIVE) | ||
885 | clear_bit(fw_ddb_index, ha->ddb_idx_map); | ||
886 | |||
887 | goto exit_ddb_event; | ||
888 | } | ||
889 | |||
890 | old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; | 864 | old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; |
891 | DEBUG2(ql4_printk(KERN_INFO, ha, | 865 | DEBUG2(ql4_printk(KERN_INFO, ha, |
892 | "%s: DDB - old state = 0x%x, new state = 0x%x for " | 866 | "%s: DDB - old state = 0x%x, new state = 0x%x for " |
@@ -900,9 +874,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | |||
900 | switch (state) { | 874 | switch (state) { |
901 | case DDB_DS_SESSION_ACTIVE: | 875 | case DDB_DS_SESSION_ACTIVE: |
902 | case DDB_DS_DISCOVERY: | 876 | case DDB_DS_DISCOVERY: |
903 | iscsi_conn_start(ddb_entry->conn); | 877 | ddb_entry->unblock_sess(ddb_entry->sess); |
904 | iscsi_conn_login_event(ddb_entry->conn, | ||
905 | ISCSI_CONN_STATE_LOGGED_IN); | ||
906 | qla4xxx_update_session_conn_param(ha, ddb_entry); | 878 | qla4xxx_update_session_conn_param(ha, ddb_entry); |
907 | status = QLA_SUCCESS; | 879 | status = QLA_SUCCESS; |
908 | break; | 880 | break; |
@@ -936,9 +908,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | |||
936 | switch (state) { | 908 | switch (state) { |
937 | case DDB_DS_SESSION_ACTIVE: | 909 | case DDB_DS_SESSION_ACTIVE: |
938 | case DDB_DS_DISCOVERY: | 910 | case DDB_DS_DISCOVERY: |
939 | iscsi_conn_start(ddb_entry->conn); | 911 | ddb_entry->unblock_sess(ddb_entry->sess); |
940 | iscsi_conn_login_event(ddb_entry->conn, | ||
941 | ISCSI_CONN_STATE_LOGGED_IN); | ||
942 | qla4xxx_update_session_conn_param(ha, ddb_entry); | 912 | qla4xxx_update_session_conn_param(ha, ddb_entry); |
943 | status = QLA_SUCCESS; | 913 | status = QLA_SUCCESS; |
944 | break; | 914 | break; |
@@ -954,7 +924,198 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | |||
954 | __func__)); | 924 | __func__)); |
955 | break; | 925 | break; |
956 | } | 926 | } |
927 | return status; | ||
928 | } | ||
929 | |||
930 | void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry) | ||
931 | { | ||
932 | /* | ||
933 | * This triggers a relogin. After the relogin_timer | ||
934 | * expires, the relogin gets scheduled. We must wait a | ||
935 | * minimum amount of time since receiving an 0x8014 AEN | ||
936 | * with failed device_state or a logout response before | ||
937 | * we can issue another relogin. | ||
938 | * | ||
939 | * Firmware pads this timeout: (time2wait +1). | ||
940 | * Driver retry to login should be longer than F/W. | ||
941 | * Otherwise F/W will fail | ||
942 | * set_ddb() mbx cmd with 0x4005 since it still | ||
943 | * counting down its time2wait. | ||
944 | */ | ||
945 | atomic_set(&ddb_entry->relogin_timer, 0); | ||
946 | atomic_set(&ddb_entry->retry_relogin_timer, | ||
947 | ddb_entry->default_time2wait + 4); | ||
948 | |||
949 | } | ||
950 | |||
951 | int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | ||
952 | struct ddb_entry *ddb_entry, uint32_t state) | ||
953 | { | ||
954 | uint32_t old_fw_ddb_device_state; | ||
955 | int status = QLA_ERROR; | ||
956 | |||
957 | old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; | ||
958 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
959 | "%s: DDB - old state = 0x%x, new state = 0x%x for " | ||
960 | "index [%d]\n", __func__, | ||
961 | ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); | ||
962 | |||
963 | ddb_entry->fw_ddb_device_state = state; | ||
964 | |||
965 | switch (old_fw_ddb_device_state) { | ||
966 | case DDB_DS_LOGIN_IN_PROCESS: | ||
967 | case DDB_DS_NO_CONNECTION_ACTIVE: | ||
968 | switch (state) { | ||
969 | case DDB_DS_SESSION_ACTIVE: | ||
970 | ddb_entry->unblock_sess(ddb_entry->sess); | ||
971 | qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); | ||
972 | status = QLA_SUCCESS; | ||
973 | break; | ||
974 | case DDB_DS_SESSION_FAILED: | ||
975 | iscsi_block_session(ddb_entry->sess); | ||
976 | if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) | ||
977 | qla4xxx_arm_relogin_timer(ddb_entry); | ||
978 | status = QLA_SUCCESS; | ||
979 | break; | ||
980 | } | ||
981 | break; | ||
982 | case DDB_DS_SESSION_ACTIVE: | ||
983 | switch (state) { | ||
984 | case DDB_DS_SESSION_FAILED: | ||
985 | iscsi_block_session(ddb_entry->sess); | ||
986 | if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) | ||
987 | qla4xxx_arm_relogin_timer(ddb_entry); | ||
988 | status = QLA_SUCCESS; | ||
989 | break; | ||
990 | } | ||
991 | break; | ||
992 | case DDB_DS_SESSION_FAILED: | ||
993 | switch (state) { | ||
994 | case DDB_DS_SESSION_ACTIVE: | ||
995 | ddb_entry->unblock_sess(ddb_entry->sess); | ||
996 | qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); | ||
997 | status = QLA_SUCCESS; | ||
998 | break; | ||
999 | case DDB_DS_SESSION_FAILED: | ||
1000 | if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) | ||
1001 | qla4xxx_arm_relogin_timer(ddb_entry); | ||
1002 | status = QLA_SUCCESS; | ||
1003 | break; | ||
1004 | } | ||
1005 | break; | ||
1006 | default: | ||
1007 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unknown Event\n", | ||
1008 | __func__)); | ||
1009 | break; | ||
1010 | } | ||
1011 | return status; | ||
1012 | } | ||
1013 | |||
1014 | /** | ||
1015 | * qla4xxx_process_ddb_changed - process ddb state change | ||
1016 | * @ha - Pointer to host adapter structure. | ||
1017 | * @fw_ddb_index - Firmware's device database index | ||
1018 | * @state - Device state | ||
1019 | * | ||
1020 | * This routine processes a Decive Database Changed AEN Event. | ||
1021 | **/ | ||
1022 | int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, | ||
1023 | uint32_t fw_ddb_index, | ||
1024 | uint32_t state, uint32_t conn_err) | ||
1025 | { | ||
1026 | struct ddb_entry *ddb_entry; | ||
1027 | int status = QLA_ERROR; | ||
1028 | |||
1029 | /* check for out of range index */ | ||
1030 | if (fw_ddb_index >= MAX_DDB_ENTRIES) | ||
1031 | goto exit_ddb_event; | ||
1032 | |||
1033 | /* Get the corresponging ddb entry */ | ||
1034 | ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); | ||
1035 | /* Device does not currently exist in our database. */ | ||
1036 | if (ddb_entry == NULL) { | ||
1037 | ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n", | ||
1038 | __func__, fw_ddb_index); | ||
1039 | |||
1040 | if (state == DDB_DS_NO_CONNECTION_ACTIVE) | ||
1041 | clear_bit(fw_ddb_index, ha->ddb_idx_map); | ||
1042 | |||
1043 | goto exit_ddb_event; | ||
1044 | } | ||
1045 | |||
1046 | ddb_entry->ddb_change(ha, fw_ddb_index, ddb_entry, state); | ||
957 | 1047 | ||
958 | exit_ddb_event: | 1048 | exit_ddb_event: |
959 | return status; | 1049 | return status; |
960 | } | 1050 | } |
1051 | |||
1052 | /** | ||
1053 | * qla4xxx_login_flash_ddb - Login to target (DDB) | ||
1054 | * @cls_session: Pointer to the session to login | ||
1055 | * | ||
1056 | * This routine logins to the target. | ||
1057 | * Issues setddb and conn open mbx | ||
1058 | **/ | ||
1059 | void qla4xxx_login_flash_ddb(struct iscsi_cls_session *cls_session) | ||
1060 | { | ||
1061 | struct iscsi_session *sess; | ||
1062 | struct ddb_entry *ddb_entry; | ||
1063 | struct scsi_qla_host *ha; | ||
1064 | struct dev_db_entry *fw_ddb_entry = NULL; | ||
1065 | dma_addr_t fw_ddb_dma; | ||
1066 | uint32_t mbx_sts = 0; | ||
1067 | int ret; | ||
1068 | |||
1069 | sess = cls_session->dd_data; | ||
1070 | ddb_entry = sess->dd_data; | ||
1071 | ha = ddb_entry->ha; | ||
1072 | |||
1073 | if (!test_bit(AF_LINK_UP, &ha->flags)) | ||
1074 | return; | ||
1075 | |||
1076 | if (ddb_entry->ddb_type != FLASH_DDB) { | ||
1077 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
1078 | "Skipping login to non FLASH DB")); | ||
1079 | goto exit_login; | ||
1080 | } | ||
1081 | |||
1082 | fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, | ||
1083 | &fw_ddb_dma); | ||
1084 | if (fw_ddb_entry == NULL) { | ||
1085 | DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); | ||
1086 | goto exit_login; | ||
1087 | } | ||
1088 | |||
1089 | if (ddb_entry->fw_ddb_index == INVALID_ENTRY) { | ||
1090 | ret = qla4xxx_get_ddb_index(ha, &ddb_entry->fw_ddb_index); | ||
1091 | if (ret == QLA_ERROR) | ||
1092 | goto exit_login; | ||
1093 | |||
1094 | ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; | ||
1095 | ha->tot_ddbs++; | ||
1096 | } | ||
1097 | |||
1098 | memcpy(fw_ddb_entry, &ddb_entry->fw_ddb_entry, | ||
1099 | sizeof(struct dev_db_entry)); | ||
1100 | ddb_entry->sess->target_id = ddb_entry->fw_ddb_index; | ||
1101 | |||
1102 | ret = qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, | ||
1103 | fw_ddb_dma, &mbx_sts); | ||
1104 | if (ret == QLA_ERROR) { | ||
1105 | DEBUG2(ql4_printk(KERN_ERR, ha, "Set DDB failed\n")); | ||
1106 | goto exit_login; | ||
1107 | } | ||
1108 | |||
1109 | ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; | ||
1110 | ret = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); | ||
1111 | if (ret == QLA_ERROR) { | ||
1112 | ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, | ||
1113 | sess->targetname); | ||
1114 | goto exit_login; | ||
1115 | } | ||
1116 | |||
1117 | exit_login: | ||
1118 | if (fw_ddb_entry) | ||
1119 | dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); | ||
1120 | } | ||
1121 | |||