static void mptsas_smp_handler()

in fusion/mptsas.c [2240:2371]


static void mptsas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
		struct sas_rphy *rphy)
{
	MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
	MPT_FRAME_HDR *mf;
	SmpPassthroughRequest_t *smpreq;
	int flagsLength;
	unsigned long timeleft;
	char *psge;
	u64 sas_address = 0;
	unsigned int reslen = 0;
	int ret = -EINVAL;

	/* do we need to support multiple segments? */
	if (job->request_payload.sg_cnt > 1 ||
	    job->reply_payload.sg_cnt > 1) {
		printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u, rsp %u\n",
		    ioc->name, __func__, job->request_payload.payload_len,
		    job->reply_payload.payload_len);
		goto out;
	}

	ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
	if (ret)
		goto out;

	mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
	if (!mf) {
		ret = -ENOMEM;
		goto out_unlock;
	}

	smpreq = (SmpPassthroughRequest_t *)mf;
	memset(smpreq, 0, sizeof(*smpreq));

	smpreq->RequestDataLength =
		cpu_to_le16(job->request_payload.payload_len - 4);
	smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;

	if (rphy)
		sas_address = rphy->identify.sas_address;
	else {
		struct mptsas_portinfo *port_info;

		mutex_lock(&ioc->sas_topology_mutex);
		port_info = ioc->hba_port_info;
		if (port_info && port_info->phy_info)
			sas_address =
				port_info->phy_info[0].phy->identify.sas_address;
		mutex_unlock(&ioc->sas_topology_mutex);
	}

	*((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);

	psge = (char *)
		(((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));

	/* request */
	flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
		       MPI_SGE_FLAGS_END_OF_BUFFER |
		       MPI_SGE_FLAGS_DIRECTION)
		       << MPI_SGE_FLAGS_SHIFT;

	if (!dma_map_sg(&ioc->pcidev->dev, job->request_payload.sg_list,
			1, PCI_DMA_BIDIRECTIONAL))
		goto put_mf;

	flagsLength |= (sg_dma_len(job->request_payload.sg_list) - 4);
	ioc->add_sge(psge, flagsLength,
			sg_dma_address(job->request_payload.sg_list));
	psge += ioc->SGE_size;

	/* response */
	flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
		MPI_SGE_FLAGS_SYSTEM_ADDRESS |
		MPI_SGE_FLAGS_IOC_TO_HOST |
		MPI_SGE_FLAGS_END_OF_BUFFER;

	flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;

	if (!dma_map_sg(&ioc->pcidev->dev, job->reply_payload.sg_list,
			1, PCI_DMA_BIDIRECTIONAL))
		goto unmap_out;
	flagsLength |= sg_dma_len(job->reply_payload.sg_list) + 4;
	ioc->add_sge(psge, flagsLength,
			sg_dma_address(job->reply_payload.sg_list));

	INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
	mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);

	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
	if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
		ret = -ETIME;
		mpt_free_msg_frame(ioc, mf);
		mf = NULL;
		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
			goto unmap_in;
		if (!timeleft)
			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
		goto unmap_in;
	}
	mf = NULL;

	if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
		SmpPassthroughReply_t *smprep;

		smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
		memcpy(job->reply, smprep, sizeof(*smprep));
		job->reply_len = sizeof(*smprep);
		reslen = smprep->ResponseDataLength;
	} else {
		printk(MYIOC_s_ERR_FMT
		    "%s: smp passthru reply failed to be returned\n",
		    ioc->name, __func__);
		ret = -ENXIO;
	}

unmap_in:
	dma_unmap_sg(&ioc->pcidev->dev, job->reply_payload.sg_list, 1,
			PCI_DMA_BIDIRECTIONAL);
unmap_out:
	dma_unmap_sg(&ioc->pcidev->dev, job->request_payload.sg_list, 1,
			PCI_DMA_BIDIRECTIONAL);
put_mf:
	if (mf)
		mpt_free_msg_frame(ioc, mf);
out_unlock:
	CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
	mutex_unlock(&ioc->sas_mgmt.mutex);
out:
	bsg_job_done(job, ret, reslen);
}