diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_rport.c')
| -rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 82 | 
1 files changed, 61 insertions, 21 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 0472bb73221..747d73c5c8a 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -267,6 +267,10 @@ static void fc_rport_work(struct work_struct *work)  			       "(%6x).\n", ids.port_id);  			event = RPORT_EV_FAILED;  		} +		if (rport->port_id != FC_FID_DIR_SERV) +			if (rport_ops->event_callback) +				rport_ops->event_callback(lport, rport, +							  RPORT_EV_FAILED);  		put_device(&rport->dev);  		rport = new_rport;  		rdata = new_rport->dd_data; @@ -325,11 +329,20 @@ int fc_rport_login(struct fc_rport *rport)  int fc_rport_logoff(struct fc_rport *rport)  {  	struct fc_rport_libfc_priv *rdata = rport->dd_data; +	struct fc_lport *lport = rdata->local_port;  	mutex_lock(&rdata->rp_mutex);  	FC_DEBUG_RPORT("Remove port (%6x)\n", rport->port_id); +	if (rdata->rp_state == RPORT_ST_NONE) { +		FC_DEBUG_RPORT("(%6x): Port (%6x) in NONE state," +			       " not removing", fc_host_port_id(lport->host), +			       rport->port_id); +		mutex_unlock(&rdata->rp_mutex); +		goto out; +	} +  	fc_rport_enter_logo(rport);  	/* @@ -349,6 +362,7 @@ int fc_rport_logoff(struct fc_rport *rport)  	mutex_unlock(&rdata->rp_mutex); +out:  	return 0;  } @@ -430,6 +444,7 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp)  	case RPORT_ST_PRLI:  	case RPORT_ST_LOGO:  		rdata->event = RPORT_EV_FAILED; +		fc_rport_state_enter(rport, RPORT_ST_NONE);  		queue_work(rport_event_queue,  			   &rdata->event_work);  		break; @@ -494,7 +509,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,  	struct fc_rport *rport = rp_arg;  	struct fc_rport_libfc_priv *rdata = rport->dd_data;  	struct fc_lport *lport = rdata->local_port; -	struct fc_els_flogi *plp; +	struct fc_els_flogi *plp = NULL;  	unsigned int tov;  	u16 csp_seq;  	u16 cssp_seq; @@ -505,17 +520,19 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,  	FC_DEBUG_RPORT("Received a PLOGI response from port (%6x)\n",  		       rport->port_id); -	if (IS_ERR(fp)) { -		fc_rport_error_retry(rport, fp); -		goto err; -	} -  	if (rdata->rp_state != RPORT_ST_PLOGI) {  		FC_DBG("Received a PLOGI response, but in state %s\n",  		       fc_rport_state(rport)); +		if (IS_ERR(fp)) +			goto err;  		goto out;  	} +	if (IS_ERR(fp)) { +		fc_rport_error_retry(rport, fp); +		goto err; +	} +  	op = fc_frame_payload_op(fp);  	if (op == ELS_LS_ACC &&  	    (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) { @@ -614,17 +631,19 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,  	FC_DEBUG_RPORT("Received a PRLI response from port (%6x)\n",  		       rport->port_id); -	if (IS_ERR(fp)) { -		fc_rport_error_retry(rport, fp); -		goto err; -	} -  	if (rdata->rp_state != RPORT_ST_PRLI) {  		FC_DBG("Received a PRLI response, but in state %s\n",  		       fc_rport_state(rport)); +		if (IS_ERR(fp)) +			goto err;  		goto out;  	} +	if (IS_ERR(fp)) { +		fc_rport_error_retry(rport, fp); +		goto err; +	} +  	op = fc_frame_payload_op(fp);  	if (op == ELS_LS_ACC) {  		pp = fc_frame_payload_get(fp, sizeof(*pp)); @@ -646,6 +665,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,  	} else {  		FC_DBG("Bad ELS response\n");  		rdata->event = RPORT_EV_FAILED; +		fc_rport_state_enter(rport, RPORT_ST_NONE);  		queue_work(rport_event_queue, &rdata->event_work);  	} @@ -678,23 +698,26 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,  	FC_DEBUG_RPORT("Received a LOGO response from port (%6x)\n",  		       rport->port_id); -	if (IS_ERR(fp)) { -		fc_rport_error_retry(rport, fp); -		goto err; -	} -  	if (rdata->rp_state != RPORT_ST_LOGO) {  		FC_DEBUG_RPORT("Received a LOGO response, but in state %s\n",  			       fc_rport_state(rport)); +		if (IS_ERR(fp)) +			goto err;  		goto out;  	} +	if (IS_ERR(fp)) { +		fc_rport_error_retry(rport, fp); +		goto err; +	} +  	op = fc_frame_payload_op(fp);  	if (op == ELS_LS_ACC) {  		fc_rport_enter_rtv(rport);  	} else {  		FC_DBG("Bad ELS response\n");  		rdata->event = RPORT_EV_LOGO; +		fc_rport_state_enter(rport, RPORT_ST_NONE);  		queue_work(rport_event_queue, &rdata->event_work);  	} @@ -764,17 +787,19 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,  	FC_DEBUG_RPORT("Received a RTV response from port (%6x)\n",  		       rport->port_id); -	if (IS_ERR(fp)) { -		fc_rport_error(rport, fp); -		goto err; -	} -  	if (rdata->rp_state != RPORT_ST_RTV) {  		FC_DBG("Received a RTV response, but in state %s\n",  		       fc_rport_state(rport)); +		if (IS_ERR(fp)) +			goto err;  		goto out;  	} +	if (IS_ERR(fp)) { +		fc_rport_error(rport, fp); +		goto err; +	} +  	op = fc_frame_payload_op(fp);  	if (op == ELS_LS_ACC) {  		struct fc_els_rtv_acc *rtv; @@ -1007,6 +1032,8 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport,  	default:  		FC_DEBUG_RPORT("incoming PLOGI from %x in unexpected "  			       "state %d\n", sid, rdata->rp_state); +		fc_frame_free(fp); +		return;  		break;  	} @@ -1098,6 +1125,8 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport,  		reason = ELS_RJT_NONE;  		break;  	default: +		fc_frame_free(rx_fp); +		return;  		break;  	}  	len = fr_len(rx_fp) - sizeof(*fh); @@ -1227,6 +1256,11 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp,  		       "while in state %s\n", ntoh24(fh->fh_s_id),  		       fc_rport_state(rport)); +	if (rdata->rp_state == RPORT_ST_NONE) { +		fc_frame_free(fp); +		return; +	} +  	rjt_data.fp = NULL;  	rjt_data.reason = ELS_RJT_UNAB;  	rjt_data.explan = ELS_EXPL_NONE; @@ -1256,7 +1290,13 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp,  		       "while in state %s\n", ntoh24(fh->fh_s_id),  		       fc_rport_state(rport)); +	if (rdata->rp_state == RPORT_ST_NONE) { +		fc_frame_free(fp); +		return; +	} +  	rdata->event = RPORT_EV_LOGO; +	fc_rport_state_enter(rport, RPORT_ST_NONE);  	queue_work(rport_event_queue, &rdata->event_work);  	lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);  |