diff mbox

[02/14] lpfc: Fix sg_reset on SCSI device causing kernel crash

Message ID 57acc585.HP3iyAK6go/SCR18%james.smart@broadcom.com (mailing list archive)
State Changes Requested, archived
Headers show

Commit Message

James Smart Aug. 11, 2016, 6:35 p.m. UTC
Fix sg_reset on SCSI device causing kernel crash

Driver could reference stale node pointers in task mgmt call.
Changed to use resetting cmd and look up node pointer in task mgmt
function.

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <james.smart@broadcom.com>
---
 drivers/scsi/lpfc/lpfc_scsi.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

Comments

Johannes Thumshirn Aug. 12, 2016, 8:28 a.m. UTC | #1
On Thu, Aug 11, 2016 at 11:35:49AM -0700, James Smart wrote:
> 
> Fix sg_reset on SCSI device causing kernel crash
> 
> Driver could reference stale node pointers in task mgmt call.
> Changed to use resetting cmd and look up node pointer in task mgmt
> function.
> 
> Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
> Signed-off-by: James Smart <james.smart@broadcom.com>
> ---
>  drivers/scsi/lpfc/lpfc_scsi.c | 18 +++++++++++-------
>  1 file changed, 11 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
> index d197aa1..c100477 100644
> --- a/drivers/scsi/lpfc/lpfc_scsi.c
> +++ b/drivers/scsi/lpfc/lpfc_scsi.c
> @@ -4945,18 +4945,21 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd)
>   *   0x2002 - Success.
>   **/
>  static int
> -lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
> -		    unsigned  tgt_id, uint64_t lun_id,
> -		    uint8_t task_mgmt_cmd)
> +lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd,
> +		   unsigned int tgt_id, uint64_t lun_id,
> +		   uint8_t task_mgmt_cmd)
>  {
>  	struct lpfc_hba   *phba = vport->phba;
>  	struct lpfc_scsi_buf *lpfc_cmd;
>  	struct lpfc_iocbq *iocbq;
>  	struct lpfc_iocbq *iocbqrsp;
> -	struct lpfc_nodelist *pnode = rdata->pnode;
> +	struct lpfc_rport_data *rdata;
> +	struct lpfc_nodelist *pnode;
>  	int ret;
>  	int status;
>  
> +	rdata = lpfc_rport_data_from_scsi_device(cmnd->device);

	if (!rdata  || !rdata->pnode)
		return FAILED;

As you do it in lpfc_chk_tgt_mapped() and lpfc_device_reset_handler()?


> +	pnode = rdata->pnode;
>  	if (!pnode || !NLP_CHK_NODE_ACT(pnode))
>  		return FAILED;
>  
> @@ -4965,6 +4968,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
>  		return FAILED;
>  	lpfc_cmd->timeout = phba->cfg_task_mgmt_tmo;
>  	lpfc_cmd->rdata = rdata;
> +	lpfc_cmd->pCmd = cmnd;
>  
>  	status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun_id,
>  					   task_mgmt_cmd);
> @@ -5171,7 +5175,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
>  	fc_host_post_vendor_event(shost, fc_get_event_number(),
>  		sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID);
>  
> -	status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id,
> +	status = lpfc_send_taskmgmt(vport, cmnd, tgt_id, lun_id,
>  						FCP_LUN_RESET);
>  
>  	lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
> @@ -5249,7 +5253,7 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
>  	fc_host_post_vendor_event(shost, fc_get_event_number(),
>  		sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID);
>  
> -	status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id,
> +	status = lpfc_send_taskmgmt(vport, cmnd, tgt_id, lun_id,
>  					FCP_TARGET_RESET);
>  
>  	lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
> @@ -5328,7 +5332,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
>  		if (!match)
>  			continue;
>  
> -		status = lpfc_send_taskmgmt(vport, ndlp->rport->dd_data,
> +		status = lpfc_send_taskmgmt(vport, cmnd,
>  					i, 0, FCP_TARGET_RESET);
>  
>  		if (status != SUCCESS) {
> -- 
> 2.5.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index d197aa1..c100477 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -4945,18 +4945,21 @@  lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd)
  *   0x2002 - Success.
  **/
 static int
-lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
-		    unsigned  tgt_id, uint64_t lun_id,
-		    uint8_t task_mgmt_cmd)
+lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd,
+		   unsigned int tgt_id, uint64_t lun_id,
+		   uint8_t task_mgmt_cmd)
 {
 	struct lpfc_hba   *phba = vport->phba;
 	struct lpfc_scsi_buf *lpfc_cmd;
 	struct lpfc_iocbq *iocbq;
 	struct lpfc_iocbq *iocbqrsp;
-	struct lpfc_nodelist *pnode = rdata->pnode;
+	struct lpfc_rport_data *rdata;
+	struct lpfc_nodelist *pnode;
 	int ret;
 	int status;
 
+	rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
+	pnode = rdata->pnode;
 	if (!pnode || !NLP_CHK_NODE_ACT(pnode))
 		return FAILED;
 
@@ -4965,6 +4968,7 @@  lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
 		return FAILED;
 	lpfc_cmd->timeout = phba->cfg_task_mgmt_tmo;
 	lpfc_cmd->rdata = rdata;
+	lpfc_cmd->pCmd = cmnd;
 
 	status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun_id,
 					   task_mgmt_cmd);
@@ -5171,7 +5175,7 @@  lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 	fc_host_post_vendor_event(shost, fc_get_event_number(),
 		sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID);
 
-	status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id,
+	status = lpfc_send_taskmgmt(vport, cmnd, tgt_id, lun_id,
 						FCP_LUN_RESET);
 
 	lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
@@ -5249,7 +5253,7 @@  lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
 	fc_host_post_vendor_event(shost, fc_get_event_number(),
 		sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID);
 
-	status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id,
+	status = lpfc_send_taskmgmt(vport, cmnd, tgt_id, lun_id,
 					FCP_TARGET_RESET);
 
 	lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
@@ -5328,7 +5332,7 @@  lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
 		if (!match)
 			continue;
 
-		status = lpfc_send_taskmgmt(vport, ndlp->rport->dd_data,
+		status = lpfc_send_taskmgmt(vport, cmnd,
 					i, 0, FCP_TARGET_RESET);
 
 		if (status != SUCCESS) {