diff options
Diffstat (limited to 'drivers/scsi/ibmvscsi/ibmvfc.c')
| -rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.c | 82 | 
1 files changed, 64 insertions, 18 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index d0eab5700dc5..00684e11976b 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -160,8 +160,8 @@ static void ibmvfc_npiv_logout(struct ibmvfc_host *);  static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *);  static void ibmvfc_tgt_move_login(struct ibmvfc_target *); -static void ibmvfc_release_sub_crqs(struct ibmvfc_host *); -static void ibmvfc_init_sub_crqs(struct ibmvfc_host *); +static void ibmvfc_dereg_sub_crqs(struct ibmvfc_host *); +static void ibmvfc_reg_sub_crqs(struct ibmvfc_host *);  static const char *unknown_error = "unknown error"; @@ -917,7 +917,7 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)  	struct vio_dev *vdev = to_vio_dev(vhost->dev);  	unsigned long flags; -	ibmvfc_release_sub_crqs(vhost); +	ibmvfc_dereg_sub_crqs(vhost);  	/* Re-enable the CRQ */  	do { @@ -936,7 +936,7 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)  	spin_unlock(vhost->crq.q_lock);  	spin_unlock_irqrestore(vhost->host->host_lock, flags); -	ibmvfc_init_sub_crqs(vhost); +	ibmvfc_reg_sub_crqs(vhost);  	return rc;  } @@ -955,7 +955,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)  	struct vio_dev *vdev = to_vio_dev(vhost->dev);  	struct ibmvfc_queue *crq = &vhost->crq; -	ibmvfc_release_sub_crqs(vhost); +	ibmvfc_dereg_sub_crqs(vhost);  	/* Close the CRQ */  	do { @@ -988,7 +988,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)  	spin_unlock(vhost->crq.q_lock);  	spin_unlock_irqrestore(vhost->host->host_lock, flags); -	ibmvfc_init_sub_crqs(vhost); +	ibmvfc_reg_sub_crqs(vhost);  	return rc;  } @@ -5682,6 +5682,8 @@ static int ibmvfc_alloc_queue(struct ibmvfc_host *vhost,  	queue->cur = 0;  	queue->fmt = fmt;  	queue->size = PAGE_SIZE / fmt_size; + +	queue->vhost = vhost;  	return 0;  } @@ -5757,9 +5759,6 @@ static int ibmvfc_register_scsi_channel(struct ibmvfc_host *vhost,  	ENTER; -	if (ibmvfc_alloc_queue(vhost, scrq, IBMVFC_SUB_CRQ_FMT)) -		return -ENOMEM; -  	rc = h_reg_sub_crq(vdev->unit_address, scrq->msg_token, PAGE_SIZE,  			   &scrq->cookie, &scrq->hw_irq); @@ -5790,7 +5789,6 @@ static int ibmvfc_register_scsi_channel(struct ibmvfc_host *vhost,  	}  	scrq->hwq_id = index; -	scrq->vhost = vhost;  	LEAVE;  	return 0; @@ -5800,7 +5798,6 @@ irq_failed:  		rc = plpar_hcall_norets(H_FREE_SUB_CRQ, vdev->unit_address, scrq->cookie);  	} while (rtas_busy_delay(rc));  reg_failed: -	ibmvfc_free_queue(vhost, scrq);  	LEAVE;  	return rc;  } @@ -5826,12 +5823,50 @@ static void ibmvfc_deregister_scsi_channel(struct ibmvfc_host *vhost, int index)  	if (rc)  		dev_err(dev, "Failed to free sub-crq[%d]: rc=%ld\n", index, rc); -	ibmvfc_free_queue(vhost, scrq); +	/* Clean out the queue */ +	memset(scrq->msgs.crq, 0, PAGE_SIZE); +	scrq->cur = 0; + +	LEAVE; +} + +static void ibmvfc_reg_sub_crqs(struct ibmvfc_host *vhost) +{ +	int i, j; + +	ENTER; +	if (!vhost->mq_enabled || !vhost->scsi_scrqs.scrqs) +		return; + +	for (i = 0; i < nr_scsi_hw_queues; i++) { +		if (ibmvfc_register_scsi_channel(vhost, i)) { +			for (j = i; j > 0; j--) +				ibmvfc_deregister_scsi_channel(vhost, j - 1); +			vhost->do_enquiry = 0; +			return; +		} +	} + +	LEAVE; +} + +static void ibmvfc_dereg_sub_crqs(struct ibmvfc_host *vhost) +{ +	int i; + +	ENTER; +	if (!vhost->mq_enabled || !vhost->scsi_scrqs.scrqs) +		return; + +	for (i = 0; i < nr_scsi_hw_queues; i++) +		ibmvfc_deregister_scsi_channel(vhost, i); +  	LEAVE;  }  static void ibmvfc_init_sub_crqs(struct ibmvfc_host *vhost)  { +	struct ibmvfc_queue *scrq;  	int i, j;  	ENTER; @@ -5847,30 +5882,41 @@ static void ibmvfc_init_sub_crqs(struct ibmvfc_host *vhost)  	}  	for (i = 0; i < nr_scsi_hw_queues; i++) { -		if (ibmvfc_register_scsi_channel(vhost, i)) { -			for (j = i; j > 0; j--) -				ibmvfc_deregister_scsi_channel(vhost, j - 1); +		scrq = &vhost->scsi_scrqs.scrqs[i]; +		if (ibmvfc_alloc_queue(vhost, scrq, IBMVFC_SUB_CRQ_FMT)) { +			for (j = i; j > 0; j--) { +				scrq = &vhost->scsi_scrqs.scrqs[j - 1]; +				ibmvfc_free_queue(vhost, scrq); +			}  			kfree(vhost->scsi_scrqs.scrqs);  			vhost->scsi_scrqs.scrqs = NULL;  			vhost->scsi_scrqs.active_queues = 0;  			vhost->do_enquiry = 0; -			break; +			vhost->mq_enabled = 0; +			return;  		}  	} +	ibmvfc_reg_sub_crqs(vhost); +  	LEAVE;  }  static void ibmvfc_release_sub_crqs(struct ibmvfc_host *vhost)  { +	struct ibmvfc_queue *scrq;  	int i;  	ENTER;  	if (!vhost->scsi_scrqs.scrqs)  		return; -	for (i = 0; i < nr_scsi_hw_queues; i++) -		ibmvfc_deregister_scsi_channel(vhost, i); +	ibmvfc_dereg_sub_crqs(vhost); + +	for (i = 0; i < nr_scsi_hw_queues; i++) { +		scrq = &vhost->scsi_scrqs.scrqs[i]; +		ibmvfc_free_queue(vhost, scrq); +	}  	kfree(vhost->scsi_scrqs.scrqs);  	vhost->scsi_scrqs.scrqs = NULL;  | 
