diff options
Diffstat (limited to 'drivers/scsi/ibmvscsi/ibmvfc.c')
| -rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.c | 434 | 
1 files changed, 304 insertions, 130 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index ea4abee7a2a..b4b805e8d7d 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -110,7 +110,7 @@ static const struct {  	{ IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_DEAD, DID_ERROR, 0, 1, "transport dead" },  	{ IBMVFC_FABRIC_MAPPED, IBMVFC_CONFIG_ERROR, DID_ERROR, 1, 1, "configuration error" },  	{ IBMVFC_FABRIC_MAPPED, IBMVFC_NAME_SERVER_FAIL, DID_ERROR, 1, 1, "name server failure" }, -	{ IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 0, 0, "link halted" }, +	{ IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 1, 0, "link halted" },  	{ IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_GENERAL, DID_OK, 1, 0, "general transport error" },  	{ IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" }, @@ -143,6 +143,7 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *);  static void ibmvfc_tgt_send_prli(struct ibmvfc_target *);  static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *);  static void ibmvfc_tgt_query_target(struct ibmvfc_target *); +static void ibmvfc_npiv_logout(struct ibmvfc_host *);  static const char *unknown_error = "unknown error"; @@ -275,7 +276,7 @@ static int ibmvfc_get_err_result(struct ibmvfc_cmd *vfc_cmd)  	int fc_rsp_len = rsp->fcp_rsp_len;  	if ((rsp->flags & FCP_RSP_LEN_VALID) && -	    ((!fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) || +	    ((fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) ||  	     rsp->data.info.rsp_code))  		return DID_ERROR << 16; @@ -431,6 +432,8 @@ static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt,  	case IBMVFC_TGT_ACTION_DEL_RPORT:  		break;  	default: +		if (action == IBMVFC_TGT_ACTION_DEL_RPORT) +			tgt->add_rport = 0;  		tgt->action = action;  		break;  	} @@ -475,6 +478,10 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,  		if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT)  			vhost->action = action;  		break; +	case IBMVFC_HOST_ACTION_LOGO_WAIT: +		if (vhost->action == IBMVFC_HOST_ACTION_LOGO) +			vhost->action = action; +		break;  	case IBMVFC_HOST_ACTION_INIT_WAIT:  		if (vhost->action == IBMVFC_HOST_ACTION_INIT)  			vhost->action = action; @@ -483,7 +490,7 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,  		switch (vhost->action) {  		case IBMVFC_HOST_ACTION_INIT_WAIT:  		case IBMVFC_HOST_ACTION_NONE: -		case IBMVFC_HOST_ACTION_TGT_ADD: +		case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:  			vhost->action = action;  			break;  		default: @@ -494,11 +501,11 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,  		if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS)  			vhost->action = action;  		break; +	case IBMVFC_HOST_ACTION_LOGO:  	case IBMVFC_HOST_ACTION_INIT:  	case IBMVFC_HOST_ACTION_TGT_DEL:  	case IBMVFC_HOST_ACTION_QUERY_TGTS:  	case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: -	case IBMVFC_HOST_ACTION_TGT_ADD:  	case IBMVFC_HOST_ACTION_NONE:  	default:  		vhost->action = action; @@ -576,7 +583,7 @@ static void ibmvfc_init_host(struct ibmvfc_host *vhost, int relogin)  		}  		list_for_each_entry(tgt, &vhost->targets, queue) -			tgt->need_login = 1; +			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);  		scsi_block_requests(vhost->host);  		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);  		vhost->job_step = ibmvfc_npiv_login; @@ -646,6 +653,7 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)  	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));  	vhost->state = IBMVFC_NO_CRQ; +	vhost->logged_in = 0;  	dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL);  	free_page((unsigned long)crq->msgs);  } @@ -692,6 +700,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)  	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));  	vhost->state = IBMVFC_NO_CRQ; +	vhost->logged_in = 0;  	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);  	/* Clean out the queue */ @@ -807,10 +816,10 @@ static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code)  }  /** - * __ibmvfc_reset_host - Reset the connection to the server (no locking) + * ibmvfc_hard_reset_host - Reset the connection to the server by breaking the CRQ   * @vhost:	struct ibmvfc host to reset   **/ -static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) +static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost)  {  	int rc; @@ -826,9 +835,25 @@ static void __ibmvfc_reset_host(struct ibmvfc_host *vhost)  }  /** - * ibmvfc_reset_host - Reset the connection to the server + * __ibmvfc_reset_host - Reset the connection to the server (no locking)   * @vhost:	struct ibmvfc host to reset   **/ +static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) +{ +	if (vhost->logged_in && vhost->action != IBMVFC_HOST_ACTION_LOGO_WAIT && +	    !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { +		scsi_block_requests(vhost->host); +		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO); +		vhost->job_step = ibmvfc_npiv_logout; +		wake_up(&vhost->work_wait_q); +	} else +		ibmvfc_hard_reset_host(vhost); +} + +/** + * ibmvfc_reset_host - Reset the connection to the server + * @vhost:	ibmvfc host struct + **/  static void ibmvfc_reset_host(struct ibmvfc_host *vhost)  {  	unsigned long flags; @@ -842,9 +867,13 @@ static void ibmvfc_reset_host(struct ibmvfc_host *vhost)   * ibmvfc_retry_host_init - Retry host initialization if allowed   * @vhost:	ibmvfc host struct   * + * Returns: 1 if init will be retried / 0 if not + *   **/ -static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost) +static int ibmvfc_retry_host_init(struct ibmvfc_host *vhost)  { +	int retry = 0; +  	if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) {  		vhost->delay_init = 1;  		if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { @@ -853,11 +882,14 @@ static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost)  			ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);  		} else if (vhost->init_retries == IBMVFC_MAX_HOST_INIT_RETRIES)  			__ibmvfc_reset_host(vhost); -		else +		else {  			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); +			retry = 1; +		}  	}  	wake_up(&vhost->work_wait_q); +	return retry;  }  /** @@ -1137,8 +1169,9 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)  	login_info->partition_num = vhost->partition_number;  	login_info->vfc_frame_version = 1;  	login_info->fcp_version = 3; +	login_info->flags = IBMVFC_FLUSH_ON_HALT;  	if (vhost->client_migrated) -		login_info->flags = IBMVFC_CLIENT_MIGRATED; +		login_info->flags |= IBMVFC_CLIENT_MIGRATED;  	login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ;  	login_info->capabilities = IBMVFC_CAN_MIGRATE; @@ -1452,6 +1485,27 @@ static void ibmvfc_log_error(struct ibmvfc_event *evt)  }  /** + * ibmvfc_relogin - Log back into the specified device + * @sdev:	scsi device struct + * + **/ +static void ibmvfc_relogin(struct scsi_device *sdev) +{ +	struct ibmvfc_host *vhost = shost_priv(sdev->host); +	struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); +	struct ibmvfc_target *tgt; + +	list_for_each_entry(tgt, &vhost->targets, queue) { +		if (rport == tgt->rport) { +			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); +			break; +		} +	} + +	ibmvfc_reinit_host(vhost); +} + +/**   * ibmvfc_scsi_done - Handle responses from commands   * @evt:	ibmvfc event to be handled   * @@ -1483,7 +1537,7 @@ static void ibmvfc_scsi_done(struct ibmvfc_event *evt)  			if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8)  				memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len);  			if ((vfc_cmd->status & IBMVFC_VIOS_FAILURE) && (vfc_cmd->error == IBMVFC_PLOGI_REQUIRED)) -				ibmvfc_reinit_host(evt->vhost); +				ibmvfc_relogin(cmnd->device);  			if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER)))  				cmnd->result = (DID_ERROR << 16); @@ -2148,13 +2202,31 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,  				struct ibmvfc_host *vhost)  {  	const char *desc = ibmvfc_get_ae_desc(crq->event); +	struct ibmvfc_target *tgt;  	ibmvfc_log(vhost, 3, "%s event received. scsi_id: %llx, wwpn: %llx,"  		   " node_name: %llx\n", desc, crq->scsi_id, crq->wwpn, crq->node_name);  	switch (crq->event) { -	case IBMVFC_AE_LINK_UP:  	case IBMVFC_AE_RESUME: +		switch (crq->link_state) { +		case IBMVFC_AE_LS_LINK_DOWN: +			ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); +			break; +		case IBMVFC_AE_LS_LINK_DEAD: +			ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); +			break; +		case IBMVFC_AE_LS_LINK_UP: +		case IBMVFC_AE_LS_LINK_BOUNCED: +		default: +			vhost->events_to_log |= IBMVFC_AE_LINKUP; +			vhost->delay_init = 1; +			__ibmvfc_reset_host(vhost); +			break; +		}; + +		break; +	case IBMVFC_AE_LINK_UP:  		vhost->events_to_log |= IBMVFC_AE_LINKUP;  		vhost->delay_init = 1;  		__ibmvfc_reset_host(vhost); @@ -2168,9 +2240,23 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,  	case IBMVFC_AE_SCN_NPORT:  	case IBMVFC_AE_SCN_GROUP:  		vhost->events_to_log |= IBMVFC_AE_RSCN; +		ibmvfc_reinit_host(vhost); +		break;  	case IBMVFC_AE_ELS_LOGO:  	case IBMVFC_AE_ELS_PRLO:  	case IBMVFC_AE_ELS_PLOGI: +		list_for_each_entry(tgt, &vhost->targets, queue) { +			if (!crq->scsi_id && !crq->wwpn && !crq->node_name) +				break; +			if (crq->scsi_id && tgt->scsi_id != crq->scsi_id) +				continue; +			if (crq->wwpn && tgt->ids.port_name != crq->wwpn) +				continue; +			if (crq->node_name && tgt->ids.node_name != crq->node_name) +				continue; +			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); +		} +  		ibmvfc_reinit_host(vhost);  		break;  	case IBMVFC_AE_LINK_DOWN: @@ -2222,6 +2308,7 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)  		return;  	case IBMVFC_CRQ_XPORT_EVENT:  		vhost->state = IBMVFC_NO_CRQ; +		vhost->logged_in = 0;  		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);  		if (crq->format == IBMVFC_PARTITION_MIGRATED) {  			/* We need to re-setup the interpartition connection */ @@ -2299,7 +2386,7 @@ static int ibmvfc_scan_finished(struct Scsi_Host *shost, unsigned long time)  		done = 1;  	} -	if (vhost->state != IBMVFC_NO_CRQ && vhost->action == IBMVFC_HOST_ACTION_NONE) +	if (vhost->scan_complete)  		done = 1;  	spin_unlock_irqrestore(shost->host_lock, flags);  	return done; @@ -2434,14 +2521,6 @@ static ssize_t ibmvfc_show_host_partition_name(struct device *dev,  			vhost->login_buf->resp.partition_name);  } -static struct device_attribute ibmvfc_host_partition_name = { -	.attr = { -		.name = "partition_name", -		.mode = S_IRUGO, -	}, -	.show = ibmvfc_show_host_partition_name, -}; -  static ssize_t ibmvfc_show_host_device_name(struct device *dev,  					    struct device_attribute *attr, char *buf)  { @@ -2452,14 +2531,6 @@ static ssize_t ibmvfc_show_host_device_name(struct device *dev,  			vhost->login_buf->resp.device_name);  } -static struct device_attribute ibmvfc_host_device_name = { -	.attr = { -		.name = "device_name", -		.mode = S_IRUGO, -	}, -	.show = ibmvfc_show_host_device_name, -}; -  static ssize_t ibmvfc_show_host_loc_code(struct device *dev,  					 struct device_attribute *attr, char *buf)  { @@ -2470,14 +2541,6 @@ static ssize_t ibmvfc_show_host_loc_code(struct device *dev,  			vhost->login_buf->resp.port_loc_code);  } -static struct device_attribute ibmvfc_host_loc_code = { -	.attr = { -		.name = "port_loc_code", -		.mode = S_IRUGO, -	}, -	.show = ibmvfc_show_host_loc_code, -}; -  static ssize_t ibmvfc_show_host_drc_name(struct device *dev,  					 struct device_attribute *attr, char *buf)  { @@ -2488,14 +2551,6 @@ static ssize_t ibmvfc_show_host_drc_name(struct device *dev,  			vhost->login_buf->resp.drc_name);  } -static struct device_attribute ibmvfc_host_drc_name = { -	.attr = { -		.name = "drc_name", -		.mode = S_IRUGO, -	}, -	.show = ibmvfc_show_host_drc_name, -}; -  static ssize_t ibmvfc_show_host_npiv_version(struct device *dev,  					     struct device_attribute *attr, char *buf)  { @@ -2504,13 +2559,13 @@ static ssize_t ibmvfc_show_host_npiv_version(struct device *dev,  	return snprintf(buf, PAGE_SIZE, "%d\n", vhost->login_buf->resp.version);  } -static struct device_attribute ibmvfc_host_npiv_version = { -	.attr = { -		.name = "npiv_version", -		.mode = S_IRUGO, -	}, -	.show = ibmvfc_show_host_npiv_version, -}; +static ssize_t ibmvfc_show_host_capabilities(struct device *dev, +					     struct device_attribute *attr, char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct ibmvfc_host *vhost = shost_priv(shost); +	return snprintf(buf, PAGE_SIZE, "%llx\n", vhost->login_buf->resp.capabilities); +}  /**   * ibmvfc_show_log_level - Show the adapter's error logging level @@ -2556,14 +2611,14 @@ static ssize_t ibmvfc_store_log_level(struct device *dev,  	return strlen(buf);  } -static struct device_attribute ibmvfc_log_level_attr = { -	.attr = { -		.name =		"log_level", -		.mode =		S_IRUGO | S_IWUSR, -	}, -	.show = ibmvfc_show_log_level, -	.store = ibmvfc_store_log_level -}; +static DEVICE_ATTR(partition_name, S_IRUGO, ibmvfc_show_host_partition_name, NULL); +static DEVICE_ATTR(device_name, S_IRUGO, ibmvfc_show_host_device_name, NULL); +static DEVICE_ATTR(port_loc_code, S_IRUGO, ibmvfc_show_host_loc_code, NULL); +static DEVICE_ATTR(drc_name, S_IRUGO, ibmvfc_show_host_drc_name, NULL); +static DEVICE_ATTR(npiv_version, S_IRUGO, ibmvfc_show_host_npiv_version, NULL); +static DEVICE_ATTR(capabilities, S_IRUGO, ibmvfc_show_host_capabilities, NULL); +static DEVICE_ATTR(log_level, S_IRUGO | S_IWUSR, +		   ibmvfc_show_log_level, ibmvfc_store_log_level);  #ifdef CONFIG_SCSI_IBMVFC_TRACE  /** @@ -2612,12 +2667,13 @@ static struct bin_attribute ibmvfc_trace_attr = {  #endif  static struct device_attribute *ibmvfc_attrs[] = { -	&ibmvfc_host_partition_name, -	&ibmvfc_host_device_name, -	&ibmvfc_host_loc_code, -	&ibmvfc_host_drc_name, -	&ibmvfc_host_npiv_version, -	&ibmvfc_log_level_attr, +	&dev_attr_partition_name, +	&dev_attr_device_name, +	&dev_attr_port_loc_code, +	&dev_attr_drc_name, +	&dev_attr_npiv_version, +	&dev_attr_capabilities, +	&dev_attr_log_level,  	NULL  }; @@ -2774,15 +2830,19 @@ static void ibmvfc_init_tgt(struct ibmvfc_target *tgt,   * @tgt:		ibmvfc target struct   * @job_step:	initialization job step   * + * Returns: 1 if step will be retried / 0 if not + *   **/ -static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, +static int ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,  				  void (*job_step) (struct ibmvfc_target *))  {  	if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) {  		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);  		wake_up(&tgt->vhost->work_wait_q); +		return 0;  	} else  		ibmvfc_init_tgt(tgt, job_step); +	return 1;  }  /* Defined in FC-LS */ @@ -2831,7 +2891,7 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)  	struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli;  	struct ibmvfc_prli_svc_parms *parms = &rsp->parms;  	u32 status = rsp->common.status; -	int index; +	int index, level = IBMVFC_DEFAULT_LOG_LEVEL;  	vhost->discovery_threads--;  	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); @@ -2850,7 +2910,7 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)  						tgt->ids.roles |= FC_PORT_ROLE_FCP_TARGET;  					if (parms->service_parms & IBMVFC_PRLI_INITIATOR_FUNC)  						tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; -					ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT); +					tgt->add_rport = 1;  				} else  					ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);  			} else if (prli_rsp[index].retry) @@ -2867,13 +2927,14 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)  		break;  	case IBMVFC_MAD_FAILED:  	default: -		tgt_err(tgt, "Process Login failed: %s (%x:%x) rc=0x%02X\n", -			ibmvfc_get_cmd_error(rsp->status, rsp->error), -			rsp->status, rsp->error, status);  		if (ibmvfc_retry_cmd(rsp->status, rsp->error)) -			ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); +			level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);  		else  			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + +		tgt_log(tgt, level, "Process Login failed: %s (%x:%x) rc=0x%02X\n", +			ibmvfc_get_cmd_error(rsp->status, rsp->error), +			rsp->status, rsp->error, status);  		break;  	}; @@ -2932,6 +2993,7 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt)  	struct ibmvfc_host *vhost = evt->vhost;  	struct ibmvfc_port_login *rsp = &evt->xfer_iu->plogi;  	u32 status = rsp->common.status; +	int level = IBMVFC_DEFAULT_LOG_LEVEL;  	vhost->discovery_threads--;  	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); @@ -2960,15 +3022,15 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt)  		break;  	case IBMVFC_MAD_FAILED:  	default: -		tgt_err(tgt, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", -			ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, -			ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, -			ibmvfc_get_ls_explain(rsp->fc_explain), rsp->fc_explain, status); -  		if (ibmvfc_retry_cmd(rsp->status, rsp->error)) -			ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); +			level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);  		else  			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + +		tgt_log(tgt, level, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", +			ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, +			ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, +			ibmvfc_get_ls_explain(rsp->fc_explain), rsp->fc_explain, status);  		break;  	}; @@ -3129,13 +3191,13 @@ static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt)  	case IBMVFC_MAD_SUCCESS:  		tgt_dbg(tgt, "ADISC succeeded\n");  		if (ibmvfc_adisc_needs_plogi(mad, tgt)) -			tgt->need_login = 1; +			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);  		break;  	case IBMVFC_MAD_DRIVER_FAILED:  		break;  	case IBMVFC_MAD_FAILED:  	default: -		tgt->need_login = 1; +		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);  		fc_reason = (mad->fc_iu.response[1] & 0x00ff0000) >> 16;  		fc_explain = (mad->fc_iu.response[1] & 0x0000ff00) >> 8;  		tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", @@ -3322,6 +3384,7 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)  	struct ibmvfc_host *vhost = evt->vhost;  	struct ibmvfc_query_tgt *rsp = &evt->xfer_iu->query_tgt;  	u32 status = rsp->common.status; +	int level = IBMVFC_DEFAULT_LOG_LEVEL;  	vhost->discovery_threads--;  	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); @@ -3341,19 +3404,19 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)  		break;  	case IBMVFC_MAD_FAILED:  	default: -		tgt_err(tgt, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", -			ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, -			ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, -			ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status); -  		if ((rsp->status & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED &&  		    rsp->error == IBMVFC_UNABLE_TO_PERFORM_REQ &&  		    rsp->fc_explain == IBMVFC_PORT_NAME_NOT_REG)  			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);  		else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) -			ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); +			level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target);  		else  			ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + +		tgt_log(tgt, level, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", +			ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, +			ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, +			ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status);  		break;  	}; @@ -3420,7 +3483,7 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id)  	}  	spin_unlock_irqrestore(vhost->host->host_lock, flags); -	tgt = mempool_alloc(vhost->tgt_pool, GFP_KERNEL); +	tgt = mempool_alloc(vhost->tgt_pool, GFP_NOIO);  	if (!tgt) {  		dev_err(vhost->dev, "Target allocation failure for scsi id %08llx\n",  			scsi_id); @@ -3472,6 +3535,7 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt)  	struct ibmvfc_host *vhost = evt->vhost;  	struct ibmvfc_discover_targets *rsp = &evt->xfer_iu->discover_targets;  	u32 mad_status = rsp->common.status; +	int level = IBMVFC_DEFAULT_LOG_LEVEL;  	switch (mad_status) {  	case IBMVFC_MAD_SUCCESS: @@ -3480,9 +3544,9 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt)  		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS);  		break;  	case IBMVFC_MAD_FAILED: -		dev_err(vhost->dev, "Discover Targets failed: %s (%x:%x)\n", -			ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); -		ibmvfc_retry_host_init(vhost); +		level += ibmvfc_retry_host_init(vhost); +		ibmvfc_log(vhost, level, "Discover Targets failed: %s (%x:%x)\n", +			   ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error);  		break;  	case IBMVFC_MAD_DRIVER_FAILED:  		break; @@ -3534,18 +3598,19 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)  	u32 mad_status = evt->xfer_iu->npiv_login.common.status;  	struct ibmvfc_npiv_login_resp *rsp = &vhost->login_buf->resp;  	unsigned int npiv_max_sectors; +	int level = IBMVFC_DEFAULT_LOG_LEVEL;  	switch (mad_status) {  	case IBMVFC_MAD_SUCCESS:  		ibmvfc_free_event(evt);  		break;  	case IBMVFC_MAD_FAILED: -		dev_err(vhost->dev, "NPIV Login failed: %s (%x:%x)\n", -			ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error);  		if (ibmvfc_retry_cmd(rsp->status, rsp->error)) -			ibmvfc_retry_host_init(vhost); +			level += ibmvfc_retry_host_init(vhost);  		else  			ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); +		ibmvfc_log(vhost, level, "NPIV Login failed: %s (%x:%x)\n", +			   ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error);  		ibmvfc_free_event(evt);  		return;  	case IBMVFC_MAD_CRQ_ERROR: @@ -3578,6 +3643,7 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)  		return;  	} +	vhost->logged_in = 1;  	npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS);  	dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n",  		 rsp->partition_name, rsp->device_name, rsp->port_loc_code, @@ -3636,6 +3702,65 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *vhost)  };  /** + * ibmvfc_npiv_logout_done - Completion handler for NPIV Logout + * @vhost:		ibmvfc host struct + * + **/ +static void ibmvfc_npiv_logout_done(struct ibmvfc_event *evt) +{ +	struct ibmvfc_host *vhost = evt->vhost; +	u32 mad_status = evt->xfer_iu->npiv_logout.common.status; + +	ibmvfc_free_event(evt); + +	switch (mad_status) { +	case IBMVFC_MAD_SUCCESS: +		if (list_empty(&vhost->sent) && +		    vhost->action == IBMVFC_HOST_ACTION_LOGO_WAIT) { +			ibmvfc_init_host(vhost, 0); +			return; +		} +		break; +	case IBMVFC_MAD_FAILED: +	case IBMVFC_MAD_NOT_SUPPORTED: +	case IBMVFC_MAD_CRQ_ERROR: +	case IBMVFC_MAD_DRIVER_FAILED: +	default: +		ibmvfc_dbg(vhost, "NPIV Logout failed. 0x%X\n", mad_status); +		break; +	} + +	ibmvfc_hard_reset_host(vhost); +} + +/** + * ibmvfc_npiv_logout - Issue an NPIV Logout + * @vhost:		ibmvfc host struct + * + **/ +static void ibmvfc_npiv_logout(struct ibmvfc_host *vhost) +{ +	struct ibmvfc_npiv_logout_mad *mad; +	struct ibmvfc_event *evt; + +	evt = ibmvfc_get_event(vhost); +	ibmvfc_init_event(evt, ibmvfc_npiv_logout_done, IBMVFC_MAD_FORMAT); + +	mad = &evt->iu.npiv_logout; +	memset(mad, 0, sizeof(*mad)); +	mad->common.version = 1; +	mad->common.opcode = IBMVFC_NPIV_LOGOUT; +	mad->common.length = sizeof(struct ibmvfc_npiv_logout_mad); + +	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO_WAIT); + +	if (!ibmvfc_send_event(evt, vhost, default_timeout)) +		ibmvfc_dbg(vhost, "Sent NPIV logout\n"); +	else +		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); +} + +/**   * ibmvfc_dev_init_to_do - Is there target initialization work to do?   * @vhost:		ibmvfc host struct   * @@ -3671,6 +3796,7 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)  	switch (vhost->action) {  	case IBMVFC_HOST_ACTION_NONE:  	case IBMVFC_HOST_ACTION_INIT_WAIT: +	case IBMVFC_HOST_ACTION_LOGO_WAIT:  		return 0;  	case IBMVFC_HOST_ACTION_TGT_INIT:  	case IBMVFC_HOST_ACTION_QUERY_TGTS: @@ -3683,9 +3809,9 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)  			if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT)  				return 0;  		return 1; +	case IBMVFC_HOST_ACTION_LOGO:  	case IBMVFC_HOST_ACTION_INIT:  	case IBMVFC_HOST_ACTION_ALLOC_TGTS: -	case IBMVFC_HOST_ACTION_TGT_ADD:  	case IBMVFC_HOST_ACTION_TGT_DEL:  	case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:  	case IBMVFC_HOST_ACTION_QUERY: @@ -3740,25 +3866,26 @@ static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events)  static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)  {  	struct ibmvfc_host *vhost = tgt->vhost; -	struct fc_rport *rport = tgt->rport; +	struct fc_rport *rport;  	unsigned long flags; -	if (rport) { -		tgt_dbg(tgt, "Setting rport roles\n"); -		fc_remote_port_rolechg(rport, tgt->ids.roles); -		spin_lock_irqsave(vhost->host->host_lock, flags); -		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); +	tgt_dbg(tgt, "Adding rport\n"); +	rport = fc_remote_port_add(vhost->host, 0, &tgt->ids); +	spin_lock_irqsave(vhost->host->host_lock, flags); + +	if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { +		tgt_dbg(tgt, "Deleting rport\n"); +		list_del(&tgt->queue);  		spin_unlock_irqrestore(vhost->host->host_lock, flags); +		fc_remote_port_delete(rport); +		del_timer_sync(&tgt->timer); +		kref_put(&tgt->kref, ibmvfc_release_tgt);  		return;  	} -	tgt_dbg(tgt, "Adding rport\n"); -	rport = fc_remote_port_add(vhost->host, 0, &tgt->ids); -	spin_lock_irqsave(vhost->host->host_lock, flags); -	tgt->rport = rport; -	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);  	if (rport) {  		tgt_dbg(tgt, "rport add succeeded\n"); +		tgt->rport = rport;  		rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff;  		rport->supported_classes = 0;  		tgt->target_id = rport->scsi_target_id; @@ -3789,8 +3916,12 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)  	vhost->events_to_log = 0;  	switch (vhost->action) {  	case IBMVFC_HOST_ACTION_NONE: +	case IBMVFC_HOST_ACTION_LOGO_WAIT:  	case IBMVFC_HOST_ACTION_INIT_WAIT:  		break; +	case IBMVFC_HOST_ACTION_LOGO: +		vhost->job_step(vhost); +		break;  	case IBMVFC_HOST_ACTION_INIT:  		BUG_ON(vhost->state != IBMVFC_INITIALIZING);  		if (vhost->delay_init) { @@ -3836,11 +3967,21 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)  		if (vhost->state == IBMVFC_INITIALIZING) {  			if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) { -				ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); -				ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); -				vhost->init_retries = 0; -				spin_unlock_irqrestore(vhost->host->host_lock, flags); -				scsi_unblock_requests(vhost->host); +				if (vhost->reinit) { +					vhost->reinit = 0; +					scsi_block_requests(vhost->host); +					ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); +					spin_unlock_irqrestore(vhost->host->host_lock, flags); +				} else { +					ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); +					ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); +					wake_up(&vhost->init_wait_q); +					schedule_work(&vhost->rport_add_work_q); +					vhost->init_retries = 0; +					spin_unlock_irqrestore(vhost->host->host_lock, flags); +					scsi_unblock_requests(vhost->host); +				} +  				return;  			} else {  				ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); @@ -3871,24 +4012,6 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)  		if (!ibmvfc_dev_init_to_do(vhost))  			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED);  		break; -	case IBMVFC_HOST_ACTION_TGT_ADD: -		list_for_each_entry(tgt, &vhost->targets, queue) { -			if (tgt->action == IBMVFC_TGT_ACTION_ADD_RPORT) { -				spin_unlock_irqrestore(vhost->host->host_lock, flags); -				ibmvfc_tgt_add_rport(tgt); -				return; -			} -		} - -		if (vhost->reinit && !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { -			vhost->reinit = 0; -			scsi_block_requests(vhost->host); -			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); -		} else { -			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); -			wake_up(&vhost->init_wait_q); -		} -		break;  	default:  		break;  	}; @@ -4118,6 +4241,56 @@ nomem:  }  /** + * ibmvfc_rport_add_thread - Worker thread for rport adds + * @work:	work struct + * + **/ +static void ibmvfc_rport_add_thread(struct work_struct *work) +{ +	struct ibmvfc_host *vhost = container_of(work, struct ibmvfc_host, +						 rport_add_work_q); +	struct ibmvfc_target *tgt; +	struct fc_rport *rport; +	unsigned long flags; +	int did_work; + +	ENTER; +	spin_lock_irqsave(vhost->host->host_lock, flags); +	do { +		did_work = 0; +		if (vhost->state != IBMVFC_ACTIVE) +			break; + +		list_for_each_entry(tgt, &vhost->targets, queue) { +			if (tgt->add_rport) { +				did_work = 1; +				tgt->add_rport = 0; +				kref_get(&tgt->kref); +				rport = tgt->rport; +				if (!rport) { +					spin_unlock_irqrestore(vhost->host->host_lock, flags); +					ibmvfc_tgt_add_rport(tgt); +				} else if (get_device(&rport->dev)) { +					spin_unlock_irqrestore(vhost->host->host_lock, flags); +					tgt_dbg(tgt, "Setting rport roles\n"); +					fc_remote_port_rolechg(rport, tgt->ids.roles); +					put_device(&rport->dev); +				} + +				kref_put(&tgt->kref, ibmvfc_release_tgt); +				spin_lock_irqsave(vhost->host->host_lock, flags); +				break; +			} +		} +	} while(did_work); + +	if (vhost->state == IBMVFC_ACTIVE) +		vhost->scan_complete = 1; +	spin_unlock_irqrestore(vhost->host->host_lock, flags); +	LEAVE; +} + +/**   * ibmvfc_probe - Adapter hot plug add entry point   * @vdev:	vio device struct   * @id:	vio device id struct @@ -4160,6 +4333,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)  	strcpy(vhost->partition_name, "UNKNOWN");  	init_waitqueue_head(&vhost->work_wait_q);  	init_waitqueue_head(&vhost->init_wait_q); +	INIT_WORK(&vhost->rport_add_work_q, ibmvfc_rport_add_thread);  	if ((rc = ibmvfc_alloc_mem(vhost)))  		goto free_scsi_host;  |