diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_scsi.c')
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 954 | 
1 files changed, 797 insertions, 157 deletions
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 167b66dd34c..7991ba1980a 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2008 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   * Portions Copyright (C) 2004-2005 Christoph Hellwig              * @@ -31,8 +31,10 @@  #include <scsi/scsi_transport_fc.h>  #include "lpfc_version.h" +#include "lpfc_hw4.h"  #include "lpfc_hw.h"  #include "lpfc_sli.h" +#include "lpfc_sli4.h"  #include "lpfc_nl.h"  #include "lpfc_disc.h"  #include "lpfc_scsi.h" @@ -57,6 +59,8 @@ static char *dif_op_str[] = {  	"SCSI_PROT_READ_CONVERT",  	"SCSI_PROT_WRITE_CONVERT"  }; +static void +lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);  static void  lpfc_debug_save_data(struct scsi_cmnd *cmnd) @@ -325,7 +329,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)  	vports = lpfc_create_vport_work_array(phba);  	if (vports != NULL) -		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { +		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {  			shost = lpfc_shost_from_vport(vports[i]);  			shost_for_each_device(sdev, shost) {  				new_queue_depth = @@ -379,7 +383,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)  	vports = lpfc_create_vport_work_array(phba);  	if (vports != NULL) -		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { +		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {  			shost = lpfc_shost_from_vport(vports[i]);  			shost_for_each_device(sdev, shost) {  				if (vports[i]->cfg_lun_queue_depth <= @@ -427,7 +431,7 @@ lpfc_scsi_dev_block(struct lpfc_hba *phba)  	vports = lpfc_create_vport_work_array(phba);  	if (vports != NULL) -		for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { +		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {  			shost = lpfc_shost_from_vport(vports[i]);  			shost_for_each_device(sdev, shost) {  				rport = starget_to_rport(scsi_target(sdev)); @@ -438,22 +442,23 @@ lpfc_scsi_dev_block(struct lpfc_hba *phba)  }  /** - * lpfc_new_scsi_buf - Scsi buffer allocator + * lpfc_new_scsi_buf_s3 - Scsi buffer allocator for HBA with SLI3 IF spec   * @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, which contains all the necessary - * information needed to initiate a SCSI I/O.  The non-DMAable buffer region - * contains information to build the IOCB.  The DMAable region contains - * memory for the FCP CMND, FCP RSP, and the initial BPL.  In addition to - * allocating memory, the FCP CMND and FCP RSP BDEs are setup in the BPL - * and the BPL BDE is setup in the IOCB. + * This routine allocates a scsi buffer for device with SLI-3 interface spec, + * the scsi buffer contains all the necessary information needed to initiate + * a SCSI I/O. The non-DMAable buffer region contains information to build + * the IOCB. The DMAable region contains memory for the FCP CMND, FCP RSP, + * and the initial BPL. In addition to allocating memory, the FCP CMND and + * FCP RSP BDEs are setup in the BPL and the BPL BDE is setup in the IOCB.   *   * Return codes: - *   NULL - Error - *   Pointer to lpfc_scsi_buf data structure - Success + *   int - number of scsi buffers that were allocated. + *   0 = failure, less than num_to_alloc is a partial failure.   **/ -static struct lpfc_scsi_buf * -lpfc_new_scsi_buf(struct lpfc_vport *vport) +static int +lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc)  {  	struct lpfc_hba *phba = vport->phba;  	struct lpfc_scsi_buf *psb; @@ -463,107 +468,401 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport)  	dma_addr_t pdma_phys_fcp_rsp;  	dma_addr_t pdma_phys_bpl;  	uint16_t iotag; +	int bcnt; -	psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); -	if (!psb) -		return NULL; +	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. +		 */ +		psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, +					GFP_KERNEL, &psb->dma_handle); +		if (!psb->data) { +			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. */ +		iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq); +		if (iotag == 0) { +			pci_pool_free(phba->lpfc_scsi_dma_buf_pool, +					psb->data, psb->dma_handle); +			kfree(psb); +			break; +		} +		psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; + +		psb->fcp_cmnd = psb->data; +		psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd); +		psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) + +			sizeof(struct fcp_rsp); + +		/* Initialize local short-hand pointers. */ +		bpl = psb->fcp_bpl; +		pdma_phys_fcp_cmd = psb->dma_handle; +		pdma_phys_fcp_rsp = psb->dma_handle + sizeof(struct fcp_cmnd); +		pdma_phys_bpl = psb->dma_handle + sizeof(struct fcp_cmnd) + +			sizeof(struct fcp_rsp); + +		/* +		 * 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. +		 */ +		bpl[0].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_cmd)); +		bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd)); +		bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd); +		bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64; +		bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w); + +		/* Setup the physical region for the FCP RSP */ +		bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp)); +		bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp)); +		bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp); +		bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64; +		bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w); + +		/* +		 * Since the IOCB for the FCP I/O is built into this +		 * lpfc_scsi_buf, initialize it with all known data now. +		 */ +		iocb = &psb->cur_iocbq.iocb; +		iocb->un.fcpi64.bdl.ulpIoTag32 = 0; +		if ((phba->sli_rev == 3) && +				!(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) { +			/* fill in immediate fcp command BDE */ +			iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_IMMED; +			iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd); +			iocb->un.fcpi64.bdl.addrLow = offsetof(IOCB_t, +					unsli3.fcp_ext.icd); +			iocb->un.fcpi64.bdl.addrHigh = 0; +			iocb->ulpBdeCount = 0; +			iocb->ulpLe = 0; +			/* fill in responce BDE */ +			iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags = +							BUFF_TYPE_BDE_64; +			iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize = +				sizeof(struct fcp_rsp); +			iocb->unsli3.fcp_ext.rbde.addrLow = +				putPaddrLow(pdma_phys_fcp_rsp); +			iocb->unsli3.fcp_ext.rbde.addrHigh = +				putPaddrHigh(pdma_phys_fcp_rsp); +		} else { +			iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BLP_64; +			iocb->un.fcpi64.bdl.bdeSize = +					(2 * sizeof(struct ulp_bde64)); +			iocb->un.fcpi64.bdl.addrLow = +					putPaddrLow(pdma_phys_bpl); +			iocb->un.fcpi64.bdl.addrHigh = +					putPaddrHigh(pdma_phys_bpl); +			iocb->ulpBdeCount = 1; +			iocb->ulpLe = 1; +		} +		iocb->ulpClass = CLASS3; +		psb->status = IOSTAT_SUCCESS; +		/* Put it back into the SCSI buffer list */ +		lpfc_release_scsi_buf_s4(phba, psb); -	/* -	 * 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); -	if (!psb->data) { -		kfree(psb); -		return NULL;  	} -	/* Initialize virtual ptrs to dma_buf region. */ -	memset(psb->data, 0, phba->cfg_sg_dma_buf_size); +	return bcnt; +} -	/* Allocate iotag for psb->cur_iocbq. */ -	iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq); -	if (iotag == 0) { -		pci_pool_free(phba->lpfc_scsi_dma_buf_pool, -			      psb->data, psb->dma_handle); -		kfree (psb); -		return NULL; +/** + * lpfc_sli4_fcp_xri_aborted - Fast-path process of fcp xri abort + * @phba: pointer to lpfc hba data structure. + * @axri: pointer to the fcp xri abort wcqe structure. + * + * This routine is invoked by the worker thread to process a SLI4 fast-path + * FCP aborted xri. + **/ +void +lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, +			  struct sli4_wcqe_xri_aborted *axri) +{ +	uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); +	struct lpfc_scsi_buf *psb, *next_psb; +	unsigned long iflag = 0; + +	spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, iflag); +	list_for_each_entry_safe(psb, next_psb, +		&phba->sli4_hba.lpfc_abts_scsi_buf_list, list) { +		if (psb->cur_iocbq.sli4_xritag == xri) { +			list_del(&psb->list); +			psb->status = IOSTAT_SUCCESS; +			spin_unlock_irqrestore( +				&phba->sli4_hba.abts_scsi_buf_list_lock, +				iflag); +			lpfc_release_scsi_buf_s4(phba, psb); +			return; +		} +	} +	spin_unlock_irqrestore(&phba->sli4_hba.abts_scsi_buf_list_lock, +				iflag); +} + +/** + * lpfc_sli4_repost_scsi_sgl_list - Repsot the Scsi buffers sgl pages as block + * @phba: pointer to lpfc hba data structure. + * + * 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. + * + * Returns: 0 = success, non-zero failure. + **/ +int +lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) +{ +	struct lpfc_scsi_buf *psb; +	int index, status, bcnt = 0, rcnt = 0, rc = 0; +	LIST_HEAD(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; +			} +		} else +			/* A hole present in the XRI array, need to skip */ +			bcnt = rcnt; + +		if (index == phba->sli4_hba.scsi_xri_cnt - 1) +			/* End of XRI array for SCSI buffer, complete */ +			bcnt = rcnt; + +		/* Continue until collect up to a nembed page worth of sgls */ +		if (bcnt == 0) +			continue; +		/* Now, post the SCSI buffer list sgls as a block */ +		status = lpfc_sli4_post_scsi_sgl_block(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); +			if (status) { +				/* Put this back on the abort scsi list */ +				psb->status = IOSTAT_LOCAL_REJECT; +				psb->result = IOERR_ABORT_REQUESTED; +				rc++; +			} else +				psb->status = IOSTAT_SUCCESS; +			/* Put it back into the SCSI buffer list */ +			lpfc_release_scsi_buf_s4(phba, psb); +		}  	} -	psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; +	return rc; +} + +/** + * lpfc_new_scsi_buf_s4 - Scsi buffer allocator for HBA with SLI4 IF spec + * @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, + * the scsi buffer contains all the necessary information needed to initiate + * a SCSI I/O. + * + * Return codes: + *   int - number of scsi buffers that were allocated. + *   0 = failure, less than num_to_alloc is a partial failure. + **/ +static int +lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) +{ +	struct lpfc_hba *phba = vport->phba; +	struct lpfc_scsi_buf *psb; +	struct sli4_sge *sgl; +	IOCB_t *iocb; +	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; +	int status = 0, index; +	int bcnt; +	int non_sequential_xri = 0; +	int rc = 0; +	LIST_HEAD(sblist); -	psb->fcp_cmnd = psb->data; -	psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd); -	psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) + -							sizeof(struct fcp_rsp); +	for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { +		psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); +		if (!psb) +			break; -	/* Initialize local short-hand pointers. */ -	bpl = psb->fcp_bpl; -	pdma_phys_fcp_cmd = psb->dma_handle; -	pdma_phys_fcp_rsp = psb->dma_handle + sizeof(struct fcp_cmnd); -	pdma_phys_bpl = psb->dma_handle + sizeof(struct fcp_cmnd) + -			sizeof(struct fcp_rsp); +		/* +		 * 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); +		if (!psb->data) { +			kfree(psb); +			break; +		} -	/* -	 * 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. -	 */ -	bpl[0].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_cmd)); -	bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd)); -	bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd); -	bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64; -	bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w); +		/* Initialize virtual ptrs to dma_buf region. */ +		memset(psb->data, 0, phba->cfg_sg_dma_buf_size); -	/* Setup the physical region for the FCP RSP */ -	bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp)); -	bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp)); -	bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp); -	bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64; -	bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w); +		/* Allocate iotag for psb->cur_iocbq. */ +		iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq); +		if (iotag == 0) { +			kfree(psb); +			break; +		} -	/* -	 * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf, -	 * initialize it with all known data now. -	 */ -	iocb = &psb->cur_iocbq.iocb; -	iocb->un.fcpi64.bdl.ulpIoTag32 = 0; -	if ((phba->sli_rev == 3) && -	    !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) { -		/* fill in immediate fcp command BDE */ -		iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_IMMED; +		psb->cur_iocbq.sli4_xritag = lpfc_sli4_next_xritag(phba); +		if (psb->cur_iocbq.sli4_xritag == NO_XRI) { +			pci_pool_free(phba->lpfc_scsi_dma_buf_pool, +			      psb->data, psb->dma_handle); +			kfree(psb); +			break; +		} +		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)); +		psb->fcp_rsp = (struct fcp_rsp *)((uint8_t *)psb->fcp_cmnd + +					sizeof(struct fcp_cmnd)); + +		/* Initialize local short-hand pointers. */ +		sgl = (struct sli4_sge *)psb->fcp_bpl; +		pdma_phys_bpl = psb->dma_handle; +		pdma_phys_fcp_cmd = +			(psb->dma_handle + phba->cfg_sg_dma_buf_size) +			 - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); +		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. +		 */ +		sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd)); +		sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd)); +		bf_set(lpfc_sli4_sge_len, sgl, sizeof(struct fcp_cmnd)); +		bf_set(lpfc_sli4_sge_last, sgl, 0); +		sgl->word2 = cpu_to_le32(sgl->word2); +		sgl->word3 = cpu_to_le32(sgl->word3); +		sgl++; + +		/* Setup the physical region for the FCP RSP */ +		sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_rsp)); +		sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_rsp)); +		bf_set(lpfc_sli4_sge_len, sgl, sizeof(struct fcp_rsp)); +		bf_set(lpfc_sli4_sge_last, sgl, 1); +		sgl->word2 = cpu_to_le32(sgl->word2); +		sgl->word3 = cpu_to_le32(sgl->word3); + +		/* +		 * Since the IOCB for the FCP I/O is built into this +		 * lpfc_scsi_buf, initialize it with all known data now. +		 */ +		iocb = &psb->cur_iocbq.iocb; +		iocb->un.fcpi64.bdl.ulpIoTag32 = 0; +		iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_64; +		/* setting the BLP size to 2 * sizeof BDE may not be correct. +		 * We are setting the bpl to point to out sgl. An sgl's +		 * entries are 16 bytes, a bpl entries are 12 bytes. +		 */  		iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd); -		iocb->un.fcpi64.bdl.addrLow = offsetof(IOCB_t, -						       unsli3.fcp_ext.icd); -		iocb->un.fcpi64.bdl.addrHigh = 0; -		iocb->ulpBdeCount = 0; -		iocb->ulpLe = 0; -		/* fill in responce BDE */ -		iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; -		iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize = -						sizeof(struct fcp_rsp); -		iocb->unsli3.fcp_ext.rbde.addrLow = -						putPaddrLow(pdma_phys_fcp_rsp); -		iocb->unsli3.fcp_ext.rbde.addrHigh = -						putPaddrHigh(pdma_phys_fcp_rsp); -	} else { -		iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BLP_64; -		iocb->un.fcpi64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64)); -		iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_bpl); -		iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_bpl); +		iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_fcp_cmd); +		iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_fcp_cmd);  		iocb->ulpBdeCount = 1;  		iocb->ulpLe = 1; +		iocb->ulpClass = CLASS3; +		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->status = IOSTAT_LOCAL_REJECT; +				psb->result = IOERR_ABORT_REQUESTED; +				rc++; +			} else +				psb->status = IOSTAT_SUCCESS; +			/* Put it back into the SCSI buffer list */ +			lpfc_release_scsi_buf_s4(phba, psb); +			break; +		} +	} +	if (bcnt) { +		status = lpfc_sli4_post_scsi_sgl_block(phba, &sblist, bcnt); +		/* 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->status = IOSTAT_LOCAL_REJECT; +				psb->result = IOERR_ABORT_REQUESTED; +				rc++; +			} else +				psb->status = IOSTAT_SUCCESS; +			/* Put it back into the SCSI buffer list */ +			lpfc_release_scsi_buf_s4(phba, psb); +		}  	} -	iocb->ulpClass = CLASS3; -	return psb; +	return bcnt + non_sequential_xri - rc;  }  /** - * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list list of Hba - * @phba: The Hba for which this call is being executed. + * lpfc_new_scsi_buf - Wrapper funciton for scsi buffer allocator + * @vport: The virtual port for which this call being executed. + * @num_to_allocate: The requested number of buffers to allocate. + * + * This routine wraps the actual SCSI buffer allocator function pointer from + * the lpfc_hba struct. + * + * Return codes: + *   int - number of scsi buffers that were allocated. + *   0 = failure, less than num_to_alloc is a partial failure. + **/ +static inline int +lpfc_new_scsi_buf(struct lpfc_vport *vport, int num_to_alloc) +{ +	return vport->phba->lpfc_new_scsi_buf(vport, num_to_alloc); +} + +/** + * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA + * @phba: The HBA for which this call is being executed.   *   * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list   * and returns to caller. @@ -591,7 +890,7 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)  }  /** - * lpfc_release_scsi_buf - Return a scsi buffer back to hba's lpfc_scsi_buf_list + * lpfc_release_scsi_buf - Return a scsi buffer back to hba scsi buf list   * @phba: The Hba for which this call is being executed.   * @psb: The scsi buffer which is being released.   * @@ -599,7 +898,7 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)   * lpfc_scsi_buf_list list.   **/  static void -lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) +lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)  {  	unsigned long iflag = 0; @@ -610,21 +909,69 @@ lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)  }  /** - * lpfc_scsi_prep_dma_buf - Routine to do DMA mapping for scsi buffer + * lpfc_release_scsi_buf_s4: Return a scsi buffer back to hba scsi buf list. + * @phba: The Hba for which this call is being executed. + * @psb: The scsi buffer which is being released. + * + * This routine releases @psb scsi buffer by adding it to tail of @phba + * lpfc_scsi_buf_list list. For SLI4 XRI's are tied to the scsi buffer + * and cannot be reused for at least RA_TOV amount of time if it was + * aborted. + **/ +static void +lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) +{ +	unsigned long iflag = 0; + +	if (psb->status == IOSTAT_LOCAL_REJECT +		&& psb->result == IOERR_ABORT_REQUESTED) { +		spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, +					iflag); +		psb->pCmd = NULL; +		list_add_tail(&psb->list, +			&phba->sli4_hba.lpfc_abts_scsi_buf_list); +		spin_unlock_irqrestore(&phba->sli4_hba.abts_scsi_buf_list_lock, +					iflag); +	} else { + +		spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag); +		psb->pCmd = NULL; +		list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list); +		spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag); +	} +} + +/** + * lpfc_release_scsi_buf: Return a scsi buffer back to hba scsi buf list. + * @phba: The Hba for which this call is being executed. + * @psb: The scsi buffer which is being released. + * + * This routine releases @psb scsi buffer by adding it to tail of @phba + * lpfc_scsi_buf_list list. + **/ +static void +lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) +{ + +	phba->lpfc_release_scsi_buf(phba, psb); +} + +/** + * lpfc_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec   * @phba: The Hba for which this call is being executed.   * @lpfc_cmd: The scsi buffer which is going to be mapped.   *   * This routine does the pci dma mapping for scatter-gather list of scsi cmnd - * field of @lpfc_cmd. This routine scans through sg elements and format the - * bdea. This routine also initializes all IOCB fields which are dependent on - * scsi command request buffer. + * field of @lpfc_cmd for device with SLI-3 interface spec. This routine scans + * through sg elements and format the bdea. This routine also initializes all + * IOCB fields which are dependent on scsi command request buffer.   *   * Return codes:   *   1 - Error   *   0 - Success   **/  static int -lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) +lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)  {  	struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;  	struct scatterlist *sgel = NULL; @@ -827,8 +1174,8 @@ lpfc_cmd_blksize(struct scsi_cmnd *sc)   * @reftag:         out: ref tag (reference tag)   *   * Description: - *   Extract DIF paramters from the command if possible.  Otherwise, - *   use default paratmers. + *   Extract DIF parameters from the command if possible.  Otherwise, + *   use default parameters.   *   **/  static inline void @@ -1312,10 +1659,10 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,  	uint32_t bgstat = bgf->bgstat;  	uint64_t failing_sector = 0; -	printk(KERN_ERR "BG ERROR in cmd 0x%x lba 0x%llx blk cnt 0x%lx " +	printk(KERN_ERR "BG ERROR in cmd 0x%x lba 0x%llx blk cnt 0x%x "  			"bgstat=0x%x bghm=0x%x\n",  			cmd->cmnd[0], (unsigned long long)scsi_get_lba(cmd), -			cmd->request->nr_sectors, bgstat, bghm); +			blk_rq_sectors(cmd->request), bgstat, bghm);  	spin_lock(&_dump_buf_lock);  	if (!_dump_buf_done) { @@ -1412,6 +1759,133 @@ out:  }  /** + * lpfc_scsi_prep_dma_buf_s4 - DMA mapping for scsi buffer to SLI4 IF spec + * @phba: The Hba for which this call is being executed. + * @lpfc_cmd: The scsi buffer which is going to be mapped. + * + * This routine does the pci dma mapping for scatter-gather list of scsi cmnd + * field of @lpfc_cmd for device with SLI-4 interface spec. + * + * Return codes: + * 	1 - Error + * 	0 - Success + **/ +static int +lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) +{ +	struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; +	struct scatterlist *sgel = NULL; +	struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; +	struct sli4_sge *sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl; +	IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; +	dma_addr_t physaddr; +	uint32_t num_bde = 0; +	uint32_t dma_len; +	uint32_t dma_offset = 0; +	int nseg; + +	/* +	 * There are three possibilities here - use scatter-gather segment, use +	 * the single mapping, or neither.  Start the lpfc command prep by +	 * bumping the bpl beyond the fcp_cmnd and fcp_rsp regions to the first +	 * data bde entry. +	 */ +	if (scsi_sg_count(scsi_cmnd)) { +		/* +		 * The driver stores the segment count returned from pci_map_sg +		 * because this a count of dma-mappings used to map the use_sg +		 * pages.  They are not guaranteed to be the same for those +		 * architectures that implement an IOMMU. +		 */ + +		nseg = scsi_dma_map(scsi_cmnd); +		if (unlikely(!nseg)) +			return 1; +		sgl += 1; +		/* clear the last flag in the fcp_rsp map entry */ +		sgl->word2 = le32_to_cpu(sgl->word2); +		bf_set(lpfc_sli4_sge_last, sgl, 0); +		sgl->word2 = cpu_to_le32(sgl->word2); +		sgl += 1; + +		lpfc_cmd->seg_cnt = nseg; +		if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { +			printk(KERN_ERR "%s: Too many sg segments from " +			       "dma_map_sg.  Config %d, seg_cnt %d\n", +			       __func__, phba->cfg_sg_seg_cnt, +			       lpfc_cmd->seg_cnt); +			scsi_dma_unmap(scsi_cmnd); +			return 1; +		} + +		/* +		 * The driver established a maximum scatter-gather segment count +		 * during probe that limits the number of sg elements in any +		 * single scsi command.  Just run through the seg_cnt and format +		 * the sge's. +		 * When using SLI-3 the driver will try to fit all the BDEs into +		 * the IOCB. If it can't then the BDEs get added to a BPL as it +		 * does for SLI-2 mode. +		 */ +		scsi_for_each_sg(scsi_cmnd, sgel, nseg, num_bde) { +			physaddr = sg_dma_address(sgel); +			dma_len = sg_dma_len(sgel); +			bf_set(lpfc_sli4_sge_len, sgl, sg_dma_len(sgel)); +			sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr)); +			sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr)); +			if ((num_bde + 1) == nseg) +				bf_set(lpfc_sli4_sge_last, sgl, 1); +			else +				bf_set(lpfc_sli4_sge_last, sgl, 0); +			bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); +			sgl->word2 = cpu_to_le32(sgl->word2); +			sgl->word3 = cpu_to_le32(sgl->word3); +			dma_offset += dma_len; +			sgl++; +		} +	} else { +		sgl += 1; +		/* clear the last flag in the fcp_rsp map entry */ +		sgl->word2 = le32_to_cpu(sgl->word2); +		bf_set(lpfc_sli4_sge_last, sgl, 1); +		sgl->word2 = cpu_to_le32(sgl->word2); +	} + +	/* +	 * Finish initializing those IOCB fields that are dependent on the +	 * scsi_cmnd request_buffer.  Note that for SLI-2 the bdeSize is +	 * explicitly reinitialized. +	 * all iocb memory resources are reused. +	 */ +	fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd)); + +	/* +	 * Due to difference in data length between DIF/non-DIF paths, +	 * we need to set word 4 of IOCB here +	 */ +	iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd); +	return 0; +} + +/** + * lpfc_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer + * @phba: The Hba for which this call is being executed. + * @lpfc_cmd: The scsi buffer which is going to be mapped. + * + * This routine wraps the actual DMA mapping function pointer from the + * lpfc_hba struct. + * + * Return codes: + * 	1 - Error + * 	0 - Success + **/ +static inline int +lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) +{ +	return phba->lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); +} + +/**   * lpfc_send_scsi_error_event - Posts an event when there is SCSI error   * @phba: Pointer to hba context object.   * @vport: Pointer to vport object. @@ -1504,15 +1978,15 @@ lpfc_send_scsi_error_event(struct lpfc_hba *phba, struct lpfc_vport *vport,  }  /** - * lpfc_scsi_unprep_dma_buf - Routine to un-map DMA mapping of scatter gather - * @phba: The Hba for which this call is being executed. + * lpfc_scsi_unprep_dma_buf_s3 - Un-map DMA mapping of SG-list for SLI3 dev + * @phba: The HBA for which this call is being executed.   * @psb: The scsi buffer which is going to be un-mapped.   *   * This routine does DMA un-mapping of scatter gather list of scsi command - * field of @lpfc_cmd. + * field of @lpfc_cmd for device with SLI-3 interface spec.   **/  static void -lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) +lpfc_scsi_unprep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)  {  	/*  	 * There are only two special cases to consider.  (1) the scsi command @@ -1529,6 +2003,36 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)  }  /** + * lpfc_scsi_unprep_dma_buf_s4 - Un-map DMA mapping of SG-list for SLI4 dev + * @phba: The Hba for which this call is being executed. + * @psb: The scsi buffer which is going to be un-mapped. + * + * This routine does DMA un-mapping of scatter gather list of scsi command + * field of @lpfc_cmd for device with SLI-4 interface spec. If we have to + * remove the sgl for this scsi buffer then we will do it here. For now + * we should be able to just call the sli3 unprep routine. + **/ +static void +lpfc_scsi_unprep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) +{ +	lpfc_scsi_unprep_dma_buf_s3(phba, psb); +} + +/** + * lpfc_scsi_unprep_dma_buf - Wrapper function for unmap DMA mapping of SG-list + * @phba: The Hba for which this call is being executed. + * @psb: The scsi buffer which is going to be un-mapped. + * + * This routine does DMA un-mapping of scatter gather list of scsi command + * field of @lpfc_cmd for device with SLI-4 interface spec. + **/ +static void +lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) +{ +	phba->lpfc_scsi_unprep_dma_buf(phba, psb); +} + +/**   * lpfc_handler_fcp_err - FCP response handler   * @vport: The virtual port for which this call is being executed.   * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure. @@ -1676,7 +2180,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,   * lpfc_scsi_cmd_iocb_cmpl - Scsi cmnd IOCB completion routine   * @phba: The Hba for which this call is being executed.   * @pIocbIn: The command IOCBQ for the scsi cmnd. - * @pIocbOut: The response IOCBQ for the scsi cmnd . + * @pIocbOut: The response IOCBQ for the scsi cmnd.   *   * This routine assigns scsi command result by looking into response IOCB   * status field appropriately. This routine handles QUEUE FULL condition as @@ -1957,16 +2461,16 @@ lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd)  }  /** - * lpfc_scsi_prep_cmnd -  Routine to convert scsi cmnd to FCP information unit + * lpfc_scsi_prep_cmnd_s3 - Convert scsi cmnd to FCP infor unit for SLI3 dev   * @vport: The virtual port for which this call is being executed.   * @lpfc_cmd: The scsi command which needs to send.   * @pnode: Pointer to lpfc_nodelist.   *   * This routine initializes fcp_cmnd and iocb data structure from scsi command - * to transfer. + * to transfer for device with SLI3 interface spec.   **/  static void -lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, +lpfc_scsi_prep_cmnd_s3(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,  		    struct lpfc_nodelist *pnode)  {  	struct lpfc_hba *phba = vport->phba; @@ -2013,8 +2517,11 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,  	if (scsi_sg_count(scsi_cmnd)) {  		if (datadir == DMA_TO_DEVICE) {  			iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR; -			iocb_cmd->un.fcpi.fcpi_parm = 0; -			iocb_cmd->ulpPU = 0; +			if (phba->sli_rev < LPFC_SLI_REV4) { +				iocb_cmd->un.fcpi.fcpi_parm = 0; +				iocb_cmd->ulpPU = 0; +			} else +				iocb_cmd->ulpPU = PARM_READ_CHECK;  			fcp_cmnd->fcpCntl3 = WRITE_DATA;  			phba->fc4OutputRequests++;  		} else { @@ -2051,20 +2558,60 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,  }  /** - * lpfc_scsi_prep_task_mgmt_cmnd - Convert scsi TM cmnd to FCP information unit + * lpfc_scsi_prep_cmnd_s4 - Convert scsi cmnd to FCP infor unit for SLI4 dev + * @vport: The virtual port for which this call is being executed. + * @lpfc_cmd: The scsi command which needs to send. + * @pnode: Pointer to lpfc_nodelist. + * + * This routine initializes fcp_cmnd and iocb data structure from scsi command + * to transfer for device with SLI4 interface spec. + **/ +static void +lpfc_scsi_prep_cmnd_s4(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, +		       struct lpfc_nodelist *pnode) +{ +	/* +	 * The prep cmnd routines do not touch the sgl or its +	 * entries. We may not have to do anything different. +	 * I will leave this function in place until we can +	 * run some IO through the driver and determine if changes +	 * are needed. +	 */ +	return lpfc_scsi_prep_cmnd_s3(vport, lpfc_cmd, pnode); +} + +/** + * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit + * @vport: The virtual port for which this call is being executed. + * @lpfc_cmd: The scsi command which needs to send. + * @pnode: Pointer to lpfc_nodelist. + * + * This routine wraps the actual convert SCSI cmnd function pointer from + * the lpfc_hba struct. + **/ +static inline void +lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, +		    struct lpfc_nodelist *pnode) +{ +	vport->phba->lpfc_scsi_prep_cmnd(vport, lpfc_cmd, pnode); +} + +/** + * lpfc_scsi_prep_task_mgmt_cmnd_s3 - Convert SLI3 scsi TM cmd to FCP info unit   * @vport: The virtual port for which this call is being executed.   * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure.   * @lun: Logical unit number.   * @task_mgmt_cmd: SCSI task management command.   * - * This routine creates FCP information unit corresponding to @task_mgmt_cmd. + * This routine creates FCP information unit corresponding to @task_mgmt_cmd + * for device with SLI-3 interface spec.   *   * Return codes:   *   0 - Error   *   1 - Success   **/  static int -lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, +lpfc_scsi_prep_task_mgmt_cmd_s3(struct lpfc_vport *vport,  			     struct lpfc_scsi_buf *lpfc_cmd,  			     unsigned int lun,  			     uint8_t task_mgmt_cmd) @@ -2114,6 +2661,107 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,  }  /** + * lpfc_scsi_prep_task_mgmt_cmnd_s4 - Convert SLI4 scsi TM cmd to FCP info unit + * @vport: The virtual port for which this call is being executed. + * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure. + * @lun: Logical unit number. + * @task_mgmt_cmd: SCSI task management command. + * + * This routine creates FCP information unit corresponding to @task_mgmt_cmd + * for device with SLI-4 interface spec. + * + * Return codes: + * 	0 - Error + * 	1 - Success + **/ +static int +lpfc_scsi_prep_task_mgmt_cmd_s4(struct lpfc_vport *vport, +				struct lpfc_scsi_buf *lpfc_cmd, +				unsigned int lun, +				uint8_t task_mgmt_cmd) +{ +	/* +	 * The prep cmnd routines do not touch the sgl or its +	 * entries. We may not have to do anything different. +	 * I will leave this function in place until we can +	 * run some IO through the driver and determine if changes +	 * are needed. +	 */ +	return lpfc_scsi_prep_task_mgmt_cmd_s3(vport, lpfc_cmd, lun, +						task_mgmt_cmd); +} + +/** + * lpfc_scsi_prep_task_mgmt_cmnd - Wrapper func convert scsi TM cmd to FCP info + * @vport: The virtual port for which this call is being executed. + * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure. + * @lun: Logical unit number. + * @task_mgmt_cmd: SCSI task management command. + * + * This routine wraps the actual convert SCSI TM to FCP information unit + * function pointer from the lpfc_hba struct. + * + * Return codes: + * 	0 - Error + * 	1 - Success + **/ +static inline int +lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, +			     struct lpfc_scsi_buf *lpfc_cmd, +			     unsigned int lun, +			     uint8_t task_mgmt_cmd) +{ +	struct lpfc_hba *phba = vport->phba; + +	return phba->lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun, +						  task_mgmt_cmd); +} + +/** + * lpfc_scsi_api_table_setup - Set up scsi api fucntion jump table + * @phba: The hba struct for which this call is being executed. + * @dev_grp: The HBA PCI-Device group number. + * + * This routine sets up the SCSI interface API function jump table in @phba + * struct. + * Returns: 0 - success, -ENODEV - failure. + **/ +int +lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) +{ + +	switch (dev_grp) { +	case LPFC_PCI_DEV_LP: +		phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s3; +		phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s3; +		phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd_s3; +		phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf_s3; +		phba->lpfc_scsi_prep_task_mgmt_cmd = +					lpfc_scsi_prep_task_mgmt_cmd_s3; +		phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3; +		break; +	case LPFC_PCI_DEV_OC: +		phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s4; +		phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4; +		phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd_s4; +		phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf_s4; +		phba->lpfc_scsi_prep_task_mgmt_cmd = +					lpfc_scsi_prep_task_mgmt_cmd_s4; +		phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4; +		break; +	default: +		lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +				"1418 Invalid HBA PCI-device group: 0x%x\n", +				dev_grp); +		return -ENODEV; +		break; +	} +	phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf; +	phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth; +	return 0; +} + +/**   * lpfc_taskmgmt_def_cmpl - IOCB completion routine for task management command   * @phba: The Hba for which this call is being executed.   * @cmdiocbq: Pointer to lpfc_iocbq data structure. @@ -2178,9 +2826,8 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport,  	lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,  			 "0702 Issue Target Reset to TGT %d Data: x%x x%x\n",  			 tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); -	status = lpfc_sli_issue_iocb_wait(phba, -				       &phba->sli.ring[phba->sli.fcp_ring], -				       iocbq, iocbqrsp, lpfc_cmd->timeout); +	status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING, +					  iocbq, iocbqrsp, lpfc_cmd->timeout);  	if (status != IOCB_SUCCESS) {  		if (status == IOCB_TIMEDOUT) {  			iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; @@ -2305,7 +2952,6 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))  	struct Scsi_Host  *shost = cmnd->device->host;  	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;  	struct lpfc_hba   *phba = vport->phba; -	struct lpfc_sli   *psli = &phba->sli;  	struct lpfc_rport_data *rdata = cmnd->device->hostdata;  	struct lpfc_nodelist *ndlp = rdata->pnode;  	struct lpfc_scsi_buf *lpfc_cmd; @@ -2378,15 +3024,15 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))  		if (cmnd->cmnd[0] == READ_10)  			lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,  					"9035 BLKGRD: READ @ sector %llu, " -					 "count %lu\n", -					 (unsigned long long)scsi_get_lba(cmnd), -					cmnd->request->nr_sectors); +					"count %u\n", +					(unsigned long long)scsi_get_lba(cmnd), +					blk_rq_sectors(cmnd->request));  		else if (cmnd->cmnd[0] == WRITE_10)  			lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,  					"9036 BLKGRD: WRITE @ sector %llu, " -					"count %lu cmd=%p\n", +					"count %u cmd=%p\n",  					(unsigned long long)scsi_get_lba(cmnd), -					cmnd->request->nr_sectors, +					blk_rq_sectors(cmnd->request),  					cmnd);  		err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd); @@ -2406,15 +3052,15 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))  		if (cmnd->cmnd[0] == READ_10)  			lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,  					 "9040 dbg: READ @ sector %llu, " -					 "count %lu\n", +					 "count %u\n",  					 (unsigned long long)scsi_get_lba(cmnd), -					 cmnd->request->nr_sectors); +					 blk_rq_sectors(cmnd->request));  		else if (cmnd->cmnd[0] == WRITE_10)  			lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,  					 "9041 dbg: WRITE @ sector %llu, " -					 "count %lu cmd=%p\n", +					 "count %u cmd=%p\n",  					 (unsigned long long)scsi_get_lba(cmnd), -					 cmnd->request->nr_sectors, cmnd); +					 blk_rq_sectors(cmnd->request), cmnd);  		else  			lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,  					 "9042 dbg: parser not implemented\n"); @@ -2427,7 +3073,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))  	lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);  	atomic_inc(&ndlp->cmd_pending); -	err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring], +	err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING,  				  &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);  	if (err) {  		atomic_dec(&ndlp->cmd_pending); @@ -2490,7 +3136,6 @@ lpfc_abort_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; -	struct lpfc_sli_ring *pring = &phba->sli.ring[phba->sli.fcp_ring];  	struct lpfc_iocbq *iocb;  	struct lpfc_iocbq *abtsiocb;  	struct lpfc_scsi_buf *lpfc_cmd; @@ -2531,7 +3176,10 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)  	icmd = &abtsiocb->iocb;  	icmd->un.acxri.abortType = ABORT_TYPE_ABTS;  	icmd->un.acxri.abortContextTag = cmd->ulpContext; -	icmd->un.acxri.abortIoTag = cmd->ulpIoTag; +	if (phba->sli_rev == LPFC_SLI_REV4) +		icmd->un.acxri.abortIoTag = iocb->sli4_xritag; +	else +		icmd->un.acxri.abortIoTag = cmd->ulpIoTag;  	icmd->ulpLe = 1;  	icmd->ulpClass = cmd->ulpClass; @@ -2542,7 +3190,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)  	abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;  	abtsiocb->vport = vport; -	if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) == IOCB_ERROR) { +	if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) == +	    IOCB_ERROR) {  		lpfc_sli_release_iocbq(phba, abtsiocb);  		ret = FAILED;  		goto out; @@ -2668,8 +3317,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)  			 "0703 Issue target reset to TGT %d LUN %d "  			 "rpi x%x nlp_flag x%x\n", cmnd->device->id,  			 cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); -	status = lpfc_sli_issue_iocb_wait(phba, -					  &phba->sli.ring[phba->sli.fcp_ring], +	status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING,  					  iocbq, iocbqrsp, lpfc_cmd->timeout);  	if (status == IOCB_TIMEDOUT) {  		iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; @@ -2825,11 +3473,10 @@ lpfc_slave_alloc(struct scsi_device *sdev)  {  	struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;  	struct lpfc_hba   *phba = vport->phba; -	struct lpfc_scsi_buf *scsi_buf = NULL;  	struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); -	uint32_t total = 0, i; +	uint32_t total = 0;  	uint32_t num_to_alloc = 0; -	unsigned long flags; +	int num_allocated = 0;  	if (!rport || fc_remote_port_chkready(rport))  		return -ENXIO; @@ -2863,20 +3510,13 @@ lpfc_slave_alloc(struct scsi_device *sdev)  				 (phba->cfg_hba_queue_depth - total));  		num_to_alloc = phba->cfg_hba_queue_depth - total;  	} - -	for (i = 0; i < num_to_alloc; i++) { -		scsi_buf = lpfc_new_scsi_buf(vport); -		if (!scsi_buf) { -			lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, -					 "0706 Failed to allocate " -					 "command buffer\n"); -			break; -		} - -		spin_lock_irqsave(&phba->scsi_buf_list_lock, flags); -		phba->total_scsi_bufs++; -		list_add_tail(&scsi_buf->list, &phba->lpfc_scsi_buf_list); -		spin_unlock_irqrestore(&phba->scsi_buf_list_lock, flags); +	num_allocated = lpfc_new_scsi_buf(vport, num_to_alloc); +	if (num_to_alloc != num_allocated) { +			lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, +				 "0708 Allocation request of %d " +				 "command buffers did not succeed.  " +				 "Allocated %d buffers.\n", +				 num_to_alloc, num_allocated);  	}  	return 0;  }  |