diff options
Diffstat (limited to 'drivers/scsi/fcoe/fcoe_ctlr.c')
-rw-r--r-- | drivers/scsi/fcoe/fcoe_ctlr.c | 159 |
1 files changed, 145 insertions, 14 deletions
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 5a4c7250aa77..d68d57241ee6 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c | |||
@@ -160,6 +160,76 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode) | |||
160 | } | 160 | } |
161 | EXPORT_SYMBOL(fcoe_ctlr_init); | 161 | EXPORT_SYMBOL(fcoe_ctlr_init); |
162 | 162 | ||
163 | static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new) | ||
164 | { | ||
165 | struct fcoe_ctlr *fip = new->fip; | ||
166 | struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); | ||
167 | struct fcoe_fcf_device temp, *fcf_dev; | ||
168 | int rc = 0; | ||
169 | |||
170 | LIBFCOE_FIP_DBG(fip, "New FCF fab %16.16llx mac %pM\n", | ||
171 | new->fabric_name, new->fcf_mac); | ||
172 | |||
173 | mutex_lock(&ctlr_dev->lock); | ||
174 | |||
175 | temp.fabric_name = new->fabric_name; | ||
176 | temp.switch_name = new->switch_name; | ||
177 | temp.fc_map = new->fc_map; | ||
178 | temp.vfid = new->vfid; | ||
179 | memcpy(temp.mac, new->fcf_mac, ETH_ALEN); | ||
180 | temp.priority = new->pri; | ||
181 | temp.fka_period = new->fka_period; | ||
182 | temp.selected = 0; /* default to unselected */ | ||
183 | |||
184 | fcf_dev = fcoe_fcf_device_add(ctlr_dev, &temp); | ||
185 | if (unlikely(!fcf_dev)) { | ||
186 | rc = -ENOMEM; | ||
187 | goto out; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * The fcoe_sysfs layer can return a CONNECTED fcf that | ||
192 | * has a priv (fcf was never deleted) or a CONNECTED fcf | ||
193 | * that doesn't have a priv (fcf was deleted). However, | ||
194 | * libfcoe will always delete FCFs before trying to add | ||
195 | * them. This is ensured because both recv_adv and | ||
196 | * age_fcfs are protected by the the fcoe_ctlr's mutex. | ||
197 | * This means that we should never get a FCF with a | ||
198 | * non-NULL priv pointer. | ||
199 | */ | ||
200 | BUG_ON(fcf_dev->priv); | ||
201 | |||
202 | fcf_dev->priv = new; | ||
203 | new->fcf_dev = fcf_dev; | ||
204 | |||
205 | list_add(&new->list, &fip->fcfs); | ||
206 | fip->fcf_count++; | ||
207 | |||
208 | out: | ||
209 | mutex_unlock(&ctlr_dev->lock); | ||
210 | return rc; | ||
211 | } | ||
212 | |||
213 | static void fcoe_sysfs_fcf_del(struct fcoe_fcf *new) | ||
214 | { | ||
215 | struct fcoe_ctlr *fip = new->fip; | ||
216 | struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); | ||
217 | struct fcoe_fcf_device *fcf_dev; | ||
218 | |||
219 | list_del(&new->list); | ||
220 | fip->fcf_count--; | ||
221 | |||
222 | mutex_lock(&ctlr_dev->lock); | ||
223 | |||
224 | fcf_dev = fcoe_fcf_to_fcf_dev(new); | ||
225 | WARN_ON(!fcf_dev); | ||
226 | new->fcf_dev = NULL; | ||
227 | fcoe_fcf_device_delete(fcf_dev); | ||
228 | kfree(new); | ||
229 | |||
230 | mutex_unlock(&ctlr_dev->lock); | ||
231 | } | ||
232 | |||
163 | /** | 233 | /** |
164 | * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller | 234 | * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller |
165 | * @fip: The FCoE controller whose FCFs are to be reset | 235 | * @fip: The FCoE controller whose FCFs are to be reset |
@@ -173,10 +243,10 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip) | |||
173 | 243 | ||
174 | fip->sel_fcf = NULL; | 244 | fip->sel_fcf = NULL; |
175 | list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { | 245 | list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { |
176 | list_del(&fcf->list); | 246 | fcoe_sysfs_fcf_del(fcf); |
177 | kfree(fcf); | ||
178 | } | 247 | } |
179 | fip->fcf_count = 0; | 248 | WARN_ON(fip->fcf_count); |
249 | |||
180 | fip->sel_time = 0; | 250 | fip->sel_time = 0; |
181 | } | 251 | } |
182 | 252 | ||
@@ -717,8 +787,11 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) | |||
717 | unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); | 787 | unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); |
718 | unsigned long deadline; | 788 | unsigned long deadline; |
719 | unsigned long sel_time = 0; | 789 | unsigned long sel_time = 0; |
790 | struct list_head del_list; | ||
720 | struct fcoe_dev_stats *stats; | 791 | struct fcoe_dev_stats *stats; |
721 | 792 | ||
793 | INIT_LIST_HEAD(&del_list); | ||
794 | |||
722 | stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu()); | 795 | stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu()); |
723 | 796 | ||
724 | list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { | 797 | list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { |
@@ -739,10 +812,13 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) | |||
739 | if (time_after_eq(jiffies, deadline)) { | 812 | if (time_after_eq(jiffies, deadline)) { |
740 | if (fip->sel_fcf == fcf) | 813 | if (fip->sel_fcf == fcf) |
741 | fip->sel_fcf = NULL; | 814 | fip->sel_fcf = NULL; |
815 | /* | ||
816 | * Move to delete list so we can call | ||
817 | * fcoe_sysfs_fcf_del (which can sleep) | ||
818 | * after the put_cpu(). | ||
819 | */ | ||
742 | list_del(&fcf->list); | 820 | list_del(&fcf->list); |
743 | WARN_ON(!fip->fcf_count); | 821 | list_add(&fcf->list, &del_list); |
744 | fip->fcf_count--; | ||
745 | kfree(fcf); | ||
746 | stats->VLinkFailureCount++; | 822 | stats->VLinkFailureCount++; |
747 | } else { | 823 | } else { |
748 | if (time_after(next_timer, deadline)) | 824 | if (time_after(next_timer, deadline)) |
@@ -753,6 +829,12 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) | |||
753 | } | 829 | } |
754 | } | 830 | } |
755 | put_cpu(); | 831 | put_cpu(); |
832 | |||
833 | list_for_each_entry_safe(fcf, next, &del_list, list) { | ||
834 | /* Removes fcf from current list */ | ||
835 | fcoe_sysfs_fcf_del(fcf); | ||
836 | } | ||
837 | |||
756 | if (sel_time && !fip->sel_fcf && !fip->sel_time) { | 838 | if (sel_time && !fip->sel_fcf && !fip->sel_time) { |
757 | sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); | 839 | sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); |
758 | fip->sel_time = sel_time; | 840 | fip->sel_time = sel_time; |
@@ -903,23 +985,23 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) | |||
903 | { | 985 | { |
904 | struct fcoe_fcf *fcf; | 986 | struct fcoe_fcf *fcf; |
905 | struct fcoe_fcf new; | 987 | struct fcoe_fcf new; |
906 | struct fcoe_fcf *found; | ||
907 | unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV); | 988 | unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV); |
908 | int first = 0; | 989 | int first = 0; |
909 | int mtu_valid; | 990 | int mtu_valid; |
991 | int found = 0; | ||
992 | int rc = 0; | ||
910 | 993 | ||
911 | if (fcoe_ctlr_parse_adv(fip, skb, &new)) | 994 | if (fcoe_ctlr_parse_adv(fip, skb, &new)) |
912 | return; | 995 | return; |
913 | 996 | ||
914 | mutex_lock(&fip->ctlr_mutex); | 997 | mutex_lock(&fip->ctlr_mutex); |
915 | first = list_empty(&fip->fcfs); | 998 | first = list_empty(&fip->fcfs); |
916 | found = NULL; | ||
917 | list_for_each_entry(fcf, &fip->fcfs, list) { | 999 | list_for_each_entry(fcf, &fip->fcfs, list) { |
918 | if (fcf->switch_name == new.switch_name && | 1000 | if (fcf->switch_name == new.switch_name && |
919 | fcf->fabric_name == new.fabric_name && | 1001 | fcf->fabric_name == new.fabric_name && |
920 | fcf->fc_map == new.fc_map && | 1002 | fcf->fc_map == new.fc_map && |
921 | compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) { | 1003 | compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) { |
922 | found = fcf; | 1004 | found = 1; |
923 | break; | 1005 | break; |
924 | } | 1006 | } |
925 | } | 1007 | } |
@@ -931,9 +1013,16 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) | |||
931 | if (!fcf) | 1013 | if (!fcf) |
932 | goto out; | 1014 | goto out; |
933 | 1015 | ||
934 | fip->fcf_count++; | ||
935 | memcpy(fcf, &new, sizeof(new)); | 1016 | memcpy(fcf, &new, sizeof(new)); |
936 | list_add(&fcf->list, &fip->fcfs); | 1017 | fcf->fip = fip; |
1018 | rc = fcoe_sysfs_fcf_add(fcf); | ||
1019 | if (rc) { | ||
1020 | printk(KERN_ERR "Failed to allocate sysfs instance " | ||
1021 | "for FCF, fab %16.16llx mac %pM\n", | ||
1022 | new.fabric_name, new.fcf_mac); | ||
1023 | kfree(fcf); | ||
1024 | goto out; | ||
1025 | } | ||
937 | } else { | 1026 | } else { |
938 | /* | 1027 | /* |
939 | * Update the FCF's keep-alive descriptor flags. | 1028 | * Update the FCF's keep-alive descriptor flags. |
@@ -954,6 +1043,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) | |||
954 | fcf->fka_period = new.fka_period; | 1043 | fcf->fka_period = new.fka_period; |
955 | memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN); | 1044 | memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN); |
956 | } | 1045 | } |
1046 | |||
957 | mtu_valid = fcoe_ctlr_mtu_valid(fcf); | 1047 | mtu_valid = fcoe_ctlr_mtu_valid(fcf); |
958 | fcf->time = jiffies; | 1048 | fcf->time = jiffies; |
959 | if (!found) | 1049 | if (!found) |
@@ -996,6 +1086,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) | |||
996 | time_before(fip->sel_time, fip->timer.expires)) | 1086 | time_before(fip->sel_time, fip->timer.expires)) |
997 | mod_timer(&fip->timer, fip->sel_time); | 1087 | mod_timer(&fip->timer, fip->sel_time); |
998 | } | 1088 | } |
1089 | |||
999 | out: | 1090 | out: |
1000 | mutex_unlock(&fip->ctlr_mutex); | 1091 | mutex_unlock(&fip->ctlr_mutex); |
1001 | } | 1092 | } |
@@ -2718,9 +2809,9 @@ unlock: | |||
2718 | 2809 | ||
2719 | /** | 2810 | /** |
2720 | * fcoe_libfc_config() - Sets up libfc related properties for local port | 2811 | * fcoe_libfc_config() - Sets up libfc related properties for local port |
2721 | * @lp: The local port to configure libfc for | 2812 | * @lport: The local port to configure libfc for |
2722 | * @fip: The FCoE controller in use by the local port | 2813 | * @fip: The FCoE controller in use by the local port |
2723 | * @tt: The libfc function template | 2814 | * @tt: The libfc function template |
2724 | * @init_fcp: If non-zero, the FCP portion of libfc should be initialized | 2815 | * @init_fcp: If non-zero, the FCP portion of libfc should be initialized |
2725 | * | 2816 | * |
2726 | * Returns : 0 for success | 2817 | * Returns : 0 for success |
@@ -2753,3 +2844,43 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, | |||
2753 | return 0; | 2844 | return 0; |
2754 | } | 2845 | } |
2755 | EXPORT_SYMBOL_GPL(fcoe_libfc_config); | 2846 | EXPORT_SYMBOL_GPL(fcoe_libfc_config); |
2847 | |||
2848 | void fcoe_fcf_get_selected(struct fcoe_fcf_device *fcf_dev) | ||
2849 | { | ||
2850 | struct fcoe_ctlr_device *ctlr_dev = fcoe_fcf_dev_to_ctlr_dev(fcf_dev); | ||
2851 | struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev); | ||
2852 | struct fcoe_fcf *fcf; | ||
2853 | |||
2854 | mutex_lock(&fip->ctlr_mutex); | ||
2855 | mutex_lock(&ctlr_dev->lock); | ||
2856 | |||
2857 | fcf = fcoe_fcf_device_priv(fcf_dev); | ||
2858 | if (fcf) | ||
2859 | fcf_dev->selected = (fcf == fip->sel_fcf) ? 1 : 0; | ||
2860 | else | ||
2861 | fcf_dev->selected = 0; | ||
2862 | |||
2863 | mutex_unlock(&ctlr_dev->lock); | ||
2864 | mutex_unlock(&fip->ctlr_mutex); | ||
2865 | } | ||
2866 | EXPORT_SYMBOL(fcoe_fcf_get_selected); | ||
2867 | |||
2868 | void fcoe_ctlr_get_fip_mode(struct fcoe_ctlr_device *ctlr_dev) | ||
2869 | { | ||
2870 | struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); | ||
2871 | |||
2872 | mutex_lock(&ctlr->ctlr_mutex); | ||
2873 | switch (ctlr->mode) { | ||
2874 | case FIP_MODE_FABRIC: | ||
2875 | ctlr_dev->mode = FIP_CONN_TYPE_FABRIC; | ||
2876 | break; | ||
2877 | case FIP_MODE_VN2VN: | ||
2878 | ctlr_dev->mode = FIP_CONN_TYPE_VN2VN; | ||
2879 | break; | ||
2880 | default: | ||
2881 | ctlr_dev->mode = FIP_CONN_TYPE_UNKNOWN; | ||
2882 | break; | ||
2883 | } | ||
2884 | mutex_unlock(&ctlr->ctlr_mutex); | ||
2885 | } | ||
2886 | EXPORT_SYMBOL(fcoe_ctlr_get_fip_mode); | ||