aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/libfc/fc_rport.c69
-rw-r--r--include/scsi/libfc.h1
2 files changed, 51 insertions, 19 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 49abb839a223..324e156b5d07 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -86,6 +86,7 @@ static const char *fc_rport_state_names[] = {
86 [RPORT_ST_LOGO] = "LOGO", 86 [RPORT_ST_LOGO] = "LOGO",
87 [RPORT_ST_ADISC] = "ADISC", 87 [RPORT_ST_ADISC] = "ADISC",
88 [RPORT_ST_DELETE] = "Delete", 88 [RPORT_ST_DELETE] = "Delete",
89 [RPORT_ST_RESTART] = "Restart",
89}; 90};
90 91
91/** 92/**
@@ -99,8 +100,7 @@ static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
99 struct fc_rport_priv *rdata; 100 struct fc_rport_priv *rdata;
100 101
101 list_for_each_entry(rdata, &lport->disc.rports, peers) 102 list_for_each_entry(rdata, &lport->disc.rports, peers)
102 if (rdata->ids.port_id == port_id && 103 if (rdata->ids.port_id == port_id)
103 rdata->rp_state != RPORT_ST_DELETE)
104 return rdata; 104 return rdata;
105 return NULL; 105 return NULL;
106} 106}
@@ -235,6 +235,7 @@ static void fc_rport_work(struct work_struct *work)
235 struct fc_rport_operations *rport_ops; 235 struct fc_rport_operations *rport_ops;
236 struct fc_rport_identifiers ids; 236 struct fc_rport_identifiers ids;
237 struct fc_rport *rport; 237 struct fc_rport *rport;
238 int restart = 0;
238 239
239 mutex_lock(&rdata->rp_mutex); 240 mutex_lock(&rdata->rp_mutex);
240 event = rdata->event; 241 event = rdata->event;
@@ -287,8 +288,19 @@ static void fc_rport_work(struct work_struct *work)
287 mutex_unlock(&rdata->rp_mutex); 288 mutex_unlock(&rdata->rp_mutex);
288 289
289 if (port_id != FC_FID_DIR_SERV) { 290 if (port_id != FC_FID_DIR_SERV) {
291 /*
292 * We must drop rp_mutex before taking disc_mutex.
293 * Re-evaluate state to allow for restart.
294 * A transition to RESTART state must only happen
295 * while disc_mutex is held and rdata is on the list.
296 */
290 mutex_lock(&lport->disc.disc_mutex); 297 mutex_lock(&lport->disc.disc_mutex);
291 list_del(&rdata->peers); 298 mutex_lock(&rdata->rp_mutex);
299 if (rdata->rp_state == RPORT_ST_RESTART)
300 restart = 1;
301 else
302 list_del(&rdata->peers);
303 mutex_unlock(&rdata->rp_mutex);
292 mutex_unlock(&lport->disc.disc_mutex); 304 mutex_unlock(&lport->disc.disc_mutex);
293 } 305 }
294 306
@@ -312,7 +324,13 @@ static void fc_rport_work(struct work_struct *work)
312 mutex_unlock(&rdata->rp_mutex); 324 mutex_unlock(&rdata->rp_mutex);
313 fc_remote_port_delete(rport); 325 fc_remote_port_delete(rport);
314 } 326 }
315 kref_put(&rdata->kref, lport->tt.rport_destroy); 327 if (restart) {
328 mutex_lock(&rdata->rp_mutex);
329 FC_RPORT_DBG(rdata, "work restart\n");
330 fc_rport_enter_plogi(rdata);
331 mutex_unlock(&rdata->rp_mutex);
332 } else
333 kref_put(&rdata->kref, lport->tt.rport_destroy);
316 break; 334 break;
317 335
318 default: 336 default:
@@ -342,6 +360,12 @@ int fc_rport_login(struct fc_rport_priv *rdata)
342 FC_RPORT_DBG(rdata, "ADISC port\n"); 360 FC_RPORT_DBG(rdata, "ADISC port\n");
343 fc_rport_enter_adisc(rdata); 361 fc_rport_enter_adisc(rdata);
344 break; 362 break;
363 case RPORT_ST_RESTART:
364 break;
365 case RPORT_ST_DELETE:
366 FC_RPORT_DBG(rdata, "Restart deleted port\n");
367 fc_rport_state_enter(rdata, RPORT_ST_RESTART);
368 break;
345 default: 369 default:
346 FC_RPORT_DBG(rdata, "Login to port\n"); 370 FC_RPORT_DBG(rdata, "Login to port\n");
347 fc_rport_enter_plogi(rdata); 371 fc_rport_enter_plogi(rdata);
@@ -397,20 +421,21 @@ int fc_rport_logoff(struct fc_rport_priv *rdata)
397 421
398 if (rdata->rp_state == RPORT_ST_DELETE) { 422 if (rdata->rp_state == RPORT_ST_DELETE) {
399 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n"); 423 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
400 mutex_unlock(&rdata->rp_mutex);
401 goto out; 424 goto out;
402 } 425 }
403 426
404 fc_rport_enter_logo(rdata); 427 if (rdata->rp_state == RPORT_ST_RESTART)
428 FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n");
429 else
430 fc_rport_enter_logo(rdata);
405 431
406 /* 432 /*
407 * Change the state to Delete so that we discard 433 * Change the state to Delete so that we discard
408 * the response. 434 * the response.
409 */ 435 */
410 fc_rport_enter_delete(rdata, RPORT_EV_STOP); 436 fc_rport_enter_delete(rdata, RPORT_EV_STOP);
411 mutex_unlock(&rdata->rp_mutex);
412
413out: 437out:
438 mutex_unlock(&rdata->rp_mutex);
414 return 0; 439 return 0;
415} 440}
416 441
@@ -466,6 +491,7 @@ static void fc_rport_timeout(struct work_struct *work)
466 case RPORT_ST_READY: 491 case RPORT_ST_READY:
467 case RPORT_ST_INIT: 492 case RPORT_ST_INIT:
468 case RPORT_ST_DELETE: 493 case RPORT_ST_DELETE:
494 case RPORT_ST_RESTART:
469 break; 495 break;
470 } 496 }
471 497
@@ -499,6 +525,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
499 fc_rport_enter_logo(rdata); 525 fc_rport_enter_logo(rdata);
500 break; 526 break;
501 case RPORT_ST_DELETE: 527 case RPORT_ST_DELETE:
528 case RPORT_ST_RESTART:
502 case RPORT_ST_READY: 529 case RPORT_ST_READY:
503 case RPORT_ST_INIT: 530 case RPORT_ST_INIT:
504 break; 531 break;
@@ -1248,6 +1275,7 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
1248 } 1275 }
1249 break; 1276 break;
1250 case RPORT_ST_PRLI: 1277 case RPORT_ST_PRLI:
1278 case RPORT_ST_RTV:
1251 case RPORT_ST_READY: 1279 case RPORT_ST_READY:
1252 case RPORT_ST_ADISC: 1280 case RPORT_ST_ADISC:
1253 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d " 1281 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
@@ -1255,11 +1283,14 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
1255 /* XXX TBD - should reset */ 1283 /* XXX TBD - should reset */
1256 break; 1284 break;
1257 case RPORT_ST_DELETE: 1285 case RPORT_ST_DELETE:
1258 default: 1286 case RPORT_ST_LOGO:
1259 FC_RPORT_DBG(rdata, "Received PLOGI in unexpected state %d\n", 1287 case RPORT_ST_RESTART:
1260 rdata->rp_state); 1288 FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n",
1261 fc_frame_free(rx_fp); 1289 fc_rport_state(rdata));
1262 goto out; 1290 mutex_unlock(&rdata->rp_mutex);
1291 rjt_data.reason = ELS_RJT_BUSY;
1292 rjt_data.explan = ELS_EXPL_NONE;
1293 goto reject;
1263 } 1294 }
1264 1295
1265 /* 1296 /*
@@ -1510,14 +1541,14 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,
1510 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", 1541 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
1511 fc_rport_state(rdata)); 1542 fc_rport_state(rdata));
1512 1543
1544 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
1545
1513 /* 1546 /*
1514 * If the remote port was created due to discovery, 1547 * If the remote port was created due to discovery, set state
1515 * log back in. It may have seen a stale RSCN about us. 1548 * to log back in. It may have seen a stale RSCN about us.
1516 */ 1549 */
1517 if (rdata->rp_state != RPORT_ST_DELETE && rdata->disc_id) 1550 if (rdata->disc_id)
1518 fc_rport_enter_plogi(rdata); 1551 fc_rport_state_enter(rdata, RPORT_ST_RESTART);
1519 else
1520 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
1521 mutex_unlock(&rdata->rp_mutex); 1552 mutex_unlock(&rdata->rp_mutex);
1522 } else 1553 } else
1523 FC_RPORT_ID_DBG(lport, sid, 1554 FC_RPORT_ID_DBG(lport, sid,
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 4ff148580562..1662d73d85a7 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -145,6 +145,7 @@ enum fc_rport_state {
145 RPORT_ST_LOGO, /* port logout sent */ 145 RPORT_ST_LOGO, /* port logout sent */
146 RPORT_ST_ADISC, /* Discover Address sent */ 146 RPORT_ST_ADISC, /* Discover Address sent */
147 RPORT_ST_DELETE, /* port being deleted */ 147 RPORT_ST_DELETE, /* port being deleted */
148 RPORT_ST_RESTART, /* remote port being deleted and will restart */
148}; 149};
149 150
150/** 151/**