diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_scsi.c')
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 410 | 
1 files changed, 272 insertions, 138 deletions
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 88f3a83dbd2..66e09069f28 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -399,6 +399,14 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)  	num_rsrc_err = atomic_read(&phba->num_rsrc_err);  	num_cmd_success = atomic_read(&phba->num_cmd_success); +	/* +	 * The error and success command counters are global per +	 * driver instance.  If another handler has already +	 * operated on this error event, just exit. +	 */ +	if (num_rsrc_err == 0) +		return; +  	vports = lpfc_create_vport_work_array(phba);  	if (vports != NULL)  		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { @@ -688,7 +696,8 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,  			rrq_empty = list_empty(&phba->active_rrq_list);  			spin_unlock_irqrestore(&phba->hbalock, iflag);  			if (ndlp) { -				lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1); +				lpfc_set_rrq_active(phba, ndlp, +					psb->cur_iocbq.sli4_lxritag, rxid, 1);  				lpfc_sli4_abts_err_handler(phba, ndlp, axri);  			}  			lpfc_release_scsi_buf_s4(phba, psb); @@ -718,72 +727,162 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,  }  /** - * lpfc_sli4_repost_scsi_sgl_list - Repsot the Scsi buffers sgl pages as block + * lpfc_sli4_post_scsi_sgl_list - Psot blocks of scsi buffer sgls from a list   * @phba: pointer to lpfc hba data structure. + * @post_sblist: pointer to the scsi buffer list.   * - * This routine walks the list of scsi buffers that have been allocated and - * repost them to the HBA by using SGL block post. This is needed after a - * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine - * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list - * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers. + * This routine walks a list of scsi buffers that was passed in. It attempts + * to construct blocks of scsi buffer sgls which contains contiguous xris and + * uses the non-embedded SGL block post mailbox commands to post to the port. + * For single SCSI buffer sgl with non-contiguous xri, if any, it shall use + * embedded SGL post mailbox command for posting. The @post_sblist passed in + * must be local list, thus no lock is needed when manipulate the list.   * - * Returns: 0 = success, non-zero failure. + * Returns: 0 = failure, non-zero number of successfully posted buffers.   **/  int -lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) +lpfc_sli4_post_scsi_sgl_list(struct lpfc_hba *phba, +			     struct list_head *post_sblist, int sb_count)  { -	struct lpfc_scsi_buf *psb; -	int index, status, bcnt = 0, rcnt = 0, rc = 0; -	LIST_HEAD(sblist); +	struct lpfc_scsi_buf *psb, *psb_next; +	int status; +	int post_cnt = 0, block_cnt = 0, num_posting = 0, num_posted = 0; +	dma_addr_t pdma_phys_bpl1; +	int last_xritag = NO_XRI; +	LIST_HEAD(prep_sblist); +	LIST_HEAD(blck_sblist); +	LIST_HEAD(scsi_sblist); -	for (index = 0; index < phba->sli4_hba.scsi_xri_cnt; index++) { -		psb = phba->sli4_hba.lpfc_scsi_psb_array[index]; -		if (psb) { -			/* Remove from SCSI buffer list */ -			list_del(&psb->list); -			/* Add it to a local SCSI buffer list */ -			list_add_tail(&psb->list, &sblist); -			if (++rcnt == LPFC_NEMBED_MBOX_SGL_CNT) { -				bcnt = rcnt; -				rcnt = 0; +	/* sanity check */ +	if (sb_count <= 0) +		return -EINVAL; + +	list_for_each_entry_safe(psb, psb_next, post_sblist, list) { +		list_del_init(&psb->list); +		block_cnt++; +		if ((last_xritag != NO_XRI) && +		    (psb->cur_iocbq.sli4_xritag != last_xritag + 1)) { +			/* a hole in xri block, form a sgl posting block */ +			list_splice_init(&prep_sblist, &blck_sblist); +			post_cnt = block_cnt - 1; +			/* prepare list for next posting block */ +			list_add_tail(&psb->list, &prep_sblist); +			block_cnt = 1; +		} else { +			/* prepare list for next posting block */ +			list_add_tail(&psb->list, &prep_sblist); +			/* enough sgls for non-embed sgl mbox command */ +			if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) { +				list_splice_init(&prep_sblist, &blck_sblist); +				post_cnt = block_cnt; +				block_cnt = 0;  			} -		} else -			/* A hole present in the XRI array, need to skip */ -			bcnt = rcnt; +		} +		num_posting++; +		last_xritag = psb->cur_iocbq.sli4_xritag; -		if (index == phba->sli4_hba.scsi_xri_cnt - 1) -			/* End of XRI array for SCSI buffer, complete */ -			bcnt = rcnt; +		/* end of repost sgl list condition for SCSI buffers */ +		if (num_posting == sb_count) { +			if (post_cnt == 0) { +				/* last sgl posting block */ +				list_splice_init(&prep_sblist, &blck_sblist); +				post_cnt = block_cnt; +			} else if (block_cnt == 1) { +				/* last single sgl with non-contiguous xri */ +				if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) +					pdma_phys_bpl1 = psb->dma_phys_bpl + +								SGL_PAGE_SIZE; +				else +					pdma_phys_bpl1 = 0; +				status = lpfc_sli4_post_sgl(phba, +						psb->dma_phys_bpl, +						pdma_phys_bpl1, +						psb->cur_iocbq.sli4_xritag); +				if (status) { +					/* failure, put on abort scsi list */ +					psb->exch_busy = 1; +				} else { +					/* success, put on SCSI buffer list */ +					psb->exch_busy = 0; +					psb->status = IOSTAT_SUCCESS; +					num_posted++; +				} +				/* success, put on SCSI buffer sgl list */ +				list_add_tail(&psb->list, &scsi_sblist); +			} +		} -		/* Continue until collect up to a nembed page worth of sgls */ -		if (bcnt == 0) +		/* continue until a nembed page worth of sgls */ +		if (post_cnt == 0)  			continue; -		/* Now, post the SCSI buffer list sgls as a block */ -		if (!phba->sli4_hba.extents_in_use) -			status = lpfc_sli4_post_scsi_sgl_block(phba, -							&sblist, -							bcnt); -		else -			status = lpfc_sli4_post_scsi_sgl_blk_ext(phba, -							&sblist, -							bcnt); -		/* Reset SCSI buffer count for next round of posting */ -		bcnt = 0; -		while (!list_empty(&sblist)) { -			list_remove_head(&sblist, psb, struct lpfc_scsi_buf, -					 list); + +		/* post block of SCSI buffer list sgls */ +		status = lpfc_sli4_post_scsi_sgl_block(phba, &blck_sblist, +						       post_cnt); + +		/* don't reset xirtag due to hole in xri block */ +		if (block_cnt == 0) +			last_xritag = NO_XRI; + +		/* reset SCSI buffer post count for next round of posting */ +		post_cnt = 0; + +		/* put posted SCSI buffer-sgl posted on SCSI buffer sgl list */ +		while (!list_empty(&blck_sblist)) { +			list_remove_head(&blck_sblist, psb, +					 struct lpfc_scsi_buf, list);  			if (status) { -				/* Put this back on the abort scsi list */ +				/* failure, put on abort scsi list */  				psb->exch_busy = 1; -				rc++;  			} else { +				/* success, put on SCSI buffer list */  				psb->exch_busy = 0;  				psb->status = IOSTAT_SUCCESS; +				num_posted++;  			} -			/* Put it back into the SCSI buffer list */ -			lpfc_release_scsi_buf_s4(phba, psb); +			list_add_tail(&psb->list, &scsi_sblist);  		}  	} +	/* Push SCSI buffers with sgl posted to the availble list */ +	while (!list_empty(&scsi_sblist)) { +		list_remove_head(&scsi_sblist, psb, +				 struct lpfc_scsi_buf, list); +		lpfc_release_scsi_buf_s4(phba, psb); +	} +	return num_posted; +} + +/** + * lpfc_sli4_repost_scsi_sgl_list - Repsot all the allocated scsi buffer sgls + * @phba: pointer to lpfc hba data structure. + * + * This routine walks the list of scsi buffers that have been allocated and + * repost them to the port by using SGL block post. This is needed after a + * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine + * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list + * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers. + * + * Returns: 0 = success, non-zero failure. + **/ +int +lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) +{ +	LIST_HEAD(post_sblist); +	int num_posted, rc = 0; + +	/* get all SCSI buffers need to repost to a local list */ +	spin_lock(&phba->scsi_buf_list_lock); +	list_splice_init(&phba->lpfc_scsi_buf_list, &post_sblist); +	spin_unlock(&phba->scsi_buf_list_lock); + +	/* post the list of scsi buffer sgls to port if available */ +	if (!list_empty(&post_sblist)) { +		num_posted = lpfc_sli4_post_scsi_sgl_list(phba, &post_sblist, +						phba->sli4_hba.scsi_xri_cnt); +		/* failed to post any scsi buffer, return error */ +		if (num_posted == 0) +			rc = -EIO; +	}  	return rc;  } @@ -792,12 +891,13 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)   * @vport: The virtual port for which this call being executed.   * @num_to_allocate: The requested number of buffers to allocate.   * - * This routine allocates a scsi buffer for device with SLI-4 interface spec, + * This routine allocates scsi buffers for device with SLI-4 interface spec,   * the scsi buffer contains all the necessary information needed to initiate - * a SCSI I/O. + * a SCSI I/O. After allocating up to @num_to_allocate SCSI buffers and put + * them on a list, it post them to the port by using SGL block post.   *   * Return codes: - *   int - number of scsi buffers that were allocated. + *   int - number of scsi buffers that were allocated and posted.   *   0 = failure, less than num_to_alloc is a partial failure.   **/  static int @@ -810,22 +910,21 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)  	dma_addr_t pdma_phys_fcp_cmd;  	dma_addr_t pdma_phys_fcp_rsp;  	dma_addr_t pdma_phys_bpl, pdma_phys_bpl1; -	uint16_t iotag, last_xritag = NO_XRI, lxri = 0; -	int status = 0, index; -	int bcnt; -	int non_sequential_xri = 0; -	LIST_HEAD(sblist); +	uint16_t iotag, lxri = 0; +	int bcnt, num_posted; +	LIST_HEAD(prep_sblist); +	LIST_HEAD(post_sblist); +	LIST_HEAD(scsi_sblist);  	for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {  		psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);  		if (!psb)  			break; -  		/* -		 * Get memory from the pci pool to map the virt space to pci bus -		 * space for an I/O.  The DMA buffer includes space for the -		 * struct fcp_cmnd, struct fcp_rsp and the number of bde's -		 * necessary to support the sg_tablesize. +		 * Get memory from the pci pool to map the virt space to +		 * pci bus space for an I/O. The DMA buffer includes space +		 * for the struct fcp_cmnd, struct fcp_rsp and the number +		 * of bde's necessary to support the sg_tablesize.  		 */  		psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool,  						GFP_KERNEL, &psb->dma_handle); @@ -833,8 +932,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)  			kfree(psb);  			break;  		} - -		/* Initialize virtual ptrs to dma_buf region. */  		memset(psb->data, 0, phba->cfg_sg_dma_buf_size);  		/* Allocate iotag for psb->cur_iocbq. */ @@ -855,16 +952,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)  		}  		psb->cur_iocbq.sli4_lxritag = lxri;  		psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri]; -		if (last_xritag != NO_XRI -			&& psb->cur_iocbq.sli4_xritag != (last_xritag+1)) { -			non_sequential_xri = 1; -		} else -			list_add_tail(&psb->list, &sblist); -		last_xritag = psb->cur_iocbq.sli4_xritag; - -		index = phba->sli4_hba.scsi_xri_cnt++;  		psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; -  		psb->fcp_bpl = psb->data;  		psb->fcp_cmnd = (psb->data + phba->cfg_sg_dma_buf_size)  			- (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); @@ -880,9 +968,9 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)  		pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd);  		/* -		 * The first two bdes are the FCP_CMD and FCP_RSP.  The balance -		 * are sg list bdes.  Initialize the first two and leave the -		 * rest for queuecommand. +		 * The first two bdes are the FCP_CMD and FCP_RSP. +		 * The balance are sg list bdes. Initialize the +		 * first two and leave the rest for queuecommand.  		 */  		sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd));  		sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd)); @@ -917,62 +1005,31 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)  		iocb->ulpBdeCount = 1;  		iocb->ulpLe = 1;  		iocb->ulpClass = CLASS3; -		psb->cur_iocbq.context1  = psb; +		psb->cur_iocbq.context1 = psb;  		if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)  			pdma_phys_bpl1 = pdma_phys_bpl + SGL_PAGE_SIZE;  		else  			pdma_phys_bpl1 = 0;  		psb->dma_phys_bpl = pdma_phys_bpl; -		phba->sli4_hba.lpfc_scsi_psb_array[index] = psb; -		if (non_sequential_xri) { -			status = lpfc_sli4_post_sgl(phba, pdma_phys_bpl, -						pdma_phys_bpl1, -						psb->cur_iocbq.sli4_xritag); -			if (status) { -				/* Put this back on the abort scsi list */ -				psb->exch_busy = 1; -			} else { -				psb->exch_busy = 0; -				psb->status = IOSTAT_SUCCESS; -			} -			/* Put it back into the SCSI buffer list */ -			lpfc_release_scsi_buf_s4(phba, psb); -			break; -		} -	} -	if (bcnt) { -		if (!phba->sli4_hba.extents_in_use) -			status = lpfc_sli4_post_scsi_sgl_block(phba, -								&sblist, -								bcnt); -		else -			status = lpfc_sli4_post_scsi_sgl_blk_ext(phba, -								&sblist, -								bcnt); -		if (status) { -			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, -					"3021 SCSI SGL post error %d\n", -					status); -			bcnt = 0; -		} -		/* Reset SCSI buffer count for next round of posting */ -		while (!list_empty(&sblist)) { -			list_remove_head(&sblist, psb, struct lpfc_scsi_buf, -				 list); -			if (status) { -				/* Put this back on the abort scsi list */ -				psb->exch_busy = 1; -			} else { -				psb->exch_busy = 0; -				psb->status = IOSTAT_SUCCESS; -			} -			/* Put it back into the SCSI buffer list */ -			lpfc_release_scsi_buf_s4(phba, psb); -		} +		/* add the scsi buffer to a post list */ +		list_add_tail(&psb->list, &post_sblist); +		spin_lock_irq(&phba->scsi_buf_list_lock); +		phba->sli4_hba.scsi_xri_cnt++; +		spin_unlock_irq(&phba->scsi_buf_list_lock);  	} +	lpfc_printf_log(phba, KERN_INFO, LOG_BG, +			"3021 Allocate %d out of %d requested new SCSI " +			"buffers\n", bcnt, num_to_alloc); + +	/* post the list of scsi buffer sgls to port if available */ +	if (!list_empty(&post_sblist)) +		num_posted = lpfc_sli4_post_scsi_sgl_list(phba, +							  &post_sblist, bcnt); +	else +		num_posted = 0; -	return bcnt + non_sequential_xri; +	return num_posted;  }  /** @@ -1043,7 +1100,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)  	list_for_each_entry(lpfc_cmd, &phba->lpfc_scsi_buf_list,  							list) {  		if (lpfc_test_rrq_active(phba, ndlp, -					 lpfc_cmd->cur_iocbq.sli4_xritag)) +					 lpfc_cmd->cur_iocbq.sli4_lxritag))  			continue;  		list_del(&lpfc_cmd->list);  		found = 1; @@ -1897,7 +1954,9 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,  	dma_addr_t physaddr;  	int i = 0, num_bde = 0, status;  	int datadir = sc->sc_data_direction; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS  	uint32_t rc; +#endif  	uint32_t checking = 1;  	uint32_t reftag;  	unsigned blksize; @@ -2034,7 +2093,9 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  	int datadir = sc->sc_data_direction;  	unsigned char pgdone = 0, alldone = 0;  	unsigned blksize; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS  	uint32_t rc; +#endif  	uint32_t checking = 1;  	uint32_t reftag;  	uint8_t txop, rxop; @@ -2253,7 +2314,9 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc,  	uint32_t reftag;  	unsigned blksize;  	uint8_t txop, rxop; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS  	uint32_t rc; +#endif  	uint32_t checking = 1;  	uint32_t dma_len;  	uint32_t dma_offset = 0; @@ -2383,7 +2446,9 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  	uint32_t reftag;  	uint8_t txop, rxop;  	uint32_t dma_len; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS  	uint32_t rc; +#endif  	uint32_t checking = 1;  	uint32_t dma_offset = 0;  	int num_sge = 0; @@ -3604,11 +3669,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,  			logit = LOG_FCP | LOG_FCP_UNDER;  		lpfc_printf_vlog(vport, KERN_WARNING, logit,  			 "9030 FCP cmd x%x failed <%d/%d> " -			 "status: x%x result: x%x Data: x%x x%x\n", +			 "status: x%x result: x%x " +			 "sid: x%x did: x%x oxid: x%x " +			 "Data: x%x x%x\n",  			 cmd->cmnd[0],  			 cmd->device ? cmd->device->id : 0xffff,  			 cmd->device ? cmd->device->lun : 0xffff,  			 lpfc_cmd->status, lpfc_cmd->result, +			 vport->fc_myDID, pnode->nlp_DID, +			 phba->sli_rev == LPFC_SLI_REV4 ? +			     lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff,  			 pIocbOut->iocb.ulpContext,  			 lpfc_cmd->cur_iocbq.iocb.ulpIoTag); @@ -3689,8 +3759,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,  				 * ABTS we cannot generate and RRQ.  				 */  				lpfc_set_rrq_active(phba, pnode, -						lpfc_cmd->cur_iocbq.sli4_xritag, -						0, 0); +					lpfc_cmd->cur_iocbq.sli4_lxritag, +					0, 0);  			}  		/* else: fall through */  		default: @@ -4348,8 +4418,20 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)  	ret = fc_block_scsi_eh(cmnd);  	if (ret)  		return ret; + +	spin_lock_irq(&phba->hbalock); +	/* driver queued commands are in process of being flushed */ +	if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) { +		spin_unlock_irq(&phba->hbalock); +		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, +			"3168 SCSI Layer abort requested I/O has been " +			"flushed by LLD.\n"); +		return FAILED; +	} +  	lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;  	if (!lpfc_cmd) { +		spin_unlock_irq(&phba->hbalock);  		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,  			 "2873 SCSI Layer I/O Abort Request IO CMPL Status "  			 "x%x ID %d LUN %d\n", @@ -4357,23 +4439,34 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)  		return SUCCESS;  	} +	iocb = &lpfc_cmd->cur_iocbq; +	/* the command is in process of being cancelled */ +	if (!(iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ)) { +		spin_unlock_irq(&phba->hbalock); +		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, +			"3169 SCSI Layer abort requested I/O has been " +			"cancelled by LLD.\n"); +		return FAILED; +	}  	/*  	 * If pCmd field of the corresponding lpfc_scsi_buf structure  	 * points to a different SCSI command, then the driver has  	 * already completed this command, but the midlayer did not -	 * see the completion before the eh fired.  Just return -	 * SUCCESS. +	 * see the completion before the eh fired. Just return SUCCESS.  	 */ -	iocb = &lpfc_cmd->cur_iocbq; -	if (lpfc_cmd->pCmd != cmnd) -		goto out; +	if (lpfc_cmd->pCmd != cmnd) { +		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, +			"3170 SCSI Layer abort requested I/O has been " +			"completed by LLD.\n"); +		goto out_unlock; +	}  	BUG_ON(iocb->context1 != lpfc_cmd); -	abtsiocb = lpfc_sli_get_iocbq(phba); +	abtsiocb = __lpfc_sli_get_iocbq(phba);  	if (abtsiocb == NULL) {  		ret = FAILED; -		goto out; +		goto out_unlock;  	}  	/* @@ -4405,6 +4498,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)  	abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;  	abtsiocb->vport = vport; +	/* no longer need the lock after this point */ +	spin_unlock_irq(&phba->hbalock); +  	if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) ==  	    IOCB_ERROR) {  		lpfc_sli_release_iocbq(phba, abtsiocb); @@ -4421,10 +4517,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)  	wait_event_timeout(waitq,  			  (lpfc_cmd->pCmd != cmnd),  			   (2*vport->cfg_devloss_tmo*HZ)); - -	spin_lock_irq(shost->host_lock);  	lpfc_cmd->waitq = NULL; -	spin_unlock_irq(shost->host_lock);  	if (lpfc_cmd->pCmd == cmnd) {  		ret = FAILED; @@ -4434,8 +4527,11 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)  				 "LUN %d\n",  				 ret, cmnd->device->id, cmnd->device->lun);  	} +	goto out; - out: +out_unlock: +	spin_unlock_irq(&phba->hbalock); +out:  	lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,  			 "0749 SCSI Layer I/O Abort Request Status x%x ID %d "  			 "LUN %d\n", ret, cmnd->device->id, @@ -4863,6 +4959,43 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)  }  /** + * lpfc_host_reset_handler - scsi_host_template eh_host_reset_handler entry pt + * @cmnd: Pointer to scsi_cmnd data structure. + * + * This routine does host reset to the adaptor port. It brings the HBA + * offline, performs a board restart, and then brings the board back online. + * The lpfc_offline calls lpfc_sli_hba_down which will abort and local + * reject all outstanding SCSI commands to the host and error returned + * back to SCSI mid-level. As this will be SCSI mid-level's last resort + * of error handling, it will only return error if resetting of the adapter + * is not successful; in all other cases, will return success. + * + * Return code : + *  0x2003 - Error + *  0x2002 - Success + **/ +static int +lpfc_host_reset_handler(struct scsi_cmnd *cmnd) +{ +	struct Scsi_Host *shost = cmnd->device->host; +	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; +	struct lpfc_hba *phba = vport->phba; +	int rc, ret = SUCCESS; + +	lpfc_offline_prep(phba); +	lpfc_offline(phba); +	rc = lpfc_sli_brdrestart(phba); +	if (rc) +		ret = FAILED; +	lpfc_online(phba); +	lpfc_unblock_mgmt_io(phba); + +	lpfc_printf_log(phba, KERN_ERR, LOG_FCP, +			"3172 SCSI layer issued Host Reset Data: x%x\n", ret); +	return ret; +} + +/**   * lpfc_slave_alloc - scsi_host_template slave_alloc entry point   * @sdev: Pointer to scsi_device.   * @@ -4994,6 +5127,7 @@ struct scsi_host_template lpfc_template = {  	.eh_device_reset_handler = lpfc_device_reset_handler,  	.eh_target_reset_handler = lpfc_target_reset_handler,  	.eh_bus_reset_handler	= lpfc_bus_reset_handler, +	.eh_host_reset_handler  = lpfc_host_reset_handler,  	.slave_alloc		= lpfc_slave_alloc,  	.slave_configure	= lpfc_slave_configure,  	.slave_destroy		= lpfc_slave_destroy,  |