diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_lport.c')
-rw-r--r-- | drivers/scsi/libfc/fc_lport.c | 864 |
1 files changed, 605 insertions, 259 deletions
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index bd2f77197447..d126ecfff704 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c | |||
@@ -56,7 +56,7 @@ | |||
56 | * at the same time. | 56 | * at the same time. |
57 | * | 57 | * |
58 | * When discovery succeeds or fails a callback is made to the lport as | 58 | * When discovery succeeds or fails a callback is made to the lport as |
59 | * notification. Currently, succesful discovery causes the lport to take no | 59 | * notification. Currently, successful discovery causes the lport to take no |
60 | * action. A failure will cause the lport to reset. There is likely a circular | 60 | * action. A failure will cause the lport to reset. There is likely a circular |
61 | * locking problem with this implementation. | 61 | * locking problem with this implementation. |
62 | */ | 62 | */ |
@@ -88,12 +88,16 @@ | |||
88 | */ | 88 | */ |
89 | 89 | ||
90 | #include <linux/timer.h> | 90 | #include <linux/timer.h> |
91 | #include <linux/slab.h> | ||
91 | #include <asm/unaligned.h> | 92 | #include <asm/unaligned.h> |
92 | 93 | ||
93 | #include <scsi/fc/fc_gs.h> | 94 | #include <scsi/fc/fc_gs.h> |
94 | 95 | ||
95 | #include <scsi/libfc.h> | 96 | #include <scsi/libfc.h> |
96 | #include <scsi/fc_encode.h> | 97 | #include <scsi/fc_encode.h> |
98 | #include <linux/scatterlist.h> | ||
99 | |||
100 | #include "fc_libfc.h" | ||
97 | 101 | ||
98 | /* Fabric IDs to use for point-to-point mode, chosen on whims. */ | 102 | /* Fabric IDs to use for point-to-point mode, chosen on whims. */ |
99 | #define FC_LOCAL_PTP_FID_LO 0x010101 | 103 | #define FC_LOCAL_PTP_FID_LO 0x010101 |
@@ -106,8 +110,7 @@ static void fc_lport_error(struct fc_lport *, struct fc_frame *); | |||
106 | static void fc_lport_enter_reset(struct fc_lport *); | 110 | static void fc_lport_enter_reset(struct fc_lport *); |
107 | static void fc_lport_enter_flogi(struct fc_lport *); | 111 | static void fc_lport_enter_flogi(struct fc_lport *); |
108 | static void fc_lport_enter_dns(struct fc_lport *); | 112 | static void fc_lport_enter_dns(struct fc_lport *); |
109 | static void fc_lport_enter_rpn_id(struct fc_lport *); | 113 | static void fc_lport_enter_ns(struct fc_lport *, enum fc_lport_state); |
110 | static void fc_lport_enter_rft_id(struct fc_lport *); | ||
111 | static void fc_lport_enter_scr(struct fc_lport *); | 114 | static void fc_lport_enter_scr(struct fc_lport *); |
112 | static void fc_lport_enter_ready(struct fc_lport *); | 115 | static void fc_lport_enter_ready(struct fc_lport *); |
113 | static void fc_lport_enter_logo(struct fc_lport *); | 116 | static void fc_lport_enter_logo(struct fc_lport *); |
@@ -116,14 +119,40 @@ static const char *fc_lport_state_names[] = { | |||
116 | [LPORT_ST_DISABLED] = "disabled", | 119 | [LPORT_ST_DISABLED] = "disabled", |
117 | [LPORT_ST_FLOGI] = "FLOGI", | 120 | [LPORT_ST_FLOGI] = "FLOGI", |
118 | [LPORT_ST_DNS] = "dNS", | 121 | [LPORT_ST_DNS] = "dNS", |
119 | [LPORT_ST_RPN_ID] = "RPN_ID", | 122 | [LPORT_ST_RNN_ID] = "RNN_ID", |
123 | [LPORT_ST_RSNN_NN] = "RSNN_NN", | ||
124 | [LPORT_ST_RSPN_ID] = "RSPN_ID", | ||
120 | [LPORT_ST_RFT_ID] = "RFT_ID", | 125 | [LPORT_ST_RFT_ID] = "RFT_ID", |
126 | [LPORT_ST_RFF_ID] = "RFF_ID", | ||
121 | [LPORT_ST_SCR] = "SCR", | 127 | [LPORT_ST_SCR] = "SCR", |
122 | [LPORT_ST_READY] = "Ready", | 128 | [LPORT_ST_READY] = "Ready", |
123 | [LPORT_ST_LOGO] = "LOGO", | 129 | [LPORT_ST_LOGO] = "LOGO", |
124 | [LPORT_ST_RESET] = "reset", | 130 | [LPORT_ST_RESET] = "reset", |
125 | }; | 131 | }; |
126 | 132 | ||
133 | /** | ||
134 | * struct fc_bsg_info - FC Passthrough managemet structure | ||
135 | * @job: The passthrough job | ||
136 | * @lport: The local port to pass through a command | ||
137 | * @rsp_code: The expected response code | ||
138 | * @sg: job->reply_payload.sg_list | ||
139 | * @nents: job->reply_payload.sg_cnt | ||
140 | * @offset: The offset into the response data | ||
141 | */ | ||
142 | struct fc_bsg_info { | ||
143 | struct fc_bsg_job *job; | ||
144 | struct fc_lport *lport; | ||
145 | u16 rsp_code; | ||
146 | struct scatterlist *sg; | ||
147 | u32 nents; | ||
148 | size_t offset; | ||
149 | }; | ||
150 | |||
151 | /** | ||
152 | * fc_frame_drop() - Dummy frame handler | ||
153 | * @lport: The local port the frame was received on | ||
154 | * @fp: The received frame | ||
155 | */ | ||
127 | static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp) | 156 | static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp) |
128 | { | 157 | { |
129 | fc_frame_free(fp); | 158 | fc_frame_free(fp); |
@@ -150,8 +179,8 @@ static void fc_lport_rport_callback(struct fc_lport *lport, | |||
150 | switch (event) { | 179 | switch (event) { |
151 | case RPORT_EV_READY: | 180 | case RPORT_EV_READY: |
152 | if (lport->state == LPORT_ST_DNS) { | 181 | if (lport->state == LPORT_ST_DNS) { |
153 | lport->dns_rp = rdata; | 182 | lport->dns_rdata = rdata; |
154 | fc_lport_enter_rpn_id(lport); | 183 | fc_lport_enter_ns(lport, LPORT_ST_RNN_ID); |
155 | } else { | 184 | } else { |
156 | FC_LPORT_DBG(lport, "Received an READY event " | 185 | FC_LPORT_DBG(lport, "Received an READY event " |
157 | "on port (%6x) for the directory " | 186 | "on port (%6x) for the directory " |
@@ -165,7 +194,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, | |||
165 | case RPORT_EV_LOGO: | 194 | case RPORT_EV_LOGO: |
166 | case RPORT_EV_FAILED: | 195 | case RPORT_EV_FAILED: |
167 | case RPORT_EV_STOP: | 196 | case RPORT_EV_STOP: |
168 | lport->dns_rp = NULL; | 197 | lport->dns_rdata = NULL; |
169 | break; | 198 | break; |
170 | case RPORT_EV_NONE: | 199 | case RPORT_EV_NONE: |
171 | break; | 200 | break; |
@@ -189,8 +218,8 @@ static const char *fc_lport_state(struct fc_lport *lport) | |||
189 | 218 | ||
190 | /** | 219 | /** |
191 | * fc_lport_ptp_setup() - Create an rport for point-to-point mode | 220 | * fc_lport_ptp_setup() - Create an rport for point-to-point mode |
192 | * @lport: The lport to attach the ptp rport to | 221 | * @lport: The lport to attach the ptp rport to |
193 | * @fid: The FID of the ptp rport | 222 | * @remote_fid: The FID of the ptp rport |
194 | * @remote_wwpn: The WWPN of the ptp rport | 223 | * @remote_wwpn: The WWPN of the ptp rport |
195 | * @remote_wwnn: The WWNN of the ptp rport | 224 | * @remote_wwnn: The WWNN of the ptp rport |
196 | */ | 225 | */ |
@@ -199,18 +228,22 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, | |||
199 | u64 remote_wwnn) | 228 | u64 remote_wwnn) |
200 | { | 229 | { |
201 | mutex_lock(&lport->disc.disc_mutex); | 230 | mutex_lock(&lport->disc.disc_mutex); |
202 | if (lport->ptp_rp) | 231 | if (lport->ptp_rdata) |
203 | lport->tt.rport_logoff(lport->ptp_rp); | 232 | lport->tt.rport_logoff(lport->ptp_rdata); |
204 | lport->ptp_rp = lport->tt.rport_create(lport, remote_fid); | 233 | lport->ptp_rdata = lport->tt.rport_create(lport, remote_fid); |
205 | lport->ptp_rp->ids.port_name = remote_wwpn; | 234 | lport->ptp_rdata->ids.port_name = remote_wwpn; |
206 | lport->ptp_rp->ids.node_name = remote_wwnn; | 235 | lport->ptp_rdata->ids.node_name = remote_wwnn; |
207 | mutex_unlock(&lport->disc.disc_mutex); | 236 | mutex_unlock(&lport->disc.disc_mutex); |
208 | 237 | ||
209 | lport->tt.rport_login(lport->ptp_rp); | 238 | lport->tt.rport_login(lport->ptp_rdata); |
210 | 239 | ||
211 | fc_lport_enter_ready(lport); | 240 | fc_lport_enter_ready(lport); |
212 | } | 241 | } |
213 | 242 | ||
243 | /** | ||
244 | * fc_get_host_port_type() - Return the port type of the given Scsi_Host | ||
245 | * @shost: The SCSI host whose port type is to be determined | ||
246 | */ | ||
214 | void fc_get_host_port_type(struct Scsi_Host *shost) | 247 | void fc_get_host_port_type(struct Scsi_Host *shost) |
215 | { | 248 | { |
216 | /* TODO - currently just NPORT */ | 249 | /* TODO - currently just NPORT */ |
@@ -218,17 +251,33 @@ void fc_get_host_port_type(struct Scsi_Host *shost) | |||
218 | } | 251 | } |
219 | EXPORT_SYMBOL(fc_get_host_port_type); | 252 | EXPORT_SYMBOL(fc_get_host_port_type); |
220 | 253 | ||
254 | /** | ||
255 | * fc_get_host_port_state() - Return the port state of the given Scsi_Host | ||
256 | * @shost: The SCSI host whose port state is to be determined | ||
257 | */ | ||
221 | void fc_get_host_port_state(struct Scsi_Host *shost) | 258 | void fc_get_host_port_state(struct Scsi_Host *shost) |
222 | { | 259 | { |
223 | struct fc_lport *lp = shost_priv(shost); | 260 | struct fc_lport *lport = shost_priv(shost); |
224 | 261 | ||
225 | if (lp->link_up) | 262 | mutex_lock(&lport->lp_mutex); |
226 | fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; | 263 | if (!lport->link_up) |
264 | fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; | ||
227 | else | 265 | else |
228 | fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; | 266 | switch (lport->state) { |
267 | case LPORT_ST_READY: | ||
268 | fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; | ||
269 | break; | ||
270 | default: | ||
271 | fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; | ||
272 | } | ||
273 | mutex_unlock(&lport->lp_mutex); | ||
229 | } | 274 | } |
230 | EXPORT_SYMBOL(fc_get_host_port_state); | 275 | EXPORT_SYMBOL(fc_get_host_port_state); |
231 | 276 | ||
277 | /** | ||
278 | * fc_get_host_speed() - Return the speed of the given Scsi_Host | ||
279 | * @shost: The SCSI host whose port speed is to be determined | ||
280 | */ | ||
232 | void fc_get_host_speed(struct Scsi_Host *shost) | 281 | void fc_get_host_speed(struct Scsi_Host *shost) |
233 | { | 282 | { |
234 | struct fc_lport *lport = shost_priv(shost); | 283 | struct fc_lport *lport = shost_priv(shost); |
@@ -237,24 +286,28 @@ void fc_get_host_speed(struct Scsi_Host *shost) | |||
237 | } | 286 | } |
238 | EXPORT_SYMBOL(fc_get_host_speed); | 287 | EXPORT_SYMBOL(fc_get_host_speed); |
239 | 288 | ||
289 | /** | ||
290 | * fc_get_host_stats() - Return the Scsi_Host's statistics | ||
291 | * @shost: The SCSI host whose statistics are to be returned | ||
292 | */ | ||
240 | struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) | 293 | struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) |
241 | { | 294 | { |
242 | struct fc_host_statistics *fcoe_stats; | 295 | struct fc_host_statistics *fcoe_stats; |
243 | struct fc_lport *lp = shost_priv(shost); | 296 | struct fc_lport *lport = shost_priv(shost); |
244 | struct timespec v0, v1; | 297 | struct timespec v0, v1; |
245 | unsigned int cpu; | 298 | unsigned int cpu; |
246 | 299 | ||
247 | fcoe_stats = &lp->host_stats; | 300 | fcoe_stats = &lport->host_stats; |
248 | memset(fcoe_stats, 0, sizeof(struct fc_host_statistics)); | 301 | memset(fcoe_stats, 0, sizeof(struct fc_host_statistics)); |
249 | 302 | ||
250 | jiffies_to_timespec(jiffies, &v0); | 303 | jiffies_to_timespec(jiffies, &v0); |
251 | jiffies_to_timespec(lp->boot_time, &v1); | 304 | jiffies_to_timespec(lport->boot_time, &v1); |
252 | fcoe_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec); | 305 | fcoe_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec); |
253 | 306 | ||
254 | for_each_possible_cpu(cpu) { | 307 | for_each_possible_cpu(cpu) { |
255 | struct fcoe_dev_stats *stats; | 308 | struct fcoe_dev_stats *stats; |
256 | 309 | ||
257 | stats = per_cpu_ptr(lp->dev_stats, cpu); | 310 | stats = per_cpu_ptr(lport->dev_stats, cpu); |
258 | 311 | ||
259 | fcoe_stats->tx_frames += stats->TxFrames; | 312 | fcoe_stats->tx_frames += stats->TxFrames; |
260 | fcoe_stats->tx_words += stats->TxWords; | 313 | fcoe_stats->tx_words += stats->TxWords; |
@@ -279,12 +332,15 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) | |||
279 | } | 332 | } |
280 | EXPORT_SYMBOL(fc_get_host_stats); | 333 | EXPORT_SYMBOL(fc_get_host_stats); |
281 | 334 | ||
282 | /* | 335 | /** |
283 | * Fill in FLOGI command for request. | 336 | * fc_lport_flogi_fill() - Fill in FLOGI command for request |
337 | * @lport: The local port the FLOGI is for | ||
338 | * @flogi: The FLOGI command | ||
339 | * @op: The opcode | ||
284 | */ | 340 | */ |
285 | static void | 341 | static void fc_lport_flogi_fill(struct fc_lport *lport, |
286 | fc_lport_flogi_fill(struct fc_lport *lport, struct fc_els_flogi *flogi, | 342 | struct fc_els_flogi *flogi, |
287 | unsigned int op) | 343 | unsigned int op) |
288 | { | 344 | { |
289 | struct fc_els_csp *sp; | 345 | struct fc_els_csp *sp; |
290 | struct fc_els_cssp *cp; | 346 | struct fc_els_cssp *cp; |
@@ -312,8 +368,10 @@ fc_lport_flogi_fill(struct fc_lport *lport, struct fc_els_flogi *flogi, | |||
312 | } | 368 | } |
313 | } | 369 | } |
314 | 370 | ||
315 | /* | 371 | /** |
316 | * Add a supported FC-4 type. | 372 | * fc_lport_add_fc4_type() - Add a supported FC-4 type to a local port |
373 | * @lport: The local port to add a new FC-4 type to | ||
374 | * @type: The new FC-4 type | ||
317 | */ | 375 | */ |
318 | static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) | 376 | static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) |
319 | { | 377 | { |
@@ -325,11 +383,11 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) | |||
325 | 383 | ||
326 | /** | 384 | /** |
327 | * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report. | 385 | * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report. |
386 | * @sp: The sequence in the RLIR exchange | ||
387 | * @fp: The RLIR request frame | ||
328 | * @lport: Fibre Channel local port recieving the RLIR | 388 | * @lport: Fibre Channel local port recieving the RLIR |
329 | * @sp: current sequence in the RLIR exchange | ||
330 | * @fp: RLIR request frame | ||
331 | * | 389 | * |
332 | * Locking Note: The lport lock is exected to be held before calling | 390 | * Locking Note: The lport lock is expected to be held before calling |
333 | * this function. | 391 | * this function. |
334 | */ | 392 | */ |
335 | static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp, | 393 | static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp, |
@@ -344,11 +402,11 @@ static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp, | |||
344 | 402 | ||
345 | /** | 403 | /** |
346 | * fc_lport_recv_echo_req() - Handle received ECHO request | 404 | * fc_lport_recv_echo_req() - Handle received ECHO request |
347 | * @lport: Fibre Channel local port recieving the ECHO | 405 | * @sp: The sequence in the ECHO exchange |
348 | * @sp: current sequence in the ECHO exchange | 406 | * @fp: ECHO request frame |
349 | * @fp: ECHO request frame | 407 | * @lport: The local port recieving the ECHO |
350 | * | 408 | * |
351 | * Locking Note: The lport lock is exected to be held before calling | 409 | * Locking Note: The lport lock is expected to be held before calling |
352 | * this function. | 410 | * this function. |
353 | */ | 411 | */ |
354 | static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, | 412 | static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, |
@@ -361,7 +419,7 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, | |||
361 | void *dp; | 419 | void *dp; |
362 | u32 f_ctl; | 420 | u32 f_ctl; |
363 | 421 | ||
364 | FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n", | 422 | FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n", |
365 | fc_lport_state(lport)); | 423 | fc_lport_state(lport)); |
366 | 424 | ||
367 | len = fr_len(in_fp) - sizeof(struct fc_frame_header); | 425 | len = fr_len(in_fp) - sizeof(struct fc_frame_header); |
@@ -374,7 +432,7 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, | |||
374 | if (fp) { | 432 | if (fp) { |
375 | dp = fc_frame_payload_get(fp, len); | 433 | dp = fc_frame_payload_get(fp, len); |
376 | memcpy(dp, pp, len); | 434 | memcpy(dp, pp, len); |
377 | *((u32 *)dp) = htonl(ELS_LS_ACC << 24); | 435 | *((__be32 *)dp) = htonl(ELS_LS_ACC << 24); |
378 | sp = lport->tt.seq_start_next(sp); | 436 | sp = lport->tt.seq_start_next(sp); |
379 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; | 437 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; |
380 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, | 438 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, |
@@ -385,12 +443,12 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, | |||
385 | } | 443 | } |
386 | 444 | ||
387 | /** | 445 | /** |
388 | * fc_lport_recv_echo_req() - Handle received Request Node ID data request | 446 | * fc_lport_recv_rnid_req() - Handle received Request Node ID data request |
389 | * @lport: Fibre Channel local port recieving the RNID | 447 | * @sp: The sequence in the RNID exchange |
390 | * @sp: current sequence in the RNID exchange | 448 | * @fp: The RNID request frame |
391 | * @fp: RNID request frame | 449 | * @lport: The local port recieving the RNID |
392 | * | 450 | * |
393 | * Locking Note: The lport lock is exected to be held before calling | 451 | * Locking Note: The lport lock is expected to be held before calling |
394 | * this function. | 452 | * this function. |
395 | */ | 453 | */ |
396 | static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, | 454 | static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, |
@@ -453,9 +511,9 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, | |||
453 | 511 | ||
454 | /** | 512 | /** |
455 | * fc_lport_recv_logo_req() - Handle received fabric LOGO request | 513 | * fc_lport_recv_logo_req() - Handle received fabric LOGO request |
456 | * @lport: Fibre Channel local port recieving the LOGO | 514 | * @sp: The sequence in the LOGO exchange |
457 | * @sp: current sequence in the LOGO exchange | 515 | * @fp: The LOGO request frame |
458 | * @fp: LOGO request frame | 516 | * @lport: The local port recieving the LOGO |
459 | * | 517 | * |
460 | * Locking Note: The lport lock is exected to be held before calling | 518 | * Locking Note: The lport lock is exected to be held before calling |
461 | * this function. | 519 | * this function. |
@@ -470,7 +528,7 @@ static void fc_lport_recv_logo_req(struct fc_seq *sp, struct fc_frame *fp, | |||
470 | 528 | ||
471 | /** | 529 | /** |
472 | * fc_fabric_login() - Start the lport state machine | 530 | * fc_fabric_login() - Start the lport state machine |
473 | * @lport: The lport that should log into the fabric | 531 | * @lport: The local port that should log into the fabric |
474 | * | 532 | * |
475 | * Locking Note: This function should not be called | 533 | * Locking Note: This function should not be called |
476 | * with the lport lock held. | 534 | * with the lport lock held. |
@@ -480,7 +538,9 @@ int fc_fabric_login(struct fc_lport *lport) | |||
480 | int rc = -1; | 538 | int rc = -1; |
481 | 539 | ||
482 | mutex_lock(&lport->lp_mutex); | 540 | mutex_lock(&lport->lp_mutex); |
483 | if (lport->state == LPORT_ST_DISABLED) { | 541 | if (lport->state == LPORT_ST_DISABLED || |
542 | lport->state == LPORT_ST_LOGO) { | ||
543 | fc_lport_state_enter(lport, LPORT_ST_RESET); | ||
484 | fc_lport_enter_reset(lport); | 544 | fc_lport_enter_reset(lport); |
485 | rc = 0; | 545 | rc = 0; |
486 | } | 546 | } |
@@ -491,47 +551,69 @@ int fc_fabric_login(struct fc_lport *lport) | |||
491 | EXPORT_SYMBOL(fc_fabric_login); | 551 | EXPORT_SYMBOL(fc_fabric_login); |
492 | 552 | ||
493 | /** | 553 | /** |
494 | * fc_linkup() - Handler for transport linkup events | 554 | * __fc_linkup() - Handler for transport linkup events |
495 | * @lport: The lport whose link is up | 555 | * @lport: The lport whose link is up |
556 | * | ||
557 | * Locking: must be called with the lp_mutex held | ||
496 | */ | 558 | */ |
497 | void fc_linkup(struct fc_lport *lport) | 559 | void __fc_linkup(struct fc_lport *lport) |
498 | { | 560 | { |
499 | printk(KERN_INFO "libfc: Link up on port (%6x)\n", | ||
500 | fc_host_port_id(lport->host)); | ||
501 | |||
502 | mutex_lock(&lport->lp_mutex); | ||
503 | if (!lport->link_up) { | 561 | if (!lport->link_up) { |
504 | lport->link_up = 1; | 562 | lport->link_up = 1; |
505 | 563 | ||
506 | if (lport->state == LPORT_ST_RESET) | 564 | if (lport->state == LPORT_ST_RESET) |
507 | fc_lport_enter_flogi(lport); | 565 | fc_lport_enter_flogi(lport); |
508 | } | 566 | } |
567 | } | ||
568 | |||
569 | /** | ||
570 | * fc_linkup() - Handler for transport linkup events | ||
571 | * @lport: The local port whose link is up | ||
572 | */ | ||
573 | void fc_linkup(struct fc_lport *lport) | ||
574 | { | ||
575 | printk(KERN_INFO "host%d: libfc: Link up on port (%6x)\n", | ||
576 | lport->host->host_no, fc_host_port_id(lport->host)); | ||
577 | |||
578 | mutex_lock(&lport->lp_mutex); | ||
579 | __fc_linkup(lport); | ||
509 | mutex_unlock(&lport->lp_mutex); | 580 | mutex_unlock(&lport->lp_mutex); |
510 | } | 581 | } |
511 | EXPORT_SYMBOL(fc_linkup); | 582 | EXPORT_SYMBOL(fc_linkup); |
512 | 583 | ||
513 | /** | 584 | /** |
514 | * fc_linkdown() - Handler for transport linkdown events | 585 | * __fc_linkdown() - Handler for transport linkdown events |
515 | * @lport: The lport whose link is down | 586 | * @lport: The lport whose link is down |
587 | * | ||
588 | * Locking: must be called with the lp_mutex held | ||
516 | */ | 589 | */ |
517 | void fc_linkdown(struct fc_lport *lport) | 590 | void __fc_linkdown(struct fc_lport *lport) |
518 | { | 591 | { |
519 | mutex_lock(&lport->lp_mutex); | ||
520 | printk(KERN_INFO "libfc: Link down on port (%6x)\n", | ||
521 | fc_host_port_id(lport->host)); | ||
522 | |||
523 | if (lport->link_up) { | 592 | if (lport->link_up) { |
524 | lport->link_up = 0; | 593 | lport->link_up = 0; |
525 | fc_lport_enter_reset(lport); | 594 | fc_lport_enter_reset(lport); |
526 | lport->tt.fcp_cleanup(lport); | 595 | lport->tt.fcp_cleanup(lport); |
527 | } | 596 | } |
597 | } | ||
598 | |||
599 | /** | ||
600 | * fc_linkdown() - Handler for transport linkdown events | ||
601 | * @lport: The local port whose link is down | ||
602 | */ | ||
603 | void fc_linkdown(struct fc_lport *lport) | ||
604 | { | ||
605 | printk(KERN_INFO "host%d: libfc: Link down on port (%6x)\n", | ||
606 | lport->host->host_no, fc_host_port_id(lport->host)); | ||
607 | |||
608 | mutex_lock(&lport->lp_mutex); | ||
609 | __fc_linkdown(lport); | ||
528 | mutex_unlock(&lport->lp_mutex); | 610 | mutex_unlock(&lport->lp_mutex); |
529 | } | 611 | } |
530 | EXPORT_SYMBOL(fc_linkdown); | 612 | EXPORT_SYMBOL(fc_linkdown); |
531 | 613 | ||
532 | /** | 614 | /** |
533 | * fc_fabric_logoff() - Logout of the fabric | 615 | * fc_fabric_logoff() - Logout of the fabric |
534 | * @lport: fc_lport pointer to logoff the fabric | 616 | * @lport: The local port to logoff the fabric |
535 | * | 617 | * |
536 | * Return value: | 618 | * Return value: |
537 | * 0 for success, -1 for failure | 619 | * 0 for success, -1 for failure |
@@ -540,8 +622,8 @@ int fc_fabric_logoff(struct fc_lport *lport) | |||
540 | { | 622 | { |
541 | lport->tt.disc_stop_final(lport); | 623 | lport->tt.disc_stop_final(lport); |
542 | mutex_lock(&lport->lp_mutex); | 624 | mutex_lock(&lport->lp_mutex); |
543 | if (lport->dns_rp) | 625 | if (lport->dns_rdata) |
544 | lport->tt.rport_logoff(lport->dns_rp); | 626 | lport->tt.rport_logoff(lport->dns_rdata); |
545 | mutex_unlock(&lport->lp_mutex); | 627 | mutex_unlock(&lport->lp_mutex); |
546 | lport->tt.rport_flush_queue(); | 628 | lport->tt.rport_flush_queue(); |
547 | mutex_lock(&lport->lp_mutex); | 629 | mutex_lock(&lport->lp_mutex); |
@@ -553,11 +635,9 @@ int fc_fabric_logoff(struct fc_lport *lport) | |||
553 | EXPORT_SYMBOL(fc_fabric_logoff); | 635 | EXPORT_SYMBOL(fc_fabric_logoff); |
554 | 636 | ||
555 | /** | 637 | /** |
556 | * fc_lport_destroy() - unregister a fc_lport | 638 | * fc_lport_destroy() - Unregister a fc_lport |
557 | * @lport: fc_lport pointer to unregister | 639 | * @lport: The local port to unregister |
558 | * | 640 | * |
559 | * Return value: | ||
560 | * None | ||
561 | * Note: | 641 | * Note: |
562 | * exit routine for fc_lport instance | 642 | * exit routine for fc_lport instance |
563 | * clean-up all the allocated memory | 643 | * clean-up all the allocated memory |
@@ -580,13 +660,9 @@ int fc_lport_destroy(struct fc_lport *lport) | |||
580 | EXPORT_SYMBOL(fc_lport_destroy); | 660 | EXPORT_SYMBOL(fc_lport_destroy); |
581 | 661 | ||
582 | /** | 662 | /** |
583 | * fc_set_mfs() - sets up the mfs for the corresponding fc_lport | 663 | * fc_set_mfs() - Set the maximum frame size for a local port |
584 | * @lport: fc_lport pointer to unregister | 664 | * @lport: The local port to set the MFS for |
585 | * @mfs: the new mfs for fc_lport | 665 | * @mfs: The new MFS |
586 | * | ||
587 | * Set mfs for the given fc_lport to the new mfs. | ||
588 | * | ||
589 | * Return: 0 for success | ||
590 | */ | 666 | */ |
591 | int fc_set_mfs(struct fc_lport *lport, u32 mfs) | 667 | int fc_set_mfs(struct fc_lport *lport, u32 mfs) |
592 | { | 668 | { |
@@ -617,7 +693,7 @@ EXPORT_SYMBOL(fc_set_mfs); | |||
617 | 693 | ||
618 | /** | 694 | /** |
619 | * fc_lport_disc_callback() - Callback for discovery events | 695 | * fc_lport_disc_callback() - Callback for discovery events |
620 | * @lport: FC local port | 696 | * @lport: The local port receiving the event |
621 | * @event: The discovery event | 697 | * @event: The discovery event |
622 | */ | 698 | */ |
623 | void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event) | 699 | void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event) |
@@ -627,8 +703,9 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event) | |||
627 | FC_LPORT_DBG(lport, "Discovery succeeded\n"); | 703 | FC_LPORT_DBG(lport, "Discovery succeeded\n"); |
628 | break; | 704 | break; |
629 | case DISC_EV_FAILED: | 705 | case DISC_EV_FAILED: |
630 | printk(KERN_ERR "libfc: Discovery failed for port (%6x)\n", | 706 | printk(KERN_ERR "host%d: libfc: " |
631 | fc_host_port_id(lport->host)); | 707 | "Discovery failed for port (%6x)\n", |
708 | lport->host->host_no, fc_host_port_id(lport->host)); | ||
632 | mutex_lock(&lport->lp_mutex); | 709 | mutex_lock(&lport->lp_mutex); |
633 | fc_lport_enter_reset(lport); | 710 | fc_lport_enter_reset(lport); |
634 | mutex_unlock(&lport->lp_mutex); | 711 | mutex_unlock(&lport->lp_mutex); |
@@ -641,7 +718,7 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event) | |||
641 | 718 | ||
642 | /** | 719 | /** |
643 | * fc_rport_enter_ready() - Enter the ready state and start discovery | 720 | * fc_rport_enter_ready() - Enter the ready state and start discovery |
644 | * @lport: Fibre Channel local port that is ready | 721 | * @lport: The local port that is ready |
645 | * | 722 | * |
646 | * Locking Note: The lport lock is expected to be held before calling | 723 | * Locking Note: The lport lock is expected to be held before calling |
647 | * this routine. | 724 | * this routine. |
@@ -652,22 +729,46 @@ static void fc_lport_enter_ready(struct fc_lport *lport) | |||
652 | fc_lport_state(lport)); | 729 | fc_lport_state(lport)); |
653 | 730 | ||
654 | fc_lport_state_enter(lport, LPORT_ST_READY); | 731 | fc_lport_state_enter(lport, LPORT_ST_READY); |
732 | if (lport->vport) | ||
733 | fc_vport_set_state(lport->vport, FC_VPORT_ACTIVE); | ||
734 | fc_vports_linkchange(lport); | ||
655 | 735 | ||
656 | if (!lport->ptp_rp) | 736 | if (!lport->ptp_rdata) |
657 | lport->tt.disc_start(fc_lport_disc_callback, lport); | 737 | lport->tt.disc_start(fc_lport_disc_callback, lport); |
658 | } | 738 | } |
659 | 739 | ||
660 | /** | 740 | /** |
741 | * fc_lport_set_port_id() - set the local port Port ID | ||
742 | * @lport: The local port which will have its Port ID set. | ||
743 | * @port_id: The new port ID. | ||
744 | * @fp: The frame containing the incoming request, or NULL. | ||
745 | * | ||
746 | * Locking Note: The lport lock is expected to be held before calling | ||
747 | * this function. | ||
748 | */ | ||
749 | static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id, | ||
750 | struct fc_frame *fp) | ||
751 | { | ||
752 | if (port_id) | ||
753 | printk(KERN_INFO "host%d: Assigned Port ID %6x\n", | ||
754 | lport->host->host_no, port_id); | ||
755 | |||
756 | fc_host_port_id(lport->host) = port_id; | ||
757 | if (lport->tt.lport_set_port_id) | ||
758 | lport->tt.lport_set_port_id(lport, port_id, fp); | ||
759 | } | ||
760 | |||
761 | /** | ||
661 | * fc_lport_recv_flogi_req() - Receive a FLOGI request | 762 | * fc_lport_recv_flogi_req() - Receive a FLOGI request |
662 | * @sp_in: The sequence the FLOGI is on | 763 | * @sp_in: The sequence the FLOGI is on |
663 | * @rx_fp: The frame the FLOGI is in | 764 | * @rx_fp: The FLOGI frame |
664 | * @lport: The lport that recieved the request | 765 | * @lport: The local port that recieved the request |
665 | * | 766 | * |
666 | * A received FLOGI request indicates a point-to-point connection. | 767 | * A received FLOGI request indicates a point-to-point connection. |
667 | * Accept it with the common service parameters indicating our N port. | 768 | * Accept it with the common service parameters indicating our N port. |
668 | * Set up to do a PLOGI if we have the higher-number WWPN. | 769 | * Set up to do a PLOGI if we have the higher-number WWPN. |
669 | * | 770 | * |
670 | * Locking Note: The lport lock is exected to be held before calling | 771 | * Locking Note: The lport lock is expected to be held before calling |
671 | * this function. | 772 | * this function. |
672 | */ | 773 | */ |
673 | static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, | 774 | static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, |
@@ -695,8 +796,9 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, | |||
695 | goto out; | 796 | goto out; |
696 | remote_wwpn = get_unaligned_be64(&flp->fl_wwpn); | 797 | remote_wwpn = get_unaligned_be64(&flp->fl_wwpn); |
697 | if (remote_wwpn == lport->wwpn) { | 798 | if (remote_wwpn == lport->wwpn) { |
698 | printk(KERN_WARNING "libfc: Received FLOGI from port " | 799 | printk(KERN_WARNING "host%d: libfc: Received FLOGI from port " |
699 | "with same WWPN %llx\n", remote_wwpn); | 800 | "with same WWPN %llx\n", |
801 | lport->host->host_no, remote_wwpn); | ||
700 | goto out; | 802 | goto out; |
701 | } | 803 | } |
702 | FC_LPORT_DBG(lport, "FLOGI from port WWPN %llx\n", remote_wwpn); | 804 | FC_LPORT_DBG(lport, "FLOGI from port WWPN %llx\n", remote_wwpn); |
@@ -715,7 +817,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, | |||
715 | remote_fid = FC_LOCAL_PTP_FID_HI; | 817 | remote_fid = FC_LOCAL_PTP_FID_HI; |
716 | } | 818 | } |
717 | 819 | ||
718 | fc_host_port_id(lport->host) = local_fid; | 820 | fc_lport_set_port_id(lport, local_fid, rx_fp); |
719 | 821 | ||
720 | fp = fc_frame_alloc(lport, sizeof(*flp)); | 822 | fp = fc_frame_alloc(lport, sizeof(*flp)); |
721 | if (fp) { | 823 | if (fp) { |
@@ -747,9 +849,9 @@ out: | |||
747 | 849 | ||
748 | /** | 850 | /** |
749 | * fc_lport_recv_req() - The generic lport request handler | 851 | * fc_lport_recv_req() - The generic lport request handler |
750 | * @lport: The lport that received the request | 852 | * @lport: The local port that received the request |
751 | * @sp: The sequence the request is on | 853 | * @sp: The sequence the request is on |
752 | * @fp: The frame the request is in | 854 | * @fp: The request frame |
753 | * | 855 | * |
754 | * This function will see if the lport handles the request or | 856 | * This function will see if the lport handles the request or |
755 | * if an rport should handle the request. | 857 | * if an rport should handle the request. |
@@ -817,8 +919,8 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, | |||
817 | } | 919 | } |
818 | 920 | ||
819 | /** | 921 | /** |
820 | * fc_lport_reset() - Reset an lport | 922 | * fc_lport_reset() - Reset a local port |
821 | * @lport: The lport which should be reset | 923 | * @lport: The local port which should be reset |
822 | * | 924 | * |
823 | * Locking Note: This functions should not be called with the | 925 | * Locking Note: This functions should not be called with the |
824 | * lport lock held. | 926 | * lport lock held. |
@@ -834,29 +936,31 @@ int fc_lport_reset(struct fc_lport *lport) | |||
834 | EXPORT_SYMBOL(fc_lport_reset); | 936 | EXPORT_SYMBOL(fc_lport_reset); |
835 | 937 | ||
836 | /** | 938 | /** |
837 | * fc_lport_reset_locked() - Reset the local port | 939 | * fc_lport_reset_locked() - Reset the local port w/ the lport lock held |
838 | * @lport: Fibre Channel local port to be reset | 940 | * @lport: The local port to be reset |
839 | * | 941 | * |
840 | * Locking Note: The lport lock is expected to be held before calling | 942 | * Locking Note: The lport lock is expected to be held before calling |
841 | * this routine. | 943 | * this routine. |
842 | */ | 944 | */ |
843 | static void fc_lport_reset_locked(struct fc_lport *lport) | 945 | static void fc_lport_reset_locked(struct fc_lport *lport) |
844 | { | 946 | { |
845 | if (lport->dns_rp) | 947 | if (lport->dns_rdata) |
846 | lport->tt.rport_logoff(lport->dns_rp); | 948 | lport->tt.rport_logoff(lport->dns_rdata); |
847 | 949 | ||
848 | lport->ptp_rp = NULL; | 950 | lport->ptp_rdata = NULL; |
849 | 951 | ||
850 | lport->tt.disc_stop(lport); | 952 | lport->tt.disc_stop(lport); |
851 | 953 | ||
852 | lport->tt.exch_mgr_reset(lport, 0, 0); | 954 | lport->tt.exch_mgr_reset(lport, 0, 0); |
853 | fc_host_fabric_name(lport->host) = 0; | 955 | fc_host_fabric_name(lport->host) = 0; |
854 | fc_host_port_id(lport->host) = 0; | 956 | |
957 | if (fc_host_port_id(lport->host)) | ||
958 | fc_lport_set_port_id(lport, 0, NULL); | ||
855 | } | 959 | } |
856 | 960 | ||
857 | /** | 961 | /** |
858 | * fc_lport_enter_reset() - Reset the local port | 962 | * fc_lport_enter_reset() - Reset the local port |
859 | * @lport: Fibre Channel local port to be reset | 963 | * @lport: The local port to be reset |
860 | * | 964 | * |
861 | * Locking Note: The lport lock is expected to be held before calling | 965 | * Locking Note: The lport lock is expected to be held before calling |
862 | * this routine. | 966 | * this routine. |
@@ -866,15 +970,25 @@ static void fc_lport_enter_reset(struct fc_lport *lport) | |||
866 | FC_LPORT_DBG(lport, "Entered RESET state from %s state\n", | 970 | FC_LPORT_DBG(lport, "Entered RESET state from %s state\n", |
867 | fc_lport_state(lport)); | 971 | fc_lport_state(lport)); |
868 | 972 | ||
973 | if (lport->state == LPORT_ST_DISABLED || lport->state == LPORT_ST_LOGO) | ||
974 | return; | ||
975 | |||
976 | if (lport->vport) { | ||
977 | if (lport->link_up) | ||
978 | fc_vport_set_state(lport->vport, FC_VPORT_INITIALIZING); | ||
979 | else | ||
980 | fc_vport_set_state(lport->vport, FC_VPORT_LINKDOWN); | ||
981 | } | ||
869 | fc_lport_state_enter(lport, LPORT_ST_RESET); | 982 | fc_lport_state_enter(lport, LPORT_ST_RESET); |
983 | fc_vports_linkchange(lport); | ||
870 | fc_lport_reset_locked(lport); | 984 | fc_lport_reset_locked(lport); |
871 | if (lport->link_up) | 985 | if (lport->link_up) |
872 | fc_lport_enter_flogi(lport); | 986 | fc_lport_enter_flogi(lport); |
873 | } | 987 | } |
874 | 988 | ||
875 | /** | 989 | /** |
876 | * fc_lport_enter_disabled() - disable the local port | 990 | * fc_lport_enter_disabled() - Disable the local port |
877 | * @lport: Fibre Channel local port to be reset | 991 | * @lport: The local port to be reset |
878 | * | 992 | * |
879 | * Locking Note: The lport lock is expected to be held before calling | 993 | * Locking Note: The lport lock is expected to be held before calling |
880 | * this routine. | 994 | * this routine. |
@@ -885,13 +999,14 @@ static void fc_lport_enter_disabled(struct fc_lport *lport) | |||
885 | fc_lport_state(lport)); | 999 | fc_lport_state(lport)); |
886 | 1000 | ||
887 | fc_lport_state_enter(lport, LPORT_ST_DISABLED); | 1001 | fc_lport_state_enter(lport, LPORT_ST_DISABLED); |
1002 | fc_vports_linkchange(lport); | ||
888 | fc_lport_reset_locked(lport); | 1003 | fc_lport_reset_locked(lport); |
889 | } | 1004 | } |
890 | 1005 | ||
891 | /** | 1006 | /** |
892 | * fc_lport_error() - Handler for any errors | 1007 | * fc_lport_error() - Handler for any errors |
893 | * @lport: The fc_lport object | 1008 | * @lport: The local port that the error was on |
894 | * @fp: The frame pointer | 1009 | * @fp: The error code encoded in a frame pointer |
895 | * | 1010 | * |
896 | * If the error was caused by a resource allocation failure | 1011 | * If the error was caused by a resource allocation failure |
897 | * then wait for half a second and retry, otherwise retry | 1012 | * then wait for half a second and retry, otherwise retry |
@@ -922,8 +1037,11 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) | |||
922 | case LPORT_ST_DISABLED: | 1037 | case LPORT_ST_DISABLED: |
923 | case LPORT_ST_READY: | 1038 | case LPORT_ST_READY: |
924 | case LPORT_ST_RESET: | 1039 | case LPORT_ST_RESET: |
925 | case LPORT_ST_RPN_ID: | 1040 | case LPORT_ST_RNN_ID: |
1041 | case LPORT_ST_RSNN_NN: | ||
1042 | case LPORT_ST_RSPN_ID: | ||
926 | case LPORT_ST_RFT_ID: | 1043 | case LPORT_ST_RFT_ID: |
1044 | case LPORT_ST_RFF_ID: | ||
927 | case LPORT_ST_SCR: | 1045 | case LPORT_ST_SCR: |
928 | case LPORT_ST_DNS: | 1046 | case LPORT_ST_DNS: |
929 | case LPORT_ST_FLOGI: | 1047 | case LPORT_ST_FLOGI: |
@@ -936,33 +1054,33 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) | |||
936 | } | 1054 | } |
937 | 1055 | ||
938 | /** | 1056 | /** |
939 | * fc_lport_rft_id_resp() - Handle response to Register Fibre | 1057 | * fc_lport_ns_resp() - Handle response to a name server |
940 | * Channel Types by ID (RPN_ID) request | 1058 | * registration exchange |
941 | * @sp: current sequence in RPN_ID exchange | 1059 | * @sp: current sequence in exchange |
942 | * @fp: response frame | 1060 | * @fp: response frame |
943 | * @lp_arg: Fibre Channel host port instance | 1061 | * @lp_arg: Fibre Channel host port instance |
944 | * | 1062 | * |
945 | * Locking Note: This function will be called without the lport lock | 1063 | * Locking Note: This function will be called without the lport lock |
946 | * held, but it will lock, call an _enter_* function or fc_lport_error | 1064 | * held, but it will lock, call an _enter_* function or fc_lport_error() |
947 | * and then unlock the lport. | 1065 | * and then unlock the lport. |
948 | */ | 1066 | */ |
949 | static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp, | 1067 | static void fc_lport_ns_resp(struct fc_seq *sp, struct fc_frame *fp, |
950 | void *lp_arg) | 1068 | void *lp_arg) |
951 | { | 1069 | { |
952 | struct fc_lport *lport = lp_arg; | 1070 | struct fc_lport *lport = lp_arg; |
953 | struct fc_frame_header *fh; | 1071 | struct fc_frame_header *fh; |
954 | struct fc_ct_hdr *ct; | 1072 | struct fc_ct_hdr *ct; |
955 | 1073 | ||
956 | FC_LPORT_DBG(lport, "Received a RFT_ID %s\n", fc_els_resp_type(fp)); | 1074 | FC_LPORT_DBG(lport, "Received a ns %s\n", fc_els_resp_type(fp)); |
957 | 1075 | ||
958 | if (fp == ERR_PTR(-FC_EX_CLOSED)) | 1076 | if (fp == ERR_PTR(-FC_EX_CLOSED)) |
959 | return; | 1077 | return; |
960 | 1078 | ||
961 | mutex_lock(&lport->lp_mutex); | 1079 | mutex_lock(&lport->lp_mutex); |
962 | 1080 | ||
963 | if (lport->state != LPORT_ST_RFT_ID) { | 1081 | if (lport->state < LPORT_ST_RNN_ID || lport->state > LPORT_ST_RFF_ID) { |
964 | FC_LPORT_DBG(lport, "Received a RFT_ID response, but in state " | 1082 | FC_LPORT_DBG(lport, "Received a name server response, " |
965 | "%s\n", fc_lport_state(lport)); | 1083 | "but in state %s\n", fc_lport_state(lport)); |
966 | if (IS_ERR(fp)) | 1084 | if (IS_ERR(fp)) |
967 | goto err; | 1085 | goto err; |
968 | goto out; | 1086 | goto out; |
@@ -980,63 +1098,28 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
980 | ct->ct_fs_type == FC_FST_DIR && | 1098 | ct->ct_fs_type == FC_FST_DIR && |
981 | ct->ct_fs_subtype == FC_NS_SUBTYPE && | 1099 | ct->ct_fs_subtype == FC_NS_SUBTYPE && |
982 | ntohs(ct->ct_cmd) == FC_FS_ACC) | 1100 | ntohs(ct->ct_cmd) == FC_FS_ACC) |
983 | fc_lport_enter_scr(lport); | 1101 | switch (lport->state) { |
984 | else | 1102 | case LPORT_ST_RNN_ID: |
985 | fc_lport_error(lport, fp); | 1103 | fc_lport_enter_ns(lport, LPORT_ST_RSNN_NN); |
986 | out: | 1104 | break; |
987 | fc_frame_free(fp); | 1105 | case LPORT_ST_RSNN_NN: |
988 | err: | 1106 | fc_lport_enter_ns(lport, LPORT_ST_RSPN_ID); |
989 | mutex_unlock(&lport->lp_mutex); | 1107 | break; |
990 | } | 1108 | case LPORT_ST_RSPN_ID: |
991 | 1109 | fc_lport_enter_ns(lport, LPORT_ST_RFT_ID); | |
992 | /** | 1110 | break; |
993 | * fc_lport_rpn_id_resp() - Handle response to Register Port | 1111 | case LPORT_ST_RFT_ID: |
994 | * Name by ID (RPN_ID) request | 1112 | fc_lport_enter_ns(lport, LPORT_ST_RFF_ID); |
995 | * @sp: current sequence in RPN_ID exchange | 1113 | break; |
996 | * @fp: response frame | 1114 | case LPORT_ST_RFF_ID: |
997 | * @lp_arg: Fibre Channel host port instance | 1115 | fc_lport_enter_scr(lport); |
998 | * | 1116 | break; |
999 | * Locking Note: This function will be called without the lport lock | 1117 | default: |
1000 | * held, but it will lock, call an _enter_* function or fc_lport_error | 1118 | /* should have already been caught by state checks */ |
1001 | * and then unlock the lport. | 1119 | break; |
1002 | */ | 1120 | } |
1003 | static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, | ||
1004 | void *lp_arg) | ||
1005 | { | ||
1006 | struct fc_lport *lport = lp_arg; | ||
1007 | struct fc_frame_header *fh; | ||
1008 | struct fc_ct_hdr *ct; | ||
1009 | |||
1010 | FC_LPORT_DBG(lport, "Received a RPN_ID %s\n", fc_els_resp_type(fp)); | ||
1011 | |||
1012 | if (fp == ERR_PTR(-FC_EX_CLOSED)) | ||
1013 | return; | ||
1014 | |||
1015 | mutex_lock(&lport->lp_mutex); | ||
1016 | |||
1017 | if (lport->state != LPORT_ST_RPN_ID) { | ||
1018 | FC_LPORT_DBG(lport, "Received a RPN_ID response, but in state " | ||
1019 | "%s\n", fc_lport_state(lport)); | ||
1020 | if (IS_ERR(fp)) | ||
1021 | goto err; | ||
1022 | goto out; | ||
1023 | } | ||
1024 | |||
1025 | if (IS_ERR(fp)) { | ||
1026 | fc_lport_error(lport, fp); | ||
1027 | goto err; | ||
1028 | } | ||
1029 | |||
1030 | fh = fc_frame_header_get(fp); | ||
1031 | ct = fc_frame_payload_get(fp, sizeof(*ct)); | ||
1032 | if (fh && ct && fh->fh_type == FC_TYPE_CT && | ||
1033 | ct->ct_fs_type == FC_FST_DIR && | ||
1034 | ct->ct_fs_subtype == FC_NS_SUBTYPE && | ||
1035 | ntohs(ct->ct_cmd) == FC_FS_ACC) | ||
1036 | fc_lport_enter_rft_id(lport); | ||
1037 | else | 1121 | else |
1038 | fc_lport_error(lport, fp); | 1122 | fc_lport_error(lport, fp); |
1039 | |||
1040 | out: | 1123 | out: |
1041 | fc_frame_free(fp); | 1124 | fc_frame_free(fp); |
1042 | err: | 1125 | err: |
@@ -1045,8 +1128,8 @@ err: | |||
1045 | 1128 | ||
1046 | /** | 1129 | /** |
1047 | * fc_lport_scr_resp() - Handle response to State Change Register (SCR) request | 1130 | * fc_lport_scr_resp() - Handle response to State Change Register (SCR) request |
1048 | * @sp: current sequence in SCR exchange | 1131 | * @sp: current sequence in SCR exchange |
1049 | * @fp: response frame | 1132 | * @fp: response frame |
1050 | * @lp_arg: Fibre Channel lport port instance that sent the registration request | 1133 | * @lp_arg: Fibre Channel lport port instance that sent the registration request |
1051 | * | 1134 | * |
1052 | * Locking Note: This function will be called without the lport lock | 1135 | * Locking Note: This function will be called without the lport lock |
@@ -1092,8 +1175,8 @@ err: | |||
1092 | } | 1175 | } |
1093 | 1176 | ||
1094 | /** | 1177 | /** |
1095 | * fc_lport_enter_scr() - Send a State Change Register (SCR) request | 1178 | * fc_lport_enter_scr() - Send a SCR (State Change Register) request |
1096 | * @lport: Fibre Channel local port to register for state changes | 1179 | * @lport: The local port to register for state changes |
1097 | * | 1180 | * |
1098 | * Locking Note: The lport lock is expected to be held before calling | 1181 | * Locking Note: The lport lock is expected to be held before calling |
1099 | * this routine. | 1182 | * this routine. |
@@ -1114,78 +1197,74 @@ static void fc_lport_enter_scr(struct fc_lport *lport) | |||
1114 | } | 1197 | } |
1115 | 1198 | ||
1116 | if (!lport->tt.elsct_send(lport, FC_FID_FCTRL, fp, ELS_SCR, | 1199 | if (!lport->tt.elsct_send(lport, FC_FID_FCTRL, fp, ELS_SCR, |
1117 | fc_lport_scr_resp, lport, lport->e_d_tov)) | 1200 | fc_lport_scr_resp, lport, |
1118 | fc_lport_error(lport, fp); | 1201 | 2 * lport->r_a_tov)) |
1202 | fc_lport_error(lport, NULL); | ||
1119 | } | 1203 | } |
1120 | 1204 | ||
1121 | /** | 1205 | /** |
1122 | * fc_lport_enter_rft_id() - Register FC4-types with the name server | 1206 | * fc_lport_enter_ns() - register some object with the name server |
1123 | * @lport: Fibre Channel local port to register | 1207 | * @lport: Fibre Channel local port to register |
1124 | * | 1208 | * |
1125 | * Locking Note: The lport lock is expected to be held before calling | 1209 | * Locking Note: The lport lock is expected to be held before calling |
1126 | * this routine. | 1210 | * this routine. |
1127 | */ | 1211 | */ |
1128 | static void fc_lport_enter_rft_id(struct fc_lport *lport) | 1212 | static void fc_lport_enter_ns(struct fc_lport *lport, enum fc_lport_state state) |
1129 | { | 1213 | { |
1130 | struct fc_frame *fp; | 1214 | struct fc_frame *fp; |
1131 | struct fc_ns_fts *lps; | 1215 | enum fc_ns_req cmd; |
1132 | int i; | 1216 | int size = sizeof(struct fc_ct_hdr); |
1217 | size_t len; | ||
1133 | 1218 | ||
1134 | FC_LPORT_DBG(lport, "Entered RFT_ID state from %s state\n", | 1219 | FC_LPORT_DBG(lport, "Entered %s state from %s state\n", |
1220 | fc_lport_state_names[state], | ||
1135 | fc_lport_state(lport)); | 1221 | fc_lport_state(lport)); |
1136 | 1222 | ||
1137 | fc_lport_state_enter(lport, LPORT_ST_RFT_ID); | 1223 | fc_lport_state_enter(lport, state); |
1138 | 1224 | ||
1139 | lps = &lport->fcts; | 1225 | switch (state) { |
1140 | i = sizeof(lps->ff_type_map) / sizeof(lps->ff_type_map[0]); | 1226 | case LPORT_ST_RNN_ID: |
1141 | while (--i >= 0) | 1227 | cmd = FC_NS_RNN_ID; |
1142 | if (ntohl(lps->ff_type_map[i]) != 0) | 1228 | size += sizeof(struct fc_ns_rn_id); |
1143 | break; | 1229 | break; |
1144 | if (i < 0) { | 1230 | case LPORT_ST_RSNN_NN: |
1145 | /* nothing to register, move on to SCR */ | 1231 | len = strnlen(fc_host_symbolic_name(lport->host), 255); |
1146 | fc_lport_enter_scr(lport); | 1232 | /* if there is no symbolic name, skip to RFT_ID */ |
1147 | return; | 1233 | if (!len) |
1148 | } | 1234 | return fc_lport_enter_ns(lport, LPORT_ST_RFT_ID); |
1149 | 1235 | cmd = FC_NS_RSNN_NN; | |
1150 | fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) + | 1236 | size += sizeof(struct fc_ns_rsnn) + len; |
1151 | sizeof(struct fc_ns_rft)); | 1237 | break; |
1152 | if (!fp) { | 1238 | case LPORT_ST_RSPN_ID: |
1153 | fc_lport_error(lport, fp); | 1239 | len = strnlen(fc_host_symbolic_name(lport->host), 255); |
1240 | /* if there is no symbolic name, skip to RFT_ID */ | ||
1241 | if (!len) | ||
1242 | return fc_lport_enter_ns(lport, LPORT_ST_RFT_ID); | ||
1243 | cmd = FC_NS_RSPN_ID; | ||
1244 | size += sizeof(struct fc_ns_rspn) + len; | ||
1245 | break; | ||
1246 | case LPORT_ST_RFT_ID: | ||
1247 | cmd = FC_NS_RFT_ID; | ||
1248 | size += sizeof(struct fc_ns_rft); | ||
1249 | break; | ||
1250 | case LPORT_ST_RFF_ID: | ||
1251 | cmd = FC_NS_RFF_ID; | ||
1252 | size += sizeof(struct fc_ns_rff_id); | ||
1253 | break; | ||
1254 | default: | ||
1255 | fc_lport_error(lport, NULL); | ||
1154 | return; | 1256 | return; |
1155 | } | 1257 | } |
1156 | 1258 | ||
1157 | if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RFT_ID, | 1259 | fp = fc_frame_alloc(lport, size); |
1158 | fc_lport_rft_id_resp, | ||
1159 | lport, lport->e_d_tov)) | ||
1160 | fc_lport_error(lport, fp); | ||
1161 | } | ||
1162 | |||
1163 | /** | ||
1164 | * fc_rport_enter_rft_id() - Register port name with the name server | ||
1165 | * @lport: Fibre Channel local port to register | ||
1166 | * | ||
1167 | * Locking Note: The lport lock is expected to be held before calling | ||
1168 | * this routine. | ||
1169 | */ | ||
1170 | static void fc_lport_enter_rpn_id(struct fc_lport *lport) | ||
1171 | { | ||
1172 | struct fc_frame *fp; | ||
1173 | |||
1174 | FC_LPORT_DBG(lport, "Entered RPN_ID state from %s state\n", | ||
1175 | fc_lport_state(lport)); | ||
1176 | |||
1177 | fc_lport_state_enter(lport, LPORT_ST_RPN_ID); | ||
1178 | |||
1179 | fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) + | ||
1180 | sizeof(struct fc_ns_rn_id)); | ||
1181 | if (!fp) { | 1260 | if (!fp) { |
1182 | fc_lport_error(lport, fp); | 1261 | fc_lport_error(lport, fp); |
1183 | return; | 1262 | return; |
1184 | } | 1263 | } |
1185 | 1264 | ||
1186 | if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RPN_ID, | 1265 | if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, cmd, |
1187 | fc_lport_rpn_id_resp, | 1266 | fc_lport_ns_resp, |
1188 | lport, lport->e_d_tov)) | 1267 | lport, 3 * lport->r_a_tov)) |
1189 | fc_lport_error(lport, fp); | 1268 | fc_lport_error(lport, fp); |
1190 | } | 1269 | } |
1191 | 1270 | ||
@@ -1194,8 +1273,8 @@ static struct fc_rport_operations fc_lport_rport_ops = { | |||
1194 | }; | 1273 | }; |
1195 | 1274 | ||
1196 | /** | 1275 | /** |
1197 | * fc_rport_enter_dns() - Create a rport to the name server | 1276 | * fc_rport_enter_dns() - Create a fc_rport for the name server |
1198 | * @lport: Fibre Channel local port requesting a rport for the name server | 1277 | * @lport: The local port requesting a remote port for the name server |
1199 | * | 1278 | * |
1200 | * Locking Note: The lport lock is expected to be held before calling | 1279 | * Locking Note: The lport lock is expected to be held before calling |
1201 | * this routine. | 1280 | * this routine. |
@@ -1224,8 +1303,8 @@ err: | |||
1224 | } | 1303 | } |
1225 | 1304 | ||
1226 | /** | 1305 | /** |
1227 | * fc_lport_timeout() - Handler for the retry_work timer. | 1306 | * fc_lport_timeout() - Handler for the retry_work timer |
1228 | * @work: The work struct of the fc_lport | 1307 | * @work: The work struct of the local port |
1229 | */ | 1308 | */ |
1230 | static void fc_lport_timeout(struct work_struct *work) | 1309 | static void fc_lport_timeout(struct work_struct *work) |
1231 | { | 1310 | { |
@@ -1237,21 +1316,25 @@ static void fc_lport_timeout(struct work_struct *work) | |||
1237 | 1316 | ||
1238 | switch (lport->state) { | 1317 | switch (lport->state) { |
1239 | case LPORT_ST_DISABLED: | 1318 | case LPORT_ST_DISABLED: |
1319 | WARN_ON(1); | ||
1320 | break; | ||
1240 | case LPORT_ST_READY: | 1321 | case LPORT_ST_READY: |
1241 | case LPORT_ST_RESET: | ||
1242 | WARN_ON(1); | 1322 | WARN_ON(1); |
1243 | break; | 1323 | break; |
1324 | case LPORT_ST_RESET: | ||
1325 | break; | ||
1244 | case LPORT_ST_FLOGI: | 1326 | case LPORT_ST_FLOGI: |
1245 | fc_lport_enter_flogi(lport); | 1327 | fc_lport_enter_flogi(lport); |
1246 | break; | 1328 | break; |
1247 | case LPORT_ST_DNS: | 1329 | case LPORT_ST_DNS: |
1248 | fc_lport_enter_dns(lport); | 1330 | fc_lport_enter_dns(lport); |
1249 | break; | 1331 | break; |
1250 | case LPORT_ST_RPN_ID: | 1332 | case LPORT_ST_RNN_ID: |
1251 | fc_lport_enter_rpn_id(lport); | 1333 | case LPORT_ST_RSNN_NN: |
1252 | break; | 1334 | case LPORT_ST_RSPN_ID: |
1253 | case LPORT_ST_RFT_ID: | 1335 | case LPORT_ST_RFT_ID: |
1254 | fc_lport_enter_rft_id(lport); | 1336 | case LPORT_ST_RFF_ID: |
1337 | fc_lport_enter_ns(lport, lport->state); | ||
1255 | break; | 1338 | break; |
1256 | case LPORT_ST_SCR: | 1339 | case LPORT_ST_SCR: |
1257 | fc_lport_enter_scr(lport); | 1340 | fc_lport_enter_scr(lport); |
@@ -1266,16 +1349,16 @@ static void fc_lport_timeout(struct work_struct *work) | |||
1266 | 1349 | ||
1267 | /** | 1350 | /** |
1268 | * fc_lport_logo_resp() - Handle response to LOGO request | 1351 | * fc_lport_logo_resp() - Handle response to LOGO request |
1269 | * @sp: current sequence in LOGO exchange | 1352 | * @sp: The sequence that the LOGO was on |
1270 | * @fp: response frame | 1353 | * @fp: The LOGO frame |
1271 | * @lp_arg: Fibre Channel lport port instance that sent the LOGO request | 1354 | * @lp_arg: The lport port that received the LOGO request |
1272 | * | 1355 | * |
1273 | * Locking Note: This function will be called without the lport lock | 1356 | * Locking Note: This function will be called without the lport lock |
1274 | * held, but it will lock, call an _enter_* function or fc_lport_error | 1357 | * held, but it will lock, call an _enter_* function or fc_lport_error() |
1275 | * and then unlock the lport. | 1358 | * and then unlock the lport. |
1276 | */ | 1359 | */ |
1277 | static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, | 1360 | void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, |
1278 | void *lp_arg) | 1361 | void *lp_arg) |
1279 | { | 1362 | { |
1280 | struct fc_lport *lport = lp_arg; | 1363 | struct fc_lport *lport = lp_arg; |
1281 | u8 op; | 1364 | u8 op; |
@@ -1311,10 +1394,11 @@ out: | |||
1311 | err: | 1394 | err: |
1312 | mutex_unlock(&lport->lp_mutex); | 1395 | mutex_unlock(&lport->lp_mutex); |
1313 | } | 1396 | } |
1397 | EXPORT_SYMBOL(fc_lport_logo_resp); | ||
1314 | 1398 | ||
1315 | /** | 1399 | /** |
1316 | * fc_rport_enter_logo() - Logout of the fabric | 1400 | * fc_rport_enter_logo() - Logout of the fabric |
1317 | * @lport: Fibre Channel local port to be logged out | 1401 | * @lport: The local port to be logged out |
1318 | * | 1402 | * |
1319 | * Locking Note: The lport lock is expected to be held before calling | 1403 | * Locking Note: The lport lock is expected to be held before calling |
1320 | * this routine. | 1404 | * this routine. |
@@ -1328,6 +1412,7 @@ static void fc_lport_enter_logo(struct fc_lport *lport) | |||
1328 | fc_lport_state(lport)); | 1412 | fc_lport_state(lport)); |
1329 | 1413 | ||
1330 | fc_lport_state_enter(lport, LPORT_ST_LOGO); | 1414 | fc_lport_state_enter(lport, LPORT_ST_LOGO); |
1415 | fc_vports_linkchange(lport); | ||
1331 | 1416 | ||
1332 | fp = fc_frame_alloc(lport, sizeof(*logo)); | 1417 | fp = fc_frame_alloc(lport, sizeof(*logo)); |
1333 | if (!fp) { | 1418 | if (!fp) { |
@@ -1336,22 +1421,23 @@ static void fc_lport_enter_logo(struct fc_lport *lport) | |||
1336 | } | 1421 | } |
1337 | 1422 | ||
1338 | if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_LOGO, | 1423 | if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_LOGO, |
1339 | fc_lport_logo_resp, lport, lport->e_d_tov)) | 1424 | fc_lport_logo_resp, lport, |
1340 | fc_lport_error(lport, fp); | 1425 | 2 * lport->r_a_tov)) |
1426 | fc_lport_error(lport, NULL); | ||
1341 | } | 1427 | } |
1342 | 1428 | ||
1343 | /** | 1429 | /** |
1344 | * fc_lport_flogi_resp() - Handle response to FLOGI request | 1430 | * fc_lport_flogi_resp() - Handle response to FLOGI request |
1345 | * @sp: current sequence in FLOGI exchange | 1431 | * @sp: The sequence that the FLOGI was on |
1346 | * @fp: response frame | 1432 | * @fp: The FLOGI response frame |
1347 | * @lp_arg: Fibre Channel lport port instance that sent the FLOGI request | 1433 | * @lp_arg: The lport port that received the FLOGI response |
1348 | * | 1434 | * |
1349 | * Locking Note: This function will be called without the lport lock | 1435 | * Locking Note: This function will be called without the lport lock |
1350 | * held, but it will lock, call an _enter_* function or fc_lport_error | 1436 | * held, but it will lock, call an _enter_* function or fc_lport_error() |
1351 | * and then unlock the lport. | 1437 | * and then unlock the lport. |
1352 | */ | 1438 | */ |
1353 | static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, | 1439 | void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, |
1354 | void *lp_arg) | 1440 | void *lp_arg) |
1355 | { | 1441 | { |
1356 | struct fc_lport *lport = lp_arg; | 1442 | struct fc_lport *lport = lp_arg; |
1357 | struct fc_frame_header *fh; | 1443 | struct fc_frame_header *fh; |
@@ -1385,11 +1471,6 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
1385 | fh = fc_frame_header_get(fp); | 1471 | fh = fc_frame_header_get(fp); |
1386 | did = ntoh24(fh->fh_d_id); | 1472 | did = ntoh24(fh->fh_d_id); |
1387 | if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) { | 1473 | if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) { |
1388 | |||
1389 | printk(KERN_INFO "libfc: Assigned FID (%6x) in FLOGI response\n", | ||
1390 | did); | ||
1391 | fc_host_port_id(lport->host) = did; | ||
1392 | |||
1393 | flp = fc_frame_payload_get(fp, sizeof(*flp)); | 1474 | flp = fc_frame_payload_get(fp, sizeof(*flp)); |
1394 | if (flp) { | 1475 | if (flp) { |
1395 | mfs = ntohs(flp->fl_csp.sp_bb_data) & | 1476 | mfs = ntohs(flp->fl_csp.sp_bb_data) & |
@@ -1402,12 +1483,18 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
1402 | e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov); | 1483 | e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov); |
1403 | if (csp_flags & FC_SP_FT_EDTR) | 1484 | if (csp_flags & FC_SP_FT_EDTR) |
1404 | e_d_tov /= 1000000; | 1485 | e_d_tov /= 1000000; |
1486 | |||
1487 | lport->npiv_enabled = !!(csp_flags & FC_SP_FT_NPIV_ACC); | ||
1488 | |||
1405 | if ((csp_flags & FC_SP_FT_FPORT) == 0) { | 1489 | if ((csp_flags & FC_SP_FT_FPORT) == 0) { |
1406 | if (e_d_tov > lport->e_d_tov) | 1490 | if (e_d_tov > lport->e_d_tov) |
1407 | lport->e_d_tov = e_d_tov; | 1491 | lport->e_d_tov = e_d_tov; |
1408 | lport->r_a_tov = 2 * e_d_tov; | 1492 | lport->r_a_tov = 2 * e_d_tov; |
1409 | printk(KERN_INFO "libfc: Port (%6x) entered " | 1493 | fc_lport_set_port_id(lport, did, fp); |
1410 | "point to point mode\n", did); | 1494 | printk(KERN_INFO "host%d: libfc: " |
1495 | "Port (%6x) entered " | ||
1496 | "point-to-point mode\n", | ||
1497 | lport->host->host_no, did); | ||
1411 | fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id), | 1498 | fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id), |
1412 | get_unaligned_be64( | 1499 | get_unaligned_be64( |
1413 | &flp->fl_wwpn), | 1500 | &flp->fl_wwpn), |
@@ -1418,6 +1505,7 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
1418 | lport->r_a_tov = r_a_tov; | 1505 | lport->r_a_tov = r_a_tov; |
1419 | fc_host_fabric_name(lport->host) = | 1506 | fc_host_fabric_name(lport->host) = |
1420 | get_unaligned_be64(&flp->fl_wwnn); | 1507 | get_unaligned_be64(&flp->fl_wwnn); |
1508 | fc_lport_set_port_id(lport, did, fp); | ||
1421 | fc_lport_enter_dns(lport); | 1509 | fc_lport_enter_dns(lport); |
1422 | } | 1510 | } |
1423 | } | 1511 | } |
@@ -1430,6 +1518,7 @@ out: | |||
1430 | err: | 1518 | err: |
1431 | mutex_unlock(&lport->lp_mutex); | 1519 | mutex_unlock(&lport->lp_mutex); |
1432 | } | 1520 | } |
1521 | EXPORT_SYMBOL(fc_lport_flogi_resp); | ||
1433 | 1522 | ||
1434 | /** | 1523 | /** |
1435 | * fc_rport_enter_flogi() - Send a FLOGI request to the fabric manager | 1524 | * fc_rport_enter_flogi() - Send a FLOGI request to the fabric manager |
@@ -1451,12 +1540,18 @@ void fc_lport_enter_flogi(struct fc_lport *lport) | |||
1451 | if (!fp) | 1540 | if (!fp) |
1452 | return fc_lport_error(lport, fp); | 1541 | return fc_lport_error(lport, fp); |
1453 | 1542 | ||
1454 | if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_FLOGI, | 1543 | if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, |
1455 | fc_lport_flogi_resp, lport, lport->e_d_tov)) | 1544 | lport->vport ? ELS_FDISC : ELS_FLOGI, |
1456 | fc_lport_error(lport, fp); | 1545 | fc_lport_flogi_resp, lport, |
1546 | lport->vport ? 2 * lport->r_a_tov : | ||
1547 | lport->e_d_tov)) | ||
1548 | fc_lport_error(lport, NULL); | ||
1457 | } | 1549 | } |
1458 | 1550 | ||
1459 | /* Configure a fc_lport */ | 1551 | /** |
1552 | * fc_lport_config() - Configure a fc_lport | ||
1553 | * @lport: The local port to be configured | ||
1554 | */ | ||
1460 | int fc_lport_config(struct fc_lport *lport) | 1555 | int fc_lport_config(struct fc_lport *lport) |
1461 | { | 1556 | { |
1462 | INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout); | 1557 | INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout); |
@@ -1471,6 +1566,10 @@ int fc_lport_config(struct fc_lport *lport) | |||
1471 | } | 1566 | } |
1472 | EXPORT_SYMBOL(fc_lport_config); | 1567 | EXPORT_SYMBOL(fc_lport_config); |
1473 | 1568 | ||
1569 | /** | ||
1570 | * fc_lport_init() - Initialize the lport layer for a local port | ||
1571 | * @lport: The local port to initialize the exchange layer for | ||
1572 | */ | ||
1474 | int fc_lport_init(struct fc_lport *lport) | 1573 | int fc_lport_init(struct fc_lport *lport) |
1475 | { | 1574 | { |
1476 | if (!lport->tt.lport_recv) | 1575 | if (!lport->tt.lport_recv) |
@@ -1500,7 +1599,254 @@ int fc_lport_init(struct fc_lport *lport) | |||
1500 | if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT) | 1599 | if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT) |
1501 | fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT; | 1600 | fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT; |
1502 | 1601 | ||
1503 | INIT_LIST_HEAD(&lport->ema_list); | ||
1504 | return 0; | 1602 | return 0; |
1505 | } | 1603 | } |
1506 | EXPORT_SYMBOL(fc_lport_init); | 1604 | EXPORT_SYMBOL(fc_lport_init); |
1605 | |||
1606 | /** | ||
1607 | * fc_lport_bsg_resp() - The common response handler for FC Passthrough requests | ||
1608 | * @sp: The sequence for the FC Passthrough response | ||
1609 | * @fp: The response frame | ||
1610 | * @info_arg: The BSG info that the response is for | ||
1611 | */ | ||
1612 | static void fc_lport_bsg_resp(struct fc_seq *sp, struct fc_frame *fp, | ||
1613 | void *info_arg) | ||
1614 | { | ||
1615 | struct fc_bsg_info *info = info_arg; | ||
1616 | struct fc_bsg_job *job = info->job; | ||
1617 | struct fc_lport *lport = info->lport; | ||
1618 | struct fc_frame_header *fh; | ||
1619 | size_t len; | ||
1620 | void *buf; | ||
1621 | |||
1622 | if (IS_ERR(fp)) { | ||
1623 | job->reply->result = (PTR_ERR(fp) == -FC_EX_CLOSED) ? | ||
1624 | -ECONNABORTED : -ETIMEDOUT; | ||
1625 | job->reply_len = sizeof(uint32_t); | ||
1626 | job->state_flags |= FC_RQST_STATE_DONE; | ||
1627 | job->job_done(job); | ||
1628 | kfree(info); | ||
1629 | return; | ||
1630 | } | ||
1631 | |||
1632 | mutex_lock(&lport->lp_mutex); | ||
1633 | fh = fc_frame_header_get(fp); | ||
1634 | len = fr_len(fp) - sizeof(*fh); | ||
1635 | buf = fc_frame_payload_get(fp, 0); | ||
1636 | |||
1637 | if (fr_sof(fp) == FC_SOF_I3 && !ntohs(fh->fh_seq_cnt)) { | ||
1638 | /* Get the response code from the first frame payload */ | ||
1639 | unsigned short cmd = (info->rsp_code == FC_FS_ACC) ? | ||
1640 | ntohs(((struct fc_ct_hdr *)buf)->ct_cmd) : | ||
1641 | (unsigned short)fc_frame_payload_op(fp); | ||
1642 | |||
1643 | /* Save the reply status of the job */ | ||
1644 | job->reply->reply_data.ctels_reply.status = | ||
1645 | (cmd == info->rsp_code) ? | ||
1646 | FC_CTELS_STATUS_OK : FC_CTELS_STATUS_REJECT; | ||
1647 | } | ||
1648 | |||
1649 | job->reply->reply_payload_rcv_len += | ||
1650 | fc_copy_buffer_to_sglist(buf, len, info->sg, &info->nents, | ||
1651 | &info->offset, KM_BIO_SRC_IRQ, NULL); | ||
1652 | |||
1653 | if (fr_eof(fp) == FC_EOF_T && | ||
1654 | (ntoh24(fh->fh_f_ctl) & (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) == | ||
1655 | (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) { | ||
1656 | if (job->reply->reply_payload_rcv_len > | ||
1657 | job->reply_payload.payload_len) | ||
1658 | job->reply->reply_payload_rcv_len = | ||
1659 | job->reply_payload.payload_len; | ||
1660 | job->reply->result = 0; | ||
1661 | job->state_flags |= FC_RQST_STATE_DONE; | ||
1662 | job->job_done(job); | ||
1663 | kfree(info); | ||
1664 | } | ||
1665 | fc_frame_free(fp); | ||
1666 | mutex_unlock(&lport->lp_mutex); | ||
1667 | } | ||
1668 | |||
1669 | /** | ||
1670 | * fc_lport_els_request() - Send ELS passthrough request | ||
1671 | * @job: The BSG Passthrough job | ||
1672 | * @lport: The local port sending the request | ||
1673 | * @did: The destination port id | ||
1674 | * | ||
1675 | * Locking Note: The lport lock is expected to be held before calling | ||
1676 | * this routine. | ||
1677 | */ | ||
1678 | static int fc_lport_els_request(struct fc_bsg_job *job, | ||
1679 | struct fc_lport *lport, | ||
1680 | u32 did, u32 tov) | ||
1681 | { | ||
1682 | struct fc_bsg_info *info; | ||
1683 | struct fc_frame *fp; | ||
1684 | struct fc_frame_header *fh; | ||
1685 | char *pp; | ||
1686 | int len; | ||
1687 | |||
1688 | fp = fc_frame_alloc(lport, job->request_payload.payload_len); | ||
1689 | if (!fp) | ||
1690 | return -ENOMEM; | ||
1691 | |||
1692 | len = job->request_payload.payload_len; | ||
1693 | pp = fc_frame_payload_get(fp, len); | ||
1694 | |||
1695 | sg_copy_to_buffer(job->request_payload.sg_list, | ||
1696 | job->request_payload.sg_cnt, | ||
1697 | pp, len); | ||
1698 | |||
1699 | fh = fc_frame_header_get(fp); | ||
1700 | fh->fh_r_ctl = FC_RCTL_ELS_REQ; | ||
1701 | hton24(fh->fh_d_id, did); | ||
1702 | hton24(fh->fh_s_id, fc_host_port_id(lport->host)); | ||
1703 | fh->fh_type = FC_TYPE_ELS; | ||
1704 | hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ | | ||
1705 | FC_FC_END_SEQ | FC_FC_SEQ_INIT); | ||
1706 | fh->fh_cs_ctl = 0; | ||
1707 | fh->fh_df_ctl = 0; | ||
1708 | fh->fh_parm_offset = 0; | ||
1709 | |||
1710 | info = kzalloc(sizeof(struct fc_bsg_info), GFP_KERNEL); | ||
1711 | if (!info) { | ||
1712 | fc_frame_free(fp); | ||
1713 | return -ENOMEM; | ||
1714 | } | ||
1715 | |||
1716 | info->job = job; | ||
1717 | info->lport = lport; | ||
1718 | info->rsp_code = ELS_LS_ACC; | ||
1719 | info->nents = job->reply_payload.sg_cnt; | ||
1720 | info->sg = job->reply_payload.sg_list; | ||
1721 | |||
1722 | if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp, | ||
1723 | NULL, info, tov)) | ||
1724 | return -ECOMM; | ||
1725 | return 0; | ||
1726 | } | ||
1727 | |||
1728 | /** | ||
1729 | * fc_lport_ct_request() - Send CT Passthrough request | ||
1730 | * @job: The BSG Passthrough job | ||
1731 | * @lport: The local port sending the request | ||
1732 | * @did: The destination FC-ID | ||
1733 | * @tov: The timeout period to wait for the response | ||
1734 | * | ||
1735 | * Locking Note: The lport lock is expected to be held before calling | ||
1736 | * this routine. | ||
1737 | */ | ||
1738 | static int fc_lport_ct_request(struct fc_bsg_job *job, | ||
1739 | struct fc_lport *lport, u32 did, u32 tov) | ||
1740 | { | ||
1741 | struct fc_bsg_info *info; | ||
1742 | struct fc_frame *fp; | ||
1743 | struct fc_frame_header *fh; | ||
1744 | struct fc_ct_req *ct; | ||
1745 | size_t len; | ||
1746 | |||
1747 | fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) + | ||
1748 | job->request_payload.payload_len); | ||
1749 | if (!fp) | ||
1750 | return -ENOMEM; | ||
1751 | |||
1752 | len = job->request_payload.payload_len; | ||
1753 | ct = fc_frame_payload_get(fp, len); | ||
1754 | |||
1755 | sg_copy_to_buffer(job->request_payload.sg_list, | ||
1756 | job->request_payload.sg_cnt, | ||
1757 | ct, len); | ||
1758 | |||
1759 | fh = fc_frame_header_get(fp); | ||
1760 | fh->fh_r_ctl = FC_RCTL_DD_UNSOL_CTL; | ||
1761 | hton24(fh->fh_d_id, did); | ||
1762 | hton24(fh->fh_s_id, fc_host_port_id(lport->host)); | ||
1763 | fh->fh_type = FC_TYPE_CT; | ||
1764 | hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ | | ||
1765 | FC_FC_END_SEQ | FC_FC_SEQ_INIT); | ||
1766 | fh->fh_cs_ctl = 0; | ||
1767 | fh->fh_df_ctl = 0; | ||
1768 | fh->fh_parm_offset = 0; | ||
1769 | |||
1770 | info = kzalloc(sizeof(struct fc_bsg_info), GFP_KERNEL); | ||
1771 | if (!info) { | ||
1772 | fc_frame_free(fp); | ||
1773 | return -ENOMEM; | ||
1774 | } | ||
1775 | |||
1776 | info->job = job; | ||
1777 | info->lport = lport; | ||
1778 | info->rsp_code = FC_FS_ACC; | ||
1779 | info->nents = job->reply_payload.sg_cnt; | ||
1780 | info->sg = job->reply_payload.sg_list; | ||
1781 | |||
1782 | if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp, | ||
1783 | NULL, info, tov)) | ||
1784 | return -ECOMM; | ||
1785 | return 0; | ||
1786 | } | ||
1787 | |||
1788 | /** | ||
1789 | * fc_lport_bsg_request() - The common entry point for sending | ||
1790 | * FC Passthrough requests | ||
1791 | * @job: The BSG passthrough job | ||
1792 | */ | ||
1793 | int fc_lport_bsg_request(struct fc_bsg_job *job) | ||
1794 | { | ||
1795 | struct request *rsp = job->req->next_rq; | ||
1796 | struct Scsi_Host *shost = job->shost; | ||
1797 | struct fc_lport *lport = shost_priv(shost); | ||
1798 | struct fc_rport *rport; | ||
1799 | struct fc_rport_priv *rdata; | ||
1800 | int rc = -EINVAL; | ||
1801 | u32 did; | ||
1802 | |||
1803 | job->reply->reply_payload_rcv_len = 0; | ||
1804 | if (rsp) | ||
1805 | rsp->resid_len = job->reply_payload.payload_len; | ||
1806 | |||
1807 | mutex_lock(&lport->lp_mutex); | ||
1808 | |||
1809 | switch (job->request->msgcode) { | ||
1810 | case FC_BSG_RPT_ELS: | ||
1811 | rport = job->rport; | ||
1812 | if (!rport) | ||
1813 | break; | ||
1814 | |||
1815 | rdata = rport->dd_data; | ||
1816 | rc = fc_lport_els_request(job, lport, rport->port_id, | ||
1817 | rdata->e_d_tov); | ||
1818 | break; | ||
1819 | |||
1820 | case FC_BSG_RPT_CT: | ||
1821 | rport = job->rport; | ||
1822 | if (!rport) | ||
1823 | break; | ||
1824 | |||
1825 | rdata = rport->dd_data; | ||
1826 | rc = fc_lport_ct_request(job, lport, rport->port_id, | ||
1827 | rdata->e_d_tov); | ||
1828 | break; | ||
1829 | |||
1830 | case FC_BSG_HST_CT: | ||
1831 | did = ntoh24(job->request->rqst_data.h_ct.port_id); | ||
1832 | if (did == FC_FID_DIR_SERV) | ||
1833 | rdata = lport->dns_rdata; | ||
1834 | else | ||
1835 | rdata = lport->tt.rport_lookup(lport, did); | ||
1836 | |||
1837 | if (!rdata) | ||
1838 | break; | ||
1839 | |||
1840 | rc = fc_lport_ct_request(job, lport, did, rdata->e_d_tov); | ||
1841 | break; | ||
1842 | |||
1843 | case FC_BSG_HST_ELS_NOLOGIN: | ||
1844 | did = ntoh24(job->request->rqst_data.h_els.port_id); | ||
1845 | rc = fc_lport_els_request(job, lport, did, lport->e_d_tov); | ||
1846 | break; | ||
1847 | } | ||
1848 | |||
1849 | mutex_unlock(&lport->lp_mutex); | ||
1850 | return rc; | ||
1851 | } | ||
1852 | EXPORT_SYMBOL(fc_lport_bsg_request); | ||