diff options
Diffstat (limited to 'drivers/s390/scsi')
| -rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 68 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 8 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 56 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 25 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_sysfs.c | 7 | 
5 files changed, 99 insertions, 65 deletions
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 8030e25152f..c75d6f35cb5 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -553,40 +553,35 @@ static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,  		_zfcp_erp_unit_reopen(unit, clear, id, ref);  } -static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act) +static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)  { -	struct zfcp_adapter *adapter = act->adapter; -	struct zfcp_port *port = act->port; -	struct zfcp_unit *unit = act->unit; -	u32 status = act->status; - -	/* initiate follow-up actions depending on success of finished action */  	switch (act->action) { -  	case ZFCP_ERP_ACTION_REOPEN_ADAPTER: -		if (status == ZFCP_ERP_SUCCEEDED) -			_zfcp_erp_port_reopen_all(adapter, 0, "ersfa_1", NULL); -		else -			_zfcp_erp_adapter_reopen(adapter, 0, "ersfa_2", NULL); +		_zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);  		break; -  	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: -		if (status == ZFCP_ERP_SUCCEEDED) -			_zfcp_erp_port_reopen(port, 0, "ersfa_3", NULL); -		else -			_zfcp_erp_adapter_reopen(adapter, 0, "ersfa_4", NULL); +		_zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);  		break; -  	case ZFCP_ERP_ACTION_REOPEN_PORT: -		if (status == ZFCP_ERP_SUCCEEDED) -			_zfcp_erp_unit_reopen_all(port, 0, "ersfa_5", NULL); -		else -			_zfcp_erp_port_forced_reopen(port, 0, "ersfa_6", NULL); +		_zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);  		break; -  	case ZFCP_ERP_ACTION_REOPEN_UNIT: -		if (status != ZFCP_ERP_SUCCEEDED) -			_zfcp_erp_port_reopen(unit->port, 0, "ersfa_7", NULL); +		_zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL); +		break; +	} +} + +static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act) +{ +	switch (act->action) { +	case ZFCP_ERP_ACTION_REOPEN_ADAPTER: +		_zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL); +		break; +	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: +		_zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL); +		break; +	case ZFCP_ERP_ACTION_REOPEN_PORT: +		_zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL);  		break;  	}  } @@ -801,7 +796,7 @@ static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)  			return ZFCP_ERP_FAILED;  	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: -		if (status & ZFCP_STATUS_PORT_PHYS_OPEN) +		if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))  			return ZFCP_ERP_SUCCEEDED;  	}  	return ZFCP_ERP_FAILED; @@ -853,11 +848,17 @@ void zfcp_erp_port_strategy_open_lookup(struct work_struct *work)  					      gid_pn_work);  	retval = zfcp_fc_ns_gid_pn(&port->erp_action); -	if (retval == -ENOMEM) -		zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM); -	port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; -	if (retval) -		zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED); +	if (!retval) { +		port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; +		goto out; +	} +	if (retval == -ENOMEM) { +		zfcp_erp_notify(&port->erp_action, ZFCP_STATUS_ERP_LOWMEM); +		goto out; +	} +	/* all other error condtions */ +	zfcp_erp_notify(&port->erp_action, 0); +out:  	zfcp_port_put(port);  } @@ -1289,7 +1290,10 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)  	retval = zfcp_erp_strategy_statechange(erp_action, retval);  	if (retval == ZFCP_ERP_EXIT)  		goto unlock; -	zfcp_erp_strategy_followup_actions(erp_action); +	if (retval == ZFCP_ERP_SUCCEEDED) +		zfcp_erp_strategy_followup_success(erp_action); +	if (retval == ZFCP_ERP_FAILED) +		zfcp_erp_strategy_followup_failed(erp_action);   unlock:  	write_unlock(&adapter->erp_lock); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 2f0705d76b7..47daebfa7e5 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -79,11 +79,9 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)  	mutex_unlock(&wka_port->mutex); -	wait_event_timeout( -		wka_port->completion_wq, -		wka_port->status == ZFCP_WKA_PORT_ONLINE || -		wka_port->status == ZFCP_WKA_PORT_OFFLINE, -		HZ >> 1); +	wait_event(wka_port->completion_wq, +		   wka_port->status == ZFCP_WKA_PORT_ONLINE || +		   wka_port->status == ZFCP_WKA_PORT_OFFLINE);  	if (wka_port->status == ZFCP_WKA_PORT_ONLINE) {  		atomic_inc(&wka_port->refcount); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index c57658f3d34..47795fbf081 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -670,8 +670,11 @@ static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)  			       zfcp_fsf_sbal_check(adapter), 5 * HZ);  	if (ret > 0)  		return 0; -	if (!ret) +	if (!ret) {  		atomic_inc(&adapter->qdio_outb_full); +		/* assume hanging outbound queue, try queue recovery */ +		zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL); +	}  	spin_lock_bh(&adapter->req_q_lock);  	return -EIO; @@ -722,7 +725,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,  		req = zfcp_fsf_alloc_qtcb(pool);  	if (unlikely(!req)) -		return ERR_PTR(-EIO); +		return ERR_PTR(-ENOMEM);  	if (adapter->req_no == 0)  		adapter->req_no++; @@ -1010,6 +1013,23 @@ skip_fsfstatus:  		send_ct->handler(send_ct->handler_data);  } +static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale, +					    struct scatterlist *sg_req, +					    struct scatterlist *sg_resp) +{ +	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; +	sbale[2].addr   = sg_virt(sg_req); +	sbale[2].length = sg_req->length; +	sbale[3].addr   = sg_virt(sg_resp); +	sbale[3].length = sg_resp->length; +	sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; +} + +static int zfcp_fsf_one_sbal(struct scatterlist *sg) +{ +	return sg_is_last(sg) && sg->length <= PAGE_SIZE; +} +  static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,  				       struct scatterlist *sg_req,  				       struct scatterlist *sg_resp, @@ -1020,30 +1040,30 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,  	int bytes;  	if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { -		if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE || -		    !sg_is_last(sg_req) || !sg_is_last(sg_resp)) +		if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp))  			return -EOPNOTSUPP; -		sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; -		sbale[2].addr   = sg_virt(sg_req); -		sbale[2].length = sg_req->length; -		sbale[3].addr   = sg_virt(sg_resp); -		sbale[3].length = sg_resp->length; -		sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; +		zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp); +		return 0; +	} + +	/* use single, unchained SBAL if it can hold the request */ +	if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) { +		zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);  		return 0;  	}  	bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,  					sg_req, max_sbals);  	if (bytes <= 0) -		return -ENOMEM; +		return -EIO;  	req->qtcb->bottom.support.req_buf_length = bytes;  	req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;  	bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,  					sg_resp, max_sbals);  	if (bytes <= 0) -		return -ENOMEM; +		return -EIO;  	req->qtcb->bottom.support.resp_buf_length = bytes;  	return 0; @@ -1607,10 +1627,10 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)  	case FSF_ACCESS_DENIED:  		wka_port->status = ZFCP_WKA_PORT_OFFLINE;  		break; -	case FSF_PORT_ALREADY_OPEN: -		break;  	case FSF_GOOD:  		wka_port->handle = header->port_handle; +		/* fall through */ +	case FSF_PORT_ALREADY_OPEN:  		wka_port->status = ZFCP_WKA_PORT_ONLINE;  	}  out: @@ -1731,15 +1751,16 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)  		zfcp_fsf_access_denied_port(req, port);  		break;  	case FSF_PORT_BOXED: -		zfcp_erp_port_boxed(port, "fscpph2", req); -		req->status |= ZFCP_STATUS_FSFREQ_ERROR | -			       ZFCP_STATUS_FSFREQ_RETRY;  		/* can't use generic zfcp_erp_modify_port_status because  		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */  		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);  		list_for_each_entry(unit, &port->unit_list_head, list)  			atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,  					  &unit->status); +		zfcp_erp_port_boxed(port, "fscpph2", req); +		req->status |= ZFCP_STATUS_FSFREQ_ERROR | +			       ZFCP_STATUS_FSFREQ_RETRY; +  		break;  	case FSF_ADAPTER_STATUS_AVAILABLE:  		switch (header->fsf_status_qual.word[0]) { @@ -2541,7 +2562,6 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,  	bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg,  					FSF_MAX_SBALS_PER_REQ);  	if (bytes != ZFCP_CFDC_MAX_SIZE) { -		retval = -ENOMEM;  		zfcp_fsf_req_free(req);  		goto out;  	} diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 967ede73f4c..6925a178468 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -167,20 +167,21 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)  	struct zfcp_unit *unit = scpnt->device->hostdata;  	struct zfcp_fsf_req *old_req, *abrt_req;  	unsigned long flags; -	unsigned long old_req_id = (unsigned long) scpnt->host_scribble; +	unsigned long old_reqid = (unsigned long) scpnt->host_scribble;  	int retval = SUCCESS;  	int retry = 3; +	char *dbf_tag;  	/* avoid race condition between late normal completion and abort */  	write_lock_irqsave(&adapter->abort_lock, flags);  	spin_lock(&adapter->req_list_lock); -	old_req = zfcp_reqlist_find(adapter, old_req_id); +	old_req = zfcp_reqlist_find(adapter, old_reqid);  	spin_unlock(&adapter->req_list_lock);  	if (!old_req) {  		write_unlock_irqrestore(&adapter->abort_lock, flags);  		zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, -					  old_req_id); +					  old_reqid);  		return FAILED; /* completion could be in progress */  	}  	old_req->data = NULL; @@ -189,7 +190,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)  	write_unlock_irqrestore(&adapter->abort_lock, flags);  	while (retry--) { -		abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit); +		abrt_req = zfcp_fsf_abort_fcp_command(old_reqid, unit);  		if (abrt_req)  			break; @@ -197,7 +198,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)  		if (!(atomic_read(&adapter->status) &  		      ZFCP_STATUS_COMMON_RUNNING)) {  			zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, -						  old_req_id); +						  old_reqid);  			return SUCCESS;  		}  	} @@ -208,13 +209,14 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)  		   abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);  	if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) -		zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0); +		dbf_tag = "okay";  	else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) -		zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0); +		dbf_tag = "lte2";  	else { -		zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0); +		dbf_tag = "fail";  		retval = FAILED;  	} +	zfcp_scsi_dbf_event_abort(dbf_tag, adapter, scpnt, abrt_req, old_reqid);  	zfcp_fsf_req_free(abrt_req);  	return retval;  } @@ -534,6 +536,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)  	struct fc_rport_identifiers ids;  	struct fc_rport *rport; +	if (port->rport) +		return; +  	ids.node_name = port->wwnn;  	ids.port_name = port->wwpn;  	ids.port_id = port->d_id; @@ -557,8 +562,10 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port)  {  	struct fc_rport *rport = port->rport; -	if (rport) +	if (rport) {  		fc_remote_port_delete(rport); +		port->rport = NULL; +	}  }  void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 3e51e64d110..0fe5cce818c 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -494,9 +494,14 @@ static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev,  	struct Scsi_Host *scsi_host = class_to_shost(dev);  	struct zfcp_adapter *adapter =  		(struct zfcp_adapter *) scsi_host->hostdata[0]; +	u64 util; + +	spin_lock_bh(&adapter->qdio_stat_lock); +	util = adapter->req_q_util; +	spin_unlock_bh(&adapter->qdio_stat_lock);  	return sprintf(buf, "%d %llu\n", atomic_read(&adapter->qdio_outb_full), -		       (unsigned long long)adapter->req_q_util); +		       (unsigned long long)util);  }  static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL);  |