diff options
| author | Linus Torvalds <[email protected]> | 2024-01-11 14:24:32 -0800 | 
|---|---|---|
| committer | Linus Torvalds <[email protected]> | 2024-01-11 14:24:32 -0800 | 
| commit | 22d29f1112c85c1ad519a8c0403f7f7289cf060c (patch) | |
| tree | 42649f46668e27e25afb6c71065f5ae6698a78e4 /drivers/scsi/mpi3mr/mpi3mr_app.c | |
| parent | 4c72e2b8c42e57f65d8fbfb01329e79d2b450653 (diff) | |
| parent | 45a2c87f28ad0ee8c286bb6dd5686bc54f5b7160 (diff) | |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
 "Updates to the usual drivers (ufs, mpi3mr, mpt3sas, lpfc, fnic,
  hisi_sas, arcmsr, ) plus the usual assorted minor fixes and updates.
  This time around there's only a single line update to the core, so
  nothing major and barely anything minor"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (135 commits)
  scsi: ufs: core: Simplify ufshcd_auto_hibern8_update()
  scsi: ufs: core: Rename ufshcd_auto_hibern8_enable() and make it static
  scsi: ufs: qcom: Fix ESI vector mask
  scsi: ufs: host: Fix kernel-doc warning
  scsi: hisi_sas: Correct the number of global debugfs registers
  scsi: hisi_sas: Rollback some operations if FLR failed
  scsi: hisi_sas: Check before using pointer variables
  scsi: hisi_sas: Replace with standard error code return value
  scsi: hisi_sas: Set .phy_attached before notifing phyup event HISI_PHYE_PHY_UP_PM
  scsi: ufs: core: Add sysfs node for UFS RTC update
  scsi: ufs: core: Add UFS RTC support
  scsi: ufs: core: Add ufshcd_is_ufs_dev_busy()
  scsi: ufs: qcom: Remove unused definitions
  scsi: ufs: qcom: Use ufshcd_rmwl() where applicable
  scsi: ufs: qcom: Remove support for host controllers older than v2.0
  scsi: ufs: qcom: Simplify ufs_qcom_{assert/deassert}_reset
  scsi: ufs: qcom: Initialize cycles_in_1us variable in ufs_qcom_set_core_clk_ctrl()
  scsi: ufs: qcom: Sort includes alphabetically
  scsi: ufs: qcom: Remove unused ufs_qcom_hosts struct array
  scsi: ufs: qcom: Use dev_err_probe() to simplify error handling of devm_gpiod_get_optional()
  ...
Diffstat (limited to 'drivers/scsi/mpi3mr/mpi3mr_app.c')
| -rw-r--r-- | drivers/scsi/mpi3mr/mpi3mr_app.c | 536 | 
1 files changed, 428 insertions, 108 deletions
diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c index 08645a99ad6b..0380996b5ad2 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_app.c +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c @@ -223,6 +223,22 @@ static long mpi3mr_bsg_pel_enable(struct mpi3mr_ioc *mrioc,  		return rval;  	} +	if (mrioc->unrecoverable) { +		dprint_bsg_err(mrioc, "%s: unrecoverable controller\n", +			       __func__); +		return -EFAULT; +	} + +	if (mrioc->reset_in_progress) { +		dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__); +		return -EAGAIN; +	} + +	if (mrioc->stop_bsgs) { +		dprint_bsg_err(mrioc, "%s: bsgs are blocked\n", __func__); +		return -EAGAIN; +	} +  	sg_copy_to_buffer(job->request_payload.sg_list,  			  job->request_payload.sg_cnt,  			  &pel_enable, sizeof(pel_enable)); @@ -548,7 +564,36 @@ static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job)  }  /** + * mpi3mr_total_num_ioctl_sges - Count number of SGEs required + * @drv_bufs: DMA address of the buffers to be placed in sgl + * @bufcnt: Number of DMA buffers + * + * This function returns total number of data SGEs required + * including zero length SGEs and excluding management request + * and response buffer for the given list of data buffer + * descriptors + * + * Return: Number of SGE elements needed + */ +static inline u16 mpi3mr_total_num_ioctl_sges(struct mpi3mr_buf_map *drv_bufs, +					      u8 bufcnt) +{ +	u16 i, sge_count = 0; + +	for (i = 0; i < bufcnt; i++, drv_bufs++) { +		if (drv_bufs->data_dir == DMA_NONE || +		    drv_bufs->kern_buf) +			continue; +		sge_count += drv_bufs->num_dma_desc; +		if (!drv_bufs->num_dma_desc) +			sge_count++; +	} +	return sge_count; +} + +/**   * mpi3mr_bsg_build_sgl - SGL construction for MPI commands + * @mrioc: Adapter instance reference   * @mpi_req: MPI request   * @sgl_offset: offset to start sgl in the MPI request   * @drv_bufs: DMA address of the buffers to be placed in sgl @@ -560,27 +605,45 @@ static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job)   * This function places the DMA address of the given buffers in   * proper format as SGEs in the given MPI request.   * - * Return: Nothing + * Return: 0 on success,-1 on failure   */ -static void mpi3mr_bsg_build_sgl(u8 *mpi_req, uint32_t sgl_offset, -	struct mpi3mr_buf_map *drv_bufs, u8 bufcnt, u8 is_rmc, -	u8 is_rmr, u8 num_datasges) +static int mpi3mr_bsg_build_sgl(struct mpi3mr_ioc *mrioc, u8 *mpi_req, +				u32 sgl_offset, struct mpi3mr_buf_map *drv_bufs, +				u8 bufcnt, u8 is_rmc, u8 is_rmr, u8 num_datasges)  { +	struct mpi3_request_header *mpi_header = +		(struct mpi3_request_header *)mpi_req;  	u8 *sgl = (mpi_req + sgl_offset), count = 0;  	struct mpi3_mgmt_passthrough_request *rmgmt_req =  	    (struct mpi3_mgmt_passthrough_request *)mpi_req;  	struct mpi3mr_buf_map *drv_buf_iter = drv_bufs; -	u8 sgl_flags, sgl_flags_last; +	u8 flag, sgl_flags, sgl_flag_eob, sgl_flags_last, last_chain_sgl_flag; +	u16 available_sges, i, sges_needed; +	u32 sge_element_size = sizeof(struct mpi3_sge_common); +	bool chain_used = false;  	sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | -		MPI3_SGE_FLAGS_DLAS_SYSTEM | MPI3_SGE_FLAGS_END_OF_BUFFER; -	sgl_flags_last = sgl_flags | MPI3_SGE_FLAGS_END_OF_LIST; +		MPI3_SGE_FLAGS_DLAS_SYSTEM; +	sgl_flag_eob = sgl_flags | MPI3_SGE_FLAGS_END_OF_BUFFER; +	sgl_flags_last = sgl_flag_eob | MPI3_SGE_FLAGS_END_OF_LIST; +	last_chain_sgl_flag = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN | +	    MPI3_SGE_FLAGS_DLAS_SYSTEM; + +	sges_needed = mpi3mr_total_num_ioctl_sges(drv_bufs, bufcnt);  	if (is_rmc) {  		mpi3mr_add_sg_single(&rmgmt_req->command_sgl,  		    sgl_flags_last, drv_buf_iter->kern_buf_len,  		    drv_buf_iter->kern_buf_dma); -		sgl = (u8 *)drv_buf_iter->kern_buf + drv_buf_iter->bsg_buf_len; +		sgl = (u8 *)drv_buf_iter->kern_buf + +			drv_buf_iter->bsg_buf_len; +		available_sges = (drv_buf_iter->kern_buf_len - +		    drv_buf_iter->bsg_buf_len) / sge_element_size; + +		if (sges_needed > available_sges) +			return -1; + +		chain_used = true;  		drv_buf_iter++;  		count++;  		if (is_rmr) { @@ -592,23 +655,95 @@ static void mpi3mr_bsg_build_sgl(u8 *mpi_req, uint32_t sgl_offset,  		} else  			mpi3mr_build_zero_len_sge(  			    &rmgmt_req->response_sgl); +		if (num_datasges) { +			i = 0; +			goto build_sges; +		} +	} else { +		if (sgl_offset >= MPI3MR_ADMIN_REQ_FRAME_SZ) +			return -1; +		available_sges = (MPI3MR_ADMIN_REQ_FRAME_SZ - sgl_offset) / +		sge_element_size; +		if (!available_sges) +			return -1;  	}  	if (!num_datasges) {  		mpi3mr_build_zero_len_sge(sgl); -		return; +		return 0;  	} +	if (mpi_header->function == MPI3_BSG_FUNCTION_SMP_PASSTHROUGH) { +		if ((sges_needed > 2) || (sges_needed > available_sges)) +			return -1; +		for (; count < bufcnt; count++, drv_buf_iter++) { +			if (drv_buf_iter->data_dir == DMA_NONE || +			    !drv_buf_iter->num_dma_desc) +				continue; +			mpi3mr_add_sg_single(sgl, sgl_flags_last, +					     drv_buf_iter->dma_desc[0].size, +					     drv_buf_iter->dma_desc[0].dma_addr); +			sgl += sge_element_size; +		} +		return 0; +	} +	i = 0; + +build_sges:  	for (; count < bufcnt; count++, drv_buf_iter++) {  		if (drv_buf_iter->data_dir == DMA_NONE)  			continue; -		if (num_datasges == 1 || !is_rmc) -			mpi3mr_add_sg_single(sgl, sgl_flags_last, -			    drv_buf_iter->kern_buf_len, drv_buf_iter->kern_buf_dma); -		else -			mpi3mr_add_sg_single(sgl, sgl_flags, -			    drv_buf_iter->kern_buf_len, drv_buf_iter->kern_buf_dma); -		sgl += sizeof(struct mpi3_sge_common); +		if (!drv_buf_iter->num_dma_desc) { +			if (chain_used && !available_sges) +				return -1; +			if (!chain_used && (available_sges == 1) && +			    (sges_needed > 1)) +				goto setup_chain; +			flag = sgl_flag_eob; +			if (num_datasges == 1) +				flag = sgl_flags_last; +			mpi3mr_add_sg_single(sgl, flag, 0, 0); +			sgl += sge_element_size; +			sges_needed--; +			available_sges--; +			num_datasges--; +			continue; +		} +		for (; i < drv_buf_iter->num_dma_desc; i++) { +			if (chain_used && !available_sges) +				return -1; +			if (!chain_used && (available_sges == 1) && +			    (sges_needed > 1)) +				goto setup_chain; +			flag = sgl_flags; +			if (i == (drv_buf_iter->num_dma_desc - 1)) { +				if (num_datasges == 1) +					flag = sgl_flags_last; +				else +					flag = sgl_flag_eob; +			} + +			mpi3mr_add_sg_single(sgl, flag, +					     drv_buf_iter->dma_desc[i].size, +					     drv_buf_iter->dma_desc[i].dma_addr); +			sgl += sge_element_size; +			available_sges--; +			sges_needed--; +		}  		num_datasges--; +		i = 0;  	} +	return 0; + +setup_chain: +	available_sges = mrioc->ioctl_chain_sge.size / sge_element_size; +	if (sges_needed > available_sges) +		return -1; +	mpi3mr_add_sg_single(sgl, last_chain_sgl_flag, +			     (sges_needed * sge_element_size), +			     mrioc->ioctl_chain_sge.dma_addr); +	memset(mrioc->ioctl_chain_sge.addr, 0, mrioc->ioctl_chain_sge.size); +	sgl = (u8 *)mrioc->ioctl_chain_sge.addr; +	chain_used = true; +	goto build_sges;  }  /** @@ -648,14 +783,20 @@ static int mpi3mr_build_nvme_sgl(struct mpi3mr_ioc *mrioc,  	struct mpi3mr_buf_map *drv_bufs, u8 bufcnt)  {  	struct mpi3mr_nvme_pt_sge *nvme_sgl; -	u64 sgl_ptr; +	__le64 sgl_dma;  	u8 count;  	size_t length = 0; +	u16 available_sges = 0, i; +	u32 sge_element_size = sizeof(struct mpi3mr_nvme_pt_sge);  	struct mpi3mr_buf_map *drv_buf_iter = drv_bufs;  	u64 sgemod_mask = ((u64)((mrioc->facts.sge_mod_mask) <<  			    mrioc->facts.sge_mod_shift) << 32);  	u64 sgemod_val = ((u64)(mrioc->facts.sge_mod_value) <<  			  mrioc->facts.sge_mod_shift) << 32; +	u32 size; + +	nvme_sgl = (struct mpi3mr_nvme_pt_sge *) +	    ((u8 *)(nvme_encap_request->command) + MPI3MR_NVME_CMD_SGL_OFFSET);  	/*  	 * Not all commands require a data transfer. If no data, just return @@ -664,27 +805,59 @@ static int mpi3mr_build_nvme_sgl(struct mpi3mr_ioc *mrioc,  	for (count = 0; count < bufcnt; count++, drv_buf_iter++) {  		if (drv_buf_iter->data_dir == DMA_NONE)  			continue; -		sgl_ptr = (u64)drv_buf_iter->kern_buf_dma;  		length = drv_buf_iter->kern_buf_len;  		break;  	} -	if (!length) +	if (!length || !drv_buf_iter->num_dma_desc)  		return 0; -	if (sgl_ptr & sgemod_mask) { +	if (drv_buf_iter->num_dma_desc == 1) { +		available_sges = 1; +		goto build_sges; +	} + +	sgl_dma = cpu_to_le64(mrioc->ioctl_chain_sge.dma_addr); +	if (sgl_dma & sgemod_mask) {  		dprint_bsg_err(mrioc, -		    "%s: SGL address collides with SGE modifier\n", +		    "%s: SGL chain address collides with SGE modifier\n",  		    __func__);  		return -1;  	} -	sgl_ptr &= ~sgemod_mask; -	sgl_ptr |= sgemod_val; -	nvme_sgl = (struct mpi3mr_nvme_pt_sge *) -	    ((u8 *)(nvme_encap_request->command) + MPI3MR_NVME_CMD_SGL_OFFSET); +	sgl_dma &= ~sgemod_mask; +	sgl_dma |= sgemod_val; + +	memset(mrioc->ioctl_chain_sge.addr, 0, mrioc->ioctl_chain_sge.size); +	available_sges = mrioc->ioctl_chain_sge.size / sge_element_size; +	if (available_sges < drv_buf_iter->num_dma_desc) +		return -1;  	memset(nvme_sgl, 0, sizeof(struct mpi3mr_nvme_pt_sge)); -	nvme_sgl->base_addr = sgl_ptr; -	nvme_sgl->length = length; +	nvme_sgl->base_addr = sgl_dma; +	size = drv_buf_iter->num_dma_desc * sizeof(struct mpi3mr_nvme_pt_sge); +	nvme_sgl->length = cpu_to_le32(size); +	nvme_sgl->type = MPI3MR_NVMESGL_LAST_SEGMENT; +	nvme_sgl = (struct mpi3mr_nvme_pt_sge *)mrioc->ioctl_chain_sge.addr; + +build_sges: +	for (i = 0; i < drv_buf_iter->num_dma_desc; i++) { +		sgl_dma = cpu_to_le64(drv_buf_iter->dma_desc[i].dma_addr); +		if (sgl_dma & sgemod_mask) { +			dprint_bsg_err(mrioc, +				       "%s: SGL address collides with SGE modifier\n", +				       __func__); +		return -1; +		} + +		sgl_dma &= ~sgemod_mask; +		sgl_dma |= sgemod_val; + +		nvme_sgl->base_addr = sgl_dma; +		nvme_sgl->length = cpu_to_le32(drv_buf_iter->dma_desc[i].size); +		nvme_sgl->type = MPI3MR_NVMESGL_DATA_SEGMENT; +		nvme_sgl++; +		available_sges--; +	} +  	return 0;  } @@ -712,7 +885,7 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc,  	dma_addr_t prp_entry_dma, prp_page_dma, dma_addr;  	u32 offset, entry_len, dev_pgsz;  	u32 page_mask_result, page_mask; -	size_t length = 0; +	size_t length = 0, desc_len;  	u8 count;  	struct mpi3mr_buf_map *drv_buf_iter = drv_bufs;  	u64 sgemod_mask = ((u64)((mrioc->facts.sge_mod_mask) << @@ -721,6 +894,7 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc,  			  mrioc->facts.sge_mod_shift) << 32;  	u16 dev_handle = nvme_encap_request->dev_handle;  	struct mpi3mr_tgt_dev *tgtdev; +	u16 desc_count = 0;  	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);  	if (!tgtdev) { @@ -739,6 +913,21 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc,  	dev_pgsz = 1 << (tgtdev->dev_spec.pcie_inf.pgsz);  	mpi3mr_tgtdev_put(tgtdev); +	page_mask = dev_pgsz - 1; + +	if (dev_pgsz > MPI3MR_IOCTL_SGE_SIZE) { +		dprint_bsg_err(mrioc, +			       "%s: NVMe device page size(%d) is greater than ioctl data sge size(%d) for handle 0x%04x\n", +			       __func__, dev_pgsz,  MPI3MR_IOCTL_SGE_SIZE, dev_handle); +		return -1; +	} + +	if (MPI3MR_IOCTL_SGE_SIZE % dev_pgsz) { +		dprint_bsg_err(mrioc, +			       "%s: ioctl data sge size(%d) is not a multiple of NVMe device page size(%d) for handle 0x%04x\n", +			       __func__, MPI3MR_IOCTL_SGE_SIZE, dev_pgsz, dev_handle); +		return -1; +	}  	/*  	 * Not all commands require a data transfer. If no data, just return @@ -747,14 +936,26 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc,  	for (count = 0; count < bufcnt; count++, drv_buf_iter++) {  		if (drv_buf_iter->data_dir == DMA_NONE)  			continue; -		dma_addr = drv_buf_iter->kern_buf_dma;  		length = drv_buf_iter->kern_buf_len;  		break;  	} -	if (!length) +	if (!length || !drv_buf_iter->num_dma_desc)  		return 0; +	for (count = 0; count < drv_buf_iter->num_dma_desc; count++) { +		dma_addr = drv_buf_iter->dma_desc[count].dma_addr; +		if (dma_addr & page_mask) { +			dprint_bsg_err(mrioc, +				       "%s:dma_addr %pad is not aligned with page size 0x%x\n", +				       __func__,  &dma_addr, dev_pgsz); +			return -1; +		} +	} + +	dma_addr = drv_buf_iter->dma_desc[0].dma_addr; +	desc_len = drv_buf_iter->dma_desc[0].size; +  	mrioc->prp_sz = 0;  	mrioc->prp_list_virt = dma_alloc_coherent(&mrioc->pdev->dev,  	    dev_pgsz, &mrioc->prp_list_dma, GFP_KERNEL); @@ -784,7 +985,6 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc,  	 * Check if we are within 1 entry of a page boundary we don't  	 * want our first entry to be a PRP List entry.  	 */ -	page_mask = dev_pgsz - 1;  	page_mask_result = (uintptr_t)((u8 *)prp_page + prp_size) & page_mask;  	if (!page_mask_result) {  		dprint_bsg_err(mrioc, "%s: PRP page is not page aligned\n", @@ -898,18 +1098,31 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc,  			prp_entry_dma += prp_size;  		} -		/* -		 * Bump the phys address of the command's data buffer by the -		 * entry_len. -		 */ -		dma_addr += entry_len; -  		/* decrement length accounting for last partial page. */ -		if (entry_len > length) +		if (entry_len >= length) {  			length = 0; -		else +		} else { +			if (entry_len <= desc_len) { +				dma_addr += entry_len; +				desc_len -= entry_len; +			} +			if (!desc_len) { +				if ((++desc_count) >= +				   drv_buf_iter->num_dma_desc) { +					dprint_bsg_err(mrioc, +						       "%s: Invalid len %zd while building PRP\n", +						       __func__, length); +					goto err_out; +				} +				dma_addr = +				    drv_buf_iter->dma_desc[desc_count].dma_addr; +				desc_len = +				    drv_buf_iter->dma_desc[desc_count].size; +			}  			length -= entry_len; +		}  	} +  	return 0;  err_out:  	if (mrioc->prp_list_virt) { @@ -919,10 +1132,66 @@ err_out:  	}  	return -1;  } + +/** + * mpi3mr_map_data_buffer_dma - build dma descriptors for data + *                              buffers + * @mrioc: Adapter instance reference + * @drv_buf: buffer map descriptor + * @desc_count: Number of already consumed dma descriptors + * + * This function computes how many pre-allocated DMA descriptors + * are required for the given data buffer and if those number of + * descriptors are free, then setup the mapping of the scattered + * DMA address to the given data buffer, if the data direction + * of the buffer is DMA_TO_DEVICE then the actual data is copied to + * the DMA buffers + * + * Return: 0 on success, -1 on failure + */ +static int mpi3mr_map_data_buffer_dma(struct mpi3mr_ioc *mrioc, +				      struct mpi3mr_buf_map *drv_buf, +				      u16 desc_count) +{ +	u16 i, needed_desc = drv_buf->kern_buf_len / MPI3MR_IOCTL_SGE_SIZE; +	u32 buf_len = drv_buf->kern_buf_len, copied_len = 0; + +	if (drv_buf->kern_buf_len % MPI3MR_IOCTL_SGE_SIZE) +		needed_desc++; +	if ((needed_desc + desc_count) > MPI3MR_NUM_IOCTL_SGE) { +		dprint_bsg_err(mrioc, "%s: DMA descriptor mapping error %d:%d:%d\n", +			       __func__, needed_desc, desc_count, MPI3MR_NUM_IOCTL_SGE); +		return -1; +	} +	drv_buf->dma_desc = kzalloc(sizeof(*drv_buf->dma_desc) * needed_desc, +				    GFP_KERNEL); +	if (!drv_buf->dma_desc) +		return -1; +	for (i = 0; i < needed_desc; i++, desc_count++) { +		drv_buf->dma_desc[i].addr = mrioc->ioctl_sge[desc_count].addr; +		drv_buf->dma_desc[i].dma_addr = +		    mrioc->ioctl_sge[desc_count].dma_addr; +		if (buf_len < mrioc->ioctl_sge[desc_count].size) +			drv_buf->dma_desc[i].size = buf_len; +		else +			drv_buf->dma_desc[i].size = +			    mrioc->ioctl_sge[desc_count].size; +		buf_len -= drv_buf->dma_desc[i].size; +		memset(drv_buf->dma_desc[i].addr, 0, +		       mrioc->ioctl_sge[desc_count].size); +		if (drv_buf->data_dir == DMA_TO_DEVICE) { +			memcpy(drv_buf->dma_desc[i].addr, +			       drv_buf->bsg_buf + copied_len, +			       drv_buf->dma_desc[i].size); +			copied_len += drv_buf->dma_desc[i].size; +		} +	} +	drv_buf->num_dma_desc = needed_desc; +	return 0; +}  /**   * mpi3mr_bsg_process_mpt_cmds - MPI Pass through BSG handler   * @job: BSG job reference - * @reply_payload_rcv_len: length of payload recvd   *   * This function is the top level handler for MPI Pass through   * command, this does basic validation of the input data buffers, @@ -938,10 +1207,9 @@ err_out:   * Return: 0 on success and proper error codes on failure   */ -static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply_payload_rcv_len) +static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)  {  	long rval = -EINVAL; -  	struct mpi3mr_ioc *mrioc = NULL;  	u8 *mpi_req = NULL, *sense_buff_k = NULL;  	u8 mpi_msg_size = 0; @@ -949,9 +1217,10 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  	struct mpi3mr_bsg_mptcmd *karg;  	struct mpi3mr_buf_entry *buf_entries = NULL;  	struct mpi3mr_buf_map *drv_bufs = NULL, *drv_buf_iter = NULL; -	u8 count, bufcnt = 0, is_rmcb = 0, is_rmrb = 0, din_cnt = 0, dout_cnt = 0; -	u8 invalid_be = 0, erb_offset = 0xFF, mpirep_offset = 0xFF, sg_entries = 0; -	u8 block_io = 0, resp_code = 0, nvme_fmt = 0; +	u8 count, bufcnt = 0, is_rmcb = 0, is_rmrb = 0; +	u8 din_cnt = 0, dout_cnt = 0; +	u8 invalid_be = 0, erb_offset = 0xFF, mpirep_offset = 0xFF; +	u8 block_io = 0, nvme_fmt = 0, resp_code = 0;  	struct mpi3_request_header *mpi_header = NULL;  	struct mpi3_status_reply_descriptor *status_desc;  	struct mpi3_scsi_task_mgmt_request *tm_req; @@ -963,6 +1232,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  	u32 din_size = 0, dout_size = 0;  	u8 *din_buf = NULL, *dout_buf = NULL;  	u8 *sgl_iter = NULL, *sgl_din_iter = NULL, *sgl_dout_iter = NULL; +	u16 rmc_size  = 0, desc_count = 0;  	bsg_req = job->request;  	karg = (struct mpi3mr_bsg_mptcmd *)&bsg_req->cmd.mptcmd; @@ -971,6 +1241,12 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  	if (!mrioc)  		return -ENODEV; +	if (!mrioc->ioctl_sges_allocated) { +		dprint_bsg_err(mrioc, "%s: DMA memory was not allocated\n", +			       __func__); +		return -ENOMEM; +	} +  	if (karg->timeout < MPI3MR_APP_DEFAULT_TIMEOUT)  		karg->timeout = MPI3MR_APP_DEFAULT_TIMEOUT; @@ -1011,26 +1287,13 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  	for (count = 0; count < bufcnt; count++, buf_entries++, drv_buf_iter++) { -		if (sgl_dout_iter > (dout_buf + job->request_payload.payload_len)) { -			dprint_bsg_err(mrioc, "%s: data_out buffer length mismatch\n", -				__func__); -			rval = -EINVAL; -			goto out; -		} -		if (sgl_din_iter > (din_buf + job->reply_payload.payload_len)) { -			dprint_bsg_err(mrioc, "%s: data_in buffer length mismatch\n", -				__func__); -			rval = -EINVAL; -			goto out; -		} -  		switch (buf_entries->buf_type) {  		case MPI3MR_BSG_BUFTYPE_RAIDMGMT_CMD:  			sgl_iter = sgl_dout_iter;  			sgl_dout_iter += buf_entries->buf_len;  			drv_buf_iter->data_dir = DMA_TO_DEVICE;  			is_rmcb = 1; -			if (count != 0) +			if ((count != 0) || !buf_entries->buf_len)  				invalid_be = 1;  			break;  		case MPI3MR_BSG_BUFTYPE_RAIDMGMT_RESP: @@ -1038,7 +1301,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  			sgl_din_iter += buf_entries->buf_len;  			drv_buf_iter->data_dir = DMA_FROM_DEVICE;  			is_rmrb = 1; -			if (count != 1 || !is_rmcb) +			if (count != 1 || !is_rmcb || !buf_entries->buf_len)  				invalid_be = 1;  			break;  		case MPI3MR_BSG_BUFTYPE_DATA_IN: @@ -1046,7 +1309,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  			sgl_din_iter += buf_entries->buf_len;  			drv_buf_iter->data_dir = DMA_FROM_DEVICE;  			din_cnt++; -			din_size += drv_buf_iter->bsg_buf_len; +			din_size += buf_entries->buf_len;  			if ((din_cnt > 1) && !is_rmcb)  				invalid_be = 1;  			break; @@ -1055,7 +1318,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  			sgl_dout_iter += buf_entries->buf_len;  			drv_buf_iter->data_dir = DMA_TO_DEVICE;  			dout_cnt++; -			dout_size += drv_buf_iter->bsg_buf_len; +			dout_size += buf_entries->buf_len;  			if ((dout_cnt > 1) && !is_rmcb)  				invalid_be = 1;  			break; @@ -1064,12 +1327,16 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  			sgl_din_iter += buf_entries->buf_len;  			drv_buf_iter->data_dir = DMA_NONE;  			mpirep_offset = count; +			if (!buf_entries->buf_len) +				invalid_be = 1;  			break;  		case MPI3MR_BSG_BUFTYPE_ERR_RESPONSE:  			sgl_iter = sgl_din_iter;  			sgl_din_iter += buf_entries->buf_len;  			drv_buf_iter->data_dir = DMA_NONE;  			erb_offset = count; +			if (!buf_entries->buf_len) +				invalid_be = 1;  			break;  		case MPI3MR_BSG_BUFTYPE_MPI_REQUEST:  			sgl_iter = sgl_dout_iter; @@ -1096,21 +1363,31 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  			goto out;  		} -		drv_buf_iter->bsg_buf = sgl_iter; -		drv_buf_iter->bsg_buf_len = buf_entries->buf_len; - -	} -	if (!is_rmcb && (dout_cnt || din_cnt)) { -		sg_entries = dout_cnt + din_cnt; -		if (((mpi_msg_size) + (sg_entries * -		      sizeof(struct mpi3_sge_common))) > MPI3MR_ADMIN_REQ_FRAME_SZ) { -			dprint_bsg_err(mrioc, -			    "%s:%d: invalid message size passed\n", -			    __func__, __LINE__); +		if (sgl_dout_iter > (dout_buf + job->request_payload.payload_len)) { +			dprint_bsg_err(mrioc, "%s: data_out buffer length mismatch\n", +				       __func__);  			rval = -EINVAL;  			goto out;  		} +		if (sgl_din_iter > (din_buf + job->reply_payload.payload_len)) { +			dprint_bsg_err(mrioc, "%s: data_in buffer length mismatch\n", +				       __func__); +			rval = -EINVAL; +			goto out; +		} + +		drv_buf_iter->bsg_buf = sgl_iter; +		drv_buf_iter->bsg_buf_len = buf_entries->buf_len;  	} + +	if (is_rmcb && ((din_size + dout_size) > MPI3MR_MAX_APP_XFER_SIZE)) { +		dprint_bsg_err(mrioc, "%s:%d: invalid data transfer size passed for function 0x%x din_size = %d, dout_size = %d\n", +			       __func__, __LINE__, mpi_header->function, din_size, +			       dout_size); +		rval = -EINVAL; +		goto out; +	} +  	if (din_size > MPI3MR_MAX_APP_XFER_SIZE) {  		dprint_bsg_err(mrioc,  		    "%s:%d: invalid data transfer size passed for function 0x%x din_size=%d\n", @@ -1126,30 +1403,64 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  		goto out;  	} +	if (mpi_header->function == MPI3_BSG_FUNCTION_SMP_PASSTHROUGH) { +		if (din_size > MPI3MR_IOCTL_SGE_SIZE || +		    dout_size > MPI3MR_IOCTL_SGE_SIZE) { +			dprint_bsg_err(mrioc, "%s:%d: invalid message size passed:%d:%d:%d:%d\n", +				       __func__, __LINE__, din_cnt, dout_cnt, din_size, +			    dout_size); +			rval = -EINVAL; +			goto out; +		} +	} +  	drv_buf_iter = drv_bufs;  	for (count = 0; count < bufcnt; count++, drv_buf_iter++) {  		if (drv_buf_iter->data_dir == DMA_NONE)  			continue;  		drv_buf_iter->kern_buf_len = drv_buf_iter->bsg_buf_len; -		if (is_rmcb && !count) -			drv_buf_iter->kern_buf_len += ((dout_cnt + din_cnt) * -			    sizeof(struct mpi3_sge_common)); - -		if (!drv_buf_iter->kern_buf_len) -			continue; - -		drv_buf_iter->kern_buf = dma_alloc_coherent(&mrioc->pdev->dev, -		    drv_buf_iter->kern_buf_len, &drv_buf_iter->kern_buf_dma, -		    GFP_KERNEL); -		if (!drv_buf_iter->kern_buf) { -			rval = -ENOMEM; -			goto out; -		} -		if (drv_buf_iter->data_dir == DMA_TO_DEVICE) { +		if (is_rmcb && !count) { +			drv_buf_iter->kern_buf_len = +			    mrioc->ioctl_chain_sge.size; +			drv_buf_iter->kern_buf = +			    mrioc->ioctl_chain_sge.addr; +			drv_buf_iter->kern_buf_dma = +			    mrioc->ioctl_chain_sge.dma_addr; +			drv_buf_iter->dma_desc = NULL; +			drv_buf_iter->num_dma_desc = 0; +			memset(drv_buf_iter->kern_buf, 0, +			       drv_buf_iter->kern_buf_len);  			tmplen = min(drv_buf_iter->kern_buf_len, -			    drv_buf_iter->bsg_buf_len); +				     drv_buf_iter->bsg_buf_len); +			rmc_size = tmplen;  			memcpy(drv_buf_iter->kern_buf, drv_buf_iter->bsg_buf, tmplen); +		} else if (is_rmrb && (count == 1)) { +			drv_buf_iter->kern_buf_len = +			    mrioc->ioctl_resp_sge.size; +			drv_buf_iter->kern_buf = +			    mrioc->ioctl_resp_sge.addr; +			drv_buf_iter->kern_buf_dma = +			    mrioc->ioctl_resp_sge.dma_addr; +			drv_buf_iter->dma_desc = NULL; +			drv_buf_iter->num_dma_desc = 0; +			memset(drv_buf_iter->kern_buf, 0, +			       drv_buf_iter->kern_buf_len); +			tmplen = min(drv_buf_iter->kern_buf_len, +				     drv_buf_iter->bsg_buf_len); +			drv_buf_iter->kern_buf_len = tmplen; +			memset(drv_buf_iter->bsg_buf, 0, +			       drv_buf_iter->bsg_buf_len); +		} else { +			if (!drv_buf_iter->kern_buf_len) +				continue; +			if (mpi3mr_map_data_buffer_dma(mrioc, drv_buf_iter, desc_count)) { +				rval = -ENOMEM; +				dprint_bsg_err(mrioc, "%s:%d: mapping data buffers failed\n", +					       __func__, __LINE__); +			goto out; +		} +			desc_count += drv_buf_iter->num_dma_desc;  		}  	} @@ -1219,9 +1530,14 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  			goto out;  		}  	} else { -		mpi3mr_bsg_build_sgl(mpi_req, (mpi_msg_size), -		    drv_bufs, bufcnt, is_rmcb, is_rmrb, -		    (dout_cnt + din_cnt)); +		if (mpi3mr_bsg_build_sgl(mrioc, mpi_req, mpi_msg_size, +					 drv_bufs, bufcnt, is_rmcb, is_rmrb, +					 (dout_cnt + din_cnt))) { +			dprint_bsg_err(mrioc, "%s: sgl build failed\n", __func__); +			rval = -EAGAIN; +			mutex_unlock(&mrioc->bsg_cmds.mutex); +			goto out; +		}  	}  	if (mpi_header->function == MPI3_BSG_FUNCTION_SCSI_TASK_MGMT) { @@ -1257,7 +1573,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  		if (mpi_header->function == MPI3_BSG_FUNCTION_MGMT_PASSTHROUGH) {  			drv_buf_iter = &drv_bufs[0];  			dprint_dump(drv_buf_iter->kern_buf, -			    drv_buf_iter->kern_buf_len, "mpi3_mgmt_req"); +			    rmc_size, "mpi3_mgmt_req");  		}  	} @@ -1292,10 +1608,9 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  			    MPI3_BSG_FUNCTION_MGMT_PASSTHROUGH) {  				drv_buf_iter = &drv_bufs[0];  				dprint_dump(drv_buf_iter->kern_buf, -				    drv_buf_iter->kern_buf_len, "mpi3_mgmt_req"); +				    rmc_size, "mpi3_mgmt_req");  			}  		} -  		if ((mpi_header->function == MPI3_BSG_FUNCTION_NVME_ENCAPSULATED) ||  		    (mpi_header->function == MPI3_BSG_FUNCTION_SCSI_IO))  			mpi3mr_issue_tm(mrioc, @@ -1366,17 +1681,27 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply  	for (count = 0; count < bufcnt; count++, drv_buf_iter++) {  		if (drv_buf_iter->data_dir == DMA_NONE)  			continue; -		if (drv_buf_iter->data_dir == DMA_FROM_DEVICE) { -			tmplen = min(drv_buf_iter->kern_buf_len, -				     drv_buf_iter->bsg_buf_len); +		if ((count == 1) && is_rmrb) {  			memcpy(drv_buf_iter->bsg_buf, -			       drv_buf_iter->kern_buf, tmplen); +			    drv_buf_iter->kern_buf, +			    drv_buf_iter->kern_buf_len); +		} else if (drv_buf_iter->data_dir == DMA_FROM_DEVICE) { +			tmplen = 0; +			for (desc_count = 0; +			    desc_count < drv_buf_iter->num_dma_desc; +			    desc_count++) { +				memcpy(((u8 *)drv_buf_iter->bsg_buf + tmplen), +				       drv_buf_iter->dma_desc[desc_count].addr, +				       drv_buf_iter->dma_desc[desc_count].size); +				tmplen += +				    drv_buf_iter->dma_desc[desc_count].size;  		}  	} +	}  out_unlock:  	if (din_buf) { -		*reply_payload_rcv_len = +		job->reply_payload_rcv_len =  			sg_copy_from_buffer(job->reply_payload.sg_list,  					    job->reply_payload.sg_cnt,  					    din_buf, job->reply_payload.payload_len); @@ -1392,13 +1717,8 @@ out:  	kfree(mpi_req);  	if (drv_bufs) {  		drv_buf_iter = drv_bufs; -		for (count = 0; count < bufcnt; count++, drv_buf_iter++) { -			if (drv_buf_iter->kern_buf && drv_buf_iter->kern_buf_dma) -				dma_free_coherent(&mrioc->pdev->dev, -				    drv_buf_iter->kern_buf_len, -				    drv_buf_iter->kern_buf, -				    drv_buf_iter->kern_buf_dma); -		} +		for (count = 0; count < bufcnt; count++, drv_buf_iter++) +			kfree(drv_buf_iter->dma_desc);  		kfree(drv_bufs);  	}  	kfree(bsg_reply_buf); @@ -1457,7 +1777,7 @@ static int mpi3mr_bsg_request(struct bsg_job *job)  		rval = mpi3mr_bsg_process_drv_cmds(job);  		break;  	case MPI3MR_MPT_CMD: -		rval = mpi3mr_bsg_process_mpt_cmds(job, &reply_payload_rcv_len); +		rval = mpi3mr_bsg_process_mpt_cmds(job);  		break;  	default:  		pr_err("%s: unsupported BSG command(0x%08x)\n",  |