diff options
Diffstat (limited to 'drivers/scsi/libfc')
-rw-r--r-- | drivers/scsi/libfc/fc_disc.c | 39 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_elsct.c | 2 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 215 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_fcp.c | 15 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_libfc.c | 78 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_libfc.h | 2 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_lport.c | 210 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 707 |
8 files changed, 793 insertions, 475 deletions
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index c7985da88099..32f67c4b03fc 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c | |||
@@ -63,27 +63,25 @@ static void fc_disc_restart(struct fc_disc *); | |||
63 | void fc_disc_stop_rports(struct fc_disc *disc) | 63 | void fc_disc_stop_rports(struct fc_disc *disc) |
64 | { | 64 | { |
65 | struct fc_lport *lport; | 65 | struct fc_lport *lport; |
66 | struct fc_rport_priv *rdata, *next; | 66 | struct fc_rport_priv *rdata; |
67 | 67 | ||
68 | lport = disc->lport; | 68 | lport = fc_disc_lport(disc); |
69 | 69 | ||
70 | mutex_lock(&disc->disc_mutex); | 70 | mutex_lock(&disc->disc_mutex); |
71 | list_for_each_entry_safe(rdata, next, &disc->rports, peers) | 71 | list_for_each_entry_rcu(rdata, &disc->rports, peers) |
72 | lport->tt.rport_logoff(rdata); | 72 | lport->tt.rport_logoff(rdata); |
73 | mutex_unlock(&disc->disc_mutex); | 73 | mutex_unlock(&disc->disc_mutex); |
74 | } | 74 | } |
75 | 75 | ||
76 | /** | 76 | /** |
77 | * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN) | 77 | * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN) |
78 | * @sp: The sequence of the RSCN exchange | 78 | * @disc: The discovery object to which the RSCN applies |
79 | * @fp: The RSCN frame | 79 | * @fp: The RSCN frame |
80 | * @lport: The local port that the request will be sent on | ||
81 | * | 80 | * |
82 | * Locking Note: This function expects that the disc_mutex is locked | 81 | * Locking Note: This function expects that the disc_mutex is locked |
83 | * before it is called. | 82 | * before it is called. |
84 | */ | 83 | */ |
85 | static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, | 84 | static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp) |
86 | struct fc_disc *disc) | ||
87 | { | 85 | { |
88 | struct fc_lport *lport; | 86 | struct fc_lport *lport; |
89 | struct fc_els_rscn *rp; | 87 | struct fc_els_rscn *rp; |
@@ -96,7 +94,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, | |||
96 | LIST_HEAD(disc_ports); | 94 | LIST_HEAD(disc_ports); |
97 | struct fc_disc_port *dp, *next; | 95 | struct fc_disc_port *dp, *next; |
98 | 96 | ||
99 | lport = disc->lport; | 97 | lport = fc_disc_lport(disc); |
100 | 98 | ||
101 | FC_DISC_DBG(disc, "Received an RSCN event\n"); | 99 | FC_DISC_DBG(disc, "Received an RSCN event\n"); |
102 | 100 | ||
@@ -151,7 +149,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, | |||
151 | break; | 149 | break; |
152 | } | 150 | } |
153 | } | 151 | } |
154 | lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); | 152 | lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); |
155 | 153 | ||
156 | /* | 154 | /* |
157 | * If not doing a complete rediscovery, do GPN_ID on | 155 | * If not doing a complete rediscovery, do GPN_ID on |
@@ -177,25 +175,22 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, | |||
177 | return; | 175 | return; |
178 | reject: | 176 | reject: |
179 | FC_DISC_DBG(disc, "Received a bad RSCN frame\n"); | 177 | FC_DISC_DBG(disc, "Received a bad RSCN frame\n"); |
180 | rjt_data.fp = NULL; | ||
181 | rjt_data.reason = ELS_RJT_LOGIC; | 178 | rjt_data.reason = ELS_RJT_LOGIC; |
182 | rjt_data.explan = ELS_EXPL_NONE; | 179 | rjt_data.explan = ELS_EXPL_NONE; |
183 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | 180 | lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data); |
184 | fc_frame_free(fp); | 181 | fc_frame_free(fp); |
185 | } | 182 | } |
186 | 183 | ||
187 | /** | 184 | /** |
188 | * fc_disc_recv_req() - Handle incoming requests | 185 | * fc_disc_recv_req() - Handle incoming requests |
189 | * @sp: The sequence of the request exchange | ||
190 | * @fp: The request frame | ||
191 | * @lport: The local port receiving the request | 186 | * @lport: The local port receiving the request |
187 | * @fp: The request frame | ||
192 | * | 188 | * |
193 | * Locking Note: This function is called from the EM and will lock | 189 | * Locking Note: This function is called from the EM and will lock |
194 | * the disc_mutex before calling the handler for the | 190 | * the disc_mutex before calling the handler for the |
195 | * request. | 191 | * request. |
196 | */ | 192 | */ |
197 | static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, | 193 | static void fc_disc_recv_req(struct fc_lport *lport, struct fc_frame *fp) |
198 | struct fc_lport *lport) | ||
199 | { | 194 | { |
200 | u8 op; | 195 | u8 op; |
201 | struct fc_disc *disc = &lport->disc; | 196 | struct fc_disc *disc = &lport->disc; |
@@ -204,7 +199,7 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, | |||
204 | switch (op) { | 199 | switch (op) { |
205 | case ELS_RSCN: | 200 | case ELS_RSCN: |
206 | mutex_lock(&disc->disc_mutex); | 201 | mutex_lock(&disc->disc_mutex); |
207 | fc_disc_recv_rscn_req(sp, fp, disc); | 202 | fc_disc_recv_rscn_req(disc, fp); |
208 | mutex_unlock(&disc->disc_mutex); | 203 | mutex_unlock(&disc->disc_mutex); |
209 | break; | 204 | break; |
210 | default: | 205 | default: |
@@ -275,7 +270,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, | |||
275 | */ | 270 | */ |
276 | static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) | 271 | static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) |
277 | { | 272 | { |
278 | struct fc_lport *lport = disc->lport; | 273 | struct fc_lport *lport = fc_disc_lport(disc); |
279 | struct fc_rport_priv *rdata; | 274 | struct fc_rport_priv *rdata; |
280 | 275 | ||
281 | FC_DISC_DBG(disc, "Discovery complete\n"); | 276 | FC_DISC_DBG(disc, "Discovery complete\n"); |
@@ -292,7 +287,7 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) | |||
292 | * Skip ports which were never discovered. These are the dNS port | 287 | * Skip ports which were never discovered. These are the dNS port |
293 | * and ports which were created by PLOGI. | 288 | * and ports which were created by PLOGI. |
294 | */ | 289 | */ |
295 | list_for_each_entry(rdata, &disc->rports, peers) { | 290 | list_for_each_entry_rcu(rdata, &disc->rports, peers) { |
296 | if (!rdata->disc_id) | 291 | if (!rdata->disc_id) |
297 | continue; | 292 | continue; |
298 | if (rdata->disc_id == disc->disc_id) | 293 | if (rdata->disc_id == disc->disc_id) |
@@ -313,7 +308,7 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) | |||
313 | */ | 308 | */ |
314 | static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) | 309 | static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) |
315 | { | 310 | { |
316 | struct fc_lport *lport = disc->lport; | 311 | struct fc_lport *lport = fc_disc_lport(disc); |
317 | unsigned long delay = 0; | 312 | unsigned long delay = 0; |
318 | 313 | ||
319 | FC_DISC_DBG(disc, "Error %ld, retries %d/%d\n", | 314 | FC_DISC_DBG(disc, "Error %ld, retries %d/%d\n", |
@@ -353,7 +348,7 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) | |||
353 | static void fc_disc_gpn_ft_req(struct fc_disc *disc) | 348 | static void fc_disc_gpn_ft_req(struct fc_disc *disc) |
354 | { | 349 | { |
355 | struct fc_frame *fp; | 350 | struct fc_frame *fp; |
356 | struct fc_lport *lport = disc->lport; | 351 | struct fc_lport *lport = fc_disc_lport(disc); |
357 | 352 | ||
358 | WARN_ON(!fc_lport_test_ready(lport)); | 353 | WARN_ON(!fc_lport_test_ready(lport)); |
359 | 354 | ||
@@ -396,7 +391,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) | |||
396 | struct fc_rport_identifiers ids; | 391 | struct fc_rport_identifiers ids; |
397 | struct fc_rport_priv *rdata; | 392 | struct fc_rport_priv *rdata; |
398 | 393 | ||
399 | lport = disc->lport; | 394 | lport = fc_disc_lport(disc); |
400 | disc->seq_count++; | 395 | disc->seq_count++; |
401 | 396 | ||
402 | /* | 397 | /* |
@@ -733,7 +728,7 @@ int fc_disc_init(struct fc_lport *lport) | |||
733 | mutex_init(&disc->disc_mutex); | 728 | mutex_init(&disc->disc_mutex); |
734 | INIT_LIST_HEAD(&disc->rports); | 729 | INIT_LIST_HEAD(&disc->rports); |
735 | 730 | ||
736 | disc->lport = lport; | 731 | disc->priv = lport; |
737 | 732 | ||
738 | return 0; | 733 | return 0; |
739 | } | 734 | } |
diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index e9412b710fab..9b25969e2ad0 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c | |||
@@ -64,7 +64,7 @@ struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did, | |||
64 | } | 64 | } |
65 | 65 | ||
66 | fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type, | 66 | fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type, |
67 | FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); | 67 | FC_FCTL_REQ, 0); |
68 | 68 | ||
69 | return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec); | 69 | return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec); |
70 | } | 70 | } |
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 104e0fba7c43..b8560ad8cf66 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c | |||
@@ -129,11 +129,11 @@ struct fc_exch_mgr_anchor { | |||
129 | }; | 129 | }; |
130 | 130 | ||
131 | static void fc_exch_rrq(struct fc_exch *); | 131 | static void fc_exch_rrq(struct fc_exch *); |
132 | static void fc_seq_ls_acc(struct fc_seq *); | 132 | static void fc_seq_ls_acc(struct fc_frame *); |
133 | static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason, | 133 | static void fc_seq_ls_rjt(struct fc_frame *, enum fc_els_rjt_reason, |
134 | enum fc_els_rjt_explan); | 134 | enum fc_els_rjt_explan); |
135 | static void fc_exch_els_rec(struct fc_seq *, struct fc_frame *); | 135 | static void fc_exch_els_rec(struct fc_frame *); |
136 | static void fc_exch_els_rrq(struct fc_seq *, struct fc_frame *); | 136 | static void fc_exch_els_rrq(struct fc_frame *); |
137 | 137 | ||
138 | /* | 138 | /* |
139 | * Internal implementation notes. | 139 | * Internal implementation notes. |
@@ -464,6 +464,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp, | |||
464 | 464 | ||
465 | f_ctl = ntoh24(fh->fh_f_ctl); | 465 | f_ctl = ntoh24(fh->fh_f_ctl); |
466 | fc_exch_setup_hdr(ep, fp, f_ctl); | 466 | fc_exch_setup_hdr(ep, fp, f_ctl); |
467 | fr_encaps(fp) = ep->encaps; | ||
467 | 468 | ||
468 | /* | 469 | /* |
469 | * update sequence count if this frame is carrying | 470 | * update sequence count if this frame is carrying |
@@ -1002,28 +1003,30 @@ static void fc_exch_set_addr(struct fc_exch *ep, | |||
1002 | /** | 1003 | /** |
1003 | * fc_seq_els_rsp_send() - Send an ELS response using infomation from | 1004 | * fc_seq_els_rsp_send() - Send an ELS response using infomation from |
1004 | * the existing sequence/exchange. | 1005 | * the existing sequence/exchange. |
1005 | * @sp: The sequence/exchange to get information from | 1006 | * @fp: The received frame |
1006 | * @els_cmd: The ELS command to be sent | 1007 | * @els_cmd: The ELS command to be sent |
1007 | * @els_data: The ELS data to be sent | 1008 | * @els_data: The ELS data to be sent |
1009 | * | ||
1010 | * The received frame is not freed. | ||
1008 | */ | 1011 | */ |
1009 | static void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd, | 1012 | static void fc_seq_els_rsp_send(struct fc_frame *fp, enum fc_els_cmd els_cmd, |
1010 | struct fc_seq_els_data *els_data) | 1013 | struct fc_seq_els_data *els_data) |
1011 | { | 1014 | { |
1012 | switch (els_cmd) { | 1015 | switch (els_cmd) { |
1013 | case ELS_LS_RJT: | 1016 | case ELS_LS_RJT: |
1014 | fc_seq_ls_rjt(sp, els_data->reason, els_data->explan); | 1017 | fc_seq_ls_rjt(fp, els_data->reason, els_data->explan); |
1015 | break; | 1018 | break; |
1016 | case ELS_LS_ACC: | 1019 | case ELS_LS_ACC: |
1017 | fc_seq_ls_acc(sp); | 1020 | fc_seq_ls_acc(fp); |
1018 | break; | 1021 | break; |
1019 | case ELS_RRQ: | 1022 | case ELS_RRQ: |
1020 | fc_exch_els_rrq(sp, els_data->fp); | 1023 | fc_exch_els_rrq(fp); |
1021 | break; | 1024 | break; |
1022 | case ELS_REC: | 1025 | case ELS_REC: |
1023 | fc_exch_els_rec(sp, els_data->fp); | 1026 | fc_exch_els_rec(fp); |
1024 | break; | 1027 | break; |
1025 | default: | 1028 | default: |
1026 | FC_EXCH_DBG(fc_seq_exch(sp), "Invalid ELS CMD:%x\n", els_cmd); | 1029 | FC_LPORT_DBG(fr_dev(fp), "Invalid ELS CMD:%x\n", els_cmd); |
1027 | } | 1030 | } |
1028 | } | 1031 | } |
1029 | 1032 | ||
@@ -1230,11 +1233,35 @@ free: | |||
1230 | } | 1233 | } |
1231 | 1234 | ||
1232 | /** | 1235 | /** |
1233 | * fc_exch_recv_req() - Handler for an incoming request where is other | 1236 | * fc_seq_assign() - Assign exchange and sequence for incoming request |
1234 | * end is originating the sequence | 1237 | * @lport: The local port that received the request |
1238 | * @fp: The request frame | ||
1239 | * | ||
1240 | * On success, the sequence pointer will be returned and also in fr_seq(@fp). | ||
1241 | */ | ||
1242 | static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp) | ||
1243 | { | ||
1244 | struct fc_exch_mgr_anchor *ema; | ||
1245 | |||
1246 | WARN_ON(lport != fr_dev(fp)); | ||
1247 | WARN_ON(fr_seq(fp)); | ||
1248 | fr_seq(fp) = NULL; | ||
1249 | |||
1250 | list_for_each_entry(ema, &lport->ema_list, ema_list) | ||
1251 | if ((!ema->match || ema->match(fp)) && | ||
1252 | fc_seq_lookup_recip(lport, ema->mp, fp) != FC_RJT_NONE) | ||
1253 | break; | ||
1254 | return fr_seq(fp); | ||
1255 | } | ||
1256 | |||
1257 | /** | ||
1258 | * fc_exch_recv_req() - Handler for an incoming request | ||
1235 | * @lport: The local port that received the request | 1259 | * @lport: The local port that received the request |
1236 | * @mp: The EM that the exchange is on | 1260 | * @mp: The EM that the exchange is on |
1237 | * @fp: The request frame | 1261 | * @fp: The request frame |
1262 | * | ||
1263 | * This is used when the other end is originating the exchange | ||
1264 | * and the sequence. | ||
1238 | */ | 1265 | */ |
1239 | static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp, | 1266 | static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp, |
1240 | struct fc_frame *fp) | 1267 | struct fc_frame *fp) |
@@ -1252,13 +1279,23 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp, | |||
1252 | fc_frame_free(fp); | 1279 | fc_frame_free(fp); |
1253 | return; | 1280 | return; |
1254 | } | 1281 | } |
1282 | fr_dev(fp) = lport; | ||
1283 | |||
1284 | BUG_ON(fr_seq(fp)); /* XXX remove later */ | ||
1285 | |||
1286 | /* | ||
1287 | * If the RX_ID is 0xffff, don't allocate an exchange. | ||
1288 | * The upper-level protocol may request one later, if needed. | ||
1289 | */ | ||
1290 | if (fh->fh_rx_id == htons(FC_XID_UNKNOWN)) | ||
1291 | return lport->tt.lport_recv(lport, fp); | ||
1255 | 1292 | ||
1256 | fr_seq(fp) = NULL; | ||
1257 | reject = fc_seq_lookup_recip(lport, mp, fp); | 1293 | reject = fc_seq_lookup_recip(lport, mp, fp); |
1258 | if (reject == FC_RJT_NONE) { | 1294 | if (reject == FC_RJT_NONE) { |
1259 | sp = fr_seq(fp); /* sequence will be held */ | 1295 | sp = fr_seq(fp); /* sequence will be held */ |
1260 | ep = fc_seq_exch(sp); | 1296 | ep = fc_seq_exch(sp); |
1261 | fc_seq_send_ack(sp, fp); | 1297 | fc_seq_send_ack(sp, fp); |
1298 | ep->encaps = fr_encaps(fp); | ||
1262 | 1299 | ||
1263 | /* | 1300 | /* |
1264 | * Call the receive function. | 1301 | * Call the receive function. |
@@ -1274,7 +1311,7 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp, | |||
1274 | if (ep->resp) | 1311 | if (ep->resp) |
1275 | ep->resp(sp, fp, ep->arg); | 1312 | ep->resp(sp, fp, ep->arg); |
1276 | else | 1313 | else |
1277 | lport->tt.lport_recv(lport, sp, fp); | 1314 | lport->tt.lport_recv(lport, fp); |
1278 | fc_exch_release(ep); /* release from lookup */ | 1315 | fc_exch_release(ep); /* release from lookup */ |
1279 | } else { | 1316 | } else { |
1280 | FC_LPORT_DBG(lport, "exch/seq lookup failed: reject %x\n", | 1317 | FC_LPORT_DBG(lport, "exch/seq lookup failed: reject %x\n", |
@@ -1542,53 +1579,55 @@ static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp) | |||
1542 | 1579 | ||
1543 | /** | 1580 | /** |
1544 | * fc_seq_ls_acc() - Accept sequence with LS_ACC | 1581 | * fc_seq_ls_acc() - Accept sequence with LS_ACC |
1545 | * @req_sp: The request sequence | 1582 | * @rx_fp: The received frame, not freed here. |
1546 | * | 1583 | * |
1547 | * If this fails due to allocation or transmit congestion, assume the | 1584 | * If this fails due to allocation or transmit congestion, assume the |
1548 | * originator will repeat the sequence. | 1585 | * originator will repeat the sequence. |
1549 | */ | 1586 | */ |
1550 | static void fc_seq_ls_acc(struct fc_seq *req_sp) | 1587 | static void fc_seq_ls_acc(struct fc_frame *rx_fp) |
1551 | { | 1588 | { |
1552 | struct fc_seq *sp; | 1589 | struct fc_lport *lport; |
1553 | struct fc_els_ls_acc *acc; | 1590 | struct fc_els_ls_acc *acc; |
1554 | struct fc_frame *fp; | 1591 | struct fc_frame *fp; |
1555 | 1592 | ||
1556 | sp = fc_seq_start_next(req_sp); | 1593 | lport = fr_dev(rx_fp); |
1557 | fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc)); | 1594 | fp = fc_frame_alloc(lport, sizeof(*acc)); |
1558 | if (fp) { | 1595 | if (!fp) |
1559 | acc = fc_frame_payload_get(fp, sizeof(*acc)); | 1596 | return; |
1560 | memset(acc, 0, sizeof(*acc)); | 1597 | acc = fc_frame_payload_get(fp, sizeof(*acc)); |
1561 | acc->la_cmd = ELS_LS_ACC; | 1598 | memset(acc, 0, sizeof(*acc)); |
1562 | fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); | 1599 | acc->la_cmd = ELS_LS_ACC; |
1563 | } | 1600 | fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); |
1601 | lport->tt.frame_send(lport, fp); | ||
1564 | } | 1602 | } |
1565 | 1603 | ||
1566 | /** | 1604 | /** |
1567 | * fc_seq_ls_rjt() - Reject a sequence with ELS LS_RJT | 1605 | * fc_seq_ls_rjt() - Reject a sequence with ELS LS_RJT |
1568 | * @req_sp: The request sequence | 1606 | * @rx_fp: The received frame, not freed here. |
1569 | * @reason: The reason the sequence is being rejected | 1607 | * @reason: The reason the sequence is being rejected |
1570 | * @explan: The explaination for the rejection | 1608 | * @explan: The explanation for the rejection |
1571 | * | 1609 | * |
1572 | * If this fails due to allocation or transmit congestion, assume the | 1610 | * If this fails due to allocation or transmit congestion, assume the |
1573 | * originator will repeat the sequence. | 1611 | * originator will repeat the sequence. |
1574 | */ | 1612 | */ |
1575 | static void fc_seq_ls_rjt(struct fc_seq *req_sp, enum fc_els_rjt_reason reason, | 1613 | static void fc_seq_ls_rjt(struct fc_frame *rx_fp, enum fc_els_rjt_reason reason, |
1576 | enum fc_els_rjt_explan explan) | 1614 | enum fc_els_rjt_explan explan) |
1577 | { | 1615 | { |
1578 | struct fc_seq *sp; | 1616 | struct fc_lport *lport; |
1579 | struct fc_els_ls_rjt *rjt; | 1617 | struct fc_els_ls_rjt *rjt; |
1580 | struct fc_frame *fp; | 1618 | struct fc_frame *fp; |
1581 | 1619 | ||
1582 | sp = fc_seq_start_next(req_sp); | 1620 | lport = fr_dev(rx_fp); |
1583 | fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*rjt)); | 1621 | fp = fc_frame_alloc(lport, sizeof(*rjt)); |
1584 | if (fp) { | 1622 | if (!fp) |
1585 | rjt = fc_frame_payload_get(fp, sizeof(*rjt)); | 1623 | return; |
1586 | memset(rjt, 0, sizeof(*rjt)); | 1624 | rjt = fc_frame_payload_get(fp, sizeof(*rjt)); |
1587 | rjt->er_cmd = ELS_LS_RJT; | 1625 | memset(rjt, 0, sizeof(*rjt)); |
1588 | rjt->er_reason = reason; | 1626 | rjt->er_cmd = ELS_LS_RJT; |
1589 | rjt->er_explan = explan; | 1627 | rjt->er_reason = reason; |
1590 | fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); | 1628 | rjt->er_explan = explan; |
1591 | } | 1629 | fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); |
1630 | lport->tt.frame_send(lport, fp); | ||
1592 | } | 1631 | } |
1593 | 1632 | ||
1594 | /** | 1633 | /** |
@@ -1691,17 +1730,33 @@ void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did) | |||
1691 | EXPORT_SYMBOL(fc_exch_mgr_reset); | 1730 | EXPORT_SYMBOL(fc_exch_mgr_reset); |
1692 | 1731 | ||
1693 | /** | 1732 | /** |
1733 | * fc_exch_lookup() - find an exchange | ||
1734 | * @lport: The local port | ||
1735 | * @xid: The exchange ID | ||
1736 | * | ||
1737 | * Returns exchange pointer with hold for caller, or NULL if not found. | ||
1738 | */ | ||
1739 | static struct fc_exch *fc_exch_lookup(struct fc_lport *lport, u32 xid) | ||
1740 | { | ||
1741 | struct fc_exch_mgr_anchor *ema; | ||
1742 | |||
1743 | list_for_each_entry(ema, &lport->ema_list, ema_list) | ||
1744 | if (ema->mp->min_xid <= xid && xid <= ema->mp->max_xid) | ||
1745 | return fc_exch_find(ema->mp, xid); | ||
1746 | return NULL; | ||
1747 | } | ||
1748 | |||
1749 | /** | ||
1694 | * fc_exch_els_rec() - Handler for ELS REC (Read Exchange Concise) requests | 1750 | * fc_exch_els_rec() - Handler for ELS REC (Read Exchange Concise) requests |
1695 | * @sp: The sequence the REC is on | 1751 | * @rfp: The REC frame, not freed here. |
1696 | * @rfp: The REC frame | ||
1697 | * | 1752 | * |
1698 | * Note that the requesting port may be different than the S_ID in the request. | 1753 | * Note that the requesting port may be different than the S_ID in the request. |
1699 | */ | 1754 | */ |
1700 | static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp) | 1755 | static void fc_exch_els_rec(struct fc_frame *rfp) |
1701 | { | 1756 | { |
1757 | struct fc_lport *lport; | ||
1702 | struct fc_frame *fp; | 1758 | struct fc_frame *fp; |
1703 | struct fc_exch *ep; | 1759 | struct fc_exch *ep; |
1704 | struct fc_exch_mgr *em; | ||
1705 | struct fc_els_rec *rp; | 1760 | struct fc_els_rec *rp; |
1706 | struct fc_els_rec_acc *acc; | 1761 | struct fc_els_rec_acc *acc; |
1707 | enum fc_els_rjt_reason reason = ELS_RJT_LOGIC; | 1762 | enum fc_els_rjt_reason reason = ELS_RJT_LOGIC; |
@@ -1710,6 +1765,7 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp) | |||
1710 | u16 rxid; | 1765 | u16 rxid; |
1711 | u16 oxid; | 1766 | u16 oxid; |
1712 | 1767 | ||
1768 | lport = fr_dev(rfp); | ||
1713 | rp = fc_frame_payload_get(rfp, sizeof(*rp)); | 1769 | rp = fc_frame_payload_get(rfp, sizeof(*rp)); |
1714 | explan = ELS_EXPL_INV_LEN; | 1770 | explan = ELS_EXPL_INV_LEN; |
1715 | if (!rp) | 1771 | if (!rp) |
@@ -1718,35 +1774,19 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp) | |||
1718 | rxid = ntohs(rp->rec_rx_id); | 1774 | rxid = ntohs(rp->rec_rx_id); |
1719 | oxid = ntohs(rp->rec_ox_id); | 1775 | oxid = ntohs(rp->rec_ox_id); |
1720 | 1776 | ||
1721 | /* | 1777 | ep = fc_exch_lookup(lport, |
1722 | * Currently it's hard to find the local S_ID from the exchange | 1778 | sid == fc_host_port_id(lport->host) ? oxid : rxid); |
1723 | * manager. This will eventually be fixed, but for now it's easier | ||
1724 | * to lookup the subject exchange twice, once as if we were | ||
1725 | * the initiator, and then again if we weren't. | ||
1726 | */ | ||
1727 | em = fc_seq_exch(sp)->em; | ||
1728 | ep = fc_exch_find(em, oxid); | ||
1729 | explan = ELS_EXPL_OXID_RXID; | 1779 | explan = ELS_EXPL_OXID_RXID; |
1730 | if (ep && ep->oid == sid) { | 1780 | if (!ep) |
1731 | if (ep->rxid != FC_XID_UNKNOWN && | 1781 | goto reject; |
1732 | rxid != FC_XID_UNKNOWN && | 1782 | if (ep->oid != sid || oxid != ep->oxid) |
1733 | ep->rxid != rxid) | 1783 | goto rel; |
1734 | goto rel; | 1784 | if (rxid != FC_XID_UNKNOWN && rxid != ep->rxid) |
1735 | } else { | 1785 | goto rel; |
1736 | if (ep) | 1786 | fp = fc_frame_alloc(lport, sizeof(*acc)); |
1737 | fc_exch_release(ep); | 1787 | if (!fp) |
1738 | ep = NULL; | ||
1739 | if (rxid != FC_XID_UNKNOWN) | ||
1740 | ep = fc_exch_find(em, rxid); | ||
1741 | if (!ep) | ||
1742 | goto reject; | ||
1743 | } | ||
1744 | |||
1745 | fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc)); | ||
1746 | if (!fp) { | ||
1747 | fc_exch_done(sp); | ||
1748 | goto out; | 1788 | goto out; |
1749 | } | 1789 | |
1750 | acc = fc_frame_payload_get(fp, sizeof(*acc)); | 1790 | acc = fc_frame_payload_get(fp, sizeof(*acc)); |
1751 | memset(acc, 0, sizeof(*acc)); | 1791 | memset(acc, 0, sizeof(*acc)); |
1752 | acc->reca_cmd = ELS_LS_ACC; | 1792 | acc->reca_cmd = ELS_LS_ACC; |
@@ -1761,18 +1801,16 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp) | |||
1761 | acc->reca_e_stat = htonl(ep->esb_stat & (ESB_ST_RESP | | 1801 | acc->reca_e_stat = htonl(ep->esb_stat & (ESB_ST_RESP | |
1762 | ESB_ST_SEQ_INIT | | 1802 | ESB_ST_SEQ_INIT | |
1763 | ESB_ST_COMPLETE)); | 1803 | ESB_ST_COMPLETE)); |
1764 | sp = fc_seq_start_next(sp); | 1804 | fc_fill_reply_hdr(fp, rfp, FC_RCTL_ELS_REP, 0); |
1765 | fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); | 1805 | lport->tt.frame_send(lport, fp); |
1766 | out: | 1806 | out: |
1767 | fc_exch_release(ep); | 1807 | fc_exch_release(ep); |
1768 | fc_frame_free(rfp); | ||
1769 | return; | 1808 | return; |
1770 | 1809 | ||
1771 | rel: | 1810 | rel: |
1772 | fc_exch_release(ep); | 1811 | fc_exch_release(ep); |
1773 | reject: | 1812 | reject: |
1774 | fc_seq_ls_rjt(sp, reason, explan); | 1813 | fc_seq_ls_rjt(rfp, reason, explan); |
1775 | fc_frame_free(rfp); | ||
1776 | } | 1814 | } |
1777 | 1815 | ||
1778 | /** | 1816 | /** |
@@ -1947,20 +1985,20 @@ retry: | |||
1947 | spin_unlock_bh(&ep->ex_lock); | 1985 | spin_unlock_bh(&ep->ex_lock); |
1948 | } | 1986 | } |
1949 | 1987 | ||
1950 | |||
1951 | /** | 1988 | /** |
1952 | * fc_exch_els_rrq() - Handler for ELS RRQ (Reset Recovery Qualifier) requests | 1989 | * fc_exch_els_rrq() - Handler for ELS RRQ (Reset Recovery Qualifier) requests |
1953 | * @sp: The sequence that the RRQ is on | 1990 | * @fp: The RRQ frame, not freed here. |
1954 | * @fp: The RRQ frame | ||
1955 | */ | 1991 | */ |
1956 | static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp) | 1992 | static void fc_exch_els_rrq(struct fc_frame *fp) |
1957 | { | 1993 | { |
1994 | struct fc_lport *lport; | ||
1958 | struct fc_exch *ep = NULL; /* request or subject exchange */ | 1995 | struct fc_exch *ep = NULL; /* request or subject exchange */ |
1959 | struct fc_els_rrq *rp; | 1996 | struct fc_els_rrq *rp; |
1960 | u32 sid; | 1997 | u32 sid; |
1961 | u16 xid; | 1998 | u16 xid; |
1962 | enum fc_els_rjt_explan explan; | 1999 | enum fc_els_rjt_explan explan; |
1963 | 2000 | ||
2001 | lport = fr_dev(fp); | ||
1964 | rp = fc_frame_payload_get(fp, sizeof(*rp)); | 2002 | rp = fc_frame_payload_get(fp, sizeof(*rp)); |
1965 | explan = ELS_EXPL_INV_LEN; | 2003 | explan = ELS_EXPL_INV_LEN; |
1966 | if (!rp) | 2004 | if (!rp) |
@@ -1969,11 +2007,10 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp) | |||
1969 | /* | 2007 | /* |
1970 | * lookup subject exchange. | 2008 | * lookup subject exchange. |
1971 | */ | 2009 | */ |
1972 | ep = fc_seq_exch(sp); | ||
1973 | sid = ntoh24(rp->rrq_s_id); /* subject source */ | 2010 | sid = ntoh24(rp->rrq_s_id); /* subject source */ |
1974 | xid = ep->did == sid ? ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id); | 2011 | xid = fc_host_port_id(lport->host) == sid ? |
1975 | ep = fc_exch_find(ep->em, xid); | 2012 | ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id); |
1976 | 2013 | ep = fc_exch_lookup(lport, xid); | |
1977 | explan = ELS_EXPL_OXID_RXID; | 2014 | explan = ELS_EXPL_OXID_RXID; |
1978 | if (!ep) | 2015 | if (!ep) |
1979 | goto reject; | 2016 | goto reject; |
@@ -2004,15 +2041,14 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp) | |||
2004 | /* | 2041 | /* |
2005 | * Send LS_ACC. | 2042 | * Send LS_ACC. |
2006 | */ | 2043 | */ |
2007 | fc_seq_ls_acc(sp); | 2044 | fc_seq_ls_acc(fp); |
2008 | goto out; | 2045 | goto out; |
2009 | 2046 | ||
2010 | unlock_reject: | 2047 | unlock_reject: |
2011 | spin_unlock_bh(&ep->ex_lock); | 2048 | spin_unlock_bh(&ep->ex_lock); |
2012 | reject: | 2049 | reject: |
2013 | fc_seq_ls_rjt(sp, ELS_RJT_LOGIC, explan); | 2050 | fc_seq_ls_rjt(fp, ELS_RJT_LOGIC, explan); |
2014 | out: | 2051 | out: |
2015 | fc_frame_free(fp); | ||
2016 | if (ep) | 2052 | if (ep) |
2017 | fc_exch_release(ep); /* drop hold from fc_exch_find */ | 2053 | fc_exch_release(ep); /* drop hold from fc_exch_find */ |
2018 | } | 2054 | } |
@@ -2243,7 +2279,7 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp) | |||
2243 | fc_exch_recv_seq_resp(ema->mp, fp); | 2279 | fc_exch_recv_seq_resp(ema->mp, fp); |
2244 | else if (f_ctl & FC_FC_SEQ_CTX) | 2280 | else if (f_ctl & FC_FC_SEQ_CTX) |
2245 | fc_exch_recv_resp(ema->mp, fp); | 2281 | fc_exch_recv_resp(ema->mp, fp); |
2246 | else | 2282 | else /* no EX_CTX and no SEQ_CTX */ |
2247 | fc_exch_recv_req(lport, ema->mp, fp); | 2283 | fc_exch_recv_req(lport, ema->mp, fp); |
2248 | break; | 2284 | break; |
2249 | default: | 2285 | default: |
@@ -2281,6 +2317,9 @@ int fc_exch_init(struct fc_lport *lport) | |||
2281 | if (!lport->tt.seq_exch_abort) | 2317 | if (!lport->tt.seq_exch_abort) |
2282 | lport->tt.seq_exch_abort = fc_seq_exch_abort; | 2318 | lport->tt.seq_exch_abort = fc_seq_exch_abort; |
2283 | 2319 | ||
2320 | if (!lport->tt.seq_assign) | ||
2321 | lport->tt.seq_assign = fc_seq_assign; | ||
2322 | |||
2284 | return 0; | 2323 | return 0; |
2285 | } | 2324 | } |
2286 | EXPORT_SYMBOL(fc_exch_init); | 2325 | EXPORT_SYMBOL(fc_exch_init); |
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index ec1f66c4a9d4..eac4d09314eb 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c | |||
@@ -580,10 +580,8 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, | |||
580 | fsp, seq_blen, lport->lso_max, t_blen); | 580 | fsp, seq_blen, lport->lso_max, t_blen); |
581 | } | 581 | } |
582 | 582 | ||
583 | WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD); | ||
584 | if (t_blen > 512) | 583 | if (t_blen > 512) |
585 | t_blen &= ~(512 - 1); /* round down to block size */ | 584 | t_blen &= ~(512 - 1); /* round down to block size */ |
586 | WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD); /* won't go below 256 */ | ||
587 | sc = fsp->cmd; | 585 | sc = fsp->cmd; |
588 | 586 | ||
589 | remaining = seq_blen; | 587 | remaining = seq_blen; |
@@ -745,7 +743,7 @@ static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg) | |||
745 | fh = fc_frame_header_get(fp); | 743 | fh = fc_frame_header_get(fp); |
746 | r_ctl = fh->fh_r_ctl; | 744 | r_ctl = fh->fh_r_ctl; |
747 | 745 | ||
748 | if (!(lport->state & LPORT_ST_READY)) | 746 | if (lport->state != LPORT_ST_READY) |
749 | goto out; | 747 | goto out; |
750 | if (fc_fcp_lock_pkt(fsp)) | 748 | if (fc_fcp_lock_pkt(fsp)) |
751 | goto out; | 749 | goto out; |
@@ -1110,7 +1108,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp, | |||
1110 | 1108 | ||
1111 | fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id, | 1109 | fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id, |
1112 | rpriv->local_port->port_id, FC_TYPE_FCP, | 1110 | rpriv->local_port->port_id, FC_TYPE_FCP, |
1113 | FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); | 1111 | FC_FCTL_REQ, 0); |
1114 | 1112 | ||
1115 | seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy, | 1113 | seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy, |
1116 | fsp, 0); | 1114 | fsp, 0); |
@@ -1383,7 +1381,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) | |||
1383 | fr_seq(fp) = fsp->seq_ptr; | 1381 | fr_seq(fp) = fsp->seq_ptr; |
1384 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id, | 1382 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id, |
1385 | rpriv->local_port->port_id, FC_TYPE_ELS, | 1383 | rpriv->local_port->port_id, FC_TYPE_ELS, |
1386 | FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); | 1384 | FC_FCTL_REQ, 0); |
1387 | if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC, | 1385 | if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC, |
1388 | fc_fcp_rec_resp, fsp, | 1386 | fc_fcp_rec_resp, fsp, |
1389 | jiffies_to_msecs(FC_SCSI_REC_TOV))) { | 1387 | jiffies_to_msecs(FC_SCSI_REC_TOV))) { |
@@ -1641,7 +1639,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) | |||
1641 | 1639 | ||
1642 | fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id, | 1640 | fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id, |
1643 | rpriv->local_port->port_id, FC_TYPE_FCP, | 1641 | rpriv->local_port->port_id, FC_TYPE_FCP, |
1644 | FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); | 1642 | FC_FCTL_REQ, 0); |
1645 | 1643 | ||
1646 | seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL, | 1644 | seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL, |
1647 | fsp, jiffies_to_msecs(FC_SCSI_REC_TOV)); | 1645 | fsp, jiffies_to_msecs(FC_SCSI_REC_TOV)); |
@@ -1973,6 +1971,11 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) | |||
1973 | break; | 1971 | break; |
1974 | } | 1972 | } |
1975 | 1973 | ||
1974 | if (lport->state != LPORT_ST_READY && fsp->status_code != FC_COMPLETE) { | ||
1975 | sc_cmd->result = (DID_REQUEUE << 16); | ||
1976 | FC_FCP_DBG(fsp, "Returning DID_REQUEUE to scsi-ml\n"); | ||
1977 | } | ||
1978 | |||
1976 | spin_lock_irqsave(&si->scsi_queue_lock, flags); | 1979 | spin_lock_irqsave(&si->scsi_queue_lock, flags); |
1977 | list_del(&fsp->list); | 1980 | list_del(&fsp->list); |
1978 | spin_unlock_irqrestore(&si->scsi_queue_lock, flags); | 1981 | spin_unlock_irqrestore(&si->scsi_queue_lock, flags); |
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c index 39f4b6ab04b4..6a48c28e4420 100644 --- a/drivers/scsi/libfc/fc_libfc.c +++ b/drivers/scsi/libfc/fc_libfc.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/crc32.h> | 23 | #include <linux/crc32.h> |
24 | 24 | ||
25 | #include <scsi/libfc.h> | 25 | #include <scsi/libfc.h> |
26 | #include <scsi/fc_encode.h> | ||
26 | 27 | ||
27 | #include "fc_libfc.h" | 28 | #include "fc_libfc.h" |
28 | 29 | ||
@@ -132,3 +133,80 @@ u32 fc_copy_buffer_to_sglist(void *buf, size_t len, | |||
132 | } | 133 | } |
133 | return copy_len; | 134 | return copy_len; |
134 | } | 135 | } |
136 | |||
137 | /** | ||
138 | * fc_fill_hdr() - fill FC header fields based on request | ||
139 | * @fp: reply frame containing header to be filled in | ||
140 | * @in_fp: request frame containing header to use in filling in reply | ||
141 | * @r_ctl: R_CTL value for header | ||
142 | * @f_ctl: F_CTL value for header, with 0 pad | ||
143 | * @seq_cnt: sequence count for the header, ignored if frame has a sequence | ||
144 | * @parm_offset: parameter / offset value | ||
145 | */ | ||
146 | void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp, | ||
147 | enum fc_rctl r_ctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset) | ||
148 | { | ||
149 | struct fc_frame_header *fh; | ||
150 | struct fc_frame_header *in_fh; | ||
151 | struct fc_seq *sp; | ||
152 | u32 fill; | ||
153 | |||
154 | fh = __fc_frame_header_get(fp); | ||
155 | in_fh = __fc_frame_header_get(in_fp); | ||
156 | |||
157 | if (f_ctl & FC_FC_END_SEQ) { | ||
158 | fill = -fr_len(fp) & 3; | ||
159 | if (fill) { | ||
160 | /* TODO, this may be a problem with fragmented skb */ | ||
161 | memset(skb_put(fp_skb(fp), fill), 0, fill); | ||
162 | f_ctl |= fill; | ||
163 | } | ||
164 | fr_eof(fp) = FC_EOF_T; | ||
165 | } else { | ||
166 | WARN_ON(fr_len(fp) % 4 != 0); /* no pad to non last frame */ | ||
167 | fr_eof(fp) = FC_EOF_N; | ||
168 | } | ||
169 | |||
170 | fh->fh_r_ctl = r_ctl; | ||
171 | memcpy(fh->fh_d_id, in_fh->fh_s_id, sizeof(fh->fh_d_id)); | ||
172 | memcpy(fh->fh_s_id, in_fh->fh_d_id, sizeof(fh->fh_s_id)); | ||
173 | fh->fh_type = in_fh->fh_type; | ||
174 | hton24(fh->fh_f_ctl, f_ctl); | ||
175 | fh->fh_ox_id = in_fh->fh_ox_id; | ||
176 | fh->fh_rx_id = in_fh->fh_rx_id; | ||
177 | fh->fh_cs_ctl = 0; | ||
178 | fh->fh_df_ctl = 0; | ||
179 | fh->fh_parm_offset = htonl(parm_offset); | ||
180 | |||
181 | sp = fr_seq(in_fp); | ||
182 | if (sp) { | ||
183 | fr_seq(fp) = sp; | ||
184 | fh->fh_seq_id = sp->id; | ||
185 | seq_cnt = sp->cnt; | ||
186 | } else { | ||
187 | fh->fh_seq_id = 0; | ||
188 | } | ||
189 | fh->fh_seq_cnt = ntohs(seq_cnt); | ||
190 | fr_sof(fp) = seq_cnt ? FC_SOF_N3 : FC_SOF_I3; | ||
191 | fr_encaps(fp) = fr_encaps(in_fp); | ||
192 | } | ||
193 | EXPORT_SYMBOL(fc_fill_hdr); | ||
194 | |||
195 | /** | ||
196 | * fc_fill_reply_hdr() - fill FC reply header fields based on request | ||
197 | * @fp: reply frame containing header to be filled in | ||
198 | * @in_fp: request frame containing header to use in filling in reply | ||
199 | * @r_ctl: R_CTL value for reply | ||
200 | * @parm_offset: parameter / offset value | ||
201 | */ | ||
202 | void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp, | ||
203 | enum fc_rctl r_ctl, u32 parm_offset) | ||
204 | { | ||
205 | struct fc_seq *sp; | ||
206 | |||
207 | sp = fr_seq(in_fp); | ||
208 | if (sp) | ||
209 | fr_seq(fp) = fr_dev(in_fp)->tt.seq_start_next(sp); | ||
210 | fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset); | ||
211 | } | ||
212 | EXPORT_SYMBOL(fc_fill_reply_hdr); | ||
diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h index f5c0ca4b6ef8..16d2162dda1f 100644 --- a/drivers/scsi/libfc/fc_libfc.h +++ b/drivers/scsi/libfc/fc_libfc.h | |||
@@ -52,7 +52,7 @@ extern unsigned int fc_debug_logging; | |||
52 | #define FC_DISC_DBG(disc, fmt, args...) \ | 52 | #define FC_DISC_DBG(disc, fmt, args...) \ |
53 | FC_CHECK_LOGGING(FC_DISC_LOGGING, \ | 53 | FC_CHECK_LOGGING(FC_DISC_LOGGING, \ |
54 | printk(KERN_INFO "host%u: disc: " fmt, \ | 54 | printk(KERN_INFO "host%u: disc: " fmt, \ |
55 | (disc)->lport->host->host_no, \ | 55 | fc_disc_lport(disc)->host->host_no, \ |
56 | ##args)) | 56 | ##args)) |
57 | 57 | ||
58 | #define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \ | 58 | #define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \ |
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 79c9e3ccd341..6eb334a8a7fa 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c | |||
@@ -375,41 +375,36 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) | |||
375 | 375 | ||
376 | /** | 376 | /** |
377 | * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report. | 377 | * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report. |
378 | * @sp: The sequence in the RLIR exchange | ||
379 | * @fp: The RLIR request frame | ||
380 | * @lport: Fibre Channel local port recieving the RLIR | 378 | * @lport: Fibre Channel local port recieving the RLIR |
379 | * @fp: The RLIR request frame | ||
381 | * | 380 | * |
382 | * Locking Note: The lport lock is expected to be held before calling | 381 | * Locking Note: The lport lock is expected to be held before calling |
383 | * this function. | 382 | * this function. |
384 | */ | 383 | */ |
385 | static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp, | 384 | static void fc_lport_recv_rlir_req(struct fc_lport *lport, struct fc_frame *fp) |
386 | struct fc_lport *lport) | ||
387 | { | 385 | { |
388 | FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n", | 386 | FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n", |
389 | fc_lport_state(lport)); | 387 | fc_lport_state(lport)); |
390 | 388 | ||
391 | lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); | 389 | lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); |
392 | fc_frame_free(fp); | 390 | fc_frame_free(fp); |
393 | } | 391 | } |
394 | 392 | ||
395 | /** | 393 | /** |
396 | * fc_lport_recv_echo_req() - Handle received ECHO request | 394 | * fc_lport_recv_echo_req() - Handle received ECHO request |
397 | * @sp: The sequence in the ECHO exchange | ||
398 | * @fp: ECHO request frame | ||
399 | * @lport: The local port recieving the ECHO | 395 | * @lport: The local port recieving the ECHO |
396 | * @fp: ECHO request frame | ||
400 | * | 397 | * |
401 | * Locking Note: The lport lock is expected to be held before calling | 398 | * Locking Note: The lport lock is expected to be held before calling |
402 | * this function. | 399 | * this function. |
403 | */ | 400 | */ |
404 | static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, | 401 | static void fc_lport_recv_echo_req(struct fc_lport *lport, |
405 | struct fc_lport *lport) | 402 | struct fc_frame *in_fp) |
406 | { | 403 | { |
407 | struct fc_frame *fp; | 404 | struct fc_frame *fp; |
408 | struct fc_exch *ep = fc_seq_exch(sp); | ||
409 | unsigned int len; | 405 | unsigned int len; |
410 | void *pp; | 406 | void *pp; |
411 | void *dp; | 407 | void *dp; |
412 | u32 f_ctl; | ||
413 | 408 | ||
414 | FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n", | 409 | FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n", |
415 | fc_lport_state(lport)); | 410 | fc_lport_state(lport)); |
@@ -425,29 +420,24 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, | |||
425 | dp = fc_frame_payload_get(fp, len); | 420 | dp = fc_frame_payload_get(fp, len); |
426 | memcpy(dp, pp, len); | 421 | memcpy(dp, pp, len); |
427 | *((__be32 *)dp) = htonl(ELS_LS_ACC << 24); | 422 | *((__be32 *)dp) = htonl(ELS_LS_ACC << 24); |
428 | sp = lport->tt.seq_start_next(sp); | 423 | fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0); |
429 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; | 424 | lport->tt.frame_send(lport, fp); |
430 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, | ||
431 | FC_TYPE_ELS, f_ctl, 0); | ||
432 | lport->tt.seq_send(lport, sp, fp); | ||
433 | } | 425 | } |
434 | fc_frame_free(in_fp); | 426 | fc_frame_free(in_fp); |
435 | } | 427 | } |
436 | 428 | ||
437 | /** | 429 | /** |
438 | * fc_lport_recv_rnid_req() - Handle received Request Node ID data request | 430 | * fc_lport_recv_rnid_req() - Handle received Request Node ID data request |
439 | * @sp: The sequence in the RNID exchange | ||
440 | * @fp: The RNID request frame | ||
441 | * @lport: The local port recieving the RNID | 431 | * @lport: The local port recieving the RNID |
432 | * @fp: The RNID request frame | ||
442 | * | 433 | * |
443 | * Locking Note: The lport lock is expected to be held before calling | 434 | * Locking Note: The lport lock is expected to be held before calling |
444 | * this function. | 435 | * this function. |
445 | */ | 436 | */ |
446 | static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, | 437 | static void fc_lport_recv_rnid_req(struct fc_lport *lport, |
447 | struct fc_lport *lport) | 438 | struct fc_frame *in_fp) |
448 | { | 439 | { |
449 | struct fc_frame *fp; | 440 | struct fc_frame *fp; |
450 | struct fc_exch *ep = fc_seq_exch(sp); | ||
451 | struct fc_els_rnid *req; | 441 | struct fc_els_rnid *req; |
452 | struct { | 442 | struct { |
453 | struct fc_els_rnid_resp rnid; | 443 | struct fc_els_rnid_resp rnid; |
@@ -457,17 +447,15 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, | |||
457 | struct fc_seq_els_data rjt_data; | 447 | struct fc_seq_els_data rjt_data; |
458 | u8 fmt; | 448 | u8 fmt; |
459 | size_t len; | 449 | size_t len; |
460 | u32 f_ctl; | ||
461 | 450 | ||
462 | FC_LPORT_DBG(lport, "Received RNID request while in state %s\n", | 451 | FC_LPORT_DBG(lport, "Received RNID request while in state %s\n", |
463 | fc_lport_state(lport)); | 452 | fc_lport_state(lport)); |
464 | 453 | ||
465 | req = fc_frame_payload_get(in_fp, sizeof(*req)); | 454 | req = fc_frame_payload_get(in_fp, sizeof(*req)); |
466 | if (!req) { | 455 | if (!req) { |
467 | rjt_data.fp = NULL; | ||
468 | rjt_data.reason = ELS_RJT_LOGIC; | 456 | rjt_data.reason = ELS_RJT_LOGIC; |
469 | rjt_data.explan = ELS_EXPL_NONE; | 457 | rjt_data.explan = ELS_EXPL_NONE; |
470 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | 458 | lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data); |
471 | } else { | 459 | } else { |
472 | fmt = req->rnid_fmt; | 460 | fmt = req->rnid_fmt; |
473 | len = sizeof(*rp); | 461 | len = sizeof(*rp); |
@@ -490,12 +478,8 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, | |||
490 | memcpy(&rp->gen, &lport->rnid_gen, | 478 | memcpy(&rp->gen, &lport->rnid_gen, |
491 | sizeof(rp->gen)); | 479 | sizeof(rp->gen)); |
492 | } | 480 | } |
493 | sp = lport->tt.seq_start_next(sp); | 481 | fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0); |
494 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; | 482 | lport->tt.frame_send(lport, fp); |
495 | f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; | ||
496 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, | ||
497 | FC_TYPE_ELS, f_ctl, 0); | ||
498 | lport->tt.seq_send(lport, sp, fp); | ||
499 | } | 483 | } |
500 | } | 484 | } |
501 | fc_frame_free(in_fp); | 485 | fc_frame_free(in_fp); |
@@ -503,17 +487,15 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, | |||
503 | 487 | ||
504 | /** | 488 | /** |
505 | * fc_lport_recv_logo_req() - Handle received fabric LOGO request | 489 | * fc_lport_recv_logo_req() - Handle received fabric LOGO request |
506 | * @sp: The sequence in the LOGO exchange | ||
507 | * @fp: The LOGO request frame | ||
508 | * @lport: The local port recieving the LOGO | 490 | * @lport: The local port recieving the LOGO |
491 | * @fp: The LOGO request frame | ||
509 | * | 492 | * |
510 | * Locking Note: The lport lock is exected to be held before calling | 493 | * Locking Note: The lport lock is exected to be held before calling |
511 | * this function. | 494 | * this function. |
512 | */ | 495 | */ |
513 | static void fc_lport_recv_logo_req(struct fc_seq *sp, struct fc_frame *fp, | 496 | static void fc_lport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) |
514 | struct fc_lport *lport) | ||
515 | { | 497 | { |
516 | lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); | 498 | lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); |
517 | fc_lport_enter_reset(lport); | 499 | fc_lport_enter_reset(lport); |
518 | fc_frame_free(fp); | 500 | fc_frame_free(fp); |
519 | } | 501 | } |
@@ -755,10 +737,37 @@ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id, | |||
755 | } | 737 | } |
756 | 738 | ||
757 | /** | 739 | /** |
740 | * fc_lport_set_port_id() - set the local port Port ID for point-to-multipoint | ||
741 | * @lport: The local port which will have its Port ID set. | ||
742 | * @port_id: The new port ID. | ||
743 | * | ||
744 | * Called by the lower-level driver when transport sets the local port_id. | ||
745 | * This is used in VN_port to VN_port mode for FCoE, and causes FLOGI and | ||
746 | * discovery to be skipped. | ||
747 | */ | ||
748 | void fc_lport_set_local_id(struct fc_lport *lport, u32 port_id) | ||
749 | { | ||
750 | mutex_lock(&lport->lp_mutex); | ||
751 | |||
752 | fc_lport_set_port_id(lport, port_id, NULL); | ||
753 | |||
754 | switch (lport->state) { | ||
755 | case LPORT_ST_RESET: | ||
756 | case LPORT_ST_FLOGI: | ||
757 | if (port_id) | ||
758 | fc_lport_enter_ready(lport); | ||
759 | break; | ||
760 | default: | ||
761 | break; | ||
762 | } | ||
763 | mutex_unlock(&lport->lp_mutex); | ||
764 | } | ||
765 | EXPORT_SYMBOL(fc_lport_set_local_id); | ||
766 | |||
767 | /** | ||
758 | * fc_lport_recv_flogi_req() - Receive a FLOGI request | 768 | * fc_lport_recv_flogi_req() - Receive a FLOGI request |
759 | * @sp_in: The sequence the FLOGI is on | ||
760 | * @rx_fp: The FLOGI frame | ||
761 | * @lport: The local port that recieved the request | 769 | * @lport: The local port that recieved the request |
770 | * @rx_fp: The FLOGI frame | ||
762 | * | 771 | * |
763 | * A received FLOGI request indicates a point-to-point connection. | 772 | * A received FLOGI request indicates a point-to-point connection. |
764 | * Accept it with the common service parameters indicating our N port. | 773 | * Accept it with the common service parameters indicating our N port. |
@@ -767,26 +776,21 @@ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id, | |||
767 | * Locking Note: The lport lock is expected to be held before calling | 776 | * Locking Note: The lport lock is expected to be held before calling |
768 | * this function. | 777 | * this function. |
769 | */ | 778 | */ |
770 | static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, | 779 | static void fc_lport_recv_flogi_req(struct fc_lport *lport, |
771 | struct fc_frame *rx_fp, | 780 | struct fc_frame *rx_fp) |
772 | struct fc_lport *lport) | ||
773 | { | 781 | { |
774 | struct fc_frame *fp; | 782 | struct fc_frame *fp; |
775 | struct fc_frame_header *fh; | 783 | struct fc_frame_header *fh; |
776 | struct fc_seq *sp; | ||
777 | struct fc_exch *ep; | ||
778 | struct fc_els_flogi *flp; | 784 | struct fc_els_flogi *flp; |
779 | struct fc_els_flogi *new_flp; | 785 | struct fc_els_flogi *new_flp; |
780 | u64 remote_wwpn; | 786 | u64 remote_wwpn; |
781 | u32 remote_fid; | 787 | u32 remote_fid; |
782 | u32 local_fid; | 788 | u32 local_fid; |
783 | u32 f_ctl; | ||
784 | 789 | ||
785 | FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n", | 790 | FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n", |
786 | fc_lport_state(lport)); | 791 | fc_lport_state(lport)); |
787 | 792 | ||
788 | fh = fc_frame_header_get(rx_fp); | 793 | remote_fid = fc_frame_sid(rx_fp); |
789 | remote_fid = ntoh24(fh->fh_s_id); | ||
790 | flp = fc_frame_payload_get(rx_fp, sizeof(*flp)); | 794 | flp = fc_frame_payload_get(rx_fp, sizeof(*flp)); |
791 | if (!flp) | 795 | if (!flp) |
792 | goto out; | 796 | goto out; |
@@ -817,7 +821,6 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, | |||
817 | 821 | ||
818 | fp = fc_frame_alloc(lport, sizeof(*flp)); | 822 | fp = fc_frame_alloc(lport, sizeof(*flp)); |
819 | if (fp) { | 823 | if (fp) { |
820 | sp = lport->tt.seq_start_next(fr_seq(rx_fp)); | ||
821 | new_flp = fc_frame_payload_get(fp, sizeof(*flp)); | 824 | new_flp = fc_frame_payload_get(fp, sizeof(*flp)); |
822 | fc_lport_flogi_fill(lport, new_flp, ELS_FLOGI); | 825 | fc_lport_flogi_fill(lport, new_flp, ELS_FLOGI); |
823 | new_flp->fl_cmd = (u8) ELS_LS_ACC; | 826 | new_flp->fl_cmd = (u8) ELS_LS_ACC; |
@@ -826,27 +829,24 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, | |||
826 | * Send the response. If this fails, the originator should | 829 | * Send the response. If this fails, the originator should |
827 | * repeat the sequence. | 830 | * repeat the sequence. |
828 | */ | 831 | */ |
829 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; | 832 | fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); |
830 | ep = fc_seq_exch(sp); | 833 | fh = fc_frame_header_get(fp); |
831 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, remote_fid, local_fid, | 834 | hton24(fh->fh_s_id, local_fid); |
832 | FC_TYPE_ELS, f_ctl, 0); | 835 | hton24(fh->fh_d_id, remote_fid); |
833 | lport->tt.seq_send(lport, sp, fp); | 836 | lport->tt.frame_send(lport, fp); |
834 | 837 | ||
835 | } else { | 838 | } else { |
836 | fc_lport_error(lport, fp); | 839 | fc_lport_error(lport, fp); |
837 | } | 840 | } |
838 | fc_lport_ptp_setup(lport, remote_fid, remote_wwpn, | 841 | fc_lport_ptp_setup(lport, remote_fid, remote_wwpn, |
839 | get_unaligned_be64(&flp->fl_wwnn)); | 842 | get_unaligned_be64(&flp->fl_wwnn)); |
840 | |||
841 | out: | 843 | out: |
842 | sp = fr_seq(rx_fp); | ||
843 | fc_frame_free(rx_fp); | 844 | fc_frame_free(rx_fp); |
844 | } | 845 | } |
845 | 846 | ||
846 | /** | 847 | /** |
847 | * fc_lport_recv_req() - The generic lport request handler | 848 | * fc_lport_recv_req() - The generic lport request handler |
848 | * @lport: The local port that received the request | 849 | * @lport: The local port that received the request |
849 | * @sp: The sequence the request is on | ||
850 | * @fp: The request frame | 850 | * @fp: The request frame |
851 | * | 851 | * |
852 | * This function will see if the lport handles the request or | 852 | * This function will see if the lport handles the request or |
@@ -855,11 +855,10 @@ out: | |||
855 | * Locking Note: This function should not be called with the lport | 855 | * Locking Note: This function should not be called with the lport |
856 | * lock held becuase it will grab the lock. | 856 | * lock held becuase it will grab the lock. |
857 | */ | 857 | */ |
858 | static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, | 858 | static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp) |
859 | struct fc_frame *fp) | ||
860 | { | 859 | { |
861 | struct fc_frame_header *fh = fc_frame_header_get(fp); | 860 | struct fc_frame_header *fh = fc_frame_header_get(fp); |
862 | void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *); | 861 | void (*recv)(struct fc_lport *, struct fc_frame *); |
863 | 862 | ||
864 | mutex_lock(&lport->lp_mutex); | 863 | mutex_lock(&lport->lp_mutex); |
865 | 864 | ||
@@ -878,11 +877,11 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, | |||
878 | recv = lport->tt.rport_recv_req; | 877 | recv = lport->tt.rport_recv_req; |
879 | switch (fc_frame_payload_op(fp)) { | 878 | switch (fc_frame_payload_op(fp)) { |
880 | case ELS_FLOGI: | 879 | case ELS_FLOGI: |
881 | recv = fc_lport_recv_flogi_req; | 880 | if (!lport->point_to_multipoint) |
881 | recv = fc_lport_recv_flogi_req; | ||
882 | break; | 882 | break; |
883 | case ELS_LOGO: | 883 | case ELS_LOGO: |
884 | fh = fc_frame_header_get(fp); | 884 | if (fc_frame_sid(fp) == FC_FID_FLOGI) |
885 | if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) | ||
886 | recv = fc_lport_recv_logo_req; | 885 | recv = fc_lport_recv_logo_req; |
887 | break; | 886 | break; |
888 | case ELS_RSCN: | 887 | case ELS_RSCN: |
@@ -899,19 +898,13 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, | |||
899 | break; | 898 | break; |
900 | } | 899 | } |
901 | 900 | ||
902 | recv(sp, fp, lport); | 901 | recv(lport, fp); |
903 | } else { | 902 | } else { |
904 | FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n", | 903 | FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n", |
905 | fr_eof(fp)); | 904 | fr_eof(fp)); |
906 | fc_frame_free(fp); | 905 | fc_frame_free(fp); |
907 | } | 906 | } |
908 | mutex_unlock(&lport->lp_mutex); | 907 | mutex_unlock(&lport->lp_mutex); |
909 | |||
910 | /* | ||
911 | * The common exch_done for all request may not be good | ||
912 | * if any request requires longer hold on exhange. XXX | ||
913 | */ | ||
914 | lport->tt.exch_done(sp); | ||
915 | } | 908 | } |
916 | 909 | ||
917 | /** | 910 | /** |
@@ -954,7 +947,7 @@ static void fc_lport_reset_locked(struct fc_lport *lport) | |||
954 | lport->tt.exch_mgr_reset(lport, 0, 0); | 947 | lport->tt.exch_mgr_reset(lport, 0, 0); |
955 | fc_host_fabric_name(lport->host) = 0; | 948 | fc_host_fabric_name(lport->host) = 0; |
956 | 949 | ||
957 | if (lport->port_id) | 950 | if (lport->port_id && (!lport->point_to_multipoint || !lport->link_up)) |
958 | fc_lport_set_port_id(lport, 0, NULL); | 951 | fc_lport_set_port_id(lport, 0, NULL); |
959 | } | 952 | } |
960 | 953 | ||
@@ -1019,38 +1012,24 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) | |||
1019 | PTR_ERR(fp), fc_lport_state(lport), | 1012 | PTR_ERR(fp), fc_lport_state(lport), |
1020 | lport->retry_count); | 1013 | lport->retry_count); |
1021 | 1014 | ||
1022 | if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) { | 1015 | if (PTR_ERR(fp) == -FC_EX_CLOSED) |
1023 | /* | 1016 | return; |
1024 | * Memory allocation failure, or the exchange timed out. | 1017 | |
1025 | * Retry after delay | 1018 | /* |
1026 | */ | 1019 | * Memory allocation failure, or the exchange timed out |
1027 | if (lport->retry_count < lport->max_retry_count) { | 1020 | * or we received LS_RJT. |
1028 | lport->retry_count++; | 1021 | * Retry after delay |
1029 | if (!fp) | 1022 | */ |
1030 | delay = msecs_to_jiffies(500); | 1023 | if (lport->retry_count < lport->max_retry_count) { |
1031 | else | 1024 | lport->retry_count++; |
1032 | delay = msecs_to_jiffies(lport->e_d_tov); | 1025 | if (!fp) |
1033 | 1026 | delay = msecs_to_jiffies(500); | |
1034 | schedule_delayed_work(&lport->retry_work, delay); | 1027 | else |
1035 | } else { | 1028 | delay = msecs_to_jiffies(lport->e_d_tov); |
1036 | switch (lport->state) { | 1029 | |
1037 | case LPORT_ST_DISABLED: | 1030 | schedule_delayed_work(&lport->retry_work, delay); |
1038 | case LPORT_ST_READY: | 1031 | } else |
1039 | case LPORT_ST_RESET: | 1032 | fc_lport_enter_reset(lport); |
1040 | case LPORT_ST_RNN_ID: | ||
1041 | case LPORT_ST_RSNN_NN: | ||
1042 | case LPORT_ST_RSPN_ID: | ||
1043 | case LPORT_ST_RFT_ID: | ||
1044 | case LPORT_ST_RFF_ID: | ||
1045 | case LPORT_ST_SCR: | ||
1046 | case LPORT_ST_DNS: | ||
1047 | case LPORT_ST_FLOGI: | ||
1048 | case LPORT_ST_LOGO: | ||
1049 | fc_lport_enter_reset(lport); | ||
1050 | break; | ||
1051 | } | ||
1052 | } | ||
1053 | } | ||
1054 | } | 1033 | } |
1055 | 1034 | ||
1056 | /** | 1035 | /** |
@@ -1440,7 +1419,6 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
1440 | void *lp_arg) | 1419 | void *lp_arg) |
1441 | { | 1420 | { |
1442 | struct fc_lport *lport = lp_arg; | 1421 | struct fc_lport *lport = lp_arg; |
1443 | struct fc_frame_header *fh; | ||
1444 | struct fc_els_flogi *flp; | 1422 | struct fc_els_flogi *flp; |
1445 | u32 did; | 1423 | u32 did; |
1446 | u16 csp_flags; | 1424 | u16 csp_flags; |
@@ -1468,9 +1446,14 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
1468 | goto err; | 1446 | goto err; |
1469 | } | 1447 | } |
1470 | 1448 | ||
1471 | fh = fc_frame_header_get(fp); | 1449 | did = fc_frame_did(fp); |
1472 | did = ntoh24(fh->fh_d_id); | 1450 | |
1473 | if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) { | 1451 | if (!did) { |
1452 | FC_LPORT_DBG(lport, "Bad FLOGI response\n"); | ||
1453 | goto out; | ||
1454 | } | ||
1455 | |||
1456 | if (fc_frame_payload_op(fp) == ELS_LS_ACC) { | ||
1474 | flp = fc_frame_payload_get(fp, sizeof(*flp)); | 1457 | flp = fc_frame_payload_get(fp, sizeof(*flp)); |
1475 | if (flp) { | 1458 | if (flp) { |
1476 | mfs = ntohs(flp->fl_csp.sp_bb_data) & | 1459 | mfs = ntohs(flp->fl_csp.sp_bb_data) & |
@@ -1495,7 +1478,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
1495 | "Port (%6.6x) entered " | 1478 | "Port (%6.6x) entered " |
1496 | "point-to-point mode\n", | 1479 | "point-to-point mode\n", |
1497 | lport->host->host_no, did); | 1480 | lport->host->host_no, did); |
1498 | fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id), | 1481 | fc_lport_ptp_setup(lport, fc_frame_sid(fp), |
1499 | get_unaligned_be64( | 1482 | get_unaligned_be64( |
1500 | &flp->fl_wwpn), | 1483 | &flp->fl_wwpn), |
1501 | get_unaligned_be64( | 1484 | get_unaligned_be64( |
@@ -1509,9 +1492,8 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
1509 | fc_lport_enter_dns(lport); | 1492 | fc_lport_enter_dns(lport); |
1510 | } | 1493 | } |
1511 | } | 1494 | } |
1512 | } else { | 1495 | } else |
1513 | FC_LPORT_DBG(lport, "Bad FLOGI response\n"); | 1496 | fc_lport_error(lport, fp); |
1514 | } | ||
1515 | 1497 | ||
1516 | out: | 1498 | out: |
1517 | fc_frame_free(fp); | 1499 | fc_frame_free(fp); |
@@ -1536,6 +1518,12 @@ void fc_lport_enter_flogi(struct fc_lport *lport) | |||
1536 | 1518 | ||
1537 | fc_lport_state_enter(lport, LPORT_ST_FLOGI); | 1519 | fc_lport_state_enter(lport, LPORT_ST_FLOGI); |
1538 | 1520 | ||
1521 | if (lport->point_to_multipoint) { | ||
1522 | if (lport->port_id) | ||
1523 | fc_lport_enter_ready(lport); | ||
1524 | return; | ||
1525 | } | ||
1526 | |||
1539 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); | 1527 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); |
1540 | if (!fp) | 1528 | if (!fp) |
1541 | return fc_lport_error(lport, fp); | 1529 | return fc_lport_error(lport, fp); |
@@ -1701,8 +1689,7 @@ static int fc_lport_els_request(struct fc_bsg_job *job, | |||
1701 | hton24(fh->fh_d_id, did); | 1689 | hton24(fh->fh_d_id, did); |
1702 | hton24(fh->fh_s_id, lport->port_id); | 1690 | hton24(fh->fh_s_id, lport->port_id); |
1703 | fh->fh_type = FC_TYPE_ELS; | 1691 | fh->fh_type = FC_TYPE_ELS; |
1704 | hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ | | 1692 | hton24(fh->fh_f_ctl, FC_FCTL_REQ); |
1705 | FC_FC_END_SEQ | FC_FC_SEQ_INIT); | ||
1706 | fh->fh_cs_ctl = 0; | 1693 | fh->fh_cs_ctl = 0; |
1707 | fh->fh_df_ctl = 0; | 1694 | fh->fh_df_ctl = 0; |
1708 | fh->fh_parm_offset = 0; | 1695 | fh->fh_parm_offset = 0; |
@@ -1761,8 +1748,7 @@ static int fc_lport_ct_request(struct fc_bsg_job *job, | |||
1761 | hton24(fh->fh_d_id, did); | 1748 | hton24(fh->fh_d_id, did); |
1762 | hton24(fh->fh_s_id, lport->port_id); | 1749 | hton24(fh->fh_s_id, lport->port_id); |
1763 | fh->fh_type = FC_TYPE_CT; | 1750 | fh->fh_type = FC_TYPE_CT; |
1764 | hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ | | 1751 | hton24(fh->fh_f_ctl, FC_FCTL_REQ); |
1765 | FC_FC_END_SEQ | FC_FC_SEQ_INIT); | ||
1766 | fh->fh_cs_ctl = 0; | 1752 | fh->fh_cs_ctl = 0; |
1767 | fh->fh_df_ctl = 0; | 1753 | fh->fh_df_ctl = 0; |
1768 | fh->fh_parm_offset = 0; | 1754 | fh->fh_parm_offset = 0; |
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 39e440f0f54a..25479cc7f170 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c | |||
@@ -60,6 +60,7 @@ | |||
60 | 60 | ||
61 | struct workqueue_struct *rport_event_queue; | 61 | struct workqueue_struct *rport_event_queue; |
62 | 62 | ||
63 | static void fc_rport_enter_flogi(struct fc_rport_priv *); | ||
63 | static void fc_rport_enter_plogi(struct fc_rport_priv *); | 64 | static void fc_rport_enter_plogi(struct fc_rport_priv *); |
64 | static void fc_rport_enter_prli(struct fc_rport_priv *); | 65 | static void fc_rport_enter_prli(struct fc_rport_priv *); |
65 | static void fc_rport_enter_rtv(struct fc_rport_priv *); | 66 | static void fc_rport_enter_rtv(struct fc_rport_priv *); |
@@ -67,14 +68,10 @@ static void fc_rport_enter_ready(struct fc_rport_priv *); | |||
67 | static void fc_rport_enter_logo(struct fc_rport_priv *); | 68 | static void fc_rport_enter_logo(struct fc_rport_priv *); |
68 | static void fc_rport_enter_adisc(struct fc_rport_priv *); | 69 | static void fc_rport_enter_adisc(struct fc_rport_priv *); |
69 | 70 | ||
70 | static void fc_rport_recv_plogi_req(struct fc_lport *, | 71 | static void fc_rport_recv_plogi_req(struct fc_lport *, struct fc_frame *); |
71 | struct fc_seq *, struct fc_frame *); | 72 | static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_frame *); |
72 | static void fc_rport_recv_prli_req(struct fc_rport_priv *, | 73 | static void fc_rport_recv_prlo_req(struct fc_rport_priv *, struct fc_frame *); |
73 | struct fc_seq *, struct fc_frame *); | 74 | static void fc_rport_recv_logo_req(struct fc_lport *, struct fc_frame *); |
74 | static void fc_rport_recv_prlo_req(struct fc_rport_priv *, | ||
75 | struct fc_seq *, struct fc_frame *); | ||
76 | static void fc_rport_recv_logo_req(struct fc_lport *, | ||
77 | struct fc_seq *, struct fc_frame *); | ||
78 | static void fc_rport_timeout(struct work_struct *); | 75 | static void fc_rport_timeout(struct work_struct *); |
79 | static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *); | 76 | static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *); |
80 | static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *); | 77 | static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *); |
@@ -82,27 +79,29 @@ static void fc_rport_work(struct work_struct *); | |||
82 | 79 | ||
83 | static const char *fc_rport_state_names[] = { | 80 | static const char *fc_rport_state_names[] = { |
84 | [RPORT_ST_INIT] = "Init", | 81 | [RPORT_ST_INIT] = "Init", |
82 | [RPORT_ST_FLOGI] = "FLOGI", | ||
83 | [RPORT_ST_PLOGI_WAIT] = "PLOGI_WAIT", | ||
85 | [RPORT_ST_PLOGI] = "PLOGI", | 84 | [RPORT_ST_PLOGI] = "PLOGI", |
86 | [RPORT_ST_PRLI] = "PRLI", | 85 | [RPORT_ST_PRLI] = "PRLI", |
87 | [RPORT_ST_RTV] = "RTV", | 86 | [RPORT_ST_RTV] = "RTV", |
88 | [RPORT_ST_READY] = "Ready", | 87 | [RPORT_ST_READY] = "Ready", |
89 | [RPORT_ST_LOGO] = "LOGO", | ||
90 | [RPORT_ST_ADISC] = "ADISC", | 88 | [RPORT_ST_ADISC] = "ADISC", |
91 | [RPORT_ST_DELETE] = "Delete", | 89 | [RPORT_ST_DELETE] = "Delete", |
92 | [RPORT_ST_RESTART] = "Restart", | ||
93 | }; | 90 | }; |
94 | 91 | ||
95 | /** | 92 | /** |
96 | * fc_rport_lookup() - Lookup a remote port by port_id | 93 | * fc_rport_lookup() - Lookup a remote port by port_id |
97 | * @lport: The local port to lookup the remote port on | 94 | * @lport: The local port to lookup the remote port on |
98 | * @port_id: The remote port ID to look up | 95 | * @port_id: The remote port ID to look up |
96 | * | ||
97 | * The caller must hold either disc_mutex or rcu_read_lock(). | ||
99 | */ | 98 | */ |
100 | static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, | 99 | static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, |
101 | u32 port_id) | 100 | u32 port_id) |
102 | { | 101 | { |
103 | struct fc_rport_priv *rdata; | 102 | struct fc_rport_priv *rdata; |
104 | 103 | ||
105 | list_for_each_entry(rdata, &lport->disc.rports, peers) | 104 | list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) |
106 | if (rdata->ids.port_id == port_id) | 105 | if (rdata->ids.port_id == port_id) |
107 | return rdata; | 106 | return rdata; |
108 | return NULL; | 107 | return NULL; |
@@ -126,7 +125,7 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, | |||
126 | if (rdata) | 125 | if (rdata) |
127 | return rdata; | 126 | return rdata; |
128 | 127 | ||
129 | rdata = kzalloc(sizeof(*rdata), GFP_KERNEL); | 128 | rdata = kzalloc(sizeof(*rdata) + lport->rport_priv_size, GFP_KERNEL); |
130 | if (!rdata) | 129 | if (!rdata) |
131 | return NULL; | 130 | return NULL; |
132 | 131 | ||
@@ -147,11 +146,23 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, | |||
147 | INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); | 146 | INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); |
148 | INIT_WORK(&rdata->event_work, fc_rport_work); | 147 | INIT_WORK(&rdata->event_work, fc_rport_work); |
149 | if (port_id != FC_FID_DIR_SERV) | 148 | if (port_id != FC_FID_DIR_SERV) |
150 | list_add(&rdata->peers, &lport->disc.rports); | 149 | list_add_rcu(&rdata->peers, &lport->disc.rports); |
151 | return rdata; | 150 | return rdata; |
152 | } | 151 | } |
153 | 152 | ||
154 | /** | 153 | /** |
154 | * fc_rport_free_rcu() - Free a remote port | ||
155 | * @rcu: The rcu_head structure inside the remote port | ||
156 | */ | ||
157 | static void fc_rport_free_rcu(struct rcu_head *rcu) | ||
158 | { | ||
159 | struct fc_rport_priv *rdata; | ||
160 | |||
161 | rdata = container_of(rcu, struct fc_rport_priv, rcu); | ||
162 | kfree(rdata); | ||
163 | } | ||
164 | |||
165 | /** | ||
155 | * fc_rport_destroy() - Free a remote port after last reference is released | 166 | * fc_rport_destroy() - Free a remote port after last reference is released |
156 | * @kref: The remote port's kref | 167 | * @kref: The remote port's kref |
157 | */ | 168 | */ |
@@ -160,7 +171,7 @@ static void fc_rport_destroy(struct kref *kref) | |||
160 | struct fc_rport_priv *rdata; | 171 | struct fc_rport_priv *rdata; |
161 | 172 | ||
162 | rdata = container_of(kref, struct fc_rport_priv, kref); | 173 | rdata = container_of(kref, struct fc_rport_priv, kref); |
163 | kfree(rdata); | 174 | call_rcu(&rdata->rcu, fc_rport_free_rcu); |
164 | } | 175 | } |
165 | 176 | ||
166 | /** | 177 | /** |
@@ -194,7 +205,7 @@ EXPORT_SYMBOL(fc_set_rport_loss_tmo); | |||
194 | /** | 205 | /** |
195 | * fc_plogi_get_maxframe() - Get the maximum payload from the common service | 206 | * fc_plogi_get_maxframe() - Get the maximum payload from the common service |
196 | * parameters in a FLOGI frame | 207 | * parameters in a FLOGI frame |
197 | * @flp: The FLOGI payload | 208 | * @flp: The FLOGI or PLOGI payload |
198 | * @maxval: The maximum frame size upper limit; this may be less than what | 209 | * @maxval: The maximum frame size upper limit; this may be less than what |
199 | * is in the service parameters | 210 | * is in the service parameters |
200 | */ | 211 | */ |
@@ -246,7 +257,6 @@ static void fc_rport_work(struct work_struct *work) | |||
246 | struct fc_rport_operations *rport_ops; | 257 | struct fc_rport_operations *rport_ops; |
247 | struct fc_rport_identifiers ids; | 258 | struct fc_rport_identifiers ids; |
248 | struct fc_rport *rport; | 259 | struct fc_rport *rport; |
249 | int restart = 0; | ||
250 | 260 | ||
251 | mutex_lock(&rdata->rp_mutex); | 261 | mutex_lock(&rdata->rp_mutex); |
252 | event = rdata->event; | 262 | event = rdata->event; |
@@ -259,6 +269,7 @@ static void fc_rport_work(struct work_struct *work) | |||
259 | case RPORT_EV_READY: | 269 | case RPORT_EV_READY: |
260 | ids = rdata->ids; | 270 | ids = rdata->ids; |
261 | rdata->event = RPORT_EV_NONE; | 271 | rdata->event = RPORT_EV_NONE; |
272 | rdata->major_retries = 0; | ||
262 | kref_get(&rdata->kref); | 273 | kref_get(&rdata->kref); |
263 | mutex_unlock(&rdata->rp_mutex); | 274 | mutex_unlock(&rdata->rp_mutex); |
264 | 275 | ||
@@ -298,24 +309,6 @@ static void fc_rport_work(struct work_struct *work) | |||
298 | port_id = rdata->ids.port_id; | 309 | port_id = rdata->ids.port_id; |
299 | mutex_unlock(&rdata->rp_mutex); | 310 | mutex_unlock(&rdata->rp_mutex); |
300 | 311 | ||
301 | if (port_id != FC_FID_DIR_SERV) { | ||
302 | /* | ||
303 | * We must drop rp_mutex before taking disc_mutex. | ||
304 | * Re-evaluate state to allow for restart. | ||
305 | * A transition to RESTART state must only happen | ||
306 | * while disc_mutex is held and rdata is on the list. | ||
307 | */ | ||
308 | mutex_lock(&lport->disc.disc_mutex); | ||
309 | mutex_lock(&rdata->rp_mutex); | ||
310 | if (rdata->rp_state == RPORT_ST_RESTART) | ||
311 | restart = 1; | ||
312 | else | ||
313 | list_del(&rdata->peers); | ||
314 | rdata->event = RPORT_EV_NONE; | ||
315 | mutex_unlock(&rdata->rp_mutex); | ||
316 | mutex_unlock(&lport->disc.disc_mutex); | ||
317 | } | ||
318 | |||
319 | if (rport_ops && rport_ops->event_callback) { | 312 | if (rport_ops && rport_ops->event_callback) { |
320 | FC_RPORT_DBG(rdata, "callback ev %d\n", event); | 313 | FC_RPORT_DBG(rdata, "callback ev %d\n", event); |
321 | rport_ops->event_callback(lport, rdata, event); | 314 | rport_ops->event_callback(lport, rdata, event); |
@@ -336,13 +329,37 @@ static void fc_rport_work(struct work_struct *work) | |||
336 | mutex_unlock(&rdata->rp_mutex); | 329 | mutex_unlock(&rdata->rp_mutex); |
337 | fc_remote_port_delete(rport); | 330 | fc_remote_port_delete(rport); |
338 | } | 331 | } |
339 | if (restart) { | 332 | |
340 | mutex_lock(&rdata->rp_mutex); | 333 | mutex_lock(&lport->disc.disc_mutex); |
341 | FC_RPORT_DBG(rdata, "work restart\n"); | 334 | mutex_lock(&rdata->rp_mutex); |
342 | fc_rport_enter_plogi(rdata); | 335 | if (rdata->rp_state == RPORT_ST_DELETE) { |
336 | if (port_id == FC_FID_DIR_SERV) { | ||
337 | rdata->event = RPORT_EV_NONE; | ||
338 | mutex_unlock(&rdata->rp_mutex); | ||
339 | } else if ((rdata->flags & FC_RP_STARTED) && | ||
340 | rdata->major_retries < | ||
341 | lport->max_rport_retry_count) { | ||
342 | rdata->major_retries++; | ||
343 | rdata->event = RPORT_EV_NONE; | ||
344 | FC_RPORT_DBG(rdata, "work restart\n"); | ||
345 | fc_rport_enter_flogi(rdata); | ||
346 | mutex_unlock(&rdata->rp_mutex); | ||
347 | } else { | ||
348 | FC_RPORT_DBG(rdata, "work delete\n"); | ||
349 | list_del_rcu(&rdata->peers); | ||
350 | mutex_unlock(&rdata->rp_mutex); | ||
351 | kref_put(&rdata->kref, lport->tt.rport_destroy); | ||
352 | } | ||
353 | } else { | ||
354 | /* | ||
355 | * Re-open for events. Reissue READY event if ready. | ||
356 | */ | ||
357 | rdata->event = RPORT_EV_NONE; | ||
358 | if (rdata->rp_state == RPORT_ST_READY) | ||
359 | fc_rport_enter_ready(rdata); | ||
343 | mutex_unlock(&rdata->rp_mutex); | 360 | mutex_unlock(&rdata->rp_mutex); |
344 | } else | 361 | } |
345 | kref_put(&rdata->kref, lport->tt.rport_destroy); | 362 | mutex_unlock(&lport->disc.disc_mutex); |
346 | break; | 363 | break; |
347 | 364 | ||
348 | default: | 365 | default: |
@@ -367,20 +384,18 @@ int fc_rport_login(struct fc_rport_priv *rdata) | |||
367 | { | 384 | { |
368 | mutex_lock(&rdata->rp_mutex); | 385 | mutex_lock(&rdata->rp_mutex); |
369 | 386 | ||
387 | rdata->flags |= FC_RP_STARTED; | ||
370 | switch (rdata->rp_state) { | 388 | switch (rdata->rp_state) { |
371 | case RPORT_ST_READY: | 389 | case RPORT_ST_READY: |
372 | FC_RPORT_DBG(rdata, "ADISC port\n"); | 390 | FC_RPORT_DBG(rdata, "ADISC port\n"); |
373 | fc_rport_enter_adisc(rdata); | 391 | fc_rport_enter_adisc(rdata); |
374 | break; | 392 | break; |
375 | case RPORT_ST_RESTART: | ||
376 | break; | ||
377 | case RPORT_ST_DELETE: | 393 | case RPORT_ST_DELETE: |
378 | FC_RPORT_DBG(rdata, "Restart deleted port\n"); | 394 | FC_RPORT_DBG(rdata, "Restart deleted port\n"); |
379 | fc_rport_state_enter(rdata, RPORT_ST_RESTART); | ||
380 | break; | 395 | break; |
381 | default: | 396 | default: |
382 | FC_RPORT_DBG(rdata, "Login to port\n"); | 397 | FC_RPORT_DBG(rdata, "Login to port\n"); |
383 | fc_rport_enter_plogi(rdata); | 398 | fc_rport_enter_flogi(rdata); |
384 | break; | 399 | break; |
385 | } | 400 | } |
386 | mutex_unlock(&rdata->rp_mutex); | 401 | mutex_unlock(&rdata->rp_mutex); |
@@ -431,15 +446,12 @@ int fc_rport_logoff(struct fc_rport_priv *rdata) | |||
431 | 446 | ||
432 | FC_RPORT_DBG(rdata, "Remove port\n"); | 447 | FC_RPORT_DBG(rdata, "Remove port\n"); |
433 | 448 | ||
449 | rdata->flags &= ~FC_RP_STARTED; | ||
434 | if (rdata->rp_state == RPORT_ST_DELETE) { | 450 | if (rdata->rp_state == RPORT_ST_DELETE) { |
435 | FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n"); | 451 | FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n"); |
436 | goto out; | 452 | goto out; |
437 | } | 453 | } |
438 | 454 | fc_rport_enter_logo(rdata); | |
439 | if (rdata->rp_state == RPORT_ST_RESTART) | ||
440 | FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n"); | ||
441 | else | ||
442 | fc_rport_enter_logo(rdata); | ||
443 | 455 | ||
444 | /* | 456 | /* |
445 | * Change the state to Delete so that we discard | 457 | * Change the state to Delete so that we discard |
@@ -485,6 +497,9 @@ static void fc_rport_timeout(struct work_struct *work) | |||
485 | mutex_lock(&rdata->rp_mutex); | 497 | mutex_lock(&rdata->rp_mutex); |
486 | 498 | ||
487 | switch (rdata->rp_state) { | 499 | switch (rdata->rp_state) { |
500 | case RPORT_ST_FLOGI: | ||
501 | fc_rport_enter_flogi(rdata); | ||
502 | break; | ||
488 | case RPORT_ST_PLOGI: | 503 | case RPORT_ST_PLOGI: |
489 | fc_rport_enter_plogi(rdata); | 504 | fc_rport_enter_plogi(rdata); |
490 | break; | 505 | break; |
@@ -494,16 +509,13 @@ static void fc_rport_timeout(struct work_struct *work) | |||
494 | case RPORT_ST_RTV: | 509 | case RPORT_ST_RTV: |
495 | fc_rport_enter_rtv(rdata); | 510 | fc_rport_enter_rtv(rdata); |
496 | break; | 511 | break; |
497 | case RPORT_ST_LOGO: | ||
498 | fc_rport_enter_logo(rdata); | ||
499 | break; | ||
500 | case RPORT_ST_ADISC: | 512 | case RPORT_ST_ADISC: |
501 | fc_rport_enter_adisc(rdata); | 513 | fc_rport_enter_adisc(rdata); |
502 | break; | 514 | break; |
515 | case RPORT_ST_PLOGI_WAIT: | ||
503 | case RPORT_ST_READY: | 516 | case RPORT_ST_READY: |
504 | case RPORT_ST_INIT: | 517 | case RPORT_ST_INIT: |
505 | case RPORT_ST_DELETE: | 518 | case RPORT_ST_DELETE: |
506 | case RPORT_ST_RESTART: | ||
507 | break; | 519 | break; |
508 | } | 520 | } |
509 | 521 | ||
@@ -525,8 +537,9 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) | |||
525 | fc_rport_state(rdata), rdata->retries); | 537 | fc_rport_state(rdata), rdata->retries); |
526 | 538 | ||
527 | switch (rdata->rp_state) { | 539 | switch (rdata->rp_state) { |
540 | case RPORT_ST_FLOGI: | ||
528 | case RPORT_ST_PLOGI: | 541 | case RPORT_ST_PLOGI: |
529 | case RPORT_ST_LOGO: | 542 | rdata->flags &= ~FC_RP_STARTED; |
530 | fc_rport_enter_delete(rdata, RPORT_EV_FAILED); | 543 | fc_rport_enter_delete(rdata, RPORT_EV_FAILED); |
531 | break; | 544 | break; |
532 | case RPORT_ST_RTV: | 545 | case RPORT_ST_RTV: |
@@ -536,8 +549,8 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) | |||
536 | case RPORT_ST_ADISC: | 549 | case RPORT_ST_ADISC: |
537 | fc_rport_enter_logo(rdata); | 550 | fc_rport_enter_logo(rdata); |
538 | break; | 551 | break; |
552 | case RPORT_ST_PLOGI_WAIT: | ||
539 | case RPORT_ST_DELETE: | 553 | case RPORT_ST_DELETE: |
540 | case RPORT_ST_RESTART: | ||
541 | case RPORT_ST_READY: | 554 | case RPORT_ST_READY: |
542 | case RPORT_ST_INIT: | 555 | case RPORT_ST_INIT: |
543 | break; | 556 | break; |
@@ -579,7 +592,250 @@ static void fc_rport_error_retry(struct fc_rport_priv *rdata, | |||
579 | } | 592 | } |
580 | 593 | ||
581 | /** | 594 | /** |
582 | * fc_rport_plogi_recv_resp() - Handler for ELS PLOGI responses | 595 | * fc_rport_login_complete() - Handle parameters and completion of p-mp login. |
596 | * @rdata: The remote port which we logged into or which logged into us. | ||
597 | * @fp: The FLOGI or PLOGI request or response frame | ||
598 | * | ||
599 | * Returns non-zero error if a problem is detected with the frame. | ||
600 | * Does not free the frame. | ||
601 | * | ||
602 | * This is only used in point-to-multipoint mode for FIP currently. | ||
603 | */ | ||
604 | static int fc_rport_login_complete(struct fc_rport_priv *rdata, | ||
605 | struct fc_frame *fp) | ||
606 | { | ||
607 | struct fc_lport *lport = rdata->local_port; | ||
608 | struct fc_els_flogi *flogi; | ||
609 | unsigned int e_d_tov; | ||
610 | u16 csp_flags; | ||
611 | |||
612 | flogi = fc_frame_payload_get(fp, sizeof(*flogi)); | ||
613 | if (!flogi) | ||
614 | return -EINVAL; | ||
615 | |||
616 | csp_flags = ntohs(flogi->fl_csp.sp_features); | ||
617 | |||
618 | if (fc_frame_payload_op(fp) == ELS_FLOGI) { | ||
619 | if (csp_flags & FC_SP_FT_FPORT) { | ||
620 | FC_RPORT_DBG(rdata, "Fabric bit set in FLOGI\n"); | ||
621 | return -EINVAL; | ||
622 | } | ||
623 | } else { | ||
624 | |||
625 | /* | ||
626 | * E_D_TOV is not valid on an incoming FLOGI request. | ||
627 | */ | ||
628 | e_d_tov = ntohl(flogi->fl_csp.sp_e_d_tov); | ||
629 | if (csp_flags & FC_SP_FT_EDTR) | ||
630 | e_d_tov /= 1000000; | ||
631 | if (e_d_tov > rdata->e_d_tov) | ||
632 | rdata->e_d_tov = e_d_tov; | ||
633 | } | ||
634 | rdata->maxframe_size = fc_plogi_get_maxframe(flogi, lport->mfs); | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | /** | ||
639 | * fc_rport_flogi_resp() - Handle response to FLOGI request for p-mp mode | ||
640 | * @sp: The sequence that the FLOGI was on | ||
641 | * @fp: The FLOGI response frame | ||
642 | * @rp_arg: The remote port that received the FLOGI response | ||
643 | */ | ||
644 | void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, | ||
645 | void *rp_arg) | ||
646 | { | ||
647 | struct fc_rport_priv *rdata = rp_arg; | ||
648 | struct fc_lport *lport = rdata->local_port; | ||
649 | struct fc_els_flogi *flogi; | ||
650 | unsigned int r_a_tov; | ||
651 | |||
652 | FC_RPORT_DBG(rdata, "Received a FLOGI %s\n", fc_els_resp_type(fp)); | ||
653 | |||
654 | if (fp == ERR_PTR(-FC_EX_CLOSED)) | ||
655 | return; | ||
656 | |||
657 | mutex_lock(&rdata->rp_mutex); | ||
658 | |||
659 | if (rdata->rp_state != RPORT_ST_FLOGI) { | ||
660 | FC_RPORT_DBG(rdata, "Received a FLOGI response, but in state " | ||
661 | "%s\n", fc_rport_state(rdata)); | ||
662 | if (IS_ERR(fp)) | ||
663 | goto err; | ||
664 | goto out; | ||
665 | } | ||
666 | |||
667 | if (IS_ERR(fp)) { | ||
668 | fc_rport_error(rdata, fp); | ||
669 | goto err; | ||
670 | } | ||
671 | |||
672 | if (fc_frame_payload_op(fp) != ELS_LS_ACC) | ||
673 | goto bad; | ||
674 | if (fc_rport_login_complete(rdata, fp)) | ||
675 | goto bad; | ||
676 | |||
677 | flogi = fc_frame_payload_get(fp, sizeof(*flogi)); | ||
678 | if (!flogi) | ||
679 | goto bad; | ||
680 | r_a_tov = ntohl(flogi->fl_csp.sp_r_a_tov); | ||
681 | if (r_a_tov > rdata->r_a_tov) | ||
682 | rdata->r_a_tov = r_a_tov; | ||
683 | |||
684 | if (rdata->ids.port_name < lport->wwpn) | ||
685 | fc_rport_enter_plogi(rdata); | ||
686 | else | ||
687 | fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT); | ||
688 | out: | ||
689 | fc_frame_free(fp); | ||
690 | err: | ||
691 | mutex_unlock(&rdata->rp_mutex); | ||
692 | kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); | ||
693 | return; | ||
694 | bad: | ||
695 | FC_RPORT_DBG(rdata, "Bad FLOGI response\n"); | ||
696 | fc_rport_error_retry(rdata, fp); | ||
697 | goto out; | ||
698 | } | ||
699 | |||
700 | /** | ||
701 | * fc_rport_enter_flogi() - Send a FLOGI request to the remote port for p-mp | ||
702 | * @rdata: The remote port to send a FLOGI to | ||
703 | * | ||
704 | * Locking Note: The rport lock is expected to be held before calling | ||
705 | * this routine. | ||
706 | */ | ||
707 | static void fc_rport_enter_flogi(struct fc_rport_priv *rdata) | ||
708 | { | ||
709 | struct fc_lport *lport = rdata->local_port; | ||
710 | struct fc_frame *fp; | ||
711 | |||
712 | if (!lport->point_to_multipoint) | ||
713 | return fc_rport_enter_plogi(rdata); | ||
714 | |||
715 | FC_RPORT_DBG(rdata, "Entered FLOGI state from %s state\n", | ||
716 | fc_rport_state(rdata)); | ||
717 | |||
718 | fc_rport_state_enter(rdata, RPORT_ST_FLOGI); | ||
719 | |||
720 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); | ||
721 | if (!fp) | ||
722 | return fc_rport_error_retry(rdata, fp); | ||
723 | |||
724 | if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_FLOGI, | ||
725 | fc_rport_flogi_resp, rdata, | ||
726 | 2 * lport->r_a_tov)) | ||
727 | fc_rport_error_retry(rdata, NULL); | ||
728 | else | ||
729 | kref_get(&rdata->kref); | ||
730 | } | ||
731 | |||
732 | /** | ||
733 | * fc_rport_recv_flogi_req() - Handle Fabric Login (FLOGI) request in p-mp mode | ||
734 | * @lport: The local port that received the PLOGI request | ||
735 | * @rx_fp: The PLOGI request frame | ||
736 | */ | ||
737 | static void fc_rport_recv_flogi_req(struct fc_lport *lport, | ||
738 | struct fc_frame *rx_fp) | ||
739 | { | ||
740 | struct fc_disc *disc; | ||
741 | struct fc_els_flogi *flp; | ||
742 | struct fc_rport_priv *rdata; | ||
743 | struct fc_frame *fp = rx_fp; | ||
744 | struct fc_seq_els_data rjt_data; | ||
745 | u32 sid; | ||
746 | |||
747 | sid = fc_frame_sid(fp); | ||
748 | |||
749 | FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n"); | ||
750 | |||
751 | disc = &lport->disc; | ||
752 | mutex_lock(&disc->disc_mutex); | ||
753 | |||
754 | if (!lport->point_to_multipoint) { | ||
755 | rjt_data.reason = ELS_RJT_UNSUP; | ||
756 | rjt_data.explan = ELS_EXPL_NONE; | ||
757 | goto reject; | ||
758 | } | ||
759 | |||
760 | flp = fc_frame_payload_get(fp, sizeof(*flp)); | ||
761 | if (!flp) { | ||
762 | rjt_data.reason = ELS_RJT_LOGIC; | ||
763 | rjt_data.explan = ELS_EXPL_INV_LEN; | ||
764 | goto reject; | ||
765 | } | ||
766 | |||
767 | rdata = lport->tt.rport_lookup(lport, sid); | ||
768 | if (!rdata) { | ||
769 | rjt_data.reason = ELS_RJT_FIP; | ||
770 | rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR; | ||
771 | goto reject; | ||
772 | } | ||
773 | mutex_lock(&rdata->rp_mutex); | ||
774 | |||
775 | FC_RPORT_DBG(rdata, "Received FLOGI in %s state\n", | ||
776 | fc_rport_state(rdata)); | ||
777 | |||
778 | switch (rdata->rp_state) { | ||
779 | case RPORT_ST_INIT: | ||
780 | case RPORT_ST_DELETE: | ||
781 | mutex_unlock(&rdata->rp_mutex); | ||
782 | rjt_data.reason = ELS_RJT_FIP; | ||
783 | rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR; | ||
784 | goto reject; | ||
785 | case RPORT_ST_FLOGI: | ||
786 | case RPORT_ST_PLOGI_WAIT: | ||
787 | case RPORT_ST_PLOGI: | ||
788 | break; | ||
789 | case RPORT_ST_PRLI: | ||
790 | case RPORT_ST_RTV: | ||
791 | case RPORT_ST_READY: | ||
792 | case RPORT_ST_ADISC: | ||
793 | /* | ||
794 | * Set the remote port to be deleted and to then restart. | ||
795 | * This queues work to be sure exchanges are reset. | ||
796 | */ | ||
797 | fc_rport_enter_delete(rdata, RPORT_EV_LOGO); | ||
798 | mutex_unlock(&rdata->rp_mutex); | ||
799 | rjt_data.reason = ELS_RJT_BUSY; | ||
800 | rjt_data.explan = ELS_EXPL_NONE; | ||
801 | goto reject; | ||
802 | } | ||
803 | if (fc_rport_login_complete(rdata, fp)) { | ||
804 | mutex_unlock(&rdata->rp_mutex); | ||
805 | rjt_data.reason = ELS_RJT_LOGIC; | ||
806 | rjt_data.explan = ELS_EXPL_NONE; | ||
807 | goto reject; | ||
808 | } | ||
809 | |||
810 | fp = fc_frame_alloc(lport, sizeof(*flp)); | ||
811 | if (!fp) | ||
812 | goto out; | ||
813 | |||
814 | fc_flogi_fill(lport, fp); | ||
815 | flp = fc_frame_payload_get(fp, sizeof(*flp)); | ||
816 | flp->fl_cmd = ELS_LS_ACC; | ||
817 | |||
818 | fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); | ||
819 | lport->tt.frame_send(lport, fp); | ||
820 | |||
821 | if (rdata->ids.port_name < lport->wwpn) | ||
822 | fc_rport_enter_plogi(rdata); | ||
823 | else | ||
824 | fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT); | ||
825 | out: | ||
826 | mutex_unlock(&rdata->rp_mutex); | ||
827 | mutex_unlock(&disc->disc_mutex); | ||
828 | fc_frame_free(rx_fp); | ||
829 | return; | ||
830 | |||
831 | reject: | ||
832 | mutex_unlock(&disc->disc_mutex); | ||
833 | lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); | ||
834 | fc_frame_free(rx_fp); | ||
835 | } | ||
836 | |||
837 | /** | ||
838 | * fc_rport_plogi_resp() - Handler for ELS PLOGI responses | ||
583 | * @sp: The sequence the PLOGI is on | 839 | * @sp: The sequence the PLOGI is on |
584 | * @fp: The PLOGI response frame | 840 | * @fp: The PLOGI response frame |
585 | * @rdata_arg: The remote port that sent the PLOGI response | 841 | * @rdata_arg: The remote port that sent the PLOGI response |
@@ -594,7 +850,6 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
594 | struct fc_rport_priv *rdata = rdata_arg; | 850 | struct fc_rport_priv *rdata = rdata_arg; |
595 | struct fc_lport *lport = rdata->local_port; | 851 | struct fc_lport *lport = rdata->local_port; |
596 | struct fc_els_flogi *plp = NULL; | 852 | struct fc_els_flogi *plp = NULL; |
597 | unsigned int tov; | ||
598 | u16 csp_seq; | 853 | u16 csp_seq; |
599 | u16 cssp_seq; | 854 | u16 cssp_seq; |
600 | u8 op; | 855 | u8 op; |
@@ -622,11 +877,8 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
622 | rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn); | 877 | rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn); |
623 | rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn); | 878 | rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn); |
624 | 879 | ||
625 | tov = ntohl(plp->fl_csp.sp_e_d_tov); | 880 | if (lport->point_to_multipoint) |
626 | if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR) | 881 | fc_rport_login_complete(rdata, fp); |
627 | tov /= 1000000; | ||
628 | if (tov > rdata->e_d_tov) | ||
629 | rdata->e_d_tov = tov; | ||
630 | csp_seq = ntohs(plp->fl_csp.sp_tot_seq); | 882 | csp_seq = ntohs(plp->fl_csp.sp_tot_seq); |
631 | cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq); | 883 | cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq); |
632 | if (cssp_seq < csp_seq) | 884 | if (cssp_seq < csp_seq) |
@@ -664,6 +916,7 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) | |||
664 | rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; | 916 | rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; |
665 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); | 917 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); |
666 | if (!fp) { | 918 | if (!fp) { |
919 | FC_RPORT_DBG(rdata, "%s frame alloc failed\n", __func__); | ||
667 | fc_rport_error_retry(rdata, fp); | 920 | fc_rport_error_retry(rdata, fp); |
668 | return; | 921 | return; |
669 | } | 922 | } |
@@ -698,6 +951,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
698 | u32 roles = FC_RPORT_ROLE_UNKNOWN; | 951 | u32 roles = FC_RPORT_ROLE_UNKNOWN; |
699 | u32 fcp_parm = 0; | 952 | u32 fcp_parm = 0; |
700 | u8 op; | 953 | u8 op; |
954 | u8 resp_code = 0; | ||
701 | 955 | ||
702 | mutex_lock(&rdata->rp_mutex); | 956 | mutex_lock(&rdata->rp_mutex); |
703 | 957 | ||
@@ -722,11 +976,25 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
722 | op = fc_frame_payload_op(fp); | 976 | op = fc_frame_payload_op(fp); |
723 | if (op == ELS_LS_ACC) { | 977 | if (op == ELS_LS_ACC) { |
724 | pp = fc_frame_payload_get(fp, sizeof(*pp)); | 978 | pp = fc_frame_payload_get(fp, sizeof(*pp)); |
725 | if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) { | 979 | if (!pp) |
726 | fcp_parm = ntohl(pp->spp.spp_params); | 980 | goto out; |
727 | if (fcp_parm & FCP_SPPF_RETRY) | 981 | |
728 | rdata->flags |= FC_RP_FLAGS_RETRY; | 982 | resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK); |
983 | FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x\n", | ||
984 | pp->spp.spp_flags); | ||
985 | if (resp_code != FC_SPP_RESP_ACK) { | ||
986 | if (resp_code == FC_SPP_RESP_CONF) | ||
987 | fc_rport_error(rdata, fp); | ||
988 | else | ||
989 | fc_rport_error_retry(rdata, fp); | ||
990 | goto out; | ||
729 | } | 991 | } |
992 | if (pp->prli.prli_spp_len < sizeof(pp->spp)) | ||
993 | goto out; | ||
994 | |||
995 | fcp_parm = ntohl(pp->spp.spp_params); | ||
996 | if (fcp_parm & FCP_SPPF_RETRY) | ||
997 | rdata->flags |= FC_RP_FLAGS_RETRY; | ||
730 | 998 | ||
731 | rdata->supported_classes = FC_COS_CLASS3; | 999 | rdata->supported_classes = FC_COS_CLASS3; |
732 | if (fcp_parm & FCP_SPPF_INIT_FCN) | 1000 | if (fcp_parm & FCP_SPPF_INIT_FCN) |
@@ -739,55 +1007,9 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
739 | 1007 | ||
740 | } else { | 1008 | } else { |
741 | FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n"); | 1009 | FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n"); |
742 | fc_rport_enter_delete(rdata, RPORT_EV_FAILED); | ||
743 | } | ||
744 | |||
745 | out: | ||
746 | fc_frame_free(fp); | ||
747 | err: | ||
748 | mutex_unlock(&rdata->rp_mutex); | ||
749 | kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); | ||
750 | } | ||
751 | |||
752 | /** | ||
753 | * fc_rport_logo_resp() - Handler for logout (LOGO) responses | ||
754 | * @sp: The sequence the LOGO was on | ||
755 | * @fp: The LOGO response frame | ||
756 | * @rdata_arg: The remote port that sent the LOGO response | ||
757 | * | ||
758 | * Locking Note: This function will be called without the rport lock | ||
759 | * held, but it will lock, call an _enter_* function or fc_rport_error | ||
760 | * and then unlock the rport. | ||
761 | */ | ||
762 | static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, | ||
763 | void *rdata_arg) | ||
764 | { | ||
765 | struct fc_rport_priv *rdata = rdata_arg; | ||
766 | u8 op; | ||
767 | |||
768 | mutex_lock(&rdata->rp_mutex); | ||
769 | |||
770 | FC_RPORT_DBG(rdata, "Received a LOGO %s\n", fc_els_resp_type(fp)); | ||
771 | |||
772 | if (rdata->rp_state != RPORT_ST_LOGO) { | ||
773 | FC_RPORT_DBG(rdata, "Received a LOGO response, but in state " | ||
774 | "%s\n", fc_rport_state(rdata)); | ||
775 | if (IS_ERR(fp)) | ||
776 | goto err; | ||
777 | goto out; | ||
778 | } | ||
779 | |||
780 | if (IS_ERR(fp)) { | ||
781 | fc_rport_error_retry(rdata, fp); | 1010 | fc_rport_error_retry(rdata, fp); |
782 | goto err; | ||
783 | } | 1011 | } |
784 | 1012 | ||
785 | op = fc_frame_payload_op(fp); | ||
786 | if (op != ELS_LS_ACC) | ||
787 | FC_RPORT_DBG(rdata, "Bad ELS response op %x for LOGO command\n", | ||
788 | op); | ||
789 | fc_rport_enter_delete(rdata, RPORT_EV_LOGO); | ||
790 | |||
791 | out: | 1013 | out: |
792 | fc_frame_free(fp); | 1014 | fc_frame_free(fp); |
793 | err: | 1015 | err: |
@@ -937,6 +1159,24 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) | |||
937 | } | 1159 | } |
938 | 1160 | ||
939 | /** | 1161 | /** |
1162 | * fc_rport_logo_resp() - Handler for logout (LOGO) responses | ||
1163 | * @sp: The sequence the LOGO was on | ||
1164 | * @fp: The LOGO response frame | ||
1165 | * @lport_arg: The local port | ||
1166 | */ | ||
1167 | static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, | ||
1168 | void *lport_arg) | ||
1169 | { | ||
1170 | struct fc_lport *lport = lport_arg; | ||
1171 | |||
1172 | FC_RPORT_ID_DBG(lport, fc_seq_exch(sp)->did, | ||
1173 | "Received a LOGO %s\n", fc_els_resp_type(fp)); | ||
1174 | if (IS_ERR(fp)) | ||
1175 | return; | ||
1176 | fc_frame_free(fp); | ||
1177 | } | ||
1178 | |||
1179 | /** | ||
940 | * fc_rport_enter_logo() - Send a logout (LOGO) request | 1180 | * fc_rport_enter_logo() - Send a logout (LOGO) request |
941 | * @rdata: The remote port to send the LOGO request to | 1181 | * @rdata: The remote port to send the LOGO request to |
942 | * | 1182 | * |
@@ -948,23 +1188,14 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) | |||
948 | struct fc_lport *lport = rdata->local_port; | 1188 | struct fc_lport *lport = rdata->local_port; |
949 | struct fc_frame *fp; | 1189 | struct fc_frame *fp; |
950 | 1190 | ||
951 | FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n", | 1191 | FC_RPORT_DBG(rdata, "Port sending LOGO from %s state\n", |
952 | fc_rport_state(rdata)); | 1192 | fc_rport_state(rdata)); |
953 | 1193 | ||
954 | fc_rport_state_enter(rdata, RPORT_ST_LOGO); | ||
955 | |||
956 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo)); | 1194 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo)); |
957 | if (!fp) { | 1195 | if (!fp) |
958 | fc_rport_error_retry(rdata, fp); | ||
959 | return; | 1196 | return; |
960 | } | 1197 | (void)lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO, |
961 | 1198 | fc_rport_logo_resp, lport, 0); | |
962 | if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO, | ||
963 | fc_rport_logo_resp, rdata, | ||
964 | 2 * lport->r_a_tov)) | ||
965 | fc_rport_error_retry(rdata, NULL); | ||
966 | else | ||
967 | kref_get(&rdata->kref); | ||
968 | } | 1199 | } |
969 | 1200 | ||
970 | /** | 1201 | /** |
@@ -1013,7 +1244,7 @@ static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
1013 | get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name || | 1244 | get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name || |
1014 | get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) { | 1245 | get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) { |
1015 | FC_RPORT_DBG(rdata, "ADISC error or mismatch\n"); | 1246 | FC_RPORT_DBG(rdata, "ADISC error or mismatch\n"); |
1016 | fc_rport_enter_plogi(rdata); | 1247 | fc_rport_enter_flogi(rdata); |
1017 | } else { | 1248 | } else { |
1018 | FC_RPORT_DBG(rdata, "ADISC OK\n"); | 1249 | FC_RPORT_DBG(rdata, "ADISC OK\n"); |
1019 | fc_rport_enter_ready(rdata); | 1250 | fc_rport_enter_ready(rdata); |
@@ -1058,29 +1289,25 @@ static void fc_rport_enter_adisc(struct fc_rport_priv *rdata) | |||
1058 | /** | 1289 | /** |
1059 | * fc_rport_recv_adisc_req() - Handler for Address Discovery (ADISC) requests | 1290 | * fc_rport_recv_adisc_req() - Handler for Address Discovery (ADISC) requests |
1060 | * @rdata: The remote port that sent the ADISC request | 1291 | * @rdata: The remote port that sent the ADISC request |
1061 | * @sp: The sequence the ADISC request was on | ||
1062 | * @in_fp: The ADISC request frame | 1292 | * @in_fp: The ADISC request frame |
1063 | * | 1293 | * |
1064 | * Locking Note: Called with the lport and rport locks held. | 1294 | * Locking Note: Called with the lport and rport locks held. |
1065 | */ | 1295 | */ |
1066 | static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata, | 1296 | static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata, |
1067 | struct fc_seq *sp, struct fc_frame *in_fp) | 1297 | struct fc_frame *in_fp) |
1068 | { | 1298 | { |
1069 | struct fc_lport *lport = rdata->local_port; | 1299 | struct fc_lport *lport = rdata->local_port; |
1070 | struct fc_frame *fp; | 1300 | struct fc_frame *fp; |
1071 | struct fc_exch *ep = fc_seq_exch(sp); | ||
1072 | struct fc_els_adisc *adisc; | 1301 | struct fc_els_adisc *adisc; |
1073 | struct fc_seq_els_data rjt_data; | 1302 | struct fc_seq_els_data rjt_data; |
1074 | u32 f_ctl; | ||
1075 | 1303 | ||
1076 | FC_RPORT_DBG(rdata, "Received ADISC request\n"); | 1304 | FC_RPORT_DBG(rdata, "Received ADISC request\n"); |
1077 | 1305 | ||
1078 | adisc = fc_frame_payload_get(in_fp, sizeof(*adisc)); | 1306 | adisc = fc_frame_payload_get(in_fp, sizeof(*adisc)); |
1079 | if (!adisc) { | 1307 | if (!adisc) { |
1080 | rjt_data.fp = NULL; | ||
1081 | rjt_data.reason = ELS_RJT_PROT; | 1308 | rjt_data.reason = ELS_RJT_PROT; |
1082 | rjt_data.explan = ELS_EXPL_INV_LEN; | 1309 | rjt_data.explan = ELS_EXPL_INV_LEN; |
1083 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | 1310 | lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data); |
1084 | goto drop; | 1311 | goto drop; |
1085 | } | 1312 | } |
1086 | 1313 | ||
@@ -1090,11 +1317,8 @@ static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata, | |||
1090 | fc_adisc_fill(lport, fp); | 1317 | fc_adisc_fill(lport, fp); |
1091 | adisc = fc_frame_payload_get(fp, sizeof(*adisc)); | 1318 | adisc = fc_frame_payload_get(fp, sizeof(*adisc)); |
1092 | adisc->adisc_cmd = ELS_LS_ACC; | 1319 | adisc->adisc_cmd = ELS_LS_ACC; |
1093 | sp = lport->tt.seq_start_next(sp); | 1320 | fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0); |
1094 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; | 1321 | lport->tt.frame_send(lport, fp); |
1095 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, | ||
1096 | FC_TYPE_ELS, f_ctl, 0); | ||
1097 | lport->tt.seq_send(lport, sp, fp); | ||
1098 | drop: | 1322 | drop: |
1099 | fc_frame_free(in_fp); | 1323 | fc_frame_free(in_fp); |
1100 | } | 1324 | } |
@@ -1102,25 +1326,22 @@ drop: | |||
1102 | /** | 1326 | /** |
1103 | * fc_rport_recv_rls_req() - Handle received Read Link Status request | 1327 | * fc_rport_recv_rls_req() - Handle received Read Link Status request |
1104 | * @rdata: The remote port that sent the RLS request | 1328 | * @rdata: The remote port that sent the RLS request |
1105 | * @sp: The sequence that the RLS was on | ||
1106 | * @rx_fp: The PRLI request frame | 1329 | * @rx_fp: The PRLI request frame |
1107 | * | 1330 | * |
1108 | * Locking Note: The rport lock is expected to be held before calling | 1331 | * Locking Note: The rport lock is expected to be held before calling |
1109 | * this function. | 1332 | * this function. |
1110 | */ | 1333 | */ |
1111 | static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata, | 1334 | static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata, |
1112 | struct fc_seq *sp, struct fc_frame *rx_fp) | 1335 | struct fc_frame *rx_fp) |
1113 | 1336 | ||
1114 | { | 1337 | { |
1115 | struct fc_lport *lport = rdata->local_port; | 1338 | struct fc_lport *lport = rdata->local_port; |
1116 | struct fc_frame *fp; | 1339 | struct fc_frame *fp; |
1117 | struct fc_exch *ep = fc_seq_exch(sp); | ||
1118 | struct fc_els_rls *rls; | 1340 | struct fc_els_rls *rls; |
1119 | struct fc_els_rls_resp *rsp; | 1341 | struct fc_els_rls_resp *rsp; |
1120 | struct fc_els_lesb *lesb; | 1342 | struct fc_els_lesb *lesb; |
1121 | struct fc_seq_els_data rjt_data; | 1343 | struct fc_seq_els_data rjt_data; |
1122 | struct fc_host_statistics *hst; | 1344 | struct fc_host_statistics *hst; |
1123 | u32 f_ctl; | ||
1124 | 1345 | ||
1125 | FC_RPORT_DBG(rdata, "Received RLS request while in state %s\n", | 1346 | FC_RPORT_DBG(rdata, "Received RLS request while in state %s\n", |
1126 | fc_rport_state(rdata)); | 1347 | fc_rport_state(rdata)); |
@@ -1157,16 +1378,12 @@ static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata, | |||
1157 | lesb->lesb_inv_crc = htonl(hst->invalid_crc_count); | 1378 | lesb->lesb_inv_crc = htonl(hst->invalid_crc_count); |
1158 | } | 1379 | } |
1159 | 1380 | ||
1160 | sp = lport->tt.seq_start_next(sp); | 1381 | fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); |
1161 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; | 1382 | lport->tt.frame_send(lport, fp); |
1162 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, | ||
1163 | FC_TYPE_ELS, f_ctl, 0); | ||
1164 | lport->tt.seq_send(lport, sp, fp); | ||
1165 | goto out; | 1383 | goto out; |
1166 | 1384 | ||
1167 | out_rjt: | 1385 | out_rjt: |
1168 | rjt_data.fp = NULL; | 1386 | lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); |
1169 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | ||
1170 | out: | 1387 | out: |
1171 | fc_frame_free(rx_fp); | 1388 | fc_frame_free(rx_fp); |
1172 | } | 1389 | } |
@@ -1174,7 +1391,6 @@ out: | |||
1174 | /** | 1391 | /** |
1175 | * fc_rport_recv_els_req() - Handler for validated ELS requests | 1392 | * fc_rport_recv_els_req() - Handler for validated ELS requests |
1176 | * @lport: The local port that received the ELS request | 1393 | * @lport: The local port that received the ELS request |
1177 | * @sp: The sequence that the ELS request was on | ||
1178 | * @fp: The ELS request frame | 1394 | * @fp: The ELS request frame |
1179 | * | 1395 | * |
1180 | * Handle incoming ELS requests that require port login. | 1396 | * Handle incoming ELS requests that require port login. |
@@ -1182,21 +1398,13 @@ out: | |||
1182 | * | 1398 | * |
1183 | * Locking Note: Called with the lport lock held. | 1399 | * Locking Note: Called with the lport lock held. |
1184 | */ | 1400 | */ |
1185 | static void fc_rport_recv_els_req(struct fc_lport *lport, | 1401 | static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp) |
1186 | struct fc_seq *sp, struct fc_frame *fp) | ||
1187 | { | 1402 | { |
1188 | struct fc_rport_priv *rdata; | 1403 | struct fc_rport_priv *rdata; |
1189 | struct fc_frame_header *fh; | ||
1190 | struct fc_seq_els_data els_data; | 1404 | struct fc_seq_els_data els_data; |
1191 | 1405 | ||
1192 | els_data.fp = NULL; | ||
1193 | els_data.reason = ELS_RJT_UNAB; | ||
1194 | els_data.explan = ELS_EXPL_PLOGI_REQD; | ||
1195 | |||
1196 | fh = fc_frame_header_get(fp); | ||
1197 | |||
1198 | mutex_lock(&lport->disc.disc_mutex); | 1406 | mutex_lock(&lport->disc.disc_mutex); |
1199 | rdata = lport->tt.rport_lookup(lport, ntoh24(fh->fh_s_id)); | 1407 | rdata = lport->tt.rport_lookup(lport, fc_frame_sid(fp)); |
1200 | if (!rdata) { | 1408 | if (!rdata) { |
1201 | mutex_unlock(&lport->disc.disc_mutex); | 1409 | mutex_unlock(&lport->disc.disc_mutex); |
1202 | goto reject; | 1410 | goto reject; |
@@ -1217,24 +1425,24 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, | |||
1217 | 1425 | ||
1218 | switch (fc_frame_payload_op(fp)) { | 1426 | switch (fc_frame_payload_op(fp)) { |
1219 | case ELS_PRLI: | 1427 | case ELS_PRLI: |
1220 | fc_rport_recv_prli_req(rdata, sp, fp); | 1428 | fc_rport_recv_prli_req(rdata, fp); |
1221 | break; | 1429 | break; |
1222 | case ELS_PRLO: | 1430 | case ELS_PRLO: |
1223 | fc_rport_recv_prlo_req(rdata, sp, fp); | 1431 | fc_rport_recv_prlo_req(rdata, fp); |
1224 | break; | 1432 | break; |
1225 | case ELS_ADISC: | 1433 | case ELS_ADISC: |
1226 | fc_rport_recv_adisc_req(rdata, sp, fp); | 1434 | fc_rport_recv_adisc_req(rdata, fp); |
1227 | break; | 1435 | break; |
1228 | case ELS_RRQ: | 1436 | case ELS_RRQ: |
1229 | els_data.fp = fp; | 1437 | lport->tt.seq_els_rsp_send(fp, ELS_RRQ, NULL); |
1230 | lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); | 1438 | fc_frame_free(fp); |
1231 | break; | 1439 | break; |
1232 | case ELS_REC: | 1440 | case ELS_REC: |
1233 | els_data.fp = fp; | 1441 | lport->tt.seq_els_rsp_send(fp, ELS_REC, NULL); |
1234 | lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); | 1442 | fc_frame_free(fp); |
1235 | break; | 1443 | break; |
1236 | case ELS_RLS: | 1444 | case ELS_RLS: |
1237 | fc_rport_recv_rls_req(rdata, sp, fp); | 1445 | fc_rport_recv_rls_req(rdata, fp); |
1238 | break; | 1446 | break; |
1239 | default: | 1447 | default: |
1240 | fc_frame_free(fp); /* can't happen */ | 1448 | fc_frame_free(fp); /* can't happen */ |
@@ -1245,35 +1453,38 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, | |||
1245 | return; | 1453 | return; |
1246 | 1454 | ||
1247 | reject: | 1455 | reject: |
1248 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); | 1456 | els_data.reason = ELS_RJT_UNAB; |
1457 | els_data.explan = ELS_EXPL_PLOGI_REQD; | ||
1458 | lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data); | ||
1249 | fc_frame_free(fp); | 1459 | fc_frame_free(fp); |
1250 | } | 1460 | } |
1251 | 1461 | ||
1252 | /** | 1462 | /** |
1253 | * fc_rport_recv_req() - Handler for requests | 1463 | * fc_rport_recv_req() - Handler for requests |
1254 | * @sp: The sequence the request was on | ||
1255 | * @fp: The request frame | ||
1256 | * @lport: The local port that received the request | 1464 | * @lport: The local port that received the request |
1465 | * @fp: The request frame | ||
1257 | * | 1466 | * |
1258 | * Locking Note: Called with the lport lock held. | 1467 | * Locking Note: Called with the lport lock held. |
1259 | */ | 1468 | */ |
1260 | void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, | 1469 | void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp) |
1261 | struct fc_lport *lport) | ||
1262 | { | 1470 | { |
1263 | struct fc_seq_els_data els_data; | 1471 | struct fc_seq_els_data els_data; |
1264 | 1472 | ||
1265 | /* | 1473 | /* |
1266 | * Handle PLOGI and LOGO requests separately, since they | 1474 | * Handle FLOGI, PLOGI and LOGO requests separately, since they |
1267 | * don't require prior login. | 1475 | * don't require prior login. |
1268 | * Check for unsupported opcodes first and reject them. | 1476 | * Check for unsupported opcodes first and reject them. |
1269 | * For some ops, it would be incorrect to reject with "PLOGI required". | 1477 | * For some ops, it would be incorrect to reject with "PLOGI required". |
1270 | */ | 1478 | */ |
1271 | switch (fc_frame_payload_op(fp)) { | 1479 | switch (fc_frame_payload_op(fp)) { |
1480 | case ELS_FLOGI: | ||
1481 | fc_rport_recv_flogi_req(lport, fp); | ||
1482 | break; | ||
1272 | case ELS_PLOGI: | 1483 | case ELS_PLOGI: |
1273 | fc_rport_recv_plogi_req(lport, sp, fp); | 1484 | fc_rport_recv_plogi_req(lport, fp); |
1274 | break; | 1485 | break; |
1275 | case ELS_LOGO: | 1486 | case ELS_LOGO: |
1276 | fc_rport_recv_logo_req(lport, sp, fp); | 1487 | fc_rport_recv_logo_req(lport, fp); |
1277 | break; | 1488 | break; |
1278 | case ELS_PRLI: | 1489 | case ELS_PRLI: |
1279 | case ELS_PRLO: | 1490 | case ELS_PRLO: |
@@ -1281,14 +1492,13 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, | |||
1281 | case ELS_RRQ: | 1492 | case ELS_RRQ: |
1282 | case ELS_REC: | 1493 | case ELS_REC: |
1283 | case ELS_RLS: | 1494 | case ELS_RLS: |
1284 | fc_rport_recv_els_req(lport, sp, fp); | 1495 | fc_rport_recv_els_req(lport, fp); |
1285 | break; | 1496 | break; |
1286 | default: | 1497 | default: |
1287 | fc_frame_free(fp); | ||
1288 | els_data.fp = NULL; | ||
1289 | els_data.reason = ELS_RJT_UNSUP; | 1498 | els_data.reason = ELS_RJT_UNSUP; |
1290 | els_data.explan = ELS_EXPL_NONE; | 1499 | els_data.explan = ELS_EXPL_NONE; |
1291 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); | 1500 | lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data); |
1501 | fc_frame_free(fp); | ||
1292 | break; | 1502 | break; |
1293 | } | 1503 | } |
1294 | } | 1504 | } |
@@ -1296,26 +1506,21 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, | |||
1296 | /** | 1506 | /** |
1297 | * fc_rport_recv_plogi_req() - Handler for Port Login (PLOGI) requests | 1507 | * fc_rport_recv_plogi_req() - Handler for Port Login (PLOGI) requests |
1298 | * @lport: The local port that received the PLOGI request | 1508 | * @lport: The local port that received the PLOGI request |
1299 | * @sp: The sequence that the PLOGI request was on | ||
1300 | * @rx_fp: The PLOGI request frame | 1509 | * @rx_fp: The PLOGI request frame |
1301 | * | 1510 | * |
1302 | * Locking Note: The rport lock is held before calling this function. | 1511 | * Locking Note: The rport lock is held before calling this function. |
1303 | */ | 1512 | */ |
1304 | static void fc_rport_recv_plogi_req(struct fc_lport *lport, | 1513 | static void fc_rport_recv_plogi_req(struct fc_lport *lport, |
1305 | struct fc_seq *sp, struct fc_frame *rx_fp) | 1514 | struct fc_frame *rx_fp) |
1306 | { | 1515 | { |
1307 | struct fc_disc *disc; | 1516 | struct fc_disc *disc; |
1308 | struct fc_rport_priv *rdata; | 1517 | struct fc_rport_priv *rdata; |
1309 | struct fc_frame *fp = rx_fp; | 1518 | struct fc_frame *fp = rx_fp; |
1310 | struct fc_exch *ep; | ||
1311 | struct fc_frame_header *fh; | ||
1312 | struct fc_els_flogi *pl; | 1519 | struct fc_els_flogi *pl; |
1313 | struct fc_seq_els_data rjt_data; | 1520 | struct fc_seq_els_data rjt_data; |
1314 | u32 sid, f_ctl; | 1521 | u32 sid; |
1315 | 1522 | ||
1316 | rjt_data.fp = NULL; | 1523 | sid = fc_frame_sid(fp); |
1317 | fh = fc_frame_header_get(fp); | ||
1318 | sid = ntoh24(fh->fh_s_id); | ||
1319 | 1524 | ||
1320 | FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n"); | 1525 | FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n"); |
1321 | 1526 | ||
@@ -1358,6 +1563,9 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, | |||
1358 | case RPORT_ST_INIT: | 1563 | case RPORT_ST_INIT: |
1359 | FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n"); | 1564 | FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n"); |
1360 | break; | 1565 | break; |
1566 | case RPORT_ST_PLOGI_WAIT: | ||
1567 | FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI_WAIT state\n"); | ||
1568 | break; | ||
1361 | case RPORT_ST_PLOGI: | 1569 | case RPORT_ST_PLOGI: |
1362 | FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n"); | 1570 | FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n"); |
1363 | if (rdata->ids.port_name < lport->wwpn) { | 1571 | if (rdata->ids.port_name < lport->wwpn) { |
@@ -1375,9 +1583,8 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, | |||
1375 | "- ignored for now\n", rdata->rp_state); | 1583 | "- ignored for now\n", rdata->rp_state); |
1376 | /* XXX TBD - should reset */ | 1584 | /* XXX TBD - should reset */ |
1377 | break; | 1585 | break; |
1586 | case RPORT_ST_FLOGI: | ||
1378 | case RPORT_ST_DELETE: | 1587 | case RPORT_ST_DELETE: |
1379 | case RPORT_ST_LOGO: | ||
1380 | case RPORT_ST_RESTART: | ||
1381 | FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n", | 1588 | FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n", |
1382 | fc_rport_state(rdata)); | 1589 | fc_rport_state(rdata)); |
1383 | mutex_unlock(&rdata->rp_mutex); | 1590 | mutex_unlock(&rdata->rp_mutex); |
@@ -1390,50 +1597,41 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, | |||
1390 | * Get session payload size from incoming PLOGI. | 1597 | * Get session payload size from incoming PLOGI. |
1391 | */ | 1598 | */ |
1392 | rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs); | 1599 | rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs); |
1393 | fc_frame_free(rx_fp); | ||
1394 | 1600 | ||
1395 | /* | 1601 | /* |
1396 | * Send LS_ACC. If this fails, the originator should retry. | 1602 | * Send LS_ACC. If this fails, the originator should retry. |
1397 | */ | 1603 | */ |
1398 | sp = lport->tt.seq_start_next(sp); | ||
1399 | if (!sp) | ||
1400 | goto out; | ||
1401 | fp = fc_frame_alloc(lport, sizeof(*pl)); | 1604 | fp = fc_frame_alloc(lport, sizeof(*pl)); |
1402 | if (!fp) | 1605 | if (!fp) |
1403 | goto out; | 1606 | goto out; |
1404 | 1607 | ||
1405 | fc_plogi_fill(lport, fp, ELS_LS_ACC); | 1608 | fc_plogi_fill(lport, fp, ELS_LS_ACC); |
1406 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; | 1609 | fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); |
1407 | ep = fc_seq_exch(sp); | 1610 | lport->tt.frame_send(lport, fp); |
1408 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, | ||
1409 | FC_TYPE_ELS, f_ctl, 0); | ||
1410 | lport->tt.seq_send(lport, sp, fp); | ||
1411 | fc_rport_enter_prli(rdata); | 1611 | fc_rport_enter_prli(rdata); |
1412 | out: | 1612 | out: |
1413 | mutex_unlock(&rdata->rp_mutex); | 1613 | mutex_unlock(&rdata->rp_mutex); |
1614 | fc_frame_free(rx_fp); | ||
1414 | return; | 1615 | return; |
1415 | 1616 | ||
1416 | reject: | 1617 | reject: |
1417 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | 1618 | lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data); |
1418 | fc_frame_free(fp); | 1619 | fc_frame_free(fp); |
1419 | } | 1620 | } |
1420 | 1621 | ||
1421 | /** | 1622 | /** |
1422 | * fc_rport_recv_prli_req() - Handler for process login (PRLI) requests | 1623 | * fc_rport_recv_prli_req() - Handler for process login (PRLI) requests |
1423 | * @rdata: The remote port that sent the PRLI request | 1624 | * @rdata: The remote port that sent the PRLI request |
1424 | * @sp: The sequence that the PRLI was on | ||
1425 | * @rx_fp: The PRLI request frame | 1625 | * @rx_fp: The PRLI request frame |
1426 | * | 1626 | * |
1427 | * Locking Note: The rport lock is exected to be held before calling | 1627 | * Locking Note: The rport lock is exected to be held before calling |
1428 | * this function. | 1628 | * this function. |
1429 | */ | 1629 | */ |
1430 | static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, | 1630 | static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, |
1431 | struct fc_seq *sp, struct fc_frame *rx_fp) | 1631 | struct fc_frame *rx_fp) |
1432 | { | 1632 | { |
1433 | struct fc_lport *lport = rdata->local_port; | 1633 | struct fc_lport *lport = rdata->local_port; |
1434 | struct fc_exch *ep; | ||
1435 | struct fc_frame *fp; | 1634 | struct fc_frame *fp; |
1436 | struct fc_frame_header *fh; | ||
1437 | struct { | 1635 | struct { |
1438 | struct fc_els_prli prli; | 1636 | struct fc_els_prli prli; |
1439 | struct fc_els_spp spp; | 1637 | struct fc_els_spp spp; |
@@ -1444,17 +1642,13 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, | |||
1444 | unsigned int plen; | 1642 | unsigned int plen; |
1445 | enum fc_els_spp_resp resp; | 1643 | enum fc_els_spp_resp resp; |
1446 | struct fc_seq_els_data rjt_data; | 1644 | struct fc_seq_els_data rjt_data; |
1447 | u32 f_ctl; | ||
1448 | u32 fcp_parm; | 1645 | u32 fcp_parm; |
1449 | u32 roles = FC_RPORT_ROLE_UNKNOWN; | 1646 | u32 roles = FC_RPORT_ROLE_UNKNOWN; |
1450 | 1647 | ||
1451 | rjt_data.fp = NULL; | ||
1452 | fh = fc_frame_header_get(rx_fp); | ||
1453 | |||
1454 | FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", | 1648 | FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", |
1455 | fc_rport_state(rdata)); | 1649 | fc_rport_state(rdata)); |
1456 | 1650 | ||
1457 | len = fr_len(rx_fp) - sizeof(*fh); | 1651 | len = fr_len(rx_fp) - sizeof(struct fc_frame_header); |
1458 | pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); | 1652 | pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); |
1459 | if (!pp) | 1653 | if (!pp) |
1460 | goto reject_len; | 1654 | goto reject_len; |
@@ -1475,8 +1669,6 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, | |||
1475 | rjt_data.explan = ELS_EXPL_INSUF_RES; | 1669 | rjt_data.explan = ELS_EXPL_INSUF_RES; |
1476 | goto reject; | 1670 | goto reject; |
1477 | } | 1671 | } |
1478 | sp = lport->tt.seq_start_next(sp); | ||
1479 | WARN_ON(!sp); | ||
1480 | pp = fc_frame_payload_get(fp, len); | 1672 | pp = fc_frame_payload_get(fp, len); |
1481 | WARN_ON(!pp); | 1673 | WARN_ON(!pp); |
1482 | memset(pp, 0, len); | 1674 | memset(pp, 0, len); |
@@ -1529,12 +1721,8 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, | |||
1529 | /* | 1721 | /* |
1530 | * Send LS_ACC. If this fails, the originator should retry. | 1722 | * Send LS_ACC. If this fails, the originator should retry. |
1531 | */ | 1723 | */ |
1532 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; | 1724 | fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); |
1533 | f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; | 1725 | lport->tt.frame_send(lport, fp); |
1534 | ep = fc_seq_exch(sp); | ||
1535 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, | ||
1536 | FC_TYPE_ELS, f_ctl, 0); | ||
1537 | lport->tt.seq_send(lport, sp, fp); | ||
1538 | 1726 | ||
1539 | switch (rdata->rp_state) { | 1727 | switch (rdata->rp_state) { |
1540 | case RPORT_ST_PRLI: | 1728 | case RPORT_ST_PRLI: |
@@ -1549,7 +1737,7 @@ reject_len: | |||
1549 | rjt_data.reason = ELS_RJT_PROT; | 1737 | rjt_data.reason = ELS_RJT_PROT; |
1550 | rjt_data.explan = ELS_EXPL_INV_LEN; | 1738 | rjt_data.explan = ELS_EXPL_INV_LEN; |
1551 | reject: | 1739 | reject: |
1552 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | 1740 | lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); |
1553 | drop: | 1741 | drop: |
1554 | fc_frame_free(rx_fp); | 1742 | fc_frame_free(rx_fp); |
1555 | } | 1743 | } |
@@ -1557,54 +1745,90 @@ drop: | |||
1557 | /** | 1745 | /** |
1558 | * fc_rport_recv_prlo_req() - Handler for process logout (PRLO) requests | 1746 | * fc_rport_recv_prlo_req() - Handler for process logout (PRLO) requests |
1559 | * @rdata: The remote port that sent the PRLO request | 1747 | * @rdata: The remote port that sent the PRLO request |
1560 | * @sp: The sequence that the PRLO was on | 1748 | * @rx_fp: The PRLO request frame |
1561 | * @fp: The PRLO request frame | ||
1562 | * | 1749 | * |
1563 | * Locking Note: The rport lock is exected to be held before calling | 1750 | * Locking Note: The rport lock is exected to be held before calling |
1564 | * this function. | 1751 | * this function. |
1565 | */ | 1752 | */ |
1566 | static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, | 1753 | static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, |
1567 | struct fc_seq *sp, | 1754 | struct fc_frame *rx_fp) |
1568 | struct fc_frame *fp) | ||
1569 | { | 1755 | { |
1570 | struct fc_lport *lport = rdata->local_port; | 1756 | struct fc_lport *lport = rdata->local_port; |
1571 | 1757 | struct fc_frame *fp; | |
1572 | struct fc_frame_header *fh; | 1758 | struct { |
1759 | struct fc_els_prlo prlo; | ||
1760 | struct fc_els_spp spp; | ||
1761 | } *pp; | ||
1762 | struct fc_els_spp *rspp; /* request service param page */ | ||
1763 | struct fc_els_spp *spp; /* response spp */ | ||
1764 | unsigned int len; | ||
1765 | unsigned int plen; | ||
1573 | struct fc_seq_els_data rjt_data; | 1766 | struct fc_seq_els_data rjt_data; |
1574 | 1767 | ||
1575 | fh = fc_frame_header_get(fp); | ||
1576 | |||
1577 | FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n", | 1768 | FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n", |
1578 | fc_rport_state(rdata)); | 1769 | fc_rport_state(rdata)); |
1579 | 1770 | ||
1580 | rjt_data.fp = NULL; | 1771 | len = fr_len(rx_fp) - sizeof(struct fc_frame_header); |
1581 | rjt_data.reason = ELS_RJT_UNAB; | 1772 | pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); |
1582 | rjt_data.explan = ELS_EXPL_NONE; | 1773 | if (!pp) |
1583 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | 1774 | goto reject_len; |
1584 | fc_frame_free(fp); | 1775 | plen = ntohs(pp->prlo.prlo_len); |
1776 | if (plen != 20) | ||
1777 | goto reject_len; | ||
1778 | if (plen < len) | ||
1779 | len = plen; | ||
1780 | |||
1781 | rspp = &pp->spp; | ||
1782 | |||
1783 | fp = fc_frame_alloc(lport, len); | ||
1784 | if (!fp) { | ||
1785 | rjt_data.reason = ELS_RJT_UNAB; | ||
1786 | rjt_data.explan = ELS_EXPL_INSUF_RES; | ||
1787 | goto reject; | ||
1788 | } | ||
1789 | |||
1790 | pp = fc_frame_payload_get(fp, len); | ||
1791 | WARN_ON(!pp); | ||
1792 | memset(pp, 0, len); | ||
1793 | pp->prlo.prlo_cmd = ELS_LS_ACC; | ||
1794 | pp->prlo.prlo_obs = 0x10; | ||
1795 | pp->prlo.prlo_len = htons(len); | ||
1796 | spp = &pp->spp; | ||
1797 | spp->spp_type = rspp->spp_type; | ||
1798 | spp->spp_type_ext = rspp->spp_type_ext; | ||
1799 | spp->spp_flags = FC_SPP_RESP_ACK; | ||
1800 | |||
1801 | fc_rport_enter_delete(rdata, RPORT_EV_LOGO); | ||
1802 | |||
1803 | fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); | ||
1804 | lport->tt.frame_send(lport, fp); | ||
1805 | goto drop; | ||
1806 | |||
1807 | reject_len: | ||
1808 | rjt_data.reason = ELS_RJT_PROT; | ||
1809 | rjt_data.explan = ELS_EXPL_INV_LEN; | ||
1810 | reject: | ||
1811 | lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); | ||
1812 | drop: | ||
1813 | fc_frame_free(rx_fp); | ||
1585 | } | 1814 | } |
1586 | 1815 | ||
1587 | /** | 1816 | /** |
1588 | * fc_rport_recv_logo_req() - Handler for logout (LOGO) requests | 1817 | * fc_rport_recv_logo_req() - Handler for logout (LOGO) requests |
1589 | * @lport: The local port that received the LOGO request | 1818 | * @lport: The local port that received the LOGO request |
1590 | * @sp: The sequence that the LOGO request was on | ||
1591 | * @fp: The LOGO request frame | 1819 | * @fp: The LOGO request frame |
1592 | * | 1820 | * |
1593 | * Locking Note: The rport lock is exected to be held before calling | 1821 | * Locking Note: The rport lock is exected to be held before calling |
1594 | * this function. | 1822 | * this function. |
1595 | */ | 1823 | */ |
1596 | static void fc_rport_recv_logo_req(struct fc_lport *lport, | 1824 | static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) |
1597 | struct fc_seq *sp, | ||
1598 | struct fc_frame *fp) | ||
1599 | { | 1825 | { |
1600 | struct fc_frame_header *fh; | ||
1601 | struct fc_rport_priv *rdata; | 1826 | struct fc_rport_priv *rdata; |
1602 | u32 sid; | 1827 | u32 sid; |
1603 | 1828 | ||
1604 | lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); | 1829 | lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); |
1605 | 1830 | ||
1606 | fh = fc_frame_header_get(fp); | 1831 | sid = fc_frame_sid(fp); |
1607 | sid = ntoh24(fh->fh_s_id); | ||
1608 | 1832 | ||
1609 | mutex_lock(&lport->disc.disc_mutex); | 1833 | mutex_lock(&lport->disc.disc_mutex); |
1610 | rdata = lport->tt.rport_lookup(lport, sid); | 1834 | rdata = lport->tt.rport_lookup(lport, sid); |
@@ -1614,13 +1838,6 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, | |||
1614 | fc_rport_state(rdata)); | 1838 | fc_rport_state(rdata)); |
1615 | 1839 | ||
1616 | fc_rport_enter_delete(rdata, RPORT_EV_LOGO); | 1840 | fc_rport_enter_delete(rdata, RPORT_EV_LOGO); |
1617 | |||
1618 | /* | ||
1619 | * If the remote port was created due to discovery, set state | ||
1620 | * to log back in. It may have seen a stale RSCN about us. | ||
1621 | */ | ||
1622 | if (rdata->disc_id) | ||
1623 | fc_rport_state_enter(rdata, RPORT_ST_RESTART); | ||
1624 | mutex_unlock(&rdata->rp_mutex); | 1841 | mutex_unlock(&rdata->rp_mutex); |
1625 | } else | 1842 | } else |
1626 | FC_RPORT_ID_DBG(lport, sid, | 1843 | FC_RPORT_ID_DBG(lport, sid, |