162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver
462306a36Sopenharmony_ci * Copyright (c)  2003-2014 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "qla_def.h"
762306a36Sopenharmony_ci#include "qla_target.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/blkdev.h>
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic int qla_start_scsi_type6(srb_t *sp);
1562306a36Sopenharmony_ci/**
1662306a36Sopenharmony_ci * qla2x00_get_cmd_direction() - Determine control_flag data direction.
1762306a36Sopenharmony_ci * @sp: SCSI command
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * Returns the proper CF_* direction based on CDB.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_cistatic inline uint16_t
2262306a36Sopenharmony_ciqla2x00_get_cmd_direction(srb_t *sp)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	uint16_t cflags;
2562306a36Sopenharmony_ci	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
2662306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	cflags = 0;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	/* Set transfer direction */
3162306a36Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
3262306a36Sopenharmony_ci		cflags = CF_WRITE;
3362306a36Sopenharmony_ci		vha->qla_stats.output_bytes += scsi_bufflen(cmd);
3462306a36Sopenharmony_ci		vha->qla_stats.output_requests++;
3562306a36Sopenharmony_ci	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
3662306a36Sopenharmony_ci		cflags = CF_READ;
3762306a36Sopenharmony_ci		vha->qla_stats.input_bytes += scsi_bufflen(cmd);
3862306a36Sopenharmony_ci		vha->qla_stats.input_requests++;
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci	return (cflags);
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/**
4462306a36Sopenharmony_ci * qla2x00_calc_iocbs_32() - Determine number of Command Type 2 and
4562306a36Sopenharmony_ci * Continuation Type 0 IOCBs to allocate.
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * @dsds: number of data segment descriptors needed
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci * Returns the number of IOCB entries needed to store @dsds.
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ciuint16_t
5262306a36Sopenharmony_ciqla2x00_calc_iocbs_32(uint16_t dsds)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	uint16_t iocbs;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	iocbs = 1;
5762306a36Sopenharmony_ci	if (dsds > 3) {
5862306a36Sopenharmony_ci		iocbs += (dsds - 3) / 7;
5962306a36Sopenharmony_ci		if ((dsds - 3) % 7)
6062306a36Sopenharmony_ci			iocbs++;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci	return (iocbs);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/**
6662306a36Sopenharmony_ci * qla2x00_calc_iocbs_64() - Determine number of Command Type 3 and
6762306a36Sopenharmony_ci * Continuation Type 1 IOCBs to allocate.
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * @dsds: number of data segment descriptors needed
7062306a36Sopenharmony_ci *
7162306a36Sopenharmony_ci * Returns the number of IOCB entries needed to store @dsds.
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_ciuint16_t
7462306a36Sopenharmony_ciqla2x00_calc_iocbs_64(uint16_t dsds)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	uint16_t iocbs;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	iocbs = 1;
7962306a36Sopenharmony_ci	if (dsds > 2) {
8062306a36Sopenharmony_ci		iocbs += (dsds - 2) / 5;
8162306a36Sopenharmony_ci		if ((dsds - 2) % 5)
8262306a36Sopenharmony_ci			iocbs++;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci	return (iocbs);
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/**
8862306a36Sopenharmony_ci * qla2x00_prep_cont_type0_iocb() - Initialize a Continuation Type 0 IOCB.
8962306a36Sopenharmony_ci * @vha: HA context
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci * Returns a pointer to the Continuation Type 0 IOCB packet.
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_cistatic inline cont_entry_t *
9462306a36Sopenharmony_ciqla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	cont_entry_t *cont_pkt;
9762306a36Sopenharmony_ci	struct req_que *req = vha->req;
9862306a36Sopenharmony_ci	/* Adjust ring index. */
9962306a36Sopenharmony_ci	req->ring_index++;
10062306a36Sopenharmony_ci	if (req->ring_index == req->length) {
10162306a36Sopenharmony_ci		req->ring_index = 0;
10262306a36Sopenharmony_ci		req->ring_ptr = req->ring;
10362306a36Sopenharmony_ci	} else {
10462306a36Sopenharmony_ci		req->ring_ptr++;
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	cont_pkt = (cont_entry_t *)req->ring_ptr;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* Load packet defaults. */
11062306a36Sopenharmony_ci	put_unaligned_le32(CONTINUE_TYPE, &cont_pkt->entry_type);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return (cont_pkt);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/**
11662306a36Sopenharmony_ci * qla2x00_prep_cont_type1_iocb() - Initialize a Continuation Type 1 IOCB.
11762306a36Sopenharmony_ci * @vha: HA context
11862306a36Sopenharmony_ci * @req: request queue
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci * Returns a pointer to the continuation type 1 IOCB packet.
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_cicont_a64_entry_t *
12362306a36Sopenharmony_ciqla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	cont_a64_entry_t *cont_pkt;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* Adjust ring index. */
12862306a36Sopenharmony_ci	req->ring_index++;
12962306a36Sopenharmony_ci	if (req->ring_index == req->length) {
13062306a36Sopenharmony_ci		req->ring_index = 0;
13162306a36Sopenharmony_ci		req->ring_ptr = req->ring;
13262306a36Sopenharmony_ci	} else {
13362306a36Sopenharmony_ci		req->ring_ptr++;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* Load packet defaults. */
13962306a36Sopenharmony_ci	put_unaligned_le32(IS_QLAFX00(vha->hw) ? CONTINUE_A64_TYPE_FX00 :
14062306a36Sopenharmony_ci			   CONTINUE_A64_TYPE, &cont_pkt->entry_type);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	return (cont_pkt);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ciinline int
14662306a36Sopenharmony_ciqla24xx_configure_prot_mode(srb_t *sp, uint16_t *fw_prot_opts)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* We always use DIFF Bundling for best performance */
15162306a36Sopenharmony_ci	*fw_prot_opts = 0;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/* Translate SCSI opcode to a protection opcode */
15462306a36Sopenharmony_ci	switch (scsi_get_prot_op(cmd)) {
15562306a36Sopenharmony_ci	case SCSI_PROT_READ_STRIP:
15662306a36Sopenharmony_ci		*fw_prot_opts |= PO_MODE_DIF_REMOVE;
15762306a36Sopenharmony_ci		break;
15862306a36Sopenharmony_ci	case SCSI_PROT_WRITE_INSERT:
15962306a36Sopenharmony_ci		*fw_prot_opts |= PO_MODE_DIF_INSERT;
16062306a36Sopenharmony_ci		break;
16162306a36Sopenharmony_ci	case SCSI_PROT_READ_INSERT:
16262306a36Sopenharmony_ci		*fw_prot_opts |= PO_MODE_DIF_INSERT;
16362306a36Sopenharmony_ci		break;
16462306a36Sopenharmony_ci	case SCSI_PROT_WRITE_STRIP:
16562306a36Sopenharmony_ci		*fw_prot_opts |= PO_MODE_DIF_REMOVE;
16662306a36Sopenharmony_ci		break;
16762306a36Sopenharmony_ci	case SCSI_PROT_READ_PASS:
16862306a36Sopenharmony_ci	case SCSI_PROT_WRITE_PASS:
16962306a36Sopenharmony_ci		if (cmd->prot_flags & SCSI_PROT_IP_CHECKSUM)
17062306a36Sopenharmony_ci			*fw_prot_opts |= PO_MODE_DIF_TCP_CKSUM;
17162306a36Sopenharmony_ci		else
17262306a36Sopenharmony_ci			*fw_prot_opts |= PO_MODE_DIF_PASS;
17362306a36Sopenharmony_ci		break;
17462306a36Sopenharmony_ci	default:	/* Normal Request */
17562306a36Sopenharmony_ci		*fw_prot_opts |= PO_MODE_DIF_PASS;
17662306a36Sopenharmony_ci		break;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (!(cmd->prot_flags & SCSI_PROT_GUARD_CHECK))
18062306a36Sopenharmony_ci		*fw_prot_opts |= PO_DISABLE_GUARD_CHECK;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	return scsi_prot_sg_count(cmd);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/*
18662306a36Sopenharmony_ci * qla2x00_build_scsi_iocbs_32() - Build IOCB command utilizing 32bit
18762306a36Sopenharmony_ci * capable IOCB types.
18862306a36Sopenharmony_ci *
18962306a36Sopenharmony_ci * @sp: SRB command to process
19062306a36Sopenharmony_ci * @cmd_pkt: Command type 2 IOCB
19162306a36Sopenharmony_ci * @tot_dsds: Total number of segments to transfer
19262306a36Sopenharmony_ci */
19362306a36Sopenharmony_civoid qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
19462306a36Sopenharmony_ci    uint16_t tot_dsds)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	uint16_t	avail_dsds;
19762306a36Sopenharmony_ci	struct dsd32	*cur_dsd;
19862306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
19962306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
20062306a36Sopenharmony_ci	struct scatterlist *sg;
20162306a36Sopenharmony_ci	int i;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	cmd = GET_CMD_SP(sp);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	/* Update entry type to indicate Command Type 2 IOCB */
20662306a36Sopenharmony_ci	put_unaligned_le32(COMMAND_TYPE, &cmd_pkt->entry_type);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* No data transfer */
20962306a36Sopenharmony_ci	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
21062306a36Sopenharmony_ci		cmd_pkt->byte_count = cpu_to_le32(0);
21162306a36Sopenharmony_ci		return;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	vha = sp->vha;
21562306a36Sopenharmony_ci	cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	/* Three DSDs are available in the Command Type 2 IOCB */
21862306a36Sopenharmony_ci	avail_dsds = ARRAY_SIZE(cmd_pkt->dsd32);
21962306a36Sopenharmony_ci	cur_dsd = cmd_pkt->dsd32;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* Load data segments */
22262306a36Sopenharmony_ci	scsi_for_each_sg(cmd, sg, tot_dsds, i) {
22362306a36Sopenharmony_ci		cont_entry_t *cont_pkt;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		/* Allocate additional continuation packets? */
22662306a36Sopenharmony_ci		if (avail_dsds == 0) {
22762306a36Sopenharmony_ci			/*
22862306a36Sopenharmony_ci			 * Seven DSDs are available in the Continuation
22962306a36Sopenharmony_ci			 * Type 0 IOCB.
23062306a36Sopenharmony_ci			 */
23162306a36Sopenharmony_ci			cont_pkt = qla2x00_prep_cont_type0_iocb(vha);
23262306a36Sopenharmony_ci			cur_dsd = cont_pkt->dsd;
23362306a36Sopenharmony_ci			avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
23462306a36Sopenharmony_ci		}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci		append_dsd32(&cur_dsd, sg);
23762306a36Sopenharmony_ci		avail_dsds--;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/**
24262306a36Sopenharmony_ci * qla2x00_build_scsi_iocbs_64() - Build IOCB command utilizing 64bit
24362306a36Sopenharmony_ci * capable IOCB types.
24462306a36Sopenharmony_ci *
24562306a36Sopenharmony_ci * @sp: SRB command to process
24662306a36Sopenharmony_ci * @cmd_pkt: Command type 3 IOCB
24762306a36Sopenharmony_ci * @tot_dsds: Total number of segments to transfer
24862306a36Sopenharmony_ci */
24962306a36Sopenharmony_civoid qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
25062306a36Sopenharmony_ci    uint16_t tot_dsds)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	uint16_t	avail_dsds;
25362306a36Sopenharmony_ci	struct dsd64	*cur_dsd;
25462306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
25562306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
25662306a36Sopenharmony_ci	struct scatterlist *sg;
25762306a36Sopenharmony_ci	int i;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	cmd = GET_CMD_SP(sp);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	/* Update entry type to indicate Command Type 3 IOCB */
26262306a36Sopenharmony_ci	put_unaligned_le32(COMMAND_A64_TYPE, &cmd_pkt->entry_type);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	/* No data transfer */
26562306a36Sopenharmony_ci	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
26662306a36Sopenharmony_ci		cmd_pkt->byte_count = cpu_to_le32(0);
26762306a36Sopenharmony_ci		return;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	vha = sp->vha;
27162306a36Sopenharmony_ci	cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* Two DSDs are available in the Command Type 3 IOCB */
27462306a36Sopenharmony_ci	avail_dsds = ARRAY_SIZE(cmd_pkt->dsd64);
27562306a36Sopenharmony_ci	cur_dsd = cmd_pkt->dsd64;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/* Load data segments */
27862306a36Sopenharmony_ci	scsi_for_each_sg(cmd, sg, tot_dsds, i) {
27962306a36Sopenharmony_ci		cont_a64_entry_t *cont_pkt;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		/* Allocate additional continuation packets? */
28262306a36Sopenharmony_ci		if (avail_dsds == 0) {
28362306a36Sopenharmony_ci			/*
28462306a36Sopenharmony_ci			 * Five DSDs are available in the Continuation
28562306a36Sopenharmony_ci			 * Type 1 IOCB.
28662306a36Sopenharmony_ci			 */
28762306a36Sopenharmony_ci			cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req);
28862306a36Sopenharmony_ci			cur_dsd = cont_pkt->dsd;
28962306a36Sopenharmony_ci			avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
29062306a36Sopenharmony_ci		}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		append_dsd64(&cur_dsd, sg);
29362306a36Sopenharmony_ci		avail_dsds--;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/*
29862306a36Sopenharmony_ci * Find the first handle that is not in use, starting from
29962306a36Sopenharmony_ci * req->current_outstanding_cmd + 1. The caller must hold the lock that is
30062306a36Sopenharmony_ci * associated with @req.
30162306a36Sopenharmony_ci */
30262306a36Sopenharmony_ciuint32_t qla2xxx_get_next_handle(struct req_que *req)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	uint32_t index, handle = req->current_outstanding_cmd;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	for (index = 1; index < req->num_outstanding_cmds; index++) {
30762306a36Sopenharmony_ci		handle++;
30862306a36Sopenharmony_ci		if (handle == req->num_outstanding_cmds)
30962306a36Sopenharmony_ci			handle = 1;
31062306a36Sopenharmony_ci		if (!req->outstanding_cmds[handle])
31162306a36Sopenharmony_ci			return handle;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return 0;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci/**
31862306a36Sopenharmony_ci * qla2x00_start_scsi() - Send a SCSI command to the ISP
31962306a36Sopenharmony_ci * @sp: command to send to the ISP
32062306a36Sopenharmony_ci *
32162306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero.
32262306a36Sopenharmony_ci */
32362306a36Sopenharmony_ciint
32462306a36Sopenharmony_ciqla2x00_start_scsi(srb_t *sp)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	int		nseg;
32762306a36Sopenharmony_ci	unsigned long   flags;
32862306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
32962306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
33062306a36Sopenharmony_ci	uint32_t	*clr_ptr;
33162306a36Sopenharmony_ci	uint32_t	handle;
33262306a36Sopenharmony_ci	cmd_entry_t	*cmd_pkt;
33362306a36Sopenharmony_ci	uint16_t	cnt;
33462306a36Sopenharmony_ci	uint16_t	req_cnt;
33562306a36Sopenharmony_ci	uint16_t	tot_dsds;
33662306a36Sopenharmony_ci	struct device_reg_2xxx __iomem *reg;
33762306a36Sopenharmony_ci	struct qla_hw_data *ha;
33862306a36Sopenharmony_ci	struct req_que *req;
33962306a36Sopenharmony_ci	struct rsp_que *rsp;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* Setup device pointers. */
34262306a36Sopenharmony_ci	vha = sp->vha;
34362306a36Sopenharmony_ci	ha = vha->hw;
34462306a36Sopenharmony_ci	reg = &ha->iobase->isp;
34562306a36Sopenharmony_ci	cmd = GET_CMD_SP(sp);
34662306a36Sopenharmony_ci	req = ha->req_q_map[0];
34762306a36Sopenharmony_ci	rsp = ha->rsp_q_map[0];
34862306a36Sopenharmony_ci	/* So we know we haven't pci_map'ed anything yet */
34962306a36Sopenharmony_ci	tot_dsds = 0;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Send marker if required */
35262306a36Sopenharmony_ci	if (vha->marker_needed != 0) {
35362306a36Sopenharmony_ci		if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) !=
35462306a36Sopenharmony_ci		    QLA_SUCCESS) {
35562306a36Sopenharmony_ci			return (QLA_FUNCTION_FAILED);
35662306a36Sopenharmony_ci		}
35762306a36Sopenharmony_ci		vha->marker_needed = 0;
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/* Acquire ring specific lock */
36162306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	handle = qla2xxx_get_next_handle(req);
36462306a36Sopenharmony_ci	if (handle == 0)
36562306a36Sopenharmony_ci		goto queuing_error;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* Map the sg table so we have an accurate count of sg entries needed */
36862306a36Sopenharmony_ci	if (scsi_sg_count(cmd)) {
36962306a36Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
37062306a36Sopenharmony_ci		    scsi_sg_count(cmd), cmd->sc_data_direction);
37162306a36Sopenharmony_ci		if (unlikely(!nseg))
37262306a36Sopenharmony_ci			goto queuing_error;
37362306a36Sopenharmony_ci	} else
37462306a36Sopenharmony_ci		nseg = 0;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	tot_dsds = nseg;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* Calculate the number of request entries needed. */
37962306a36Sopenharmony_ci	req_cnt = ha->isp_ops->calc_req_entries(tot_dsds);
38062306a36Sopenharmony_ci	if (req->cnt < (req_cnt + 2)) {
38162306a36Sopenharmony_ci		cnt = rd_reg_word_relaxed(ISP_REQ_Q_OUT(ha, reg));
38262306a36Sopenharmony_ci		if (req->ring_index < cnt)
38362306a36Sopenharmony_ci			req->cnt = cnt - req->ring_index;
38462306a36Sopenharmony_ci		else
38562306a36Sopenharmony_ci			req->cnt = req->length -
38662306a36Sopenharmony_ci			    (req->ring_index - cnt);
38762306a36Sopenharmony_ci		/* If still no head room then bail out */
38862306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2))
38962306a36Sopenharmony_ci			goto queuing_error;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/* Build command packet */
39362306a36Sopenharmony_ci	req->current_outstanding_cmd = handle;
39462306a36Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
39562306a36Sopenharmony_ci	sp->handle = handle;
39662306a36Sopenharmony_ci	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
39762306a36Sopenharmony_ci	req->cnt -= req_cnt;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	cmd_pkt = (cmd_entry_t *)req->ring_ptr;
40062306a36Sopenharmony_ci	cmd_pkt->handle = handle;
40162306a36Sopenharmony_ci	/* Zero out remaining portion of packet. */
40262306a36Sopenharmony_ci	clr_ptr = (uint32_t *)cmd_pkt + 2;
40362306a36Sopenharmony_ci	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
40462306a36Sopenharmony_ci	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* Set target ID and LUN number*/
40762306a36Sopenharmony_ci	SET_TARGET_ID(ha, cmd_pkt->target, sp->fcport->loop_id);
40862306a36Sopenharmony_ci	cmd_pkt->lun = cpu_to_le16(cmd->device->lun);
40962306a36Sopenharmony_ci	cmd_pkt->control_flags = cpu_to_le16(CF_SIMPLE_TAG);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* Load SCSI command packet. */
41262306a36Sopenharmony_ci	memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len);
41362306a36Sopenharmony_ci	cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* Build IOCB segments */
41662306a36Sopenharmony_ci	ha->isp_ops->build_iocbs(sp, cmd_pkt, tot_dsds);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* Set total data segment count. */
41962306a36Sopenharmony_ci	cmd_pkt->entry_count = (uint8_t)req_cnt;
42062306a36Sopenharmony_ci	wmb();
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/* Adjust ring index. */
42362306a36Sopenharmony_ci	req->ring_index++;
42462306a36Sopenharmony_ci	if (req->ring_index == req->length) {
42562306a36Sopenharmony_ci		req->ring_index = 0;
42662306a36Sopenharmony_ci		req->ring_ptr = req->ring;
42762306a36Sopenharmony_ci	} else
42862306a36Sopenharmony_ci		req->ring_ptr++;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	sp->flags |= SRB_DMA_VALID;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	/* Set chip new ring index. */
43362306a36Sopenharmony_ci	wrt_reg_word(ISP_REQ_Q_IN(ha, reg), req->ring_index);
43462306a36Sopenharmony_ci	rd_reg_word_relaxed(ISP_REQ_Q_IN(ha, reg));	/* PCI Posting. */
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	/* Manage unprocessed RIO/ZIO commands in response queue. */
43762306a36Sopenharmony_ci	if (vha->flags.process_response_queue &&
43862306a36Sopenharmony_ci	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
43962306a36Sopenharmony_ci		qla2x00_process_response_queue(rsp);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
44262306a36Sopenharmony_ci	return (QLA_SUCCESS);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ciqueuing_error:
44562306a36Sopenharmony_ci	if (tot_dsds)
44662306a36Sopenharmony_ci		scsi_dma_unmap(cmd);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	return (QLA_FUNCTION_FAILED);
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci/**
45462306a36Sopenharmony_ci * qla2x00_start_iocbs() - Execute the IOCB command
45562306a36Sopenharmony_ci * @vha: HA context
45662306a36Sopenharmony_ci * @req: request queue
45762306a36Sopenharmony_ci */
45862306a36Sopenharmony_civoid
45962306a36Sopenharmony_ciqla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
46262306a36Sopenharmony_ci	device_reg_t *reg = ISP_QUE_REG(ha, req->id);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (IS_P3P_TYPE(ha)) {
46562306a36Sopenharmony_ci		qla82xx_start_iocbs(vha);
46662306a36Sopenharmony_ci	} else {
46762306a36Sopenharmony_ci		/* Adjust ring index. */
46862306a36Sopenharmony_ci		req->ring_index++;
46962306a36Sopenharmony_ci		if (req->ring_index == req->length) {
47062306a36Sopenharmony_ci			req->ring_index = 0;
47162306a36Sopenharmony_ci			req->ring_ptr = req->ring;
47262306a36Sopenharmony_ci		} else
47362306a36Sopenharmony_ci			req->ring_ptr++;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		/* Set chip new ring index. */
47662306a36Sopenharmony_ci		if (ha->mqenable || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
47762306a36Sopenharmony_ci			wrt_reg_dword(req->req_q_in, req->ring_index);
47862306a36Sopenharmony_ci		} else if (IS_QLA83XX(ha)) {
47962306a36Sopenharmony_ci			wrt_reg_dword(req->req_q_in, req->ring_index);
48062306a36Sopenharmony_ci			rd_reg_dword_relaxed(&ha->iobase->isp24.hccr);
48162306a36Sopenharmony_ci		} else if (IS_QLAFX00(ha)) {
48262306a36Sopenharmony_ci			wrt_reg_dword(&reg->ispfx00.req_q_in, req->ring_index);
48362306a36Sopenharmony_ci			rd_reg_dword_relaxed(&reg->ispfx00.req_q_in);
48462306a36Sopenharmony_ci			QLAFX00_SET_HST_INTR(ha, ha->rqstq_intr_code);
48562306a36Sopenharmony_ci		} else if (IS_FWI2_CAPABLE(ha)) {
48662306a36Sopenharmony_ci			wrt_reg_dword(&reg->isp24.req_q_in, req->ring_index);
48762306a36Sopenharmony_ci			rd_reg_dword_relaxed(&reg->isp24.req_q_in);
48862306a36Sopenharmony_ci		} else {
48962306a36Sopenharmony_ci			wrt_reg_word(ISP_REQ_Q_IN(ha, &reg->isp),
49062306a36Sopenharmony_ci				req->ring_index);
49162306a36Sopenharmony_ci			rd_reg_word_relaxed(ISP_REQ_Q_IN(ha, &reg->isp));
49262306a36Sopenharmony_ci		}
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci/**
49762306a36Sopenharmony_ci * __qla2x00_marker() - Send a marker IOCB to the firmware.
49862306a36Sopenharmony_ci * @vha: HA context
49962306a36Sopenharmony_ci * @qpair: queue pair pointer
50062306a36Sopenharmony_ci * @loop_id: loop ID
50162306a36Sopenharmony_ci * @lun: LUN
50262306a36Sopenharmony_ci * @type: marker modifier
50362306a36Sopenharmony_ci *
50462306a36Sopenharmony_ci * Can be called from both normal and interrupt context.
50562306a36Sopenharmony_ci *
50662306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero.
50762306a36Sopenharmony_ci */
50862306a36Sopenharmony_cistatic int
50962306a36Sopenharmony_ci__qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair,
51062306a36Sopenharmony_ci    uint16_t loop_id, uint64_t lun, uint8_t type)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	mrk_entry_t *mrk;
51362306a36Sopenharmony_ci	struct mrk_entry_24xx *mrk24 = NULL;
51462306a36Sopenharmony_ci	struct req_que *req = qpair->req;
51562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
51662306a36Sopenharmony_ci	scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	mrk = (mrk_entry_t *)__qla2x00_alloc_iocbs(qpair, NULL);
51962306a36Sopenharmony_ci	if (mrk == NULL) {
52062306a36Sopenharmony_ci		ql_log(ql_log_warn, base_vha, 0x3026,
52162306a36Sopenharmony_ci		    "Failed to allocate Marker IOCB.\n");
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		return (QLA_FUNCTION_FAILED);
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	mrk24 = (struct mrk_entry_24xx *)mrk;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	mrk->entry_type = MARKER_TYPE;
52962306a36Sopenharmony_ci	mrk->modifier = type;
53062306a36Sopenharmony_ci	if (type != MK_SYNC_ALL) {
53162306a36Sopenharmony_ci		if (IS_FWI2_CAPABLE(ha)) {
53262306a36Sopenharmony_ci			mrk24->nport_handle = cpu_to_le16(loop_id);
53362306a36Sopenharmony_ci			int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun);
53462306a36Sopenharmony_ci			host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
53562306a36Sopenharmony_ci			mrk24->vp_index = vha->vp_idx;
53662306a36Sopenharmony_ci		} else {
53762306a36Sopenharmony_ci			SET_TARGET_ID(ha, mrk->target, loop_id);
53862306a36Sopenharmony_ci			mrk->lun = cpu_to_le16((uint16_t)lun);
53962306a36Sopenharmony_ci		}
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha))
54362306a36Sopenharmony_ci		mrk24->handle = QLA_SKIP_HANDLE;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	wmb();
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	qla2x00_start_iocbs(vha, req);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	return (QLA_SUCCESS);
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ciint
55362306a36Sopenharmony_ciqla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair,
55462306a36Sopenharmony_ci    uint16_t loop_id, uint64_t lun, uint8_t type)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	int ret;
55762306a36Sopenharmony_ci	unsigned long flags = 0;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	spin_lock_irqsave(qpair->qp_lock_ptr, flags);
56062306a36Sopenharmony_ci	ret = __qla2x00_marker(vha, qpair, loop_id, lun, type);
56162306a36Sopenharmony_ci	spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return (ret);
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci/*
56762306a36Sopenharmony_ci * qla2x00_issue_marker
56862306a36Sopenharmony_ci *
56962306a36Sopenharmony_ci * Issue marker
57062306a36Sopenharmony_ci * Caller CAN have hardware lock held as specified by ha_locked parameter.
57162306a36Sopenharmony_ci * Might release it, then reaquire.
57262306a36Sopenharmony_ci */
57362306a36Sopenharmony_ciint qla2x00_issue_marker(scsi_qla_host_t *vha, int ha_locked)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	if (ha_locked) {
57662306a36Sopenharmony_ci		if (__qla2x00_marker(vha, vha->hw->base_qpair, 0, 0,
57762306a36Sopenharmony_ci					MK_SYNC_ALL) != QLA_SUCCESS)
57862306a36Sopenharmony_ci			return QLA_FUNCTION_FAILED;
57962306a36Sopenharmony_ci	} else {
58062306a36Sopenharmony_ci		if (qla2x00_marker(vha, vha->hw->base_qpair, 0, 0,
58162306a36Sopenharmony_ci					MK_SYNC_ALL) != QLA_SUCCESS)
58262306a36Sopenharmony_ci			return QLA_FUNCTION_FAILED;
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci	vha->marker_needed = 0;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	return QLA_SUCCESS;
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_cistatic inline int
59062306a36Sopenharmony_ciqla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
59162306a36Sopenharmony_ci	uint16_t tot_dsds)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	struct dsd64 *cur_dsd = NULL, *next_dsd;
59462306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
59562306a36Sopenharmony_ci	struct	scatterlist *cur_seg;
59662306a36Sopenharmony_ci	uint8_t avail_dsds;
59762306a36Sopenharmony_ci	uint8_t first_iocb = 1;
59862306a36Sopenharmony_ci	uint32_t dsd_list_len;
59962306a36Sopenharmony_ci	struct dsd_dma *dsd_ptr;
60062306a36Sopenharmony_ci	struct ct6_dsd *ctx;
60162306a36Sopenharmony_ci	struct qla_qpair *qpair = sp->qpair;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	cmd = GET_CMD_SP(sp);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* Update entry type to indicate Command Type 3 IOCB */
60662306a36Sopenharmony_ci	put_unaligned_le32(COMMAND_TYPE_6, &cmd_pkt->entry_type);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/* No data transfer */
60962306a36Sopenharmony_ci	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE ||
61062306a36Sopenharmony_ci	    tot_dsds == 0) {
61162306a36Sopenharmony_ci		cmd_pkt->byte_count = cpu_to_le32(0);
61262306a36Sopenharmony_ci		return 0;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	/* Set transfer direction */
61662306a36Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
61762306a36Sopenharmony_ci		cmd_pkt->control_flags = cpu_to_le16(CF_WRITE_DATA);
61862306a36Sopenharmony_ci		qpair->counters.output_bytes += scsi_bufflen(cmd);
61962306a36Sopenharmony_ci		qpair->counters.output_requests++;
62062306a36Sopenharmony_ci	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
62162306a36Sopenharmony_ci		cmd_pkt->control_flags = cpu_to_le16(CF_READ_DATA);
62262306a36Sopenharmony_ci		qpair->counters.input_bytes += scsi_bufflen(cmd);
62362306a36Sopenharmony_ci		qpair->counters.input_requests++;
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	cur_seg = scsi_sglist(cmd);
62762306a36Sopenharmony_ci	ctx = &sp->u.scmd.ct6_ctx;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	while (tot_dsds) {
63062306a36Sopenharmony_ci		avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ?
63162306a36Sopenharmony_ci		    QLA_DSDS_PER_IOCB : tot_dsds;
63262306a36Sopenharmony_ci		tot_dsds -= avail_dsds;
63362306a36Sopenharmony_ci		dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		dsd_ptr = list_first_entry(&qpair->dsd_list, struct dsd_dma, list);
63662306a36Sopenharmony_ci		next_dsd = dsd_ptr->dsd_addr;
63762306a36Sopenharmony_ci		list_del(&dsd_ptr->list);
63862306a36Sopenharmony_ci		qpair->dsd_avail--;
63962306a36Sopenharmony_ci		list_add_tail(&dsd_ptr->list, &ctx->dsd_list);
64062306a36Sopenharmony_ci		ctx->dsd_use_cnt++;
64162306a36Sopenharmony_ci		qpair->dsd_inuse++;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci		if (first_iocb) {
64462306a36Sopenharmony_ci			first_iocb = 0;
64562306a36Sopenharmony_ci			put_unaligned_le64(dsd_ptr->dsd_list_dma,
64662306a36Sopenharmony_ci					   &cmd_pkt->fcp_dsd.address);
64762306a36Sopenharmony_ci			cmd_pkt->fcp_dsd.length = cpu_to_le32(dsd_list_len);
64862306a36Sopenharmony_ci		} else {
64962306a36Sopenharmony_ci			put_unaligned_le64(dsd_ptr->dsd_list_dma,
65062306a36Sopenharmony_ci					   &cur_dsd->address);
65162306a36Sopenharmony_ci			cur_dsd->length = cpu_to_le32(dsd_list_len);
65262306a36Sopenharmony_ci			cur_dsd++;
65362306a36Sopenharmony_ci		}
65462306a36Sopenharmony_ci		cur_dsd = next_dsd;
65562306a36Sopenharmony_ci		while (avail_dsds) {
65662306a36Sopenharmony_ci			append_dsd64(&cur_dsd, cur_seg);
65762306a36Sopenharmony_ci			cur_seg = sg_next(cur_seg);
65862306a36Sopenharmony_ci			avail_dsds--;
65962306a36Sopenharmony_ci		}
66062306a36Sopenharmony_ci	}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	/* Null termination */
66362306a36Sopenharmony_ci	cur_dsd->address = 0;
66462306a36Sopenharmony_ci	cur_dsd->length = 0;
66562306a36Sopenharmony_ci	cur_dsd++;
66662306a36Sopenharmony_ci	cmd_pkt->control_flags |= cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE);
66762306a36Sopenharmony_ci	return 0;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci/*
67162306a36Sopenharmony_ci * qla24xx_calc_dsd_lists() - Determine number of DSD list required
67262306a36Sopenharmony_ci * for Command Type 6.
67362306a36Sopenharmony_ci *
67462306a36Sopenharmony_ci * @dsds: number of data segment descriptors needed
67562306a36Sopenharmony_ci *
67662306a36Sopenharmony_ci * Returns the number of dsd list needed to store @dsds.
67762306a36Sopenharmony_ci */
67862306a36Sopenharmony_cistatic inline uint16_t
67962306a36Sopenharmony_ciqla24xx_calc_dsd_lists(uint16_t dsds)
68062306a36Sopenharmony_ci{
68162306a36Sopenharmony_ci	uint16_t dsd_lists = 0;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	dsd_lists = (dsds/QLA_DSDS_PER_IOCB);
68462306a36Sopenharmony_ci	if (dsds % QLA_DSDS_PER_IOCB)
68562306a36Sopenharmony_ci		dsd_lists++;
68662306a36Sopenharmony_ci	return dsd_lists;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci/**
69162306a36Sopenharmony_ci * qla24xx_build_scsi_iocbs() - Build IOCB command utilizing Command Type 7
69262306a36Sopenharmony_ci * IOCB types.
69362306a36Sopenharmony_ci *
69462306a36Sopenharmony_ci * @sp: SRB command to process
69562306a36Sopenharmony_ci * @cmd_pkt: Command type 3 IOCB
69662306a36Sopenharmony_ci * @tot_dsds: Total number of segments to transfer
69762306a36Sopenharmony_ci * @req: pointer to request queue
69862306a36Sopenharmony_ci */
69962306a36Sopenharmony_ciinline void
70062306a36Sopenharmony_ciqla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
70162306a36Sopenharmony_ci	uint16_t tot_dsds, struct req_que *req)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	uint16_t	avail_dsds;
70462306a36Sopenharmony_ci	struct dsd64	*cur_dsd;
70562306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
70662306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
70762306a36Sopenharmony_ci	struct scatterlist *sg;
70862306a36Sopenharmony_ci	int i;
70962306a36Sopenharmony_ci	struct qla_qpair *qpair = sp->qpair;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	cmd = GET_CMD_SP(sp);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	/* Update entry type to indicate Command Type 3 IOCB */
71462306a36Sopenharmony_ci	put_unaligned_le32(COMMAND_TYPE_7, &cmd_pkt->entry_type);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	/* No data transfer */
71762306a36Sopenharmony_ci	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
71862306a36Sopenharmony_ci		cmd_pkt->byte_count = cpu_to_le32(0);
71962306a36Sopenharmony_ci		return;
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	vha = sp->vha;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* Set transfer direction */
72562306a36Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
72662306a36Sopenharmony_ci		cmd_pkt->task_mgmt_flags = cpu_to_le16(TMF_WRITE_DATA);
72762306a36Sopenharmony_ci		qpair->counters.output_bytes += scsi_bufflen(cmd);
72862306a36Sopenharmony_ci		qpair->counters.output_requests++;
72962306a36Sopenharmony_ci	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
73062306a36Sopenharmony_ci		cmd_pkt->task_mgmt_flags = cpu_to_le16(TMF_READ_DATA);
73162306a36Sopenharmony_ci		qpair->counters.input_bytes += scsi_bufflen(cmd);
73262306a36Sopenharmony_ci		qpair->counters.input_requests++;
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/* One DSD is available in the Command Type 3 IOCB */
73662306a36Sopenharmony_ci	avail_dsds = 1;
73762306a36Sopenharmony_ci	cur_dsd = &cmd_pkt->dsd;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	/* Load data segments */
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	scsi_for_each_sg(cmd, sg, tot_dsds, i) {
74262306a36Sopenharmony_ci		cont_a64_entry_t *cont_pkt;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci		/* Allocate additional continuation packets? */
74562306a36Sopenharmony_ci		if (avail_dsds == 0) {
74662306a36Sopenharmony_ci			/*
74762306a36Sopenharmony_ci			 * Five DSDs are available in the Continuation
74862306a36Sopenharmony_ci			 * Type 1 IOCB.
74962306a36Sopenharmony_ci			 */
75062306a36Sopenharmony_ci			cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req);
75162306a36Sopenharmony_ci			cur_dsd = cont_pkt->dsd;
75262306a36Sopenharmony_ci			avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
75362306a36Sopenharmony_ci		}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci		append_dsd64(&cur_dsd, sg);
75662306a36Sopenharmony_ci		avail_dsds--;
75762306a36Sopenharmony_ci	}
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistruct fw_dif_context {
76162306a36Sopenharmony_ci	__le32	ref_tag;
76262306a36Sopenharmony_ci	__le16	app_tag;
76362306a36Sopenharmony_ci	uint8_t ref_tag_mask[4];	/* Validation/Replacement Mask*/
76462306a36Sopenharmony_ci	uint8_t app_tag_mask[2];	/* Validation/Replacement Mask*/
76562306a36Sopenharmony_ci};
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci/*
76862306a36Sopenharmony_ci * qla24xx_set_t10dif_tags_from_cmd - Extract Ref and App tags from SCSI command
76962306a36Sopenharmony_ci *
77062306a36Sopenharmony_ci */
77162306a36Sopenharmony_cistatic inline void
77262306a36Sopenharmony_ciqla24xx_set_t10dif_tags(srb_t *sp, struct fw_dif_context *pkt,
77362306a36Sopenharmony_ci    unsigned int protcnt)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	pkt->ref_tag = cpu_to_le32(scsi_prot_ref_tag(cmd));
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (cmd->prot_flags & SCSI_PROT_REF_CHECK &&
78062306a36Sopenharmony_ci	    qla2x00_hba_err_chk_enabled(sp)) {
78162306a36Sopenharmony_ci		pkt->ref_tag_mask[0] = 0xff;
78262306a36Sopenharmony_ci		pkt->ref_tag_mask[1] = 0xff;
78362306a36Sopenharmony_ci		pkt->ref_tag_mask[2] = 0xff;
78462306a36Sopenharmony_ci		pkt->ref_tag_mask[3] = 0xff;
78562306a36Sopenharmony_ci	}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	pkt->app_tag = cpu_to_le16(0);
78862306a36Sopenharmony_ci	pkt->app_tag_mask[0] = 0x0;
78962306a36Sopenharmony_ci	pkt->app_tag_mask[1] = 0x0;
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ciint
79362306a36Sopenharmony_ciqla24xx_get_one_block_sg(uint32_t blk_sz, struct qla2_sgx *sgx,
79462306a36Sopenharmony_ci	uint32_t *partial)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	struct scatterlist *sg;
79762306a36Sopenharmony_ci	uint32_t cumulative_partial, sg_len;
79862306a36Sopenharmony_ci	dma_addr_t sg_dma_addr;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	if (sgx->num_bytes == sgx->tot_bytes)
80162306a36Sopenharmony_ci		return 0;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	sg = sgx->cur_sg;
80462306a36Sopenharmony_ci	cumulative_partial = sgx->tot_partial;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	sg_dma_addr = sg_dma_address(sg);
80762306a36Sopenharmony_ci	sg_len = sg_dma_len(sg);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	sgx->dma_addr = sg_dma_addr + sgx->bytes_consumed;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	if ((cumulative_partial + (sg_len - sgx->bytes_consumed)) >= blk_sz) {
81262306a36Sopenharmony_ci		sgx->dma_len = (blk_sz - cumulative_partial);
81362306a36Sopenharmony_ci		sgx->tot_partial = 0;
81462306a36Sopenharmony_ci		sgx->num_bytes += blk_sz;
81562306a36Sopenharmony_ci		*partial = 0;
81662306a36Sopenharmony_ci	} else {
81762306a36Sopenharmony_ci		sgx->dma_len = sg_len - sgx->bytes_consumed;
81862306a36Sopenharmony_ci		sgx->tot_partial += sgx->dma_len;
81962306a36Sopenharmony_ci		*partial = 1;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	sgx->bytes_consumed += sgx->dma_len;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	if (sg_len == sgx->bytes_consumed) {
82562306a36Sopenharmony_ci		sg = sg_next(sg);
82662306a36Sopenharmony_ci		sgx->num_sg++;
82762306a36Sopenharmony_ci		sgx->cur_sg = sg;
82862306a36Sopenharmony_ci		sgx->bytes_consumed = 0;
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	return 1;
83262306a36Sopenharmony_ci}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ciint
83562306a36Sopenharmony_ciqla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp,
83662306a36Sopenharmony_ci	struct dsd64 *dsd, uint16_t tot_dsds, struct qla_tc_param *tc)
83762306a36Sopenharmony_ci{
83862306a36Sopenharmony_ci	void *next_dsd;
83962306a36Sopenharmony_ci	uint8_t avail_dsds = 0;
84062306a36Sopenharmony_ci	uint32_t dsd_list_len;
84162306a36Sopenharmony_ci	struct dsd_dma *dsd_ptr;
84262306a36Sopenharmony_ci	struct scatterlist *sg_prot;
84362306a36Sopenharmony_ci	struct dsd64 *cur_dsd = dsd;
84462306a36Sopenharmony_ci	uint16_t	used_dsds = tot_dsds;
84562306a36Sopenharmony_ci	uint32_t	prot_int; /* protection interval */
84662306a36Sopenharmony_ci	uint32_t	partial;
84762306a36Sopenharmony_ci	struct qla2_sgx sgx;
84862306a36Sopenharmony_ci	dma_addr_t	sle_dma;
84962306a36Sopenharmony_ci	uint32_t	sle_dma_len, tot_prot_dma_len = 0;
85062306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	memset(&sgx, 0, sizeof(struct qla2_sgx));
85362306a36Sopenharmony_ci	if (sp) {
85462306a36Sopenharmony_ci		cmd = GET_CMD_SP(sp);
85562306a36Sopenharmony_ci		prot_int = scsi_prot_interval(cmd);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci		sgx.tot_bytes = scsi_bufflen(cmd);
85862306a36Sopenharmony_ci		sgx.cur_sg = scsi_sglist(cmd);
85962306a36Sopenharmony_ci		sgx.sp = sp;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci		sg_prot = scsi_prot_sglist(cmd);
86262306a36Sopenharmony_ci	} else if (tc) {
86362306a36Sopenharmony_ci		prot_int      = tc->blk_sz;
86462306a36Sopenharmony_ci		sgx.tot_bytes = tc->bufflen;
86562306a36Sopenharmony_ci		sgx.cur_sg    = tc->sg;
86662306a36Sopenharmony_ci		sg_prot	      = tc->prot_sg;
86762306a36Sopenharmony_ci	} else {
86862306a36Sopenharmony_ci		BUG();
86962306a36Sopenharmony_ci		return 1;
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	while (qla24xx_get_one_block_sg(prot_int, &sgx, &partial)) {
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci		sle_dma = sgx.dma_addr;
87562306a36Sopenharmony_ci		sle_dma_len = sgx.dma_len;
87662306a36Sopenharmony_cialloc_and_fill:
87762306a36Sopenharmony_ci		/* Allocate additional continuation packets? */
87862306a36Sopenharmony_ci		if (avail_dsds == 0) {
87962306a36Sopenharmony_ci			avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ?
88062306a36Sopenharmony_ci					QLA_DSDS_PER_IOCB : used_dsds;
88162306a36Sopenharmony_ci			dsd_list_len = (avail_dsds + 1) * 12;
88262306a36Sopenharmony_ci			used_dsds -= avail_dsds;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci			/* allocate tracking DS */
88562306a36Sopenharmony_ci			dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
88662306a36Sopenharmony_ci			if (!dsd_ptr)
88762306a36Sopenharmony_ci				return 1;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci			/* allocate new list */
89062306a36Sopenharmony_ci			dsd_ptr->dsd_addr = next_dsd =
89162306a36Sopenharmony_ci			    dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC,
89262306a36Sopenharmony_ci				&dsd_ptr->dsd_list_dma);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci			if (!next_dsd) {
89562306a36Sopenharmony_ci				/*
89662306a36Sopenharmony_ci				 * Need to cleanup only this dsd_ptr, rest
89762306a36Sopenharmony_ci				 * will be done by sp_free_dma()
89862306a36Sopenharmony_ci				 */
89962306a36Sopenharmony_ci				kfree(dsd_ptr);
90062306a36Sopenharmony_ci				return 1;
90162306a36Sopenharmony_ci			}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci			if (sp) {
90462306a36Sopenharmony_ci				list_add_tail(&dsd_ptr->list,
90562306a36Sopenharmony_ci					      &sp->u.scmd.crc_ctx->dsd_list);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci				sp->flags |= SRB_CRC_CTX_DSD_VALID;
90862306a36Sopenharmony_ci			} else {
90962306a36Sopenharmony_ci				list_add_tail(&dsd_ptr->list,
91062306a36Sopenharmony_ci				    &(tc->ctx->dsd_list));
91162306a36Sopenharmony_ci				*tc->ctx_dsd_alloced = 1;
91262306a36Sopenharmony_ci			}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci			/* add new list to cmd iocb or last list */
91662306a36Sopenharmony_ci			put_unaligned_le64(dsd_ptr->dsd_list_dma,
91762306a36Sopenharmony_ci					   &cur_dsd->address);
91862306a36Sopenharmony_ci			cur_dsd->length = cpu_to_le32(dsd_list_len);
91962306a36Sopenharmony_ci			cur_dsd = next_dsd;
92062306a36Sopenharmony_ci		}
92162306a36Sopenharmony_ci		put_unaligned_le64(sle_dma, &cur_dsd->address);
92262306a36Sopenharmony_ci		cur_dsd->length = cpu_to_le32(sle_dma_len);
92362306a36Sopenharmony_ci		cur_dsd++;
92462306a36Sopenharmony_ci		avail_dsds--;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci		if (partial == 0) {
92762306a36Sopenharmony_ci			/* Got a full protection interval */
92862306a36Sopenharmony_ci			sle_dma = sg_dma_address(sg_prot) + tot_prot_dma_len;
92962306a36Sopenharmony_ci			sle_dma_len = 8;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci			tot_prot_dma_len += sle_dma_len;
93262306a36Sopenharmony_ci			if (tot_prot_dma_len == sg_dma_len(sg_prot)) {
93362306a36Sopenharmony_ci				tot_prot_dma_len = 0;
93462306a36Sopenharmony_ci				sg_prot = sg_next(sg_prot);
93562306a36Sopenharmony_ci			}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci			partial = 1; /* So as to not re-enter this block */
93862306a36Sopenharmony_ci			goto alloc_and_fill;
93962306a36Sopenharmony_ci		}
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci	/* Null termination */
94262306a36Sopenharmony_ci	cur_dsd->address = 0;
94362306a36Sopenharmony_ci	cur_dsd->length = 0;
94462306a36Sopenharmony_ci	cur_dsd++;
94562306a36Sopenharmony_ci	return 0;
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ciint
94962306a36Sopenharmony_ciqla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp,
95062306a36Sopenharmony_ci	struct dsd64 *dsd, uint16_t tot_dsds, struct qla_tc_param *tc)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	void *next_dsd;
95362306a36Sopenharmony_ci	uint8_t avail_dsds = 0;
95462306a36Sopenharmony_ci	uint32_t dsd_list_len;
95562306a36Sopenharmony_ci	struct dsd_dma *dsd_ptr;
95662306a36Sopenharmony_ci	struct scatterlist *sg, *sgl;
95762306a36Sopenharmony_ci	struct dsd64 *cur_dsd = dsd;
95862306a36Sopenharmony_ci	int	i;
95962306a36Sopenharmony_ci	uint16_t	used_dsds = tot_dsds;
96062306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	if (sp) {
96362306a36Sopenharmony_ci		cmd = GET_CMD_SP(sp);
96462306a36Sopenharmony_ci		sgl = scsi_sglist(cmd);
96562306a36Sopenharmony_ci	} else if (tc) {
96662306a36Sopenharmony_ci		sgl = tc->sg;
96762306a36Sopenharmony_ci	} else {
96862306a36Sopenharmony_ci		BUG();
96962306a36Sopenharmony_ci		return 1;
97062306a36Sopenharmony_ci	}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	for_each_sg(sgl, sg, tot_dsds, i) {
97462306a36Sopenharmony_ci		/* Allocate additional continuation packets? */
97562306a36Sopenharmony_ci		if (avail_dsds == 0) {
97662306a36Sopenharmony_ci			avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ?
97762306a36Sopenharmony_ci					QLA_DSDS_PER_IOCB : used_dsds;
97862306a36Sopenharmony_ci			dsd_list_len = (avail_dsds + 1) * 12;
97962306a36Sopenharmony_ci			used_dsds -= avail_dsds;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci			/* allocate tracking DS */
98262306a36Sopenharmony_ci			dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
98362306a36Sopenharmony_ci			if (!dsd_ptr)
98462306a36Sopenharmony_ci				return 1;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci			/* allocate new list */
98762306a36Sopenharmony_ci			dsd_ptr->dsd_addr = next_dsd =
98862306a36Sopenharmony_ci			    dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC,
98962306a36Sopenharmony_ci				&dsd_ptr->dsd_list_dma);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci			if (!next_dsd) {
99262306a36Sopenharmony_ci				/*
99362306a36Sopenharmony_ci				 * Need to cleanup only this dsd_ptr, rest
99462306a36Sopenharmony_ci				 * will be done by sp_free_dma()
99562306a36Sopenharmony_ci				 */
99662306a36Sopenharmony_ci				kfree(dsd_ptr);
99762306a36Sopenharmony_ci				return 1;
99862306a36Sopenharmony_ci			}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci			if (sp) {
100162306a36Sopenharmony_ci				list_add_tail(&dsd_ptr->list,
100262306a36Sopenharmony_ci					      &sp->u.scmd.crc_ctx->dsd_list);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci				sp->flags |= SRB_CRC_CTX_DSD_VALID;
100562306a36Sopenharmony_ci			} else {
100662306a36Sopenharmony_ci				list_add_tail(&dsd_ptr->list,
100762306a36Sopenharmony_ci				    &(tc->ctx->dsd_list));
100862306a36Sopenharmony_ci				*tc->ctx_dsd_alloced = 1;
100962306a36Sopenharmony_ci			}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci			/* add new list to cmd iocb or last list */
101262306a36Sopenharmony_ci			put_unaligned_le64(dsd_ptr->dsd_list_dma,
101362306a36Sopenharmony_ci					   &cur_dsd->address);
101462306a36Sopenharmony_ci			cur_dsd->length = cpu_to_le32(dsd_list_len);
101562306a36Sopenharmony_ci			cur_dsd = next_dsd;
101662306a36Sopenharmony_ci		}
101762306a36Sopenharmony_ci		append_dsd64(&cur_dsd, sg);
101862306a36Sopenharmony_ci		avail_dsds--;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	}
102162306a36Sopenharmony_ci	/* Null termination */
102262306a36Sopenharmony_ci	cur_dsd->address = 0;
102362306a36Sopenharmony_ci	cur_dsd->length = 0;
102462306a36Sopenharmony_ci	cur_dsd++;
102562306a36Sopenharmony_ci	return 0;
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ciint
102962306a36Sopenharmony_ciqla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
103062306a36Sopenharmony_ci	struct dsd64 *cur_dsd, uint16_t tot_dsds, struct qla_tgt_cmd *tc)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	struct dsd_dma *dsd_ptr = NULL, *dif_dsd, *nxt_dsd;
103362306a36Sopenharmony_ci	struct scatterlist *sg, *sgl;
103462306a36Sopenharmony_ci	struct crc_context *difctx = NULL;
103562306a36Sopenharmony_ci	struct scsi_qla_host *vha;
103662306a36Sopenharmony_ci	uint dsd_list_len;
103762306a36Sopenharmony_ci	uint avail_dsds = 0;
103862306a36Sopenharmony_ci	uint used_dsds = tot_dsds;
103962306a36Sopenharmony_ci	bool dif_local_dma_alloc = false;
104062306a36Sopenharmony_ci	bool direction_to_device = false;
104162306a36Sopenharmony_ci	int i;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (sp) {
104462306a36Sopenharmony_ci		struct scsi_cmnd *cmd = GET_CMD_SP(sp);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci		sgl = scsi_prot_sglist(cmd);
104762306a36Sopenharmony_ci		vha = sp->vha;
104862306a36Sopenharmony_ci		difctx = sp->u.scmd.crc_ctx;
104962306a36Sopenharmony_ci		direction_to_device = cmd->sc_data_direction == DMA_TO_DEVICE;
105062306a36Sopenharmony_ci		ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe021,
105162306a36Sopenharmony_ci		  "%s: scsi_cmnd: %p, crc_ctx: %p, sp: %p\n",
105262306a36Sopenharmony_ci			__func__, cmd, difctx, sp);
105362306a36Sopenharmony_ci	} else if (tc) {
105462306a36Sopenharmony_ci		vha = tc->vha;
105562306a36Sopenharmony_ci		sgl = tc->prot_sg;
105662306a36Sopenharmony_ci		difctx = tc->ctx;
105762306a36Sopenharmony_ci		direction_to_device = tc->dma_data_direction == DMA_TO_DEVICE;
105862306a36Sopenharmony_ci	} else {
105962306a36Sopenharmony_ci		BUG();
106062306a36Sopenharmony_ci		return 1;
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe021,
106462306a36Sopenharmony_ci	    "%s: enter (write=%u)\n", __func__, direction_to_device);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	/* if initiator doing write or target doing read */
106762306a36Sopenharmony_ci	if (direction_to_device) {
106862306a36Sopenharmony_ci		for_each_sg(sgl, sg, tot_dsds, i) {
106962306a36Sopenharmony_ci			u64 sle_phys = sg_phys(sg);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci			/* If SGE addr + len flips bits in upper 32-bits */
107262306a36Sopenharmony_ci			if (MSD(sle_phys + sg->length) ^ MSD(sle_phys)) {
107362306a36Sopenharmony_ci				ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe022,
107462306a36Sopenharmony_ci				    "%s: page boundary crossing (phys=%llx len=%x)\n",
107562306a36Sopenharmony_ci				    __func__, sle_phys, sg->length);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci				if (difctx) {
107862306a36Sopenharmony_ci					ha->dif_bundle_crossed_pages++;
107962306a36Sopenharmony_ci					dif_local_dma_alloc = true;
108062306a36Sopenharmony_ci				} else {
108162306a36Sopenharmony_ci					ql_dbg(ql_dbg_tgt + ql_dbg_verbose,
108262306a36Sopenharmony_ci					    vha, 0xe022,
108362306a36Sopenharmony_ci					    "%s: difctx pointer is NULL\n",
108462306a36Sopenharmony_ci					    __func__);
108562306a36Sopenharmony_ci				}
108662306a36Sopenharmony_ci				break;
108762306a36Sopenharmony_ci			}
108862306a36Sopenharmony_ci		}
108962306a36Sopenharmony_ci		ha->dif_bundle_writes++;
109062306a36Sopenharmony_ci	} else {
109162306a36Sopenharmony_ci		ha->dif_bundle_reads++;
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	if (ql2xdifbundlinginternalbuffers)
109562306a36Sopenharmony_ci		dif_local_dma_alloc = direction_to_device;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	if (dif_local_dma_alloc) {
109862306a36Sopenharmony_ci		u32 track_difbundl_buf = 0;
109962306a36Sopenharmony_ci		u32 ldma_sg_len = 0;
110062306a36Sopenharmony_ci		u8 ldma_needed = 1;
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci		difctx->no_dif_bundl = 0;
110362306a36Sopenharmony_ci		difctx->dif_bundl_len = 0;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci		/* Track DSD buffers */
110662306a36Sopenharmony_ci		INIT_LIST_HEAD(&difctx->ldif_dsd_list);
110762306a36Sopenharmony_ci		/* Track local DMA buffers */
110862306a36Sopenharmony_ci		INIT_LIST_HEAD(&difctx->ldif_dma_hndl_list);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		for_each_sg(sgl, sg, tot_dsds, i) {
111162306a36Sopenharmony_ci			u32 sglen = sg_dma_len(sg);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci			ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe023,
111462306a36Sopenharmony_ci			    "%s: sg[%x] (phys=%llx sglen=%x) ldma_sg_len: %x dif_bundl_len: %x ldma_needed: %x\n",
111562306a36Sopenharmony_ci			    __func__, i, (u64)sg_phys(sg), sglen, ldma_sg_len,
111662306a36Sopenharmony_ci			    difctx->dif_bundl_len, ldma_needed);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci			while (sglen) {
111962306a36Sopenharmony_ci				u32 xfrlen = 0;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci				if (ldma_needed) {
112262306a36Sopenharmony_ci					/*
112362306a36Sopenharmony_ci					 * Allocate list item to store
112462306a36Sopenharmony_ci					 * the DMA buffers
112562306a36Sopenharmony_ci					 */
112662306a36Sopenharmony_ci					dsd_ptr = kzalloc(sizeof(*dsd_ptr),
112762306a36Sopenharmony_ci					    GFP_ATOMIC);
112862306a36Sopenharmony_ci					if (!dsd_ptr) {
112962306a36Sopenharmony_ci						ql_dbg(ql_dbg_tgt, vha, 0xe024,
113062306a36Sopenharmony_ci						    "%s: failed alloc dsd_ptr\n",
113162306a36Sopenharmony_ci						    __func__);
113262306a36Sopenharmony_ci						return 1;
113362306a36Sopenharmony_ci					}
113462306a36Sopenharmony_ci					ha->dif_bundle_kallocs++;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci					/* allocate dma buffer */
113762306a36Sopenharmony_ci					dsd_ptr->dsd_addr = dma_pool_alloc
113862306a36Sopenharmony_ci						(ha->dif_bundl_pool, GFP_ATOMIC,
113962306a36Sopenharmony_ci						 &dsd_ptr->dsd_list_dma);
114062306a36Sopenharmony_ci					if (!dsd_ptr->dsd_addr) {
114162306a36Sopenharmony_ci						ql_dbg(ql_dbg_tgt, vha, 0xe024,
114262306a36Sopenharmony_ci						    "%s: failed alloc ->dsd_ptr\n",
114362306a36Sopenharmony_ci						    __func__);
114462306a36Sopenharmony_ci						/*
114562306a36Sopenharmony_ci						 * need to cleanup only this
114662306a36Sopenharmony_ci						 * dsd_ptr rest will be done
114762306a36Sopenharmony_ci						 * by sp_free_dma()
114862306a36Sopenharmony_ci						 */
114962306a36Sopenharmony_ci						kfree(dsd_ptr);
115062306a36Sopenharmony_ci						ha->dif_bundle_kallocs--;
115162306a36Sopenharmony_ci						return 1;
115262306a36Sopenharmony_ci					}
115362306a36Sopenharmony_ci					ha->dif_bundle_dma_allocs++;
115462306a36Sopenharmony_ci					ldma_needed = 0;
115562306a36Sopenharmony_ci					difctx->no_dif_bundl++;
115662306a36Sopenharmony_ci					list_add_tail(&dsd_ptr->list,
115762306a36Sopenharmony_ci					    &difctx->ldif_dma_hndl_list);
115862306a36Sopenharmony_ci				}
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci				/* xfrlen is min of dma pool size and sglen */
116162306a36Sopenharmony_ci				xfrlen = (sglen >
116262306a36Sopenharmony_ci				   (DIF_BUNDLING_DMA_POOL_SIZE - ldma_sg_len)) ?
116362306a36Sopenharmony_ci				    DIF_BUNDLING_DMA_POOL_SIZE - ldma_sg_len :
116462306a36Sopenharmony_ci				    sglen;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci				/* replace with local allocated dma buffer */
116762306a36Sopenharmony_ci				sg_pcopy_to_buffer(sgl, sg_nents(sgl),
116862306a36Sopenharmony_ci				    dsd_ptr->dsd_addr + ldma_sg_len, xfrlen,
116962306a36Sopenharmony_ci				    difctx->dif_bundl_len);
117062306a36Sopenharmony_ci				difctx->dif_bundl_len += xfrlen;
117162306a36Sopenharmony_ci				sglen -= xfrlen;
117262306a36Sopenharmony_ci				ldma_sg_len += xfrlen;
117362306a36Sopenharmony_ci				if (ldma_sg_len == DIF_BUNDLING_DMA_POOL_SIZE ||
117462306a36Sopenharmony_ci				    sg_is_last(sg)) {
117562306a36Sopenharmony_ci					ldma_needed = 1;
117662306a36Sopenharmony_ci					ldma_sg_len = 0;
117762306a36Sopenharmony_ci				}
117862306a36Sopenharmony_ci			}
117962306a36Sopenharmony_ci		}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci		track_difbundl_buf = used_dsds = difctx->no_dif_bundl;
118262306a36Sopenharmony_ci		ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe025,
118362306a36Sopenharmony_ci		    "dif_bundl_len=%x, no_dif_bundl=%x track_difbundl_buf: %x\n",
118462306a36Sopenharmony_ci		    difctx->dif_bundl_len, difctx->no_dif_bundl,
118562306a36Sopenharmony_ci		    track_difbundl_buf);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci		if (sp)
118862306a36Sopenharmony_ci			sp->flags |= SRB_DIF_BUNDL_DMA_VALID;
118962306a36Sopenharmony_ci		else
119062306a36Sopenharmony_ci			tc->prot_flags = DIF_BUNDL_DMA_VALID;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci		list_for_each_entry_safe(dif_dsd, nxt_dsd,
119362306a36Sopenharmony_ci		    &difctx->ldif_dma_hndl_list, list) {
119462306a36Sopenharmony_ci			u32 sglen = (difctx->dif_bundl_len >
119562306a36Sopenharmony_ci			    DIF_BUNDLING_DMA_POOL_SIZE) ?
119662306a36Sopenharmony_ci			    DIF_BUNDLING_DMA_POOL_SIZE : difctx->dif_bundl_len;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci			BUG_ON(track_difbundl_buf == 0);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci			/* Allocate additional continuation packets? */
120162306a36Sopenharmony_ci			if (avail_dsds == 0) {
120262306a36Sopenharmony_ci				ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha,
120362306a36Sopenharmony_ci				    0xe024,
120462306a36Sopenharmony_ci				    "%s: adding continuation iocb's\n",
120562306a36Sopenharmony_ci				    __func__);
120662306a36Sopenharmony_ci				avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ?
120762306a36Sopenharmony_ci				    QLA_DSDS_PER_IOCB : used_dsds;
120862306a36Sopenharmony_ci				dsd_list_len = (avail_dsds + 1) * 12;
120962306a36Sopenharmony_ci				used_dsds -= avail_dsds;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci				/* allocate tracking DS */
121262306a36Sopenharmony_ci				dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC);
121362306a36Sopenharmony_ci				if (!dsd_ptr) {
121462306a36Sopenharmony_ci					ql_dbg(ql_dbg_tgt, vha, 0xe026,
121562306a36Sopenharmony_ci					    "%s: failed alloc dsd_ptr\n",
121662306a36Sopenharmony_ci					    __func__);
121762306a36Sopenharmony_ci					return 1;
121862306a36Sopenharmony_ci				}
121962306a36Sopenharmony_ci				ha->dif_bundle_kallocs++;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci				difctx->no_ldif_dsd++;
122262306a36Sopenharmony_ci				/* allocate new list */
122362306a36Sopenharmony_ci				dsd_ptr->dsd_addr =
122462306a36Sopenharmony_ci				    dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC,
122562306a36Sopenharmony_ci					&dsd_ptr->dsd_list_dma);
122662306a36Sopenharmony_ci				if (!dsd_ptr->dsd_addr) {
122762306a36Sopenharmony_ci					ql_dbg(ql_dbg_tgt, vha, 0xe026,
122862306a36Sopenharmony_ci					    "%s: failed alloc ->dsd_addr\n",
122962306a36Sopenharmony_ci					    __func__);
123062306a36Sopenharmony_ci					/*
123162306a36Sopenharmony_ci					 * need to cleanup only this dsd_ptr
123262306a36Sopenharmony_ci					 *  rest will be done by sp_free_dma()
123362306a36Sopenharmony_ci					 */
123462306a36Sopenharmony_ci					kfree(dsd_ptr);
123562306a36Sopenharmony_ci					ha->dif_bundle_kallocs--;
123662306a36Sopenharmony_ci					return 1;
123762306a36Sopenharmony_ci				}
123862306a36Sopenharmony_ci				ha->dif_bundle_dma_allocs++;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci				if (sp) {
124162306a36Sopenharmony_ci					list_add_tail(&dsd_ptr->list,
124262306a36Sopenharmony_ci					    &difctx->ldif_dsd_list);
124362306a36Sopenharmony_ci					sp->flags |= SRB_CRC_CTX_DSD_VALID;
124462306a36Sopenharmony_ci				} else {
124562306a36Sopenharmony_ci					list_add_tail(&dsd_ptr->list,
124662306a36Sopenharmony_ci					    &difctx->ldif_dsd_list);
124762306a36Sopenharmony_ci					tc->ctx_dsd_alloced = 1;
124862306a36Sopenharmony_ci				}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci				/* add new list to cmd iocb or last list */
125162306a36Sopenharmony_ci				put_unaligned_le64(dsd_ptr->dsd_list_dma,
125262306a36Sopenharmony_ci						   &cur_dsd->address);
125362306a36Sopenharmony_ci				cur_dsd->length = cpu_to_le32(dsd_list_len);
125462306a36Sopenharmony_ci				cur_dsd = dsd_ptr->dsd_addr;
125562306a36Sopenharmony_ci			}
125662306a36Sopenharmony_ci			put_unaligned_le64(dif_dsd->dsd_list_dma,
125762306a36Sopenharmony_ci					   &cur_dsd->address);
125862306a36Sopenharmony_ci			cur_dsd->length = cpu_to_le32(sglen);
125962306a36Sopenharmony_ci			cur_dsd++;
126062306a36Sopenharmony_ci			avail_dsds--;
126162306a36Sopenharmony_ci			difctx->dif_bundl_len -= sglen;
126262306a36Sopenharmony_ci			track_difbundl_buf--;
126362306a36Sopenharmony_ci		}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci		ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe026,
126662306a36Sopenharmony_ci		    "%s: no_ldif_dsd:%x, no_dif_bundl:%x\n", __func__,
126762306a36Sopenharmony_ci			difctx->no_ldif_dsd, difctx->no_dif_bundl);
126862306a36Sopenharmony_ci	} else {
126962306a36Sopenharmony_ci		for_each_sg(sgl, sg, tot_dsds, i) {
127062306a36Sopenharmony_ci			/* Allocate additional continuation packets? */
127162306a36Sopenharmony_ci			if (avail_dsds == 0) {
127262306a36Sopenharmony_ci				avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ?
127362306a36Sopenharmony_ci				    QLA_DSDS_PER_IOCB : used_dsds;
127462306a36Sopenharmony_ci				dsd_list_len = (avail_dsds + 1) * 12;
127562306a36Sopenharmony_ci				used_dsds -= avail_dsds;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci				/* allocate tracking DS */
127862306a36Sopenharmony_ci				dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC);
127962306a36Sopenharmony_ci				if (!dsd_ptr) {
128062306a36Sopenharmony_ci					ql_dbg(ql_dbg_tgt + ql_dbg_verbose,
128162306a36Sopenharmony_ci					    vha, 0xe027,
128262306a36Sopenharmony_ci					    "%s: failed alloc dsd_dma...\n",
128362306a36Sopenharmony_ci					    __func__);
128462306a36Sopenharmony_ci					return 1;
128562306a36Sopenharmony_ci				}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci				/* allocate new list */
128862306a36Sopenharmony_ci				dsd_ptr->dsd_addr =
128962306a36Sopenharmony_ci				    dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC,
129062306a36Sopenharmony_ci					&dsd_ptr->dsd_list_dma);
129162306a36Sopenharmony_ci				if (!dsd_ptr->dsd_addr) {
129262306a36Sopenharmony_ci					/* need to cleanup only this dsd_ptr */
129362306a36Sopenharmony_ci					/* rest will be done by sp_free_dma() */
129462306a36Sopenharmony_ci					kfree(dsd_ptr);
129562306a36Sopenharmony_ci					return 1;
129662306a36Sopenharmony_ci				}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci				if (sp) {
129962306a36Sopenharmony_ci					list_add_tail(&dsd_ptr->list,
130062306a36Sopenharmony_ci					    &difctx->dsd_list);
130162306a36Sopenharmony_ci					sp->flags |= SRB_CRC_CTX_DSD_VALID;
130262306a36Sopenharmony_ci				} else {
130362306a36Sopenharmony_ci					list_add_tail(&dsd_ptr->list,
130462306a36Sopenharmony_ci					    &difctx->dsd_list);
130562306a36Sopenharmony_ci					tc->ctx_dsd_alloced = 1;
130662306a36Sopenharmony_ci				}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci				/* add new list to cmd iocb or last list */
130962306a36Sopenharmony_ci				put_unaligned_le64(dsd_ptr->dsd_list_dma,
131062306a36Sopenharmony_ci						   &cur_dsd->address);
131162306a36Sopenharmony_ci				cur_dsd->length = cpu_to_le32(dsd_list_len);
131262306a36Sopenharmony_ci				cur_dsd = dsd_ptr->dsd_addr;
131362306a36Sopenharmony_ci			}
131462306a36Sopenharmony_ci			append_dsd64(&cur_dsd, sg);
131562306a36Sopenharmony_ci			avail_dsds--;
131662306a36Sopenharmony_ci		}
131762306a36Sopenharmony_ci	}
131862306a36Sopenharmony_ci	/* Null termination */
131962306a36Sopenharmony_ci	cur_dsd->address = 0;
132062306a36Sopenharmony_ci	cur_dsd->length = 0;
132162306a36Sopenharmony_ci	cur_dsd++;
132262306a36Sopenharmony_ci	return 0;
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci/**
132662306a36Sopenharmony_ci * qla24xx_build_scsi_crc_2_iocbs() - Build IOCB command utilizing Command
132762306a36Sopenharmony_ci *							Type 6 IOCB types.
132862306a36Sopenharmony_ci *
132962306a36Sopenharmony_ci * @sp: SRB command to process
133062306a36Sopenharmony_ci * @cmd_pkt: Command type 3 IOCB
133162306a36Sopenharmony_ci * @tot_dsds: Total number of segments to transfer
133262306a36Sopenharmony_ci * @tot_prot_dsds: Total number of segments with protection information
133362306a36Sopenharmony_ci * @fw_prot_opts: Protection options to be passed to firmware
133462306a36Sopenharmony_ci */
133562306a36Sopenharmony_cistatic inline int
133662306a36Sopenharmony_ciqla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
133762306a36Sopenharmony_ci    uint16_t tot_dsds, uint16_t tot_prot_dsds, uint16_t fw_prot_opts)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	struct dsd64		*cur_dsd;
134062306a36Sopenharmony_ci	__be32			*fcp_dl;
134162306a36Sopenharmony_ci	scsi_qla_host_t		*vha;
134262306a36Sopenharmony_ci	struct scsi_cmnd	*cmd;
134362306a36Sopenharmony_ci	uint32_t		total_bytes = 0;
134462306a36Sopenharmony_ci	uint32_t		data_bytes;
134562306a36Sopenharmony_ci	uint32_t		dif_bytes;
134662306a36Sopenharmony_ci	uint8_t			bundling = 1;
134762306a36Sopenharmony_ci	uint16_t		blk_size;
134862306a36Sopenharmony_ci	struct crc_context	*crc_ctx_pkt = NULL;
134962306a36Sopenharmony_ci	struct qla_hw_data	*ha;
135062306a36Sopenharmony_ci	uint8_t			additional_fcpcdb_len;
135162306a36Sopenharmony_ci	uint16_t		fcp_cmnd_len;
135262306a36Sopenharmony_ci	struct fcp_cmnd		*fcp_cmnd;
135362306a36Sopenharmony_ci	dma_addr_t		crc_ctx_dma;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	cmd = GET_CMD_SP(sp);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	/* Update entry type to indicate Command Type CRC_2 IOCB */
135862306a36Sopenharmony_ci	put_unaligned_le32(COMMAND_TYPE_CRC_2, &cmd_pkt->entry_type);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	vha = sp->vha;
136162306a36Sopenharmony_ci	ha = vha->hw;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	/* No data transfer */
136462306a36Sopenharmony_ci	data_bytes = scsi_bufflen(cmd);
136562306a36Sopenharmony_ci	if (!data_bytes || cmd->sc_data_direction == DMA_NONE) {
136662306a36Sopenharmony_ci		cmd_pkt->byte_count = cpu_to_le32(0);
136762306a36Sopenharmony_ci		return QLA_SUCCESS;
136862306a36Sopenharmony_ci	}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	cmd_pkt->vp_index = sp->vha->vp_idx;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	/* Set transfer direction */
137362306a36Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
137462306a36Sopenharmony_ci		cmd_pkt->control_flags =
137562306a36Sopenharmony_ci		    cpu_to_le16(CF_WRITE_DATA);
137662306a36Sopenharmony_ci	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
137762306a36Sopenharmony_ci		cmd_pkt->control_flags =
137862306a36Sopenharmony_ci		    cpu_to_le16(CF_READ_DATA);
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) ||
138262306a36Sopenharmony_ci	    (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP) ||
138362306a36Sopenharmony_ci	    (scsi_get_prot_op(cmd) == SCSI_PROT_READ_STRIP) ||
138462306a36Sopenharmony_ci	    (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_INSERT))
138562306a36Sopenharmony_ci		bundling = 0;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	/* Allocate CRC context from global pool */
138862306a36Sopenharmony_ci	crc_ctx_pkt = sp->u.scmd.crc_ctx =
138962306a36Sopenharmony_ci	    dma_pool_zalloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	if (!crc_ctx_pkt)
139262306a36Sopenharmony_ci		goto crc_queuing_error;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	crc_ctx_pkt->crc_ctx_dma = crc_ctx_dma;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	sp->flags |= SRB_CRC_CTX_DMA_VALID;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	/* Set handle */
139962306a36Sopenharmony_ci	crc_ctx_pkt->handle = cmd_pkt->handle;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list);
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	qla24xx_set_t10dif_tags(sp, (struct fw_dif_context *)
140462306a36Sopenharmony_ci	    &crc_ctx_pkt->ref_tag, tot_prot_dsds);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	put_unaligned_le64(crc_ctx_dma, &cmd_pkt->crc_context_address);
140762306a36Sopenharmony_ci	cmd_pkt->crc_context_len = cpu_to_le16(CRC_CONTEXT_LEN_FW);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	/* Determine SCSI command length -- align to 4 byte boundary */
141062306a36Sopenharmony_ci	if (cmd->cmd_len > 16) {
141162306a36Sopenharmony_ci		additional_fcpcdb_len = cmd->cmd_len - 16;
141262306a36Sopenharmony_ci		if ((cmd->cmd_len % 4) != 0) {
141362306a36Sopenharmony_ci			/* SCSI cmd > 16 bytes must be multiple of 4 */
141462306a36Sopenharmony_ci			goto crc_queuing_error;
141562306a36Sopenharmony_ci		}
141662306a36Sopenharmony_ci		fcp_cmnd_len = 12 + cmd->cmd_len + 4;
141762306a36Sopenharmony_ci	} else {
141862306a36Sopenharmony_ci		additional_fcpcdb_len = 0;
141962306a36Sopenharmony_ci		fcp_cmnd_len = 12 + 16 + 4;
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	fcp_cmnd = &crc_ctx_pkt->fcp_cmnd;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	fcp_cmnd->additional_cdb_len = additional_fcpcdb_len;
142562306a36Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE)
142662306a36Sopenharmony_ci		fcp_cmnd->additional_cdb_len |= 1;
142762306a36Sopenharmony_ci	else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
142862306a36Sopenharmony_ci		fcp_cmnd->additional_cdb_len |= 2;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	int_to_scsilun(cmd->device->lun, &fcp_cmnd->lun);
143162306a36Sopenharmony_ci	memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
143262306a36Sopenharmony_ci	cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len);
143362306a36Sopenharmony_ci	put_unaligned_le64(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF,
143462306a36Sopenharmony_ci			   &cmd_pkt->fcp_cmnd_dseg_address);
143562306a36Sopenharmony_ci	fcp_cmnd->task_management = 0;
143662306a36Sopenharmony_ci	fcp_cmnd->task_attribute = TSK_SIMPLE;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	/* Compute dif len and adjust data len to incude protection */
144162306a36Sopenharmony_ci	dif_bytes = 0;
144262306a36Sopenharmony_ci	blk_size = cmd->device->sector_size;
144362306a36Sopenharmony_ci	dif_bytes = (data_bytes / blk_size) * 8;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	switch (scsi_get_prot_op(GET_CMD_SP(sp))) {
144662306a36Sopenharmony_ci	case SCSI_PROT_READ_INSERT:
144762306a36Sopenharmony_ci	case SCSI_PROT_WRITE_STRIP:
144862306a36Sopenharmony_ci		total_bytes = data_bytes;
144962306a36Sopenharmony_ci		data_bytes += dif_bytes;
145062306a36Sopenharmony_ci		break;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	case SCSI_PROT_READ_STRIP:
145362306a36Sopenharmony_ci	case SCSI_PROT_WRITE_INSERT:
145462306a36Sopenharmony_ci	case SCSI_PROT_READ_PASS:
145562306a36Sopenharmony_ci	case SCSI_PROT_WRITE_PASS:
145662306a36Sopenharmony_ci		total_bytes = data_bytes + dif_bytes;
145762306a36Sopenharmony_ci		break;
145862306a36Sopenharmony_ci	default:
145962306a36Sopenharmony_ci		BUG();
146062306a36Sopenharmony_ci	}
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	if (!qla2x00_hba_err_chk_enabled(sp))
146362306a36Sopenharmony_ci		fw_prot_opts |= 0x10; /* Disable Guard tag checking */
146462306a36Sopenharmony_ci	/* HBA error checking enabled */
146562306a36Sopenharmony_ci	else if (IS_PI_UNINIT_CAPABLE(ha)) {
146662306a36Sopenharmony_ci		if ((scsi_get_prot_type(GET_CMD_SP(sp)) == SCSI_PROT_DIF_TYPE1)
146762306a36Sopenharmony_ci		    || (scsi_get_prot_type(GET_CMD_SP(sp)) ==
146862306a36Sopenharmony_ci			SCSI_PROT_DIF_TYPE2))
146962306a36Sopenharmony_ci			fw_prot_opts |= BIT_10;
147062306a36Sopenharmony_ci		else if (scsi_get_prot_type(GET_CMD_SP(sp)) ==
147162306a36Sopenharmony_ci		    SCSI_PROT_DIF_TYPE3)
147262306a36Sopenharmony_ci			fw_prot_opts |= BIT_11;
147362306a36Sopenharmony_ci	}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	if (!bundling) {
147662306a36Sopenharmony_ci		cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd[0];
147762306a36Sopenharmony_ci	} else {
147862306a36Sopenharmony_ci		/*
147962306a36Sopenharmony_ci		 * Configure Bundling if we need to fetch interlaving
148062306a36Sopenharmony_ci		 * protection PCI accesses
148162306a36Sopenharmony_ci		 */
148262306a36Sopenharmony_ci		fw_prot_opts |= PO_ENABLE_DIF_BUNDLING;
148362306a36Sopenharmony_ci		crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes);
148462306a36Sopenharmony_ci		crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(tot_dsds -
148562306a36Sopenharmony_ci							tot_prot_dsds);
148662306a36Sopenharmony_ci		cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd[0];
148762306a36Sopenharmony_ci	}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	/* Finish the common fields of CRC pkt */
149062306a36Sopenharmony_ci	crc_ctx_pkt->blk_size = cpu_to_le16(blk_size);
149162306a36Sopenharmony_ci	crc_ctx_pkt->prot_opts = cpu_to_le16(fw_prot_opts);
149262306a36Sopenharmony_ci	crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes);
149362306a36Sopenharmony_ci	crc_ctx_pkt->guard_seed = cpu_to_le16(0);
149462306a36Sopenharmony_ci	/* Fibre channel byte count */
149562306a36Sopenharmony_ci	cmd_pkt->byte_count = cpu_to_le32(total_bytes);
149662306a36Sopenharmony_ci	fcp_dl = (__be32 *)(crc_ctx_pkt->fcp_cmnd.cdb + 16 +
149762306a36Sopenharmony_ci	    additional_fcpcdb_len);
149862306a36Sopenharmony_ci	*fcp_dl = htonl(total_bytes);
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	if (!data_bytes || cmd->sc_data_direction == DMA_NONE) {
150162306a36Sopenharmony_ci		cmd_pkt->byte_count = cpu_to_le32(0);
150262306a36Sopenharmony_ci		return QLA_SUCCESS;
150362306a36Sopenharmony_ci	}
150462306a36Sopenharmony_ci	/* Walks data segments */
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	cmd_pkt->control_flags |= cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	if (!bundling && tot_prot_dsds) {
150962306a36Sopenharmony_ci		if (qla24xx_walk_and_build_sglist_no_difb(ha, sp,
151062306a36Sopenharmony_ci			cur_dsd, tot_dsds, NULL))
151162306a36Sopenharmony_ci			goto crc_queuing_error;
151262306a36Sopenharmony_ci	} else if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd,
151362306a36Sopenharmony_ci			(tot_dsds - tot_prot_dsds), NULL))
151462306a36Sopenharmony_ci		goto crc_queuing_error;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	if (bundling && tot_prot_dsds) {
151762306a36Sopenharmony_ci		/* Walks dif segments */
151862306a36Sopenharmony_ci		cmd_pkt->control_flags |= cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE);
151962306a36Sopenharmony_ci		cur_dsd = &crc_ctx_pkt->u.bundling.dif_dsd;
152062306a36Sopenharmony_ci		if (qla24xx_walk_and_build_prot_sglist(ha, sp, cur_dsd,
152162306a36Sopenharmony_ci				tot_prot_dsds, NULL))
152262306a36Sopenharmony_ci			goto crc_queuing_error;
152362306a36Sopenharmony_ci	}
152462306a36Sopenharmony_ci	return QLA_SUCCESS;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_cicrc_queuing_error:
152762306a36Sopenharmony_ci	/* Cleanup will be performed by the caller */
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
153062306a36Sopenharmony_ci}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci/**
153362306a36Sopenharmony_ci * qla24xx_start_scsi() - Send a SCSI command to the ISP
153462306a36Sopenharmony_ci * @sp: command to send to the ISP
153562306a36Sopenharmony_ci *
153662306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero.
153762306a36Sopenharmony_ci */
153862306a36Sopenharmony_ciint
153962306a36Sopenharmony_ciqla24xx_start_scsi(srb_t *sp)
154062306a36Sopenharmony_ci{
154162306a36Sopenharmony_ci	int		nseg;
154262306a36Sopenharmony_ci	unsigned long   flags;
154362306a36Sopenharmony_ci	uint32_t	*clr_ptr;
154462306a36Sopenharmony_ci	uint32_t	handle;
154562306a36Sopenharmony_ci	struct cmd_type_7 *cmd_pkt;
154662306a36Sopenharmony_ci	uint16_t	cnt;
154762306a36Sopenharmony_ci	uint16_t	req_cnt;
154862306a36Sopenharmony_ci	uint16_t	tot_dsds;
154962306a36Sopenharmony_ci	struct req_que *req = NULL;
155062306a36Sopenharmony_ci	struct rsp_que *rsp;
155162306a36Sopenharmony_ci	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
155262306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
155362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	if (sp->fcport->edif.enable  && (sp->fcport->flags & FCF_FCSP_DEVICE))
155662306a36Sopenharmony_ci		return qla28xx_start_scsi_edif(sp);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	/* Setup device pointers. */
155962306a36Sopenharmony_ci	req = vha->req;
156062306a36Sopenharmony_ci	rsp = req->rsp;
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	/* So we know we haven't pci_map'ed anything yet */
156362306a36Sopenharmony_ci	tot_dsds = 0;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	/* Send marker if required */
156662306a36Sopenharmony_ci	if (vha->marker_needed != 0) {
156762306a36Sopenharmony_ci		if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) !=
156862306a36Sopenharmony_ci		    QLA_SUCCESS)
156962306a36Sopenharmony_ci			return QLA_FUNCTION_FAILED;
157062306a36Sopenharmony_ci		vha->marker_needed = 0;
157162306a36Sopenharmony_ci	}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	/* Acquire ring specific lock */
157462306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	handle = qla2xxx_get_next_handle(req);
157762306a36Sopenharmony_ci	if (handle == 0)
157862306a36Sopenharmony_ci		goto queuing_error;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	/* Map the sg table so we have an accurate count of sg entries needed */
158162306a36Sopenharmony_ci	if (scsi_sg_count(cmd)) {
158262306a36Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
158362306a36Sopenharmony_ci		    scsi_sg_count(cmd), cmd->sc_data_direction);
158462306a36Sopenharmony_ci		if (unlikely(!nseg))
158562306a36Sopenharmony_ci			goto queuing_error;
158662306a36Sopenharmony_ci	} else
158762306a36Sopenharmony_ci		nseg = 0;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	tot_dsds = nseg;
159062306a36Sopenharmony_ci	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
159362306a36Sopenharmony_ci	sp->iores.exch_cnt = 1;
159462306a36Sopenharmony_ci	sp->iores.iocb_cnt = req_cnt;
159562306a36Sopenharmony_ci	if (qla_get_fw_resources(sp->qpair, &sp->iores))
159662306a36Sopenharmony_ci		goto queuing_error;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	if (req->cnt < (req_cnt + 2)) {
159962306a36Sopenharmony_ci		if (IS_SHADOW_REG_CAPABLE(ha)) {
160062306a36Sopenharmony_ci			cnt = *req->out_ptr;
160162306a36Sopenharmony_ci		} else {
160262306a36Sopenharmony_ci			cnt = rd_reg_dword_relaxed(req->req_q_out);
160362306a36Sopenharmony_ci			if (qla2x00_check_reg16_for_disconnect(vha, cnt))
160462306a36Sopenharmony_ci				goto queuing_error;
160562306a36Sopenharmony_ci		}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci		if (req->ring_index < cnt)
160862306a36Sopenharmony_ci			req->cnt = cnt - req->ring_index;
160962306a36Sopenharmony_ci		else
161062306a36Sopenharmony_ci			req->cnt = req->length -
161162306a36Sopenharmony_ci				(req->ring_index - cnt);
161262306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2))
161362306a36Sopenharmony_ci			goto queuing_error;
161462306a36Sopenharmony_ci	}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	/* Build command packet. */
161762306a36Sopenharmony_ci	req->current_outstanding_cmd = handle;
161862306a36Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
161962306a36Sopenharmony_ci	sp->handle = handle;
162062306a36Sopenharmony_ci	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
162162306a36Sopenharmony_ci	req->cnt -= req_cnt;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
162462306a36Sopenharmony_ci	cmd_pkt->handle = make_handle(req->id, handle);
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	/* Zero out remaining portion of packet. */
162762306a36Sopenharmony_ci	/*    tagged queuing modifier -- default is TSK_SIMPLE (0). */
162862306a36Sopenharmony_ci	clr_ptr = (uint32_t *)cmd_pkt + 2;
162962306a36Sopenharmony_ci	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
163062306a36Sopenharmony_ci	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	/* Set NPORT-ID and LUN number*/
163362306a36Sopenharmony_ci	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
163462306a36Sopenharmony_ci	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
163562306a36Sopenharmony_ci	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
163662306a36Sopenharmony_ci	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
163762306a36Sopenharmony_ci	cmd_pkt->vp_index = sp->vha->vp_idx;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
164062306a36Sopenharmony_ci	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	cmd_pkt->task = TSK_SIMPLE;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	/* Load SCSI command packet. */
164562306a36Sopenharmony_ci	memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
164662306a36Sopenharmony_ci	host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	/* Build IOCB segments */
165162306a36Sopenharmony_ci	qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req);
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	/* Set total data segment count. */
165462306a36Sopenharmony_ci	cmd_pkt->entry_count = (uint8_t)req_cnt;
165562306a36Sopenharmony_ci	wmb();
165662306a36Sopenharmony_ci	/* Adjust ring index. */
165762306a36Sopenharmony_ci	req->ring_index++;
165862306a36Sopenharmony_ci	if (req->ring_index == req->length) {
165962306a36Sopenharmony_ci		req->ring_index = 0;
166062306a36Sopenharmony_ci		req->ring_ptr = req->ring;
166162306a36Sopenharmony_ci	} else
166262306a36Sopenharmony_ci		req->ring_ptr++;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	sp->qpair->cmd_cnt++;
166562306a36Sopenharmony_ci	sp->flags |= SRB_DMA_VALID;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	/* Set chip new ring index. */
166862306a36Sopenharmony_ci	wrt_reg_dword(req->req_q_in, req->ring_index);
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	/* Manage unprocessed RIO/ZIO commands in response queue. */
167162306a36Sopenharmony_ci	if (vha->flags.process_response_queue &&
167262306a36Sopenharmony_ci	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
167362306a36Sopenharmony_ci		qla24xx_process_response_queue(vha, rsp);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
167662306a36Sopenharmony_ci	return QLA_SUCCESS;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ciqueuing_error:
167962306a36Sopenharmony_ci	if (tot_dsds)
168062306a36Sopenharmony_ci		scsi_dma_unmap(cmd);
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	qla_put_fw_resources(sp->qpair, &sp->iores);
168362306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
168662306a36Sopenharmony_ci}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci/**
168962306a36Sopenharmony_ci * qla24xx_dif_start_scsi() - Send a SCSI command to the ISP
169062306a36Sopenharmony_ci * @sp: command to send to the ISP
169162306a36Sopenharmony_ci *
169262306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero.
169362306a36Sopenharmony_ci */
169462306a36Sopenharmony_ciint
169562306a36Sopenharmony_ciqla24xx_dif_start_scsi(srb_t *sp)
169662306a36Sopenharmony_ci{
169762306a36Sopenharmony_ci	int			nseg;
169862306a36Sopenharmony_ci	unsigned long		flags;
169962306a36Sopenharmony_ci	uint32_t		*clr_ptr;
170062306a36Sopenharmony_ci	uint32_t		handle;
170162306a36Sopenharmony_ci	uint16_t		cnt;
170262306a36Sopenharmony_ci	uint16_t		req_cnt = 0;
170362306a36Sopenharmony_ci	uint16_t		tot_dsds;
170462306a36Sopenharmony_ci	uint16_t		tot_prot_dsds;
170562306a36Sopenharmony_ci	uint16_t		fw_prot_opts = 0;
170662306a36Sopenharmony_ci	struct req_que		*req = NULL;
170762306a36Sopenharmony_ci	struct rsp_que		*rsp = NULL;
170862306a36Sopenharmony_ci	struct scsi_cmnd	*cmd = GET_CMD_SP(sp);
170962306a36Sopenharmony_ci	struct scsi_qla_host	*vha = sp->vha;
171062306a36Sopenharmony_ci	struct qla_hw_data	*ha = vha->hw;
171162306a36Sopenharmony_ci	struct cmd_type_crc_2	*cmd_pkt;
171262306a36Sopenharmony_ci	uint32_t		status = 0;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci#define QDSS_GOT_Q_SPACE	BIT_0
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	/* Only process protection or >16 cdb in this routine */
171762306a36Sopenharmony_ci	if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) {
171862306a36Sopenharmony_ci		if (cmd->cmd_len <= 16)
171962306a36Sopenharmony_ci			return qla24xx_start_scsi(sp);
172062306a36Sopenharmony_ci		else
172162306a36Sopenharmony_ci			return qla_start_scsi_type6(sp);
172262306a36Sopenharmony_ci	}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	/* Setup device pointers. */
172562306a36Sopenharmony_ci	req = vha->req;
172662306a36Sopenharmony_ci	rsp = req->rsp;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	/* So we know we haven't pci_map'ed anything yet */
172962306a36Sopenharmony_ci	tot_dsds = 0;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	/* Send marker if required */
173262306a36Sopenharmony_ci	if (vha->marker_needed != 0) {
173362306a36Sopenharmony_ci		if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) !=
173462306a36Sopenharmony_ci		    QLA_SUCCESS)
173562306a36Sopenharmony_ci			return QLA_FUNCTION_FAILED;
173662306a36Sopenharmony_ci		vha->marker_needed = 0;
173762306a36Sopenharmony_ci	}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	/* Acquire ring specific lock */
174062306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	handle = qla2xxx_get_next_handle(req);
174362306a36Sopenharmony_ci	if (handle == 0)
174462306a36Sopenharmony_ci		goto queuing_error;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	/* Compute number of required data segments */
174762306a36Sopenharmony_ci	/* Map the sg table so we have an accurate count of sg entries needed */
174862306a36Sopenharmony_ci	if (scsi_sg_count(cmd)) {
174962306a36Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
175062306a36Sopenharmony_ci		    scsi_sg_count(cmd), cmd->sc_data_direction);
175162306a36Sopenharmony_ci		if (unlikely(!nseg))
175262306a36Sopenharmony_ci			goto queuing_error;
175362306a36Sopenharmony_ci		else
175462306a36Sopenharmony_ci			sp->flags |= SRB_DMA_VALID;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci		if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) ||
175762306a36Sopenharmony_ci		    (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) {
175862306a36Sopenharmony_ci			struct qla2_sgx sgx;
175962306a36Sopenharmony_ci			uint32_t	partial;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci			memset(&sgx, 0, sizeof(struct qla2_sgx));
176262306a36Sopenharmony_ci			sgx.tot_bytes = scsi_bufflen(cmd);
176362306a36Sopenharmony_ci			sgx.cur_sg = scsi_sglist(cmd);
176462306a36Sopenharmony_ci			sgx.sp = sp;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci			nseg = 0;
176762306a36Sopenharmony_ci			while (qla24xx_get_one_block_sg(
176862306a36Sopenharmony_ci			    cmd->device->sector_size, &sgx, &partial))
176962306a36Sopenharmony_ci				nseg++;
177062306a36Sopenharmony_ci		}
177162306a36Sopenharmony_ci	} else
177262306a36Sopenharmony_ci		nseg = 0;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	/* number of required data segments */
177562306a36Sopenharmony_ci	tot_dsds = nseg;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	/* Compute number of required protection segments */
177862306a36Sopenharmony_ci	if (qla24xx_configure_prot_mode(sp, &fw_prot_opts)) {
177962306a36Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_prot_sglist(cmd),
178062306a36Sopenharmony_ci		    scsi_prot_sg_count(cmd), cmd->sc_data_direction);
178162306a36Sopenharmony_ci		if (unlikely(!nseg))
178262306a36Sopenharmony_ci			goto queuing_error;
178362306a36Sopenharmony_ci		else
178462306a36Sopenharmony_ci			sp->flags |= SRB_CRC_PROT_DMA_VALID;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci		if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) ||
178762306a36Sopenharmony_ci		    (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) {
178862306a36Sopenharmony_ci			nseg = scsi_bufflen(cmd) / cmd->device->sector_size;
178962306a36Sopenharmony_ci		}
179062306a36Sopenharmony_ci	} else {
179162306a36Sopenharmony_ci		nseg = 0;
179262306a36Sopenharmony_ci	}
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	req_cnt = 1;
179562306a36Sopenharmony_ci	/* Total Data and protection sg segment(s) */
179662306a36Sopenharmony_ci	tot_prot_dsds = nseg;
179762306a36Sopenharmony_ci	tot_dsds += nseg;
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
180062306a36Sopenharmony_ci	sp->iores.exch_cnt = 1;
180162306a36Sopenharmony_ci	sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
180262306a36Sopenharmony_ci	if (qla_get_fw_resources(sp->qpair, &sp->iores))
180362306a36Sopenharmony_ci		goto queuing_error;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	if (req->cnt < (req_cnt + 2)) {
180662306a36Sopenharmony_ci		if (IS_SHADOW_REG_CAPABLE(ha)) {
180762306a36Sopenharmony_ci			cnt = *req->out_ptr;
180862306a36Sopenharmony_ci		} else {
180962306a36Sopenharmony_ci			cnt = rd_reg_dword_relaxed(req->req_q_out);
181062306a36Sopenharmony_ci			if (qla2x00_check_reg16_for_disconnect(vha, cnt))
181162306a36Sopenharmony_ci				goto queuing_error;
181262306a36Sopenharmony_ci		}
181362306a36Sopenharmony_ci		if (req->ring_index < cnt)
181462306a36Sopenharmony_ci			req->cnt = cnt - req->ring_index;
181562306a36Sopenharmony_ci		else
181662306a36Sopenharmony_ci			req->cnt = req->length -
181762306a36Sopenharmony_ci				(req->ring_index - cnt);
181862306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2))
181962306a36Sopenharmony_ci			goto queuing_error;
182062306a36Sopenharmony_ci	}
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	status |= QDSS_GOT_Q_SPACE;
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	/* Build header part of command packet (excluding the OPCODE). */
182562306a36Sopenharmony_ci	req->current_outstanding_cmd = handle;
182662306a36Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
182762306a36Sopenharmony_ci	sp->handle = handle;
182862306a36Sopenharmony_ci	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
182962306a36Sopenharmony_ci	req->cnt -= req_cnt;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	/* Fill-in common area */
183262306a36Sopenharmony_ci	cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr;
183362306a36Sopenharmony_ci	cmd_pkt->handle = make_handle(req->id, handle);
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	clr_ptr = (uint32_t *)cmd_pkt + 2;
183662306a36Sopenharmony_ci	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	/* Set NPORT-ID and LUN number*/
183962306a36Sopenharmony_ci	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
184062306a36Sopenharmony_ci	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
184162306a36Sopenharmony_ci	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
184262306a36Sopenharmony_ci	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
184562306a36Sopenharmony_ci	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	/* Total Data and protection segment(s) */
184862306a36Sopenharmony_ci	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	/* Build IOCB segments and adjust for data protection segments */
185162306a36Sopenharmony_ci	if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *)
185262306a36Sopenharmony_ci	    req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) !=
185362306a36Sopenharmony_ci		QLA_SUCCESS)
185462306a36Sopenharmony_ci		goto queuing_error;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	cmd_pkt->entry_count = (uint8_t)req_cnt;
185762306a36Sopenharmony_ci	/* Specify response queue number where completion should happen */
185862306a36Sopenharmony_ci	cmd_pkt->entry_status = (uint8_t) rsp->id;
185962306a36Sopenharmony_ci	cmd_pkt->timeout = cpu_to_le16(0);
186062306a36Sopenharmony_ci	wmb();
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	/* Adjust ring index. */
186362306a36Sopenharmony_ci	req->ring_index++;
186462306a36Sopenharmony_ci	if (req->ring_index == req->length) {
186562306a36Sopenharmony_ci		req->ring_index = 0;
186662306a36Sopenharmony_ci		req->ring_ptr = req->ring;
186762306a36Sopenharmony_ci	} else
186862306a36Sopenharmony_ci		req->ring_ptr++;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	sp->qpair->cmd_cnt++;
187162306a36Sopenharmony_ci	/* Set chip new ring index. */
187262306a36Sopenharmony_ci	wrt_reg_dword(req->req_q_in, req->ring_index);
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	/* Manage unprocessed RIO/ZIO commands in response queue. */
187562306a36Sopenharmony_ci	if (vha->flags.process_response_queue &&
187662306a36Sopenharmony_ci	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
187762306a36Sopenharmony_ci		qla24xx_process_response_queue(vha, rsp);
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	return QLA_SUCCESS;
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ciqueuing_error:
188462306a36Sopenharmony_ci	if (status & QDSS_GOT_Q_SPACE) {
188562306a36Sopenharmony_ci		req->outstanding_cmds[handle] = NULL;
188662306a36Sopenharmony_ci		req->cnt += req_cnt;
188762306a36Sopenharmony_ci	}
188862306a36Sopenharmony_ci	/* Cleanup will be performed by the caller (queuecommand) */
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	qla_put_fw_resources(sp->qpair, &sp->iores);
189162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
189462306a36Sopenharmony_ci}
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci/**
189762306a36Sopenharmony_ci * qla2xxx_start_scsi_mq() - Send a SCSI command to the ISP
189862306a36Sopenharmony_ci * @sp: command to send to the ISP
189962306a36Sopenharmony_ci *
190062306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero.
190162306a36Sopenharmony_ci */
190262306a36Sopenharmony_cistatic int
190362306a36Sopenharmony_ciqla2xxx_start_scsi_mq(srb_t *sp)
190462306a36Sopenharmony_ci{
190562306a36Sopenharmony_ci	int		nseg;
190662306a36Sopenharmony_ci	unsigned long   flags;
190762306a36Sopenharmony_ci	uint32_t	*clr_ptr;
190862306a36Sopenharmony_ci	uint32_t	handle;
190962306a36Sopenharmony_ci	struct cmd_type_7 *cmd_pkt;
191062306a36Sopenharmony_ci	uint16_t	cnt;
191162306a36Sopenharmony_ci	uint16_t	req_cnt;
191262306a36Sopenharmony_ci	uint16_t	tot_dsds;
191362306a36Sopenharmony_ci	struct req_que *req = NULL;
191462306a36Sopenharmony_ci	struct rsp_que *rsp;
191562306a36Sopenharmony_ci	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
191662306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->fcport->vha;
191762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
191862306a36Sopenharmony_ci	struct qla_qpair *qpair = sp->qpair;
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	if (sp->fcport->edif.enable && (sp->fcport->flags & FCF_FCSP_DEVICE))
192162306a36Sopenharmony_ci		return qla28xx_start_scsi_edif(sp);
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	/* Acquire qpair specific lock */
192462306a36Sopenharmony_ci	spin_lock_irqsave(&qpair->qp_lock, flags);
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	/* Setup qpair pointers */
192762306a36Sopenharmony_ci	req = qpair->req;
192862306a36Sopenharmony_ci	rsp = qpair->rsp;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	/* So we know we haven't pci_map'ed anything yet */
193162306a36Sopenharmony_ci	tot_dsds = 0;
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	/* Send marker if required */
193462306a36Sopenharmony_ci	if (vha->marker_needed != 0) {
193562306a36Sopenharmony_ci		if (__qla2x00_marker(vha, qpair, 0, 0, MK_SYNC_ALL) !=
193662306a36Sopenharmony_ci		    QLA_SUCCESS) {
193762306a36Sopenharmony_ci			spin_unlock_irqrestore(&qpair->qp_lock, flags);
193862306a36Sopenharmony_ci			return QLA_FUNCTION_FAILED;
193962306a36Sopenharmony_ci		}
194062306a36Sopenharmony_ci		vha->marker_needed = 0;
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	handle = qla2xxx_get_next_handle(req);
194462306a36Sopenharmony_ci	if (handle == 0)
194562306a36Sopenharmony_ci		goto queuing_error;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	/* Map the sg table so we have an accurate count of sg entries needed */
194862306a36Sopenharmony_ci	if (scsi_sg_count(cmd)) {
194962306a36Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
195062306a36Sopenharmony_ci		    scsi_sg_count(cmd), cmd->sc_data_direction);
195162306a36Sopenharmony_ci		if (unlikely(!nseg))
195262306a36Sopenharmony_ci			goto queuing_error;
195362306a36Sopenharmony_ci	} else
195462306a36Sopenharmony_ci		nseg = 0;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	tot_dsds = nseg;
195762306a36Sopenharmony_ci	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
196062306a36Sopenharmony_ci	sp->iores.exch_cnt = 1;
196162306a36Sopenharmony_ci	sp->iores.iocb_cnt = req_cnt;
196262306a36Sopenharmony_ci	if (qla_get_fw_resources(sp->qpair, &sp->iores))
196362306a36Sopenharmony_ci		goto queuing_error;
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	if (req->cnt < (req_cnt + 2)) {
196662306a36Sopenharmony_ci		if (IS_SHADOW_REG_CAPABLE(ha)) {
196762306a36Sopenharmony_ci			cnt = *req->out_ptr;
196862306a36Sopenharmony_ci		} else {
196962306a36Sopenharmony_ci			cnt = rd_reg_dword_relaxed(req->req_q_out);
197062306a36Sopenharmony_ci			if (qla2x00_check_reg16_for_disconnect(vha, cnt))
197162306a36Sopenharmony_ci				goto queuing_error;
197262306a36Sopenharmony_ci		}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci		if (req->ring_index < cnt)
197562306a36Sopenharmony_ci			req->cnt = cnt - req->ring_index;
197662306a36Sopenharmony_ci		else
197762306a36Sopenharmony_ci			req->cnt = req->length -
197862306a36Sopenharmony_ci				(req->ring_index - cnt);
197962306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2))
198062306a36Sopenharmony_ci			goto queuing_error;
198162306a36Sopenharmony_ci	}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	/* Build command packet. */
198462306a36Sopenharmony_ci	req->current_outstanding_cmd = handle;
198562306a36Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
198662306a36Sopenharmony_ci	sp->handle = handle;
198762306a36Sopenharmony_ci	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
198862306a36Sopenharmony_ci	req->cnt -= req_cnt;
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
199162306a36Sopenharmony_ci	cmd_pkt->handle = make_handle(req->id, handle);
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	/* Zero out remaining portion of packet. */
199462306a36Sopenharmony_ci	/*    tagged queuing modifier -- default is TSK_SIMPLE (0). */
199562306a36Sopenharmony_ci	clr_ptr = (uint32_t *)cmd_pkt + 2;
199662306a36Sopenharmony_ci	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
199762306a36Sopenharmony_ci	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	/* Set NPORT-ID and LUN number*/
200062306a36Sopenharmony_ci	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
200162306a36Sopenharmony_ci	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
200262306a36Sopenharmony_ci	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
200362306a36Sopenharmony_ci	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
200462306a36Sopenharmony_ci	cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
200762306a36Sopenharmony_ci	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	cmd_pkt->task = TSK_SIMPLE;
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	/* Load SCSI command packet. */
201262306a36Sopenharmony_ci	memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
201362306a36Sopenharmony_ci	host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	/* Build IOCB segments */
201862306a36Sopenharmony_ci	qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req);
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	/* Set total data segment count. */
202162306a36Sopenharmony_ci	cmd_pkt->entry_count = (uint8_t)req_cnt;
202262306a36Sopenharmony_ci	wmb();
202362306a36Sopenharmony_ci	/* Adjust ring index. */
202462306a36Sopenharmony_ci	req->ring_index++;
202562306a36Sopenharmony_ci	if (req->ring_index == req->length) {
202662306a36Sopenharmony_ci		req->ring_index = 0;
202762306a36Sopenharmony_ci		req->ring_ptr = req->ring;
202862306a36Sopenharmony_ci	} else
202962306a36Sopenharmony_ci		req->ring_ptr++;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	sp->qpair->cmd_cnt++;
203262306a36Sopenharmony_ci	sp->flags |= SRB_DMA_VALID;
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	/* Set chip new ring index. */
203562306a36Sopenharmony_ci	wrt_reg_dword(req->req_q_in, req->ring_index);
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	/* Manage unprocessed RIO/ZIO commands in response queue. */
203862306a36Sopenharmony_ci	if (vha->flags.process_response_queue &&
203962306a36Sopenharmony_ci	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
204062306a36Sopenharmony_ci		qla24xx_process_response_queue(vha, rsp);
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	spin_unlock_irqrestore(&qpair->qp_lock, flags);
204362306a36Sopenharmony_ci	return QLA_SUCCESS;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ciqueuing_error:
204662306a36Sopenharmony_ci	if (tot_dsds)
204762306a36Sopenharmony_ci		scsi_dma_unmap(cmd);
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	qla_put_fw_resources(sp->qpair, &sp->iores);
205062306a36Sopenharmony_ci	spin_unlock_irqrestore(&qpair->qp_lock, flags);
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
205362306a36Sopenharmony_ci}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci/**
205762306a36Sopenharmony_ci * qla2xxx_dif_start_scsi_mq() - Send a SCSI command to the ISP
205862306a36Sopenharmony_ci * @sp: command to send to the ISP
205962306a36Sopenharmony_ci *
206062306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero.
206162306a36Sopenharmony_ci */
206262306a36Sopenharmony_ciint
206362306a36Sopenharmony_ciqla2xxx_dif_start_scsi_mq(srb_t *sp)
206462306a36Sopenharmony_ci{
206562306a36Sopenharmony_ci	int			nseg;
206662306a36Sopenharmony_ci	unsigned long		flags;
206762306a36Sopenharmony_ci	uint32_t		*clr_ptr;
206862306a36Sopenharmony_ci	uint32_t		handle;
206962306a36Sopenharmony_ci	uint16_t		cnt;
207062306a36Sopenharmony_ci	uint16_t		req_cnt = 0;
207162306a36Sopenharmony_ci	uint16_t		tot_dsds;
207262306a36Sopenharmony_ci	uint16_t		tot_prot_dsds;
207362306a36Sopenharmony_ci	uint16_t		fw_prot_opts = 0;
207462306a36Sopenharmony_ci	struct req_que		*req = NULL;
207562306a36Sopenharmony_ci	struct rsp_que		*rsp = NULL;
207662306a36Sopenharmony_ci	struct scsi_cmnd	*cmd = GET_CMD_SP(sp);
207762306a36Sopenharmony_ci	struct scsi_qla_host	*vha = sp->fcport->vha;
207862306a36Sopenharmony_ci	struct qla_hw_data	*ha = vha->hw;
207962306a36Sopenharmony_ci	struct cmd_type_crc_2	*cmd_pkt;
208062306a36Sopenharmony_ci	uint32_t		status = 0;
208162306a36Sopenharmony_ci	struct qla_qpair	*qpair = sp->qpair;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci#define QDSS_GOT_Q_SPACE	BIT_0
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	/* Check for host side state */
208662306a36Sopenharmony_ci	if (!qpair->online) {
208762306a36Sopenharmony_ci		cmd->result = DID_NO_CONNECT << 16;
208862306a36Sopenharmony_ci		return QLA_INTERFACE_ERROR;
208962306a36Sopenharmony_ci	}
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	if (!qpair->difdix_supported &&
209262306a36Sopenharmony_ci		scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
209362306a36Sopenharmony_ci		cmd->result = DID_NO_CONNECT << 16;
209462306a36Sopenharmony_ci		return QLA_INTERFACE_ERROR;
209562306a36Sopenharmony_ci	}
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	/* Only process protection or >16 cdb in this routine */
209862306a36Sopenharmony_ci	if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) {
209962306a36Sopenharmony_ci		if (cmd->cmd_len <= 16)
210062306a36Sopenharmony_ci			return qla2xxx_start_scsi_mq(sp);
210162306a36Sopenharmony_ci		else
210262306a36Sopenharmony_ci			return qla_start_scsi_type6(sp);
210362306a36Sopenharmony_ci	}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	spin_lock_irqsave(&qpair->qp_lock, flags);
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	/* Setup qpair pointers */
210862306a36Sopenharmony_ci	rsp = qpair->rsp;
210962306a36Sopenharmony_ci	req = qpair->req;
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	/* So we know we haven't pci_map'ed anything yet */
211262306a36Sopenharmony_ci	tot_dsds = 0;
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	/* Send marker if required */
211562306a36Sopenharmony_ci	if (vha->marker_needed != 0) {
211662306a36Sopenharmony_ci		if (__qla2x00_marker(vha, qpair, 0, 0, MK_SYNC_ALL) !=
211762306a36Sopenharmony_ci		    QLA_SUCCESS) {
211862306a36Sopenharmony_ci			spin_unlock_irqrestore(&qpair->qp_lock, flags);
211962306a36Sopenharmony_ci			return QLA_FUNCTION_FAILED;
212062306a36Sopenharmony_ci		}
212162306a36Sopenharmony_ci		vha->marker_needed = 0;
212262306a36Sopenharmony_ci	}
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	handle = qla2xxx_get_next_handle(req);
212562306a36Sopenharmony_ci	if (handle == 0)
212662306a36Sopenharmony_ci		goto queuing_error;
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	/* Compute number of required data segments */
212962306a36Sopenharmony_ci	/* Map the sg table so we have an accurate count of sg entries needed */
213062306a36Sopenharmony_ci	if (scsi_sg_count(cmd)) {
213162306a36Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
213262306a36Sopenharmony_ci		    scsi_sg_count(cmd), cmd->sc_data_direction);
213362306a36Sopenharmony_ci		if (unlikely(!nseg))
213462306a36Sopenharmony_ci			goto queuing_error;
213562306a36Sopenharmony_ci		else
213662306a36Sopenharmony_ci			sp->flags |= SRB_DMA_VALID;
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci		if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) ||
213962306a36Sopenharmony_ci		    (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) {
214062306a36Sopenharmony_ci			struct qla2_sgx sgx;
214162306a36Sopenharmony_ci			uint32_t	partial;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci			memset(&sgx, 0, sizeof(struct qla2_sgx));
214462306a36Sopenharmony_ci			sgx.tot_bytes = scsi_bufflen(cmd);
214562306a36Sopenharmony_ci			sgx.cur_sg = scsi_sglist(cmd);
214662306a36Sopenharmony_ci			sgx.sp = sp;
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci			nseg = 0;
214962306a36Sopenharmony_ci			while (qla24xx_get_one_block_sg(
215062306a36Sopenharmony_ci			    cmd->device->sector_size, &sgx, &partial))
215162306a36Sopenharmony_ci				nseg++;
215262306a36Sopenharmony_ci		}
215362306a36Sopenharmony_ci	} else
215462306a36Sopenharmony_ci		nseg = 0;
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	/* number of required data segments */
215762306a36Sopenharmony_ci	tot_dsds = nseg;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	/* Compute number of required protection segments */
216062306a36Sopenharmony_ci	if (qla24xx_configure_prot_mode(sp, &fw_prot_opts)) {
216162306a36Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_prot_sglist(cmd),
216262306a36Sopenharmony_ci		    scsi_prot_sg_count(cmd), cmd->sc_data_direction);
216362306a36Sopenharmony_ci		if (unlikely(!nseg))
216462306a36Sopenharmony_ci			goto queuing_error;
216562306a36Sopenharmony_ci		else
216662306a36Sopenharmony_ci			sp->flags |= SRB_CRC_PROT_DMA_VALID;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci		if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) ||
216962306a36Sopenharmony_ci		    (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) {
217062306a36Sopenharmony_ci			nseg = scsi_bufflen(cmd) / cmd->device->sector_size;
217162306a36Sopenharmony_ci		}
217262306a36Sopenharmony_ci	} else {
217362306a36Sopenharmony_ci		nseg = 0;
217462306a36Sopenharmony_ci	}
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	req_cnt = 1;
217762306a36Sopenharmony_ci	/* Total Data and protection sg segment(s) */
217862306a36Sopenharmony_ci	tot_prot_dsds = nseg;
217962306a36Sopenharmony_ci	tot_dsds += nseg;
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
218262306a36Sopenharmony_ci	sp->iores.exch_cnt = 1;
218362306a36Sopenharmony_ci	sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
218462306a36Sopenharmony_ci	if (qla_get_fw_resources(sp->qpair, &sp->iores))
218562306a36Sopenharmony_ci		goto queuing_error;
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	if (req->cnt < (req_cnt + 2)) {
218862306a36Sopenharmony_ci		if (IS_SHADOW_REG_CAPABLE(ha)) {
218962306a36Sopenharmony_ci			cnt = *req->out_ptr;
219062306a36Sopenharmony_ci		} else {
219162306a36Sopenharmony_ci			cnt = rd_reg_dword_relaxed(req->req_q_out);
219262306a36Sopenharmony_ci			if (qla2x00_check_reg16_for_disconnect(vha, cnt))
219362306a36Sopenharmony_ci				goto queuing_error;
219462306a36Sopenharmony_ci		}
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci		if (req->ring_index < cnt)
219762306a36Sopenharmony_ci			req->cnt = cnt - req->ring_index;
219862306a36Sopenharmony_ci		else
219962306a36Sopenharmony_ci			req->cnt = req->length -
220062306a36Sopenharmony_ci				(req->ring_index - cnt);
220162306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2))
220262306a36Sopenharmony_ci			goto queuing_error;
220362306a36Sopenharmony_ci	}
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	status |= QDSS_GOT_Q_SPACE;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	/* Build header part of command packet (excluding the OPCODE). */
220862306a36Sopenharmony_ci	req->current_outstanding_cmd = handle;
220962306a36Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
221062306a36Sopenharmony_ci	sp->handle = handle;
221162306a36Sopenharmony_ci	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
221262306a36Sopenharmony_ci	req->cnt -= req_cnt;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	/* Fill-in common area */
221562306a36Sopenharmony_ci	cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr;
221662306a36Sopenharmony_ci	cmd_pkt->handle = make_handle(req->id, handle);
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	clr_ptr = (uint32_t *)cmd_pkt + 2;
221962306a36Sopenharmony_ci	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	/* Set NPORT-ID and LUN number*/
222262306a36Sopenharmony_ci	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
222362306a36Sopenharmony_ci	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
222462306a36Sopenharmony_ci	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
222562306a36Sopenharmony_ci	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
222862306a36Sopenharmony_ci	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	/* Total Data and protection segment(s) */
223162306a36Sopenharmony_ci	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	/* Build IOCB segments and adjust for data protection segments */
223462306a36Sopenharmony_ci	if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *)
223562306a36Sopenharmony_ci	    req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) !=
223662306a36Sopenharmony_ci		QLA_SUCCESS)
223762306a36Sopenharmony_ci		goto queuing_error;
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	cmd_pkt->entry_count = (uint8_t)req_cnt;
224062306a36Sopenharmony_ci	cmd_pkt->timeout = cpu_to_le16(0);
224162306a36Sopenharmony_ci	wmb();
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	/* Adjust ring index. */
224462306a36Sopenharmony_ci	req->ring_index++;
224562306a36Sopenharmony_ci	if (req->ring_index == req->length) {
224662306a36Sopenharmony_ci		req->ring_index = 0;
224762306a36Sopenharmony_ci		req->ring_ptr = req->ring;
224862306a36Sopenharmony_ci	} else
224962306a36Sopenharmony_ci		req->ring_ptr++;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	sp->qpair->cmd_cnt++;
225262306a36Sopenharmony_ci	/* Set chip new ring index. */
225362306a36Sopenharmony_ci	wrt_reg_dword(req->req_q_in, req->ring_index);
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	/* Manage unprocessed RIO/ZIO commands in response queue. */
225662306a36Sopenharmony_ci	if (vha->flags.process_response_queue &&
225762306a36Sopenharmony_ci	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
225862306a36Sopenharmony_ci		qla24xx_process_response_queue(vha, rsp);
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	spin_unlock_irqrestore(&qpair->qp_lock, flags);
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	return QLA_SUCCESS;
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_ciqueuing_error:
226562306a36Sopenharmony_ci	if (status & QDSS_GOT_Q_SPACE) {
226662306a36Sopenharmony_ci		req->outstanding_cmds[handle] = NULL;
226762306a36Sopenharmony_ci		req->cnt += req_cnt;
226862306a36Sopenharmony_ci	}
226962306a36Sopenharmony_ci	/* Cleanup will be performed by the caller (queuecommand) */
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	qla_put_fw_resources(sp->qpair, &sp->iores);
227262306a36Sopenharmony_ci	spin_unlock_irqrestore(&qpair->qp_lock, flags);
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
227562306a36Sopenharmony_ci}
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci/* Generic Control-SRB manipulation functions. */
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci/* hardware_lock assumed to be held. */
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_civoid *
228262306a36Sopenharmony_ci__qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp)
228362306a36Sopenharmony_ci{
228462306a36Sopenharmony_ci	scsi_qla_host_t *vha = qpair->vha;
228562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
228662306a36Sopenharmony_ci	struct req_que *req = qpair->req;
228762306a36Sopenharmony_ci	device_reg_t *reg = ISP_QUE_REG(ha, req->id);
228862306a36Sopenharmony_ci	uint32_t handle;
228962306a36Sopenharmony_ci	request_t *pkt;
229062306a36Sopenharmony_ci	uint16_t cnt, req_cnt;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	pkt = NULL;
229362306a36Sopenharmony_ci	req_cnt = 1;
229462306a36Sopenharmony_ci	handle = 0;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	if (sp && (sp->type != SRB_SCSI_CMD)) {
229762306a36Sopenharmony_ci		/* Adjust entry-counts as needed. */
229862306a36Sopenharmony_ci		req_cnt = sp->iocbs;
229962306a36Sopenharmony_ci	}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	/* Check for room on request queue. */
230262306a36Sopenharmony_ci	if (req->cnt < req_cnt + 2) {
230362306a36Sopenharmony_ci		if (qpair->use_shadow_reg)
230462306a36Sopenharmony_ci			cnt = *req->out_ptr;
230562306a36Sopenharmony_ci		else if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
230662306a36Sopenharmony_ci		    IS_QLA28XX(ha))
230762306a36Sopenharmony_ci			cnt = rd_reg_dword(&reg->isp25mq.req_q_out);
230862306a36Sopenharmony_ci		else if (IS_P3P_TYPE(ha))
230962306a36Sopenharmony_ci			cnt = rd_reg_dword(reg->isp82.req_q_out);
231062306a36Sopenharmony_ci		else if (IS_FWI2_CAPABLE(ha))
231162306a36Sopenharmony_ci			cnt = rd_reg_dword(&reg->isp24.req_q_out);
231262306a36Sopenharmony_ci		else if (IS_QLAFX00(ha))
231362306a36Sopenharmony_ci			cnt = rd_reg_dword(&reg->ispfx00.req_q_out);
231462306a36Sopenharmony_ci		else
231562306a36Sopenharmony_ci			cnt = qla2x00_debounce_register(
231662306a36Sopenharmony_ci			    ISP_REQ_Q_OUT(ha, &reg->isp));
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci		if (!qpair->use_shadow_reg && cnt == ISP_REG16_DISCONNECT) {
231962306a36Sopenharmony_ci			qla_schedule_eeh_work(vha);
232062306a36Sopenharmony_ci			return NULL;
232162306a36Sopenharmony_ci		}
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci		if  (req->ring_index < cnt)
232462306a36Sopenharmony_ci			req->cnt = cnt - req->ring_index;
232562306a36Sopenharmony_ci		else
232662306a36Sopenharmony_ci			req->cnt = req->length -
232762306a36Sopenharmony_ci			    (req->ring_index - cnt);
232862306a36Sopenharmony_ci	}
232962306a36Sopenharmony_ci	if (req->cnt < req_cnt + 2)
233062306a36Sopenharmony_ci		goto queuing_error;
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	if (sp) {
233362306a36Sopenharmony_ci		handle = qla2xxx_get_next_handle(req);
233462306a36Sopenharmony_ci		if (handle == 0) {
233562306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x700b,
233662306a36Sopenharmony_ci			    "No room on outstanding cmd array.\n");
233762306a36Sopenharmony_ci			goto queuing_error;
233862306a36Sopenharmony_ci		}
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci		/* Prep command array. */
234162306a36Sopenharmony_ci		req->current_outstanding_cmd = handle;
234262306a36Sopenharmony_ci		req->outstanding_cmds[handle] = sp;
234362306a36Sopenharmony_ci		sp->handle = handle;
234462306a36Sopenharmony_ci	}
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	/* Prep packet */
234762306a36Sopenharmony_ci	req->cnt -= req_cnt;
234862306a36Sopenharmony_ci	pkt = req->ring_ptr;
234962306a36Sopenharmony_ci	memset(pkt, 0, REQUEST_ENTRY_SIZE);
235062306a36Sopenharmony_ci	if (IS_QLAFX00(ha)) {
235162306a36Sopenharmony_ci		wrt_reg_byte((u8 __force __iomem *)&pkt->entry_count, req_cnt);
235262306a36Sopenharmony_ci		wrt_reg_dword((__le32 __force __iomem *)&pkt->handle, handle);
235362306a36Sopenharmony_ci	} else {
235462306a36Sopenharmony_ci		pkt->entry_count = req_cnt;
235562306a36Sopenharmony_ci		pkt->handle = handle;
235662306a36Sopenharmony_ci	}
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci	return pkt;
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ciqueuing_error:
236162306a36Sopenharmony_ci	qpair->tgt_counters.num_alloc_iocb_failed++;
236262306a36Sopenharmony_ci	return pkt;
236362306a36Sopenharmony_ci}
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_civoid *
236662306a36Sopenharmony_ciqla2x00_alloc_iocbs_ready(struct qla_qpair *qpair, srb_t *sp)
236762306a36Sopenharmony_ci{
236862306a36Sopenharmony_ci	scsi_qla_host_t *vha = qpair->vha;
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	if (qla2x00_reset_active(vha))
237162306a36Sopenharmony_ci		return NULL;
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci	return __qla2x00_alloc_iocbs(qpair, sp);
237462306a36Sopenharmony_ci}
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_civoid *
237762306a36Sopenharmony_ciqla2x00_alloc_iocbs(struct scsi_qla_host *vha, srb_t *sp)
237862306a36Sopenharmony_ci{
237962306a36Sopenharmony_ci	return __qla2x00_alloc_iocbs(vha->hw->base_qpair, sp);
238062306a36Sopenharmony_ci}
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_cistatic void
238362306a36Sopenharmony_ciqla24xx_prli_iocb(srb_t *sp, struct logio_entry_24xx *logio)
238462306a36Sopenharmony_ci{
238562306a36Sopenharmony_ci	struct srb_iocb *lio = &sp->u.iocb_cmd;
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
238862306a36Sopenharmony_ci	logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI);
238962306a36Sopenharmony_ci	if (lio->u.logio.flags & SRB_LOGIN_NVME_PRLI) {
239062306a36Sopenharmony_ci		logio->control_flags |= cpu_to_le16(LCF_NVME_PRLI);
239162306a36Sopenharmony_ci		if (sp->vha->flags.nvme_first_burst)
239262306a36Sopenharmony_ci			logio->io_parameter[0] =
239362306a36Sopenharmony_ci				cpu_to_le32(NVME_PRLI_SP_FIRST_BURST);
239462306a36Sopenharmony_ci		if (sp->vha->flags.nvme2_enabled) {
239562306a36Sopenharmony_ci			/* Set service parameter BIT_7 for NVME CONF support */
239662306a36Sopenharmony_ci			logio->io_parameter[0] |=
239762306a36Sopenharmony_ci				cpu_to_le32(NVME_PRLI_SP_CONF);
239862306a36Sopenharmony_ci			/* Set service parameter BIT_8 for SLER support */
239962306a36Sopenharmony_ci			logio->io_parameter[0] |=
240062306a36Sopenharmony_ci				cpu_to_le32(NVME_PRLI_SP_SLER);
240162306a36Sopenharmony_ci			/* Set service parameter BIT_9 for PI control support */
240262306a36Sopenharmony_ci			logio->io_parameter[0] |=
240362306a36Sopenharmony_ci				cpu_to_le32(NVME_PRLI_SP_PI_CTRL);
240462306a36Sopenharmony_ci		}
240562306a36Sopenharmony_ci	}
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci	logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
240862306a36Sopenharmony_ci	logio->port_id[0] = sp->fcport->d_id.b.al_pa;
240962306a36Sopenharmony_ci	logio->port_id[1] = sp->fcport->d_id.b.area;
241062306a36Sopenharmony_ci	logio->port_id[2] = sp->fcport->d_id.b.domain;
241162306a36Sopenharmony_ci	logio->vp_index = sp->vha->vp_idx;
241262306a36Sopenharmony_ci}
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_cistatic void
241562306a36Sopenharmony_ciqla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)
241662306a36Sopenharmony_ci{
241762306a36Sopenharmony_ci	struct srb_iocb *lio = &sp->u.iocb_cmd;
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
242062306a36Sopenharmony_ci	logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI);
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	if (lio->u.logio.flags & SRB_LOGIN_PRLI_ONLY) {
242362306a36Sopenharmony_ci		logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI);
242462306a36Sopenharmony_ci	} else {
242562306a36Sopenharmony_ci		logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI);
242662306a36Sopenharmony_ci		if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI)
242762306a36Sopenharmony_ci			logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI);
242862306a36Sopenharmony_ci		if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI)
242962306a36Sopenharmony_ci			logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI);
243062306a36Sopenharmony_ci		if (lio->u.logio.flags & SRB_LOGIN_FCSP) {
243162306a36Sopenharmony_ci			logio->control_flags |=
243262306a36Sopenharmony_ci			    cpu_to_le16(LCF_COMMON_FEAT | LCF_SKIP_PRLI);
243362306a36Sopenharmony_ci			logio->io_parameter[0] =
243462306a36Sopenharmony_ci			    cpu_to_le32(LIO_COMM_FEAT_FCSP | LIO_COMM_FEAT_CIO);
243562306a36Sopenharmony_ci		}
243662306a36Sopenharmony_ci	}
243762306a36Sopenharmony_ci	logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
243862306a36Sopenharmony_ci	logio->port_id[0] = sp->fcport->d_id.b.al_pa;
243962306a36Sopenharmony_ci	logio->port_id[1] = sp->fcport->d_id.b.area;
244062306a36Sopenharmony_ci	logio->port_id[2] = sp->fcport->d_id.b.domain;
244162306a36Sopenharmony_ci	logio->vp_index = sp->vha->vp_idx;
244262306a36Sopenharmony_ci}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_cistatic void
244562306a36Sopenharmony_ciqla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx)
244662306a36Sopenharmony_ci{
244762306a36Sopenharmony_ci	struct qla_hw_data *ha = sp->vha->hw;
244862306a36Sopenharmony_ci	struct srb_iocb *lio = &sp->u.iocb_cmd;
244962306a36Sopenharmony_ci	uint16_t opts;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	mbx->entry_type = MBX_IOCB_TYPE;
245262306a36Sopenharmony_ci	SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
245362306a36Sopenharmony_ci	mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT);
245462306a36Sopenharmony_ci	opts = lio->u.logio.flags & SRB_LOGIN_COND_PLOGI ? BIT_0 : 0;
245562306a36Sopenharmony_ci	opts |= lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI ? BIT_1 : 0;
245662306a36Sopenharmony_ci	if (HAS_EXTENDED_IDS(ha)) {
245762306a36Sopenharmony_ci		mbx->mb1 = cpu_to_le16(sp->fcport->loop_id);
245862306a36Sopenharmony_ci		mbx->mb10 = cpu_to_le16(opts);
245962306a36Sopenharmony_ci	} else {
246062306a36Sopenharmony_ci		mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | opts);
246162306a36Sopenharmony_ci	}
246262306a36Sopenharmony_ci	mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain);
246362306a36Sopenharmony_ci	mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 |
246462306a36Sopenharmony_ci	    sp->fcport->d_id.b.al_pa);
246562306a36Sopenharmony_ci	mbx->mb9 = cpu_to_le16(sp->vha->vp_idx);
246662306a36Sopenharmony_ci}
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_cistatic void
246962306a36Sopenharmony_ciqla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio)
247062306a36Sopenharmony_ci{
247162306a36Sopenharmony_ci	u16 control_flags = LCF_COMMAND_LOGO;
247262306a36Sopenharmony_ci	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	if (sp->fcport->explicit_logout) {
247562306a36Sopenharmony_ci		control_flags |= LCF_EXPL_LOGO|LCF_FREE_NPORT;
247662306a36Sopenharmony_ci	} else {
247762306a36Sopenharmony_ci		control_flags |= LCF_IMPL_LOGO;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci		if (!sp->fcport->keep_nport_handle)
248062306a36Sopenharmony_ci			control_flags |= LCF_FREE_NPORT;
248162306a36Sopenharmony_ci	}
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	logio->control_flags = cpu_to_le16(control_flags);
248462306a36Sopenharmony_ci	logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
248562306a36Sopenharmony_ci	logio->port_id[0] = sp->fcport->d_id.b.al_pa;
248662306a36Sopenharmony_ci	logio->port_id[1] = sp->fcport->d_id.b.area;
248762306a36Sopenharmony_ci	logio->port_id[2] = sp->fcport->d_id.b.domain;
248862306a36Sopenharmony_ci	logio->vp_index = sp->vha->vp_idx;
248962306a36Sopenharmony_ci}
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_cistatic void
249262306a36Sopenharmony_ciqla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx)
249362306a36Sopenharmony_ci{
249462306a36Sopenharmony_ci	struct qla_hw_data *ha = sp->vha->hw;
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	mbx->entry_type = MBX_IOCB_TYPE;
249762306a36Sopenharmony_ci	SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
249862306a36Sopenharmony_ci	mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT);
249962306a36Sopenharmony_ci	mbx->mb1 = HAS_EXTENDED_IDS(ha) ?
250062306a36Sopenharmony_ci	    cpu_to_le16(sp->fcport->loop_id) :
250162306a36Sopenharmony_ci	    cpu_to_le16(sp->fcport->loop_id << 8);
250262306a36Sopenharmony_ci	mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain);
250362306a36Sopenharmony_ci	mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 |
250462306a36Sopenharmony_ci	    sp->fcport->d_id.b.al_pa);
250562306a36Sopenharmony_ci	mbx->mb9 = cpu_to_le16(sp->vha->vp_idx);
250662306a36Sopenharmony_ci	/* Implicit: mbx->mbx10 = 0. */
250762306a36Sopenharmony_ci}
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_cistatic void
251062306a36Sopenharmony_ciqla24xx_adisc_iocb(srb_t *sp, struct logio_entry_24xx *logio)
251162306a36Sopenharmony_ci{
251262306a36Sopenharmony_ci	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
251362306a36Sopenharmony_ci	logio->control_flags = cpu_to_le16(LCF_COMMAND_ADISC);
251462306a36Sopenharmony_ci	logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
251562306a36Sopenharmony_ci	logio->vp_index = sp->vha->vp_idx;
251662306a36Sopenharmony_ci}
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_cistatic void
251962306a36Sopenharmony_ciqla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx)
252062306a36Sopenharmony_ci{
252162306a36Sopenharmony_ci	struct qla_hw_data *ha = sp->vha->hw;
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	mbx->entry_type = MBX_IOCB_TYPE;
252462306a36Sopenharmony_ci	SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
252562306a36Sopenharmony_ci	mbx->mb0 = cpu_to_le16(MBC_GET_PORT_DATABASE);
252662306a36Sopenharmony_ci	if (HAS_EXTENDED_IDS(ha)) {
252762306a36Sopenharmony_ci		mbx->mb1 = cpu_to_le16(sp->fcport->loop_id);
252862306a36Sopenharmony_ci		mbx->mb10 = cpu_to_le16(BIT_0);
252962306a36Sopenharmony_ci	} else {
253062306a36Sopenharmony_ci		mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | BIT_0);
253162306a36Sopenharmony_ci	}
253262306a36Sopenharmony_ci	mbx->mb2 = cpu_to_le16(MSW(ha->async_pd_dma));
253362306a36Sopenharmony_ci	mbx->mb3 = cpu_to_le16(LSW(ha->async_pd_dma));
253462306a36Sopenharmony_ci	mbx->mb6 = cpu_to_le16(MSW(MSD(ha->async_pd_dma)));
253562306a36Sopenharmony_ci	mbx->mb7 = cpu_to_le16(LSW(MSD(ha->async_pd_dma)));
253662306a36Sopenharmony_ci	mbx->mb9 = cpu_to_le16(sp->vha->vp_idx);
253762306a36Sopenharmony_ci}
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_cistatic void
254062306a36Sopenharmony_ciqla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
254162306a36Sopenharmony_ci{
254262306a36Sopenharmony_ci	uint32_t flags;
254362306a36Sopenharmony_ci	uint64_t lun;
254462306a36Sopenharmony_ci	struct fc_port *fcport = sp->fcport;
254562306a36Sopenharmony_ci	scsi_qla_host_t *vha = fcport->vha;
254662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
254762306a36Sopenharmony_ci	struct srb_iocb *iocb = &sp->u.iocb_cmd;
254862306a36Sopenharmony_ci	struct req_que *req = sp->qpair->req;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	flags = iocb->u.tmf.flags;
255162306a36Sopenharmony_ci	lun = iocb->u.tmf.lun;
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	tsk->entry_type = TSK_MGMT_IOCB_TYPE;
255462306a36Sopenharmony_ci	tsk->entry_count = 1;
255562306a36Sopenharmony_ci	tsk->handle = make_handle(req->id, tsk->handle);
255662306a36Sopenharmony_ci	tsk->nport_handle = cpu_to_le16(fcport->loop_id);
255762306a36Sopenharmony_ci	tsk->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
255862306a36Sopenharmony_ci	tsk->control_flags = cpu_to_le32(flags);
255962306a36Sopenharmony_ci	tsk->port_id[0] = fcport->d_id.b.al_pa;
256062306a36Sopenharmony_ci	tsk->port_id[1] = fcport->d_id.b.area;
256162306a36Sopenharmony_ci	tsk->port_id[2] = fcport->d_id.b.domain;
256262306a36Sopenharmony_ci	tsk->vp_index = fcport->vha->vp_idx;
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci	if (flags & (TCF_LUN_RESET | TCF_ABORT_TASK_SET|
256562306a36Sopenharmony_ci	    TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
256662306a36Sopenharmony_ci		int_to_scsilun(lun, &tsk->lun);
256762306a36Sopenharmony_ci		host_to_fcp_swap((uint8_t *)&tsk->lun,
256862306a36Sopenharmony_ci			sizeof(tsk->lun));
256962306a36Sopenharmony_ci	}
257062306a36Sopenharmony_ci}
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_cistatic void
257362306a36Sopenharmony_ciqla2x00_async_done(struct srb *sp, int res)
257462306a36Sopenharmony_ci{
257562306a36Sopenharmony_ci	if (del_timer(&sp->u.iocb_cmd.timer)) {
257662306a36Sopenharmony_ci		/*
257762306a36Sopenharmony_ci		 * Successfully cancelled the timeout handler
257862306a36Sopenharmony_ci		 * ref: TMR
257962306a36Sopenharmony_ci		 */
258062306a36Sopenharmony_ci		if (kref_put(&sp->cmd_kref, qla2x00_sp_release))
258162306a36Sopenharmony_ci			return;
258262306a36Sopenharmony_ci	}
258362306a36Sopenharmony_ci	sp->async_done(sp, res);
258462306a36Sopenharmony_ci}
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_civoid
258762306a36Sopenharmony_ciqla2x00_sp_release(struct kref *kref)
258862306a36Sopenharmony_ci{
258962306a36Sopenharmony_ci	struct srb *sp = container_of(kref, struct srb, cmd_kref);
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	sp->free(sp);
259262306a36Sopenharmony_ci}
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_civoid
259562306a36Sopenharmony_ciqla2x00_init_async_sp(srb_t *sp, unsigned long tmo,
259662306a36Sopenharmony_ci		     void (*done)(struct srb *sp, int res))
259762306a36Sopenharmony_ci{
259862306a36Sopenharmony_ci	timer_setup(&sp->u.iocb_cmd.timer, qla2x00_sp_timeout, 0);
259962306a36Sopenharmony_ci	sp->done = qla2x00_async_done;
260062306a36Sopenharmony_ci	sp->async_done = done;
260162306a36Sopenharmony_ci	sp->free = qla2x00_sp_free;
260262306a36Sopenharmony_ci	sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout;
260362306a36Sopenharmony_ci	sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ;
260462306a36Sopenharmony_ci	if (IS_QLAFX00(sp->vha->hw) && sp->type == SRB_FXIOCB_DCMD)
260562306a36Sopenharmony_ci		init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
260662306a36Sopenharmony_ci	sp->start_timer = 1;
260762306a36Sopenharmony_ci}
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_cistatic void qla2x00_els_dcmd_sp_free(srb_t *sp)
261062306a36Sopenharmony_ci{
261162306a36Sopenharmony_ci	struct srb_iocb *elsio = &sp->u.iocb_cmd;
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	kfree(sp->fcport);
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci	if (elsio->u.els_logo.els_logo_pyld)
261662306a36Sopenharmony_ci		dma_free_coherent(&sp->vha->hw->pdev->dev, DMA_POOL_SIZE,
261762306a36Sopenharmony_ci		    elsio->u.els_logo.els_logo_pyld,
261862306a36Sopenharmony_ci		    elsio->u.els_logo.els_logo_pyld_dma);
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	del_timer(&elsio->timer);
262162306a36Sopenharmony_ci	qla2x00_rel_sp(sp);
262262306a36Sopenharmony_ci}
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_cistatic void
262562306a36Sopenharmony_ciqla2x00_els_dcmd_iocb_timeout(void *data)
262662306a36Sopenharmony_ci{
262762306a36Sopenharmony_ci	srb_t *sp = data;
262862306a36Sopenharmony_ci	fc_port_t *fcport = sp->fcport;
262962306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
263062306a36Sopenharmony_ci	struct srb_iocb *lio = &sp->u.iocb_cmd;
263162306a36Sopenharmony_ci	unsigned long flags = 0;
263262306a36Sopenharmony_ci	int res, h;
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x3069,
263562306a36Sopenharmony_ci	    "%s Timeout, hdl=%x, portid=%02x%02x%02x\n",
263662306a36Sopenharmony_ci	    sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area,
263762306a36Sopenharmony_ci	    fcport->d_id.b.al_pa);
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	/* Abort the exchange */
264062306a36Sopenharmony_ci	res = qla24xx_async_abort_cmd(sp, false);
264162306a36Sopenharmony_ci	if (res) {
264262306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3070,
264362306a36Sopenharmony_ci		    "mbx abort_command failed.\n");
264462306a36Sopenharmony_ci		spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
264562306a36Sopenharmony_ci		for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) {
264662306a36Sopenharmony_ci			if (sp->qpair->req->outstanding_cmds[h] == sp) {
264762306a36Sopenharmony_ci				sp->qpair->req->outstanding_cmds[h] = NULL;
264862306a36Sopenharmony_ci				break;
264962306a36Sopenharmony_ci			}
265062306a36Sopenharmony_ci		}
265162306a36Sopenharmony_ci		spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags);
265262306a36Sopenharmony_ci		complete(&lio->u.els_logo.comp);
265362306a36Sopenharmony_ci	} else {
265462306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3071,
265562306a36Sopenharmony_ci		    "mbx abort_command success.\n");
265662306a36Sopenharmony_ci	}
265762306a36Sopenharmony_ci}
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_cistatic void qla2x00_els_dcmd_sp_done(srb_t *sp, int res)
266062306a36Sopenharmony_ci{
266162306a36Sopenharmony_ci	fc_port_t *fcport = sp->fcport;
266262306a36Sopenharmony_ci	struct srb_iocb *lio = &sp->u.iocb_cmd;
266362306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x3072,
266662306a36Sopenharmony_ci	    "%s hdl=%x, portid=%02x%02x%02x done\n",
266762306a36Sopenharmony_ci	    sp->name, sp->handle, fcport->d_id.b.domain,
266862306a36Sopenharmony_ci	    fcport->d_id.b.area, fcport->d_id.b.al_pa);
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci	complete(&lio->u.els_logo.comp);
267162306a36Sopenharmony_ci}
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ciint
267462306a36Sopenharmony_ciqla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
267562306a36Sopenharmony_ci    port_id_t remote_did)
267662306a36Sopenharmony_ci{
267762306a36Sopenharmony_ci	srb_t *sp;
267862306a36Sopenharmony_ci	fc_port_t *fcport = NULL;
267962306a36Sopenharmony_ci	struct srb_iocb *elsio = NULL;
268062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
268162306a36Sopenharmony_ci	struct els_logo_payload logo_pyld;
268262306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci	fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
268562306a36Sopenharmony_ci	if (!fcport) {
268662306a36Sopenharmony_ci	       ql_log(ql_log_info, vha, 0x70e5, "fcport allocation failed\n");
268762306a36Sopenharmony_ci	       return -ENOMEM;
268862306a36Sopenharmony_ci	}
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	/* Alloc SRB structure
269162306a36Sopenharmony_ci	 * ref: INIT
269262306a36Sopenharmony_ci	 */
269362306a36Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
269462306a36Sopenharmony_ci	if (!sp) {
269562306a36Sopenharmony_ci		kfree(fcport);
269662306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x70e6,
269762306a36Sopenharmony_ci		 "SRB allocation failed\n");
269862306a36Sopenharmony_ci		return -ENOMEM;
269962306a36Sopenharmony_ci	}
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	elsio = &sp->u.iocb_cmd;
270262306a36Sopenharmony_ci	fcport->loop_id = 0xFFFF;
270362306a36Sopenharmony_ci	fcport->d_id.b.domain = remote_did.b.domain;
270462306a36Sopenharmony_ci	fcport->d_id.b.area = remote_did.b.area;
270562306a36Sopenharmony_ci	fcport->d_id.b.al_pa = remote_did.b.al_pa;
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x3073, "portid=%02x%02x%02x done\n",
270862306a36Sopenharmony_ci	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	sp->type = SRB_ELS_DCMD;
271162306a36Sopenharmony_ci	sp->name = "ELS_DCMD";
271262306a36Sopenharmony_ci	sp->fcport = fcport;
271362306a36Sopenharmony_ci	qla2x00_init_async_sp(sp, ELS_DCMD_TIMEOUT,
271462306a36Sopenharmony_ci			      qla2x00_els_dcmd_sp_done);
271562306a36Sopenharmony_ci	sp->free = qla2x00_els_dcmd_sp_free;
271662306a36Sopenharmony_ci	sp->u.iocb_cmd.timeout = qla2x00_els_dcmd_iocb_timeout;
271762306a36Sopenharmony_ci	init_completion(&sp->u.iocb_cmd.u.els_logo.comp);
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	elsio->u.els_logo.els_logo_pyld = dma_alloc_coherent(&ha->pdev->dev,
272062306a36Sopenharmony_ci			    DMA_POOL_SIZE, &elsio->u.els_logo.els_logo_pyld_dma,
272162306a36Sopenharmony_ci			    GFP_KERNEL);
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	if (!elsio->u.els_logo.els_logo_pyld) {
272462306a36Sopenharmony_ci		/* ref: INIT */
272562306a36Sopenharmony_ci		kref_put(&sp->cmd_kref, qla2x00_sp_release);
272662306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
272762306a36Sopenharmony_ci	}
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	memset(&logo_pyld, 0, sizeof(struct els_logo_payload));
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci	elsio->u.els_logo.els_cmd = els_opcode;
273262306a36Sopenharmony_ci	logo_pyld.opcode = els_opcode;
273362306a36Sopenharmony_ci	logo_pyld.s_id[0] = vha->d_id.b.al_pa;
273462306a36Sopenharmony_ci	logo_pyld.s_id[1] = vha->d_id.b.area;
273562306a36Sopenharmony_ci	logo_pyld.s_id[2] = vha->d_id.b.domain;
273662306a36Sopenharmony_ci	host_to_fcp_swap(logo_pyld.s_id, sizeof(uint32_t));
273762306a36Sopenharmony_ci	memcpy(&logo_pyld.wwpn, vha->port_name, WWN_SIZE);
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	memcpy(elsio->u.els_logo.els_logo_pyld, &logo_pyld,
274062306a36Sopenharmony_ci	    sizeof(struct els_logo_payload));
274162306a36Sopenharmony_ci	ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x3075, "LOGO buffer:");
274262306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x010a,
274362306a36Sopenharmony_ci		       elsio->u.els_logo.els_logo_pyld,
274462306a36Sopenharmony_ci		       sizeof(*elsio->u.els_logo.els_logo_pyld));
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci	rval = qla2x00_start_sp(sp);
274762306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
274862306a36Sopenharmony_ci		/* ref: INIT */
274962306a36Sopenharmony_ci		kref_put(&sp->cmd_kref, qla2x00_sp_release);
275062306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
275162306a36Sopenharmony_ci	}
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x3074,
275462306a36Sopenharmony_ci	    "%s LOGO sent, hdl=%x, loopid=%x, portid=%02x%02x%02x.\n",
275562306a36Sopenharmony_ci	    sp->name, sp->handle, fcport->loop_id, fcport->d_id.b.domain,
275662306a36Sopenharmony_ci	    fcport->d_id.b.area, fcport->d_id.b.al_pa);
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	wait_for_completion(&elsio->u.els_logo.comp);
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci	/* ref: INIT */
276162306a36Sopenharmony_ci	kref_put(&sp->cmd_kref, qla2x00_sp_release);
276262306a36Sopenharmony_ci	return rval;
276362306a36Sopenharmony_ci}
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_cistatic void
276662306a36Sopenharmony_ciqla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
276762306a36Sopenharmony_ci{
276862306a36Sopenharmony_ci	scsi_qla_host_t *vha = sp->vha;
276962306a36Sopenharmony_ci	struct srb_iocb *elsio = &sp->u.iocb_cmd;
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci	els_iocb->entry_type = ELS_IOCB_TYPE;
277262306a36Sopenharmony_ci	els_iocb->entry_count = 1;
277362306a36Sopenharmony_ci	els_iocb->sys_define = 0;
277462306a36Sopenharmony_ci	els_iocb->entry_status = 0;
277562306a36Sopenharmony_ci	els_iocb->handle = sp->handle;
277662306a36Sopenharmony_ci	els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
277762306a36Sopenharmony_ci	els_iocb->tx_dsd_count = cpu_to_le16(1);
277862306a36Sopenharmony_ci	els_iocb->vp_index = vha->vp_idx;
277962306a36Sopenharmony_ci	els_iocb->sof_type = EST_SOFI3;
278062306a36Sopenharmony_ci	els_iocb->rx_dsd_count = 0;
278162306a36Sopenharmony_ci	els_iocb->opcode = elsio->u.els_logo.els_cmd;
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	els_iocb->d_id[0] = sp->fcport->d_id.b.al_pa;
278462306a36Sopenharmony_ci	els_iocb->d_id[1] = sp->fcport->d_id.b.area;
278562306a36Sopenharmony_ci	els_iocb->d_id[2] = sp->fcport->d_id.b.domain;
278662306a36Sopenharmony_ci	/* For SID the byte order is different than DID */
278762306a36Sopenharmony_ci	els_iocb->s_id[1] = vha->d_id.b.al_pa;
278862306a36Sopenharmony_ci	els_iocb->s_id[2] = vha->d_id.b.area;
278962306a36Sopenharmony_ci	els_iocb->s_id[0] = vha->d_id.b.domain;
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci	if (elsio->u.els_logo.els_cmd == ELS_DCMD_PLOGI) {
279262306a36Sopenharmony_ci		if (vha->hw->flags.edif_enabled)
279362306a36Sopenharmony_ci			els_iocb->control_flags = cpu_to_le16(ECF_SEC_LOGIN);
279462306a36Sopenharmony_ci		else
279562306a36Sopenharmony_ci			els_iocb->control_flags = 0;
279662306a36Sopenharmony_ci		els_iocb->tx_byte_count = els_iocb->tx_len =
279762306a36Sopenharmony_ci			cpu_to_le32(sizeof(struct els_plogi_payload));
279862306a36Sopenharmony_ci		put_unaligned_le64(elsio->u.els_plogi.els_plogi_pyld_dma,
279962306a36Sopenharmony_ci				   &els_iocb->tx_address);
280062306a36Sopenharmony_ci		els_iocb->rx_dsd_count = cpu_to_le16(1);
280162306a36Sopenharmony_ci		els_iocb->rx_byte_count = els_iocb->rx_len =
280262306a36Sopenharmony_ci			cpu_to_le32(sizeof(struct els_plogi_payload));
280362306a36Sopenharmony_ci		put_unaligned_le64(elsio->u.els_plogi.els_resp_pyld_dma,
280462306a36Sopenharmony_ci				   &els_iocb->rx_address);
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci		ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073,
280762306a36Sopenharmony_ci		    "PLOGI ELS IOCB:\n");
280862306a36Sopenharmony_ci		ql_dump_buffer(ql_log_info, vha, 0x0109,
280962306a36Sopenharmony_ci		    (uint8_t *)els_iocb,
281062306a36Sopenharmony_ci		    sizeof(*els_iocb));
281162306a36Sopenharmony_ci	} else {
281262306a36Sopenharmony_ci		els_iocb->tx_byte_count =
281362306a36Sopenharmony_ci			cpu_to_le32(sizeof(struct els_logo_payload));
281462306a36Sopenharmony_ci		put_unaligned_le64(elsio->u.els_logo.els_logo_pyld_dma,
281562306a36Sopenharmony_ci				   &els_iocb->tx_address);
281662306a36Sopenharmony_ci		els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci		els_iocb->rx_byte_count = 0;
281962306a36Sopenharmony_ci		els_iocb->rx_address = 0;
282062306a36Sopenharmony_ci		els_iocb->rx_len = 0;
282162306a36Sopenharmony_ci		ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3076,
282262306a36Sopenharmony_ci		       "LOGO ELS IOCB:");
282362306a36Sopenharmony_ci		ql_dump_buffer(ql_log_info, vha, 0x010b,
282462306a36Sopenharmony_ci			       els_iocb,
282562306a36Sopenharmony_ci			       sizeof(*els_iocb));
282662306a36Sopenharmony_ci	}
282762306a36Sopenharmony_ci
282862306a36Sopenharmony_ci	sp->vha->qla_stats.control_requests++;
282962306a36Sopenharmony_ci}
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_civoid
283262306a36Sopenharmony_ciqla2x00_els_dcmd2_iocb_timeout(void *data)
283362306a36Sopenharmony_ci{
283462306a36Sopenharmony_ci	srb_t *sp = data;
283562306a36Sopenharmony_ci	fc_port_t *fcport = sp->fcport;
283662306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
283762306a36Sopenharmony_ci	unsigned long flags = 0;
283862306a36Sopenharmony_ci	int res, h;
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci	ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3069,
284162306a36Sopenharmony_ci	    "%s hdl=%x ELS Timeout, %8phC portid=%06x\n",
284262306a36Sopenharmony_ci	    sp->name, sp->handle, fcport->port_name, fcport->d_id.b24);
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	/* Abort the exchange */
284562306a36Sopenharmony_ci	res = qla24xx_async_abort_cmd(sp, false);
284662306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x3070,
284762306a36Sopenharmony_ci	    "mbx abort_command %s\n",
284862306a36Sopenharmony_ci	    (res == QLA_SUCCESS) ? "successful" : "failed");
284962306a36Sopenharmony_ci	if (res) {
285062306a36Sopenharmony_ci		spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
285162306a36Sopenharmony_ci		for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) {
285262306a36Sopenharmony_ci			if (sp->qpair->req->outstanding_cmds[h] == sp) {
285362306a36Sopenharmony_ci				sp->qpair->req->outstanding_cmds[h] = NULL;
285462306a36Sopenharmony_ci				break;
285562306a36Sopenharmony_ci			}
285662306a36Sopenharmony_ci		}
285762306a36Sopenharmony_ci		spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags);
285862306a36Sopenharmony_ci		sp->done(sp, QLA_FUNCTION_TIMEOUT);
285962306a36Sopenharmony_ci	}
286062306a36Sopenharmony_ci}
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_civoid qla2x00_els_dcmd2_free(scsi_qla_host_t *vha, struct els_plogi *els_plogi)
286362306a36Sopenharmony_ci{
286462306a36Sopenharmony_ci	if (els_plogi->els_plogi_pyld)
286562306a36Sopenharmony_ci		dma_free_coherent(&vha->hw->pdev->dev,
286662306a36Sopenharmony_ci				  els_plogi->tx_size,
286762306a36Sopenharmony_ci				  els_plogi->els_plogi_pyld,
286862306a36Sopenharmony_ci				  els_plogi->els_plogi_pyld_dma);
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	if (els_plogi->els_resp_pyld)
287162306a36Sopenharmony_ci		dma_free_coherent(&vha->hw->pdev->dev,
287262306a36Sopenharmony_ci				  els_plogi->rx_size,
287362306a36Sopenharmony_ci				  els_plogi->els_resp_pyld,
287462306a36Sopenharmony_ci				  els_plogi->els_resp_pyld_dma);
287562306a36Sopenharmony_ci}
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_cistatic void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res)
287862306a36Sopenharmony_ci{
287962306a36Sopenharmony_ci	fc_port_t *fcport = sp->fcport;
288062306a36Sopenharmony_ci	struct srb_iocb *lio = &sp->u.iocb_cmd;
288162306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
288262306a36Sopenharmony_ci	struct event_arg ea;
288362306a36Sopenharmony_ci	struct qla_work_evt *e;
288462306a36Sopenharmony_ci	struct fc_port *conflict_fcport;
288562306a36Sopenharmony_ci	port_id_t cid;	/* conflict Nport id */
288662306a36Sopenharmony_ci	const __le32 *fw_status = sp->u.iocb_cmd.u.els_plogi.fw_status;
288762306a36Sopenharmony_ci	u16 lid;
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci	ql_dbg(ql_dbg_disc, vha, 0x3072,
289062306a36Sopenharmony_ci	    "%s ELS done rc %d hdl=%x, portid=%06x %8phC\n",
289162306a36Sopenharmony_ci	    sp->name, res, sp->handle, fcport->d_id.b24, fcport->port_name);
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE);
289462306a36Sopenharmony_ci	/* For edif, set logout on delete to ensure any residual key from FW is flushed.*/
289562306a36Sopenharmony_ci	fcport->logout_on_delete = 1;
289662306a36Sopenharmony_ci	fcport->chip_reset = vha->hw->base_qpair->chip_reset;
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci	if (sp->flags & SRB_WAKEUP_ON_COMP)
289962306a36Sopenharmony_ci		complete(&lio->u.els_plogi.comp);
290062306a36Sopenharmony_ci	else {
290162306a36Sopenharmony_ci		switch (le32_to_cpu(fw_status[0])) {
290262306a36Sopenharmony_ci		case CS_DATA_UNDERRUN:
290362306a36Sopenharmony_ci		case CS_COMPLETE:
290462306a36Sopenharmony_ci			memset(&ea, 0, sizeof(ea));
290562306a36Sopenharmony_ci			ea.fcport = fcport;
290662306a36Sopenharmony_ci			ea.rc = res;
290762306a36Sopenharmony_ci			qla_handle_els_plogi_done(vha, &ea);
290862306a36Sopenharmony_ci			break;
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci		case CS_IOCB_ERROR:
291162306a36Sopenharmony_ci			switch (le32_to_cpu(fw_status[1])) {
291262306a36Sopenharmony_ci			case LSC_SCODE_PORTID_USED:
291362306a36Sopenharmony_ci				lid = le32_to_cpu(fw_status[2]) & 0xffff;
291462306a36Sopenharmony_ci				qlt_find_sess_invalidate_other(vha,
291562306a36Sopenharmony_ci				    wwn_to_u64(fcport->port_name),
291662306a36Sopenharmony_ci				    fcport->d_id, lid, &conflict_fcport);
291762306a36Sopenharmony_ci				if (conflict_fcport) {
291862306a36Sopenharmony_ci					/*
291962306a36Sopenharmony_ci					 * Another fcport shares the same
292062306a36Sopenharmony_ci					 * loop_id & nport id; conflict
292162306a36Sopenharmony_ci					 * fcport needs to finish cleanup
292262306a36Sopenharmony_ci					 * before this fcport can proceed
292362306a36Sopenharmony_ci					 * to login.
292462306a36Sopenharmony_ci					 */
292562306a36Sopenharmony_ci					conflict_fcport->conflict = fcport;
292662306a36Sopenharmony_ci					fcport->login_pause = 1;
292762306a36Sopenharmony_ci					ql_dbg(ql_dbg_disc, vha, 0x20ed,
292862306a36Sopenharmony_ci					    "%s %d %8phC pid %06x inuse with lid %#x.\n",
292962306a36Sopenharmony_ci					    __func__, __LINE__,
293062306a36Sopenharmony_ci					    fcport->port_name,
293162306a36Sopenharmony_ci					    fcport->d_id.b24, lid);
293262306a36Sopenharmony_ci				} else {
293362306a36Sopenharmony_ci					ql_dbg(ql_dbg_disc, vha, 0x20ed,
293462306a36Sopenharmony_ci					    "%s %d %8phC pid %06x inuse with lid %#x sched del\n",
293562306a36Sopenharmony_ci					    __func__, __LINE__,
293662306a36Sopenharmony_ci					    fcport->port_name,
293762306a36Sopenharmony_ci					    fcport->d_id.b24, lid);
293862306a36Sopenharmony_ci					qla2x00_clear_loop_id(fcport);
293962306a36Sopenharmony_ci					set_bit(lid, vha->hw->loop_id_map);
294062306a36Sopenharmony_ci					fcport->loop_id = lid;
294162306a36Sopenharmony_ci					fcport->keep_nport_handle = 0;
294262306a36Sopenharmony_ci					qlt_schedule_sess_for_deletion(fcport);
294362306a36Sopenharmony_ci				}
294462306a36Sopenharmony_ci				break;
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci			case LSC_SCODE_NPORT_USED:
294762306a36Sopenharmony_ci				cid.b.domain = (le32_to_cpu(fw_status[2]) >> 16)
294862306a36Sopenharmony_ci					& 0xff;
294962306a36Sopenharmony_ci				cid.b.area   = (le32_to_cpu(fw_status[2]) >>  8)
295062306a36Sopenharmony_ci					& 0xff;
295162306a36Sopenharmony_ci				cid.b.al_pa  = le32_to_cpu(fw_status[2]) & 0xff;
295262306a36Sopenharmony_ci				cid.b.rsvd_1 = 0;
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci				ql_dbg(ql_dbg_disc, vha, 0x20ec,
295562306a36Sopenharmony_ci				    "%s %d %8phC lid %#x in use with pid %06x post gnl\n",
295662306a36Sopenharmony_ci				    __func__, __LINE__, fcport->port_name,
295762306a36Sopenharmony_ci				    fcport->loop_id, cid.b24);
295862306a36Sopenharmony_ci				set_bit(fcport->loop_id,
295962306a36Sopenharmony_ci				    vha->hw->loop_id_map);
296062306a36Sopenharmony_ci				fcport->loop_id = FC_NO_LOOP_ID;
296162306a36Sopenharmony_ci				qla24xx_post_gnl_work(vha, fcport);
296262306a36Sopenharmony_ci				break;
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci			case LSC_SCODE_NOXCB:
296562306a36Sopenharmony_ci				vha->hw->exch_starvation++;
296662306a36Sopenharmony_ci				if (vha->hw->exch_starvation > 5) {
296762306a36Sopenharmony_ci					ql_log(ql_log_warn, vha, 0xd046,
296862306a36Sopenharmony_ci					    "Exchange starvation. Resetting RISC\n");
296962306a36Sopenharmony_ci					vha->hw->exch_starvation = 0;
297062306a36Sopenharmony_ci					set_bit(ISP_ABORT_NEEDED,
297162306a36Sopenharmony_ci					    &vha->dpc_flags);
297262306a36Sopenharmony_ci					qla2xxx_wake_dpc(vha);
297362306a36Sopenharmony_ci					break;
297462306a36Sopenharmony_ci				}
297562306a36Sopenharmony_ci				fallthrough;
297662306a36Sopenharmony_ci			default:
297762306a36Sopenharmony_ci				ql_dbg(ql_dbg_disc, vha, 0x20eb,
297862306a36Sopenharmony_ci				    "%s %8phC cmd error fw_status 0x%x 0x%x 0x%x\n",
297962306a36Sopenharmony_ci				    __func__, sp->fcport->port_name,
298062306a36Sopenharmony_ci				    fw_status[0], fw_status[1], fw_status[2]);
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_ci				fcport->flags &= ~FCF_ASYNC_SENT;
298362306a36Sopenharmony_ci				qlt_schedule_sess_for_deletion(fcport);
298462306a36Sopenharmony_ci				break;
298562306a36Sopenharmony_ci			}
298662306a36Sopenharmony_ci			break;
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_ci		default:
298962306a36Sopenharmony_ci			ql_dbg(ql_dbg_disc, vha, 0x20eb,
299062306a36Sopenharmony_ci			    "%s %8phC cmd error 2 fw_status 0x%x 0x%x 0x%x\n",
299162306a36Sopenharmony_ci			    __func__, sp->fcport->port_name,
299262306a36Sopenharmony_ci			    fw_status[0], fw_status[1], fw_status[2]);
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ci			sp->fcport->flags &= ~FCF_ASYNC_SENT;
299562306a36Sopenharmony_ci			qlt_schedule_sess_for_deletion(fcport);
299662306a36Sopenharmony_ci			break;
299762306a36Sopenharmony_ci		}
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_ci		e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP);
300062306a36Sopenharmony_ci		if (!e) {
300162306a36Sopenharmony_ci			struct srb_iocb *elsio = &sp->u.iocb_cmd;
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci			qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi);
300462306a36Sopenharmony_ci			/* ref: INIT */
300562306a36Sopenharmony_ci			kref_put(&sp->cmd_kref, qla2x00_sp_release);
300662306a36Sopenharmony_ci			return;
300762306a36Sopenharmony_ci		}
300862306a36Sopenharmony_ci		e->u.iosb.sp = sp;
300962306a36Sopenharmony_ci		qla2x00_post_work(vha, e);
301062306a36Sopenharmony_ci	}
301162306a36Sopenharmony_ci}
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ciint
301462306a36Sopenharmony_ciqla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode,
301562306a36Sopenharmony_ci    fc_port_t *fcport, bool wait)
301662306a36Sopenharmony_ci{
301762306a36Sopenharmony_ci	srb_t *sp;
301862306a36Sopenharmony_ci	struct srb_iocb *elsio = NULL;
301962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
302062306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
302162306a36Sopenharmony_ci	void	*ptr, *resp_ptr;
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci	/* Alloc SRB structure
302462306a36Sopenharmony_ci	 * ref: INIT
302562306a36Sopenharmony_ci	 */
302662306a36Sopenharmony_ci	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
302762306a36Sopenharmony_ci	if (!sp) {
302862306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x70e6,
302962306a36Sopenharmony_ci		 "SRB allocation failed\n");
303062306a36Sopenharmony_ci		fcport->flags &= ~FCF_ASYNC_ACTIVE;
303162306a36Sopenharmony_ci		return -ENOMEM;
303262306a36Sopenharmony_ci	}
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci	fcport->flags |= FCF_ASYNC_SENT;
303562306a36Sopenharmony_ci	qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_PEND);
303662306a36Sopenharmony_ci	elsio = &sp->u.iocb_cmd;
303762306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x3073,
303862306a36Sopenharmony_ci	       "%s Enter: PLOGI portid=%06x\n", __func__, fcport->d_id.b24);
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	if (wait)
304162306a36Sopenharmony_ci		sp->flags = SRB_WAKEUP_ON_COMP;
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci	sp->type = SRB_ELS_DCMD;
304462306a36Sopenharmony_ci	sp->name = "ELS_DCMD";
304562306a36Sopenharmony_ci	sp->fcport = fcport;
304662306a36Sopenharmony_ci	qla2x00_init_async_sp(sp, ELS_DCMD_TIMEOUT + 2,
304762306a36Sopenharmony_ci			     qla2x00_els_dcmd2_sp_done);
304862306a36Sopenharmony_ci	sp->u.iocb_cmd.timeout = qla2x00_els_dcmd2_iocb_timeout;
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci	elsio->u.els_plogi.tx_size = elsio->u.els_plogi.rx_size = DMA_POOL_SIZE;
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci	ptr = elsio->u.els_plogi.els_plogi_pyld =
305362306a36Sopenharmony_ci	    dma_alloc_coherent(&ha->pdev->dev, elsio->u.els_plogi.tx_size,
305462306a36Sopenharmony_ci		&elsio->u.els_plogi.els_plogi_pyld_dma, GFP_KERNEL);
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci	if (!elsio->u.els_plogi.els_plogi_pyld) {
305762306a36Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
305862306a36Sopenharmony_ci		goto out;
305962306a36Sopenharmony_ci	}
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_ci	resp_ptr = elsio->u.els_plogi.els_resp_pyld =
306262306a36Sopenharmony_ci	    dma_alloc_coherent(&ha->pdev->dev, elsio->u.els_plogi.rx_size,
306362306a36Sopenharmony_ci		&elsio->u.els_plogi.els_resp_pyld_dma, GFP_KERNEL);
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	if (!elsio->u.els_plogi.els_resp_pyld) {
306662306a36Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
306762306a36Sopenharmony_ci		goto out;
306862306a36Sopenharmony_ci	}
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x3073, "PLOGI %p %p\n", ptr, resp_ptr);
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci	memset(ptr, 0, sizeof(struct els_plogi_payload));
307362306a36Sopenharmony_ci	memset(resp_ptr, 0, sizeof(struct els_plogi_payload));
307462306a36Sopenharmony_ci	memcpy(elsio->u.els_plogi.els_plogi_pyld->data,
307562306a36Sopenharmony_ci	       (void *)&ha->plogi_els_payld + offsetof(struct fc_els_flogi, fl_csp),
307662306a36Sopenharmony_ci	       sizeof(ha->plogi_els_payld) - offsetof(struct fc_els_flogi, fl_csp));
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	elsio->u.els_plogi.els_cmd = els_opcode;
307962306a36Sopenharmony_ci	elsio->u.els_plogi.els_plogi_pyld->opcode = els_opcode;
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	if (els_opcode == ELS_DCMD_PLOGI && DBELL_ACTIVE(vha)) {
308262306a36Sopenharmony_ci		struct fc_els_flogi *p = ptr;
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_ci		p->fl_csp.sp_features |= cpu_to_be16(FC_SP_FT_SEC);
308562306a36Sopenharmony_ci	}
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci	ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x3073, "PLOGI buffer:\n");
308862306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x0109,
308962306a36Sopenharmony_ci	    (uint8_t *)elsio->u.els_plogi.els_plogi_pyld,
309062306a36Sopenharmony_ci	    sizeof(*elsio->u.els_plogi.els_plogi_pyld));
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	init_completion(&elsio->u.els_plogi.comp);
309362306a36Sopenharmony_ci	rval = qla2x00_start_sp(sp);
309462306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
309562306a36Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
309662306a36Sopenharmony_ci	} else {
309762306a36Sopenharmony_ci		ql_dbg(ql_dbg_disc, vha, 0x3074,
309862306a36Sopenharmony_ci		    "%s PLOGI sent, hdl=%x, loopid=%x, to port_id %06x from port_id %06x\n",
309962306a36Sopenharmony_ci		    sp->name, sp->handle, fcport->loop_id,
310062306a36Sopenharmony_ci		    fcport->d_id.b24, vha->d_id.b24);
310162306a36Sopenharmony_ci	}
310262306a36Sopenharmony_ci
310362306a36Sopenharmony_ci	if (wait) {
310462306a36Sopenharmony_ci		wait_for_completion(&elsio->u.els_plogi.comp);
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci		if (elsio->u.els_plogi.comp_status != CS_COMPLETE)
310762306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
310862306a36Sopenharmony_ci	} else {
310962306a36Sopenharmony_ci		goto done;
311062306a36Sopenharmony_ci	}
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ciout:
311362306a36Sopenharmony_ci	fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
311462306a36Sopenharmony_ci	qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi);
311562306a36Sopenharmony_ci	/* ref: INIT */
311662306a36Sopenharmony_ci	kref_put(&sp->cmd_kref, qla2x00_sp_release);
311762306a36Sopenharmony_cidone:
311862306a36Sopenharmony_ci	return rval;
311962306a36Sopenharmony_ci}
312062306a36Sopenharmony_ci
312162306a36Sopenharmony_ci/* it is assume qpair lock is held */
312262306a36Sopenharmony_civoid qla_els_pt_iocb(struct scsi_qla_host *vha,
312362306a36Sopenharmony_ci	struct els_entry_24xx *els_iocb,
312462306a36Sopenharmony_ci	struct qla_els_pt_arg *a)
312562306a36Sopenharmony_ci{
312662306a36Sopenharmony_ci	els_iocb->entry_type = ELS_IOCB_TYPE;
312762306a36Sopenharmony_ci	els_iocb->entry_count = 1;
312862306a36Sopenharmony_ci	els_iocb->sys_define = 0;
312962306a36Sopenharmony_ci	els_iocb->entry_status = 0;
313062306a36Sopenharmony_ci	els_iocb->handle = QLA_SKIP_HANDLE;
313162306a36Sopenharmony_ci	els_iocb->nport_handle = a->nport_handle;
313262306a36Sopenharmony_ci	els_iocb->rx_xchg_address = a->rx_xchg_address;
313362306a36Sopenharmony_ci	els_iocb->tx_dsd_count = cpu_to_le16(1);
313462306a36Sopenharmony_ci	els_iocb->vp_index = a->vp_idx;
313562306a36Sopenharmony_ci	els_iocb->sof_type = EST_SOFI3;
313662306a36Sopenharmony_ci	els_iocb->rx_dsd_count = cpu_to_le16(0);
313762306a36Sopenharmony_ci	els_iocb->opcode = a->els_opcode;
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	els_iocb->d_id[0] = a->did.b.al_pa;
314062306a36Sopenharmony_ci	els_iocb->d_id[1] = a->did.b.area;
314162306a36Sopenharmony_ci	els_iocb->d_id[2] = a->did.b.domain;
314262306a36Sopenharmony_ci	/* For SID the byte order is different than DID */
314362306a36Sopenharmony_ci	els_iocb->s_id[1] = vha->d_id.b.al_pa;
314462306a36Sopenharmony_ci	els_iocb->s_id[2] = vha->d_id.b.area;
314562306a36Sopenharmony_ci	els_iocb->s_id[0] = vha->d_id.b.domain;
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_ci	els_iocb->control_flags = cpu_to_le16(a->control_flags);
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	els_iocb->tx_byte_count = cpu_to_le32(a->tx_byte_count);
315062306a36Sopenharmony_ci	els_iocb->tx_len = cpu_to_le32(a->tx_len);
315162306a36Sopenharmony_ci	put_unaligned_le64(a->tx_addr, &els_iocb->tx_address);
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci	els_iocb->rx_byte_count = cpu_to_le32(a->rx_byte_count);
315462306a36Sopenharmony_ci	els_iocb->rx_len = cpu_to_le32(a->rx_len);
315562306a36Sopenharmony_ci	put_unaligned_le64(a->rx_addr, &els_iocb->rx_address);
315662306a36Sopenharmony_ci}
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_cistatic void
315962306a36Sopenharmony_ciqla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
316062306a36Sopenharmony_ci{
316162306a36Sopenharmony_ci	struct bsg_job *bsg_job = sp->u.bsg_job;
316262306a36Sopenharmony_ci	struct fc_bsg_request *bsg_request = bsg_job->request;
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_ci        els_iocb->entry_type = ELS_IOCB_TYPE;
316562306a36Sopenharmony_ci        els_iocb->entry_count = 1;
316662306a36Sopenharmony_ci        els_iocb->sys_define = 0;
316762306a36Sopenharmony_ci        els_iocb->entry_status = 0;
316862306a36Sopenharmony_ci        els_iocb->handle = sp->handle;
316962306a36Sopenharmony_ci	els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
317062306a36Sopenharmony_ci	els_iocb->tx_dsd_count = cpu_to_le16(bsg_job->request_payload.sg_cnt);
317162306a36Sopenharmony_ci	els_iocb->vp_index = sp->vha->vp_idx;
317262306a36Sopenharmony_ci        els_iocb->sof_type = EST_SOFI3;
317362306a36Sopenharmony_ci	els_iocb->rx_dsd_count = cpu_to_le16(bsg_job->reply_payload.sg_cnt);
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	els_iocb->opcode =
317662306a36Sopenharmony_ci	    sp->type == SRB_ELS_CMD_RPT ?
317762306a36Sopenharmony_ci	    bsg_request->rqst_data.r_els.els_code :
317862306a36Sopenharmony_ci	    bsg_request->rqst_data.h_els.command_code;
317962306a36Sopenharmony_ci	els_iocb->d_id[0] = sp->fcport->d_id.b.al_pa;
318062306a36Sopenharmony_ci	els_iocb->d_id[1] = sp->fcport->d_id.b.area;
318162306a36Sopenharmony_ci	els_iocb->d_id[2] = sp->fcport->d_id.b.domain;
318262306a36Sopenharmony_ci        els_iocb->control_flags = 0;
318362306a36Sopenharmony_ci        els_iocb->rx_byte_count =
318462306a36Sopenharmony_ci            cpu_to_le32(bsg_job->reply_payload.payload_len);
318562306a36Sopenharmony_ci        els_iocb->tx_byte_count =
318662306a36Sopenharmony_ci            cpu_to_le32(bsg_job->request_payload.payload_len);
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci	put_unaligned_le64(sg_dma_address(bsg_job->request_payload.sg_list),
318962306a36Sopenharmony_ci			   &els_iocb->tx_address);
319062306a36Sopenharmony_ci        els_iocb->tx_len = cpu_to_le32(sg_dma_len
319162306a36Sopenharmony_ci            (bsg_job->request_payload.sg_list));
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci	put_unaligned_le64(sg_dma_address(bsg_job->reply_payload.sg_list),
319462306a36Sopenharmony_ci			   &els_iocb->rx_address);
319562306a36Sopenharmony_ci        els_iocb->rx_len = cpu_to_le32(sg_dma_len
319662306a36Sopenharmony_ci            (bsg_job->reply_payload.sg_list));
319762306a36Sopenharmony_ci
319862306a36Sopenharmony_ci	sp->vha->qla_stats.control_requests++;
319962306a36Sopenharmony_ci}
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_cistatic void
320262306a36Sopenharmony_ciqla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb)
320362306a36Sopenharmony_ci{
320462306a36Sopenharmony_ci	uint16_t        avail_dsds;
320562306a36Sopenharmony_ci	struct dsd64	*cur_dsd;
320662306a36Sopenharmony_ci	struct scatterlist *sg;
320762306a36Sopenharmony_ci	int index;
320862306a36Sopenharmony_ci	uint16_t tot_dsds;
320962306a36Sopenharmony_ci	scsi_qla_host_t *vha = sp->vha;
321062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
321162306a36Sopenharmony_ci	struct bsg_job *bsg_job = sp->u.bsg_job;
321262306a36Sopenharmony_ci	int entry_count = 1;
321362306a36Sopenharmony_ci
321462306a36Sopenharmony_ci	memset(ct_iocb, 0, sizeof(ms_iocb_entry_t));
321562306a36Sopenharmony_ci	ct_iocb->entry_type = CT_IOCB_TYPE;
321662306a36Sopenharmony_ci	ct_iocb->entry_status = 0;
321762306a36Sopenharmony_ci	ct_iocb->handle1 = sp->handle;
321862306a36Sopenharmony_ci	SET_TARGET_ID(ha, ct_iocb->loop_id, sp->fcport->loop_id);
321962306a36Sopenharmony_ci	ct_iocb->status = cpu_to_le16(0);
322062306a36Sopenharmony_ci	ct_iocb->control_flags = cpu_to_le16(0);
322162306a36Sopenharmony_ci	ct_iocb->timeout = 0;
322262306a36Sopenharmony_ci	ct_iocb->cmd_dsd_count =
322362306a36Sopenharmony_ci	    cpu_to_le16(bsg_job->request_payload.sg_cnt);
322462306a36Sopenharmony_ci	ct_iocb->total_dsd_count =
322562306a36Sopenharmony_ci	    cpu_to_le16(bsg_job->request_payload.sg_cnt + 1);
322662306a36Sopenharmony_ci	ct_iocb->req_bytecount =
322762306a36Sopenharmony_ci	    cpu_to_le32(bsg_job->request_payload.payload_len);
322862306a36Sopenharmony_ci	ct_iocb->rsp_bytecount =
322962306a36Sopenharmony_ci	    cpu_to_le32(bsg_job->reply_payload.payload_len);
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci	put_unaligned_le64(sg_dma_address(bsg_job->request_payload.sg_list),
323262306a36Sopenharmony_ci			   &ct_iocb->req_dsd.address);
323362306a36Sopenharmony_ci	ct_iocb->req_dsd.length = ct_iocb->req_bytecount;
323462306a36Sopenharmony_ci
323562306a36Sopenharmony_ci	put_unaligned_le64(sg_dma_address(bsg_job->reply_payload.sg_list),
323662306a36Sopenharmony_ci			   &ct_iocb->rsp_dsd.address);
323762306a36Sopenharmony_ci	ct_iocb->rsp_dsd.length = ct_iocb->rsp_bytecount;
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci	avail_dsds = 1;
324062306a36Sopenharmony_ci	cur_dsd = &ct_iocb->rsp_dsd;
324162306a36Sopenharmony_ci	index = 0;
324262306a36Sopenharmony_ci	tot_dsds = bsg_job->reply_payload.sg_cnt;
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci	for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) {
324562306a36Sopenharmony_ci		cont_a64_entry_t *cont_pkt;
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_ci		/* Allocate additional continuation packets? */
324862306a36Sopenharmony_ci		if (avail_dsds == 0) {
324962306a36Sopenharmony_ci			/*
325062306a36Sopenharmony_ci			* Five DSDs are available in the Cont.
325162306a36Sopenharmony_ci			* Type 1 IOCB.
325262306a36Sopenharmony_ci			       */
325362306a36Sopenharmony_ci			cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
325462306a36Sopenharmony_ci			    vha->hw->req_q_map[0]);
325562306a36Sopenharmony_ci			cur_dsd = cont_pkt->dsd;
325662306a36Sopenharmony_ci			avail_dsds = 5;
325762306a36Sopenharmony_ci			entry_count++;
325862306a36Sopenharmony_ci		}
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_ci		append_dsd64(&cur_dsd, sg);
326162306a36Sopenharmony_ci		avail_dsds--;
326262306a36Sopenharmony_ci	}
326362306a36Sopenharmony_ci	ct_iocb->entry_count = entry_count;
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	sp->vha->qla_stats.control_requests++;
326662306a36Sopenharmony_ci}
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_cistatic void
326962306a36Sopenharmony_ciqla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
327062306a36Sopenharmony_ci{
327162306a36Sopenharmony_ci	uint16_t        avail_dsds;
327262306a36Sopenharmony_ci	struct dsd64	*cur_dsd;
327362306a36Sopenharmony_ci	struct scatterlist *sg;
327462306a36Sopenharmony_ci	int index;
327562306a36Sopenharmony_ci	uint16_t cmd_dsds, rsp_dsds;
327662306a36Sopenharmony_ci	scsi_qla_host_t *vha = sp->vha;
327762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
327862306a36Sopenharmony_ci	struct bsg_job *bsg_job = sp->u.bsg_job;
327962306a36Sopenharmony_ci	int entry_count = 1;
328062306a36Sopenharmony_ci	cont_a64_entry_t *cont_pkt = NULL;
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_ci	ct_iocb->entry_type = CT_IOCB_TYPE;
328362306a36Sopenharmony_ci        ct_iocb->entry_status = 0;
328462306a36Sopenharmony_ci        ct_iocb->sys_define = 0;
328562306a36Sopenharmony_ci        ct_iocb->handle = sp->handle;
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_ci	ct_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
328862306a36Sopenharmony_ci	ct_iocb->vp_index = sp->vha->vp_idx;
328962306a36Sopenharmony_ci	ct_iocb->comp_status = cpu_to_le16(0);
329062306a36Sopenharmony_ci
329162306a36Sopenharmony_ci	cmd_dsds = bsg_job->request_payload.sg_cnt;
329262306a36Sopenharmony_ci	rsp_dsds = bsg_job->reply_payload.sg_cnt;
329362306a36Sopenharmony_ci
329462306a36Sopenharmony_ci	ct_iocb->cmd_dsd_count = cpu_to_le16(cmd_dsds);
329562306a36Sopenharmony_ci        ct_iocb->timeout = 0;
329662306a36Sopenharmony_ci	ct_iocb->rsp_dsd_count = cpu_to_le16(rsp_dsds);
329762306a36Sopenharmony_ci        ct_iocb->cmd_byte_count =
329862306a36Sopenharmony_ci            cpu_to_le32(bsg_job->request_payload.payload_len);
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	avail_dsds = 2;
330162306a36Sopenharmony_ci	cur_dsd = ct_iocb->dsd;
330262306a36Sopenharmony_ci	index = 0;
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci	for_each_sg(bsg_job->request_payload.sg_list, sg, cmd_dsds, index) {
330562306a36Sopenharmony_ci		/* Allocate additional continuation packets? */
330662306a36Sopenharmony_ci		if (avail_dsds == 0) {
330762306a36Sopenharmony_ci			/*
330862306a36Sopenharmony_ci			 * Five DSDs are available in the Cont.
330962306a36Sopenharmony_ci			 * Type 1 IOCB.
331062306a36Sopenharmony_ci			 */
331162306a36Sopenharmony_ci			cont_pkt = qla2x00_prep_cont_type1_iocb(
331262306a36Sopenharmony_ci			    vha, ha->req_q_map[0]);
331362306a36Sopenharmony_ci			cur_dsd = cont_pkt->dsd;
331462306a36Sopenharmony_ci			avail_dsds = 5;
331562306a36Sopenharmony_ci			entry_count++;
331662306a36Sopenharmony_ci		}
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci		append_dsd64(&cur_dsd, sg);
331962306a36Sopenharmony_ci		avail_dsds--;
332062306a36Sopenharmony_ci	}
332162306a36Sopenharmony_ci
332262306a36Sopenharmony_ci	index = 0;
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci	for_each_sg(bsg_job->reply_payload.sg_list, sg, rsp_dsds, index) {
332562306a36Sopenharmony_ci		/* Allocate additional continuation packets? */
332662306a36Sopenharmony_ci		if (avail_dsds == 0) {
332762306a36Sopenharmony_ci			/*
332862306a36Sopenharmony_ci			* Five DSDs are available in the Cont.
332962306a36Sopenharmony_ci			* Type 1 IOCB.
333062306a36Sopenharmony_ci			       */
333162306a36Sopenharmony_ci			cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
333262306a36Sopenharmony_ci			    ha->req_q_map[0]);
333362306a36Sopenharmony_ci			cur_dsd = cont_pkt->dsd;
333462306a36Sopenharmony_ci			avail_dsds = 5;
333562306a36Sopenharmony_ci			entry_count++;
333662306a36Sopenharmony_ci		}
333762306a36Sopenharmony_ci
333862306a36Sopenharmony_ci		append_dsd64(&cur_dsd, sg);
333962306a36Sopenharmony_ci		avail_dsds--;
334062306a36Sopenharmony_ci	}
334162306a36Sopenharmony_ci        ct_iocb->entry_count = entry_count;
334262306a36Sopenharmony_ci}
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_ci/*
334562306a36Sopenharmony_ci * qla82xx_start_scsi() - Send a SCSI command to the ISP
334662306a36Sopenharmony_ci * @sp: command to send to the ISP
334762306a36Sopenharmony_ci *
334862306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero.
334962306a36Sopenharmony_ci */
335062306a36Sopenharmony_ciint
335162306a36Sopenharmony_ciqla82xx_start_scsi(srb_t *sp)
335262306a36Sopenharmony_ci{
335362306a36Sopenharmony_ci	int		nseg;
335462306a36Sopenharmony_ci	unsigned long   flags;
335562306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
335662306a36Sopenharmony_ci	uint32_t	*clr_ptr;
335762306a36Sopenharmony_ci	uint32_t	handle;
335862306a36Sopenharmony_ci	uint16_t	cnt;
335962306a36Sopenharmony_ci	uint16_t	req_cnt;
336062306a36Sopenharmony_ci	uint16_t	tot_dsds;
336162306a36Sopenharmony_ci	struct device_reg_82xx __iomem *reg;
336262306a36Sopenharmony_ci	uint32_t dbval;
336362306a36Sopenharmony_ci	__be32 *fcp_dl;
336462306a36Sopenharmony_ci	uint8_t additional_cdb_len;
336562306a36Sopenharmony_ci	struct ct6_dsd *ctx;
336662306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
336762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
336862306a36Sopenharmony_ci	struct req_que *req = NULL;
336962306a36Sopenharmony_ci	struct rsp_que *rsp = NULL;
337062306a36Sopenharmony_ci	struct qla_qpair *qpair = sp->qpair;
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci	/* Setup device pointers. */
337362306a36Sopenharmony_ci	reg = &ha->iobase->isp82;
337462306a36Sopenharmony_ci	cmd = GET_CMD_SP(sp);
337562306a36Sopenharmony_ci	req = vha->req;
337662306a36Sopenharmony_ci	rsp = ha->rsp_q_map[0];
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci	/* So we know we haven't pci_map'ed anything yet */
337962306a36Sopenharmony_ci	tot_dsds = 0;
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_ci	dbval = 0x04 | (ha->portnum << 5);
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci	/* Send marker if required */
338462306a36Sopenharmony_ci	if (vha->marker_needed != 0) {
338562306a36Sopenharmony_ci		if (qla2x00_marker(vha, ha->base_qpair,
338662306a36Sopenharmony_ci			0, 0, MK_SYNC_ALL) != QLA_SUCCESS) {
338762306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x300c,
338862306a36Sopenharmony_ci			    "qla2x00_marker failed for cmd=%p.\n", cmd);
338962306a36Sopenharmony_ci			return QLA_FUNCTION_FAILED;
339062306a36Sopenharmony_ci		}
339162306a36Sopenharmony_ci		vha->marker_needed = 0;
339262306a36Sopenharmony_ci	}
339362306a36Sopenharmony_ci
339462306a36Sopenharmony_ci	/* Acquire ring specific lock */
339562306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci	handle = qla2xxx_get_next_handle(req);
339862306a36Sopenharmony_ci	if (handle == 0)
339962306a36Sopenharmony_ci		goto queuing_error;
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci	/* Map the sg table so we have an accurate count of sg entries needed */
340262306a36Sopenharmony_ci	if (scsi_sg_count(cmd)) {
340362306a36Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
340462306a36Sopenharmony_ci		    scsi_sg_count(cmd), cmd->sc_data_direction);
340562306a36Sopenharmony_ci		if (unlikely(!nseg))
340662306a36Sopenharmony_ci			goto queuing_error;
340762306a36Sopenharmony_ci	} else
340862306a36Sopenharmony_ci		nseg = 0;
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_ci	tot_dsds = nseg;
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci	if (tot_dsds > ql2xshiftctondsd) {
341362306a36Sopenharmony_ci		struct cmd_type_6 *cmd_pkt;
341462306a36Sopenharmony_ci		uint16_t more_dsd_lists = 0;
341562306a36Sopenharmony_ci		struct dsd_dma *dsd_ptr;
341662306a36Sopenharmony_ci		uint16_t i;
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci		more_dsd_lists = qla24xx_calc_dsd_lists(tot_dsds);
341962306a36Sopenharmony_ci		if ((more_dsd_lists + qpair->dsd_inuse) >= NUM_DSD_CHAIN) {
342062306a36Sopenharmony_ci			ql_dbg(ql_dbg_io, vha, 0x300d,
342162306a36Sopenharmony_ci			    "Num of DSD list %d is than %d for cmd=%p.\n",
342262306a36Sopenharmony_ci			    more_dsd_lists + qpair->dsd_inuse, NUM_DSD_CHAIN,
342362306a36Sopenharmony_ci			    cmd);
342462306a36Sopenharmony_ci			goto queuing_error;
342562306a36Sopenharmony_ci		}
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci		if (more_dsd_lists <= qpair->dsd_avail)
342862306a36Sopenharmony_ci			goto sufficient_dsds;
342962306a36Sopenharmony_ci		else
343062306a36Sopenharmony_ci			more_dsd_lists -= qpair->dsd_avail;
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci		for (i = 0; i < more_dsd_lists; i++) {
343362306a36Sopenharmony_ci			dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
343462306a36Sopenharmony_ci			if (!dsd_ptr) {
343562306a36Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0x300e,
343662306a36Sopenharmony_ci				    "Failed to allocate memory for dsd_dma "
343762306a36Sopenharmony_ci				    "for cmd=%p.\n", cmd);
343862306a36Sopenharmony_ci				goto queuing_error;
343962306a36Sopenharmony_ci			}
344062306a36Sopenharmony_ci
344162306a36Sopenharmony_ci			dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool,
344262306a36Sopenharmony_ci				GFP_ATOMIC, &dsd_ptr->dsd_list_dma);
344362306a36Sopenharmony_ci			if (!dsd_ptr->dsd_addr) {
344462306a36Sopenharmony_ci				kfree(dsd_ptr);
344562306a36Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0x300f,
344662306a36Sopenharmony_ci				    "Failed to allocate memory for dsd_addr "
344762306a36Sopenharmony_ci				    "for cmd=%p.\n", cmd);
344862306a36Sopenharmony_ci				goto queuing_error;
344962306a36Sopenharmony_ci			}
345062306a36Sopenharmony_ci			list_add_tail(&dsd_ptr->list, &qpair->dsd_list);
345162306a36Sopenharmony_ci			qpair->dsd_avail++;
345262306a36Sopenharmony_ci		}
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_cisufficient_dsds:
345562306a36Sopenharmony_ci		req_cnt = 1;
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2)) {
345862306a36Sopenharmony_ci			cnt = (uint16_t)rd_reg_dword_relaxed(
345962306a36Sopenharmony_ci				&reg->req_q_out[0]);
346062306a36Sopenharmony_ci			if (req->ring_index < cnt)
346162306a36Sopenharmony_ci				req->cnt = cnt - req->ring_index;
346262306a36Sopenharmony_ci			else
346362306a36Sopenharmony_ci				req->cnt = req->length -
346462306a36Sopenharmony_ci					(req->ring_index - cnt);
346562306a36Sopenharmony_ci			if (req->cnt < (req_cnt + 2))
346662306a36Sopenharmony_ci				goto queuing_error;
346762306a36Sopenharmony_ci		}
346862306a36Sopenharmony_ci
346962306a36Sopenharmony_ci		ctx = &sp->u.scmd.ct6_ctx;
347062306a36Sopenharmony_ci
347162306a36Sopenharmony_ci		memset(ctx, 0, sizeof(struct ct6_dsd));
347262306a36Sopenharmony_ci		ctx->fcp_cmnd = dma_pool_zalloc(ha->fcp_cmnd_dma_pool,
347362306a36Sopenharmony_ci			GFP_ATOMIC, &ctx->fcp_cmnd_dma);
347462306a36Sopenharmony_ci		if (!ctx->fcp_cmnd) {
347562306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x3011,
347662306a36Sopenharmony_ci			    "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd);
347762306a36Sopenharmony_ci			goto queuing_error;
347862306a36Sopenharmony_ci		}
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci		/* Initialize the DSD list and dma handle */
348162306a36Sopenharmony_ci		INIT_LIST_HEAD(&ctx->dsd_list);
348262306a36Sopenharmony_ci		ctx->dsd_use_cnt = 0;
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci		if (cmd->cmd_len > 16) {
348562306a36Sopenharmony_ci			additional_cdb_len = cmd->cmd_len - 16;
348662306a36Sopenharmony_ci			if ((cmd->cmd_len % 4) != 0) {
348762306a36Sopenharmony_ci				/* SCSI command bigger than 16 bytes must be
348862306a36Sopenharmony_ci				 * multiple of 4
348962306a36Sopenharmony_ci				 */
349062306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x3012,
349162306a36Sopenharmony_ci				    "scsi cmd len %d not multiple of 4 "
349262306a36Sopenharmony_ci				    "for cmd=%p.\n", cmd->cmd_len, cmd);
349362306a36Sopenharmony_ci				goto queuing_error_fcp_cmnd;
349462306a36Sopenharmony_ci			}
349562306a36Sopenharmony_ci			ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4;
349662306a36Sopenharmony_ci		} else {
349762306a36Sopenharmony_ci			additional_cdb_len = 0;
349862306a36Sopenharmony_ci			ctx->fcp_cmnd_len = 12 + 16 + 4;
349962306a36Sopenharmony_ci		}
350062306a36Sopenharmony_ci
350162306a36Sopenharmony_ci		cmd_pkt = (struct cmd_type_6 *)req->ring_ptr;
350262306a36Sopenharmony_ci		cmd_pkt->handle = make_handle(req->id, handle);
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci		/* Zero out remaining portion of packet. */
350562306a36Sopenharmony_ci		/*    tagged queuing modifier -- default is TSK_SIMPLE (0). */
350662306a36Sopenharmony_ci		clr_ptr = (uint32_t *)cmd_pkt + 2;
350762306a36Sopenharmony_ci		memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
350862306a36Sopenharmony_ci		cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
350962306a36Sopenharmony_ci
351062306a36Sopenharmony_ci		/* Set NPORT-ID and LUN number*/
351162306a36Sopenharmony_ci		cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
351262306a36Sopenharmony_ci		cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
351362306a36Sopenharmony_ci		cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
351462306a36Sopenharmony_ci		cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
351562306a36Sopenharmony_ci		cmd_pkt->vp_index = sp->vha->vp_idx;
351662306a36Sopenharmony_ci
351762306a36Sopenharmony_ci		/* Build IOCB segments */
351862306a36Sopenharmony_ci		if (qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds))
351962306a36Sopenharmony_ci			goto queuing_error_fcp_cmnd;
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci		int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
352262306a36Sopenharmony_ci		host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci		/* build FCP_CMND IU */
352562306a36Sopenharmony_ci		int_to_scsilun(cmd->device->lun, &ctx->fcp_cmnd->lun);
352662306a36Sopenharmony_ci		ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci		if (cmd->sc_data_direction == DMA_TO_DEVICE)
352962306a36Sopenharmony_ci			ctx->fcp_cmnd->additional_cdb_len |= 1;
353062306a36Sopenharmony_ci		else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
353162306a36Sopenharmony_ci			ctx->fcp_cmnd->additional_cdb_len |= 2;
353262306a36Sopenharmony_ci
353362306a36Sopenharmony_ci		/* Populate the FCP_PRIO. */
353462306a36Sopenharmony_ci		if (ha->flags.fcp_prio_enabled)
353562306a36Sopenharmony_ci			ctx->fcp_cmnd->task_attribute |=
353662306a36Sopenharmony_ci			    sp->fcport->fcp_prio << 3;
353762306a36Sopenharmony_ci
353862306a36Sopenharmony_ci		memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_ci		fcp_dl = (__be32 *)(ctx->fcp_cmnd->cdb + 16 +
354162306a36Sopenharmony_ci		    additional_cdb_len);
354262306a36Sopenharmony_ci		*fcp_dl = htonl((uint32_t)scsi_bufflen(cmd));
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci		cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len);
354562306a36Sopenharmony_ci		put_unaligned_le64(ctx->fcp_cmnd_dma,
354662306a36Sopenharmony_ci				   &cmd_pkt->fcp_cmnd_dseg_address);
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci		sp->flags |= SRB_FCP_CMND_DMA_VALID;
354962306a36Sopenharmony_ci		cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
355062306a36Sopenharmony_ci		/* Set total data segment count. */
355162306a36Sopenharmony_ci		cmd_pkt->entry_count = (uint8_t)req_cnt;
355262306a36Sopenharmony_ci		/* Specify response queue number where
355362306a36Sopenharmony_ci		 * completion should happen
355462306a36Sopenharmony_ci		 */
355562306a36Sopenharmony_ci		cmd_pkt->entry_status = (uint8_t) rsp->id;
355662306a36Sopenharmony_ci	} else {
355762306a36Sopenharmony_ci		struct cmd_type_7 *cmd_pkt;
355862306a36Sopenharmony_ci
355962306a36Sopenharmony_ci		req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
356062306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2)) {
356162306a36Sopenharmony_ci			cnt = (uint16_t)rd_reg_dword_relaxed(
356262306a36Sopenharmony_ci			    &reg->req_q_out[0]);
356362306a36Sopenharmony_ci			if (req->ring_index < cnt)
356462306a36Sopenharmony_ci				req->cnt = cnt - req->ring_index;
356562306a36Sopenharmony_ci			else
356662306a36Sopenharmony_ci				req->cnt = req->length -
356762306a36Sopenharmony_ci					(req->ring_index - cnt);
356862306a36Sopenharmony_ci		}
356962306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2))
357062306a36Sopenharmony_ci			goto queuing_error;
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_ci		cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
357362306a36Sopenharmony_ci		cmd_pkt->handle = make_handle(req->id, handle);
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_ci		/* Zero out remaining portion of packet. */
357662306a36Sopenharmony_ci		/* tagged queuing modifier -- default is TSK_SIMPLE (0).*/
357762306a36Sopenharmony_ci		clr_ptr = (uint32_t *)cmd_pkt + 2;
357862306a36Sopenharmony_ci		memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
357962306a36Sopenharmony_ci		cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_ci		/* Set NPORT-ID and LUN number*/
358262306a36Sopenharmony_ci		cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
358362306a36Sopenharmony_ci		cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
358462306a36Sopenharmony_ci		cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
358562306a36Sopenharmony_ci		cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
358662306a36Sopenharmony_ci		cmd_pkt->vp_index = sp->vha->vp_idx;
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci		int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
358962306a36Sopenharmony_ci		host_to_fcp_swap((uint8_t *)&cmd_pkt->lun,
359062306a36Sopenharmony_ci		    sizeof(cmd_pkt->lun));
359162306a36Sopenharmony_ci
359262306a36Sopenharmony_ci		/* Populate the FCP_PRIO. */
359362306a36Sopenharmony_ci		if (ha->flags.fcp_prio_enabled)
359462306a36Sopenharmony_ci			cmd_pkt->task |= sp->fcport->fcp_prio << 3;
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci		/* Load SCSI command packet. */
359762306a36Sopenharmony_ci		memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
359862306a36Sopenharmony_ci		host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ci		cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_ci		/* Build IOCB segments */
360362306a36Sopenharmony_ci		qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req);
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci		/* Set total data segment count. */
360662306a36Sopenharmony_ci		cmd_pkt->entry_count = (uint8_t)req_cnt;
360762306a36Sopenharmony_ci		/* Specify response queue number where
360862306a36Sopenharmony_ci		 * completion should happen.
360962306a36Sopenharmony_ci		 */
361062306a36Sopenharmony_ci		cmd_pkt->entry_status = (uint8_t) rsp->id;
361162306a36Sopenharmony_ci
361262306a36Sopenharmony_ci	}
361362306a36Sopenharmony_ci	/* Build command packet. */
361462306a36Sopenharmony_ci	req->current_outstanding_cmd = handle;
361562306a36Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
361662306a36Sopenharmony_ci	sp->handle = handle;
361762306a36Sopenharmony_ci	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
361862306a36Sopenharmony_ci	req->cnt -= req_cnt;
361962306a36Sopenharmony_ci	wmb();
362062306a36Sopenharmony_ci
362162306a36Sopenharmony_ci	/* Adjust ring index. */
362262306a36Sopenharmony_ci	req->ring_index++;
362362306a36Sopenharmony_ci	if (req->ring_index == req->length) {
362462306a36Sopenharmony_ci		req->ring_index = 0;
362562306a36Sopenharmony_ci		req->ring_ptr = req->ring;
362662306a36Sopenharmony_ci	} else
362762306a36Sopenharmony_ci		req->ring_ptr++;
362862306a36Sopenharmony_ci
362962306a36Sopenharmony_ci	sp->flags |= SRB_DMA_VALID;
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_ci	/* Set chip new ring index. */
363262306a36Sopenharmony_ci	/* write, read and verify logic */
363362306a36Sopenharmony_ci	dbval = dbval | (req->id << 8) | (req->ring_index << 16);
363462306a36Sopenharmony_ci	if (ql2xdbwr)
363562306a36Sopenharmony_ci		qla82xx_wr_32(ha, (uintptr_t __force)ha->nxdb_wr_ptr, dbval);
363662306a36Sopenharmony_ci	else {
363762306a36Sopenharmony_ci		wrt_reg_dword(ha->nxdb_wr_ptr, dbval);
363862306a36Sopenharmony_ci		wmb();
363962306a36Sopenharmony_ci		while (rd_reg_dword(ha->nxdb_rd_ptr) != dbval) {
364062306a36Sopenharmony_ci			wrt_reg_dword(ha->nxdb_wr_ptr, dbval);
364162306a36Sopenharmony_ci			wmb();
364262306a36Sopenharmony_ci		}
364362306a36Sopenharmony_ci	}
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_ci	/* Manage unprocessed RIO/ZIO commands in response queue. */
364662306a36Sopenharmony_ci	if (vha->flags.process_response_queue &&
364762306a36Sopenharmony_ci	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
364862306a36Sopenharmony_ci		qla24xx_process_response_queue(vha, rsp);
364962306a36Sopenharmony_ci
365062306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
365162306a36Sopenharmony_ci	return QLA_SUCCESS;
365262306a36Sopenharmony_ci
365362306a36Sopenharmony_ciqueuing_error_fcp_cmnd:
365462306a36Sopenharmony_ci	dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma);
365562306a36Sopenharmony_ciqueuing_error:
365662306a36Sopenharmony_ci	if (tot_dsds)
365762306a36Sopenharmony_ci		scsi_dma_unmap(cmd);
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci	if (sp->u.scmd.crc_ctx) {
366062306a36Sopenharmony_ci		mempool_free(sp->u.scmd.crc_ctx, ha->ctx_mempool);
366162306a36Sopenharmony_ci		sp->u.scmd.crc_ctx = NULL;
366262306a36Sopenharmony_ci	}
366362306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
366462306a36Sopenharmony_ci
366562306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
366662306a36Sopenharmony_ci}
366762306a36Sopenharmony_ci
366862306a36Sopenharmony_cistatic void
366962306a36Sopenharmony_ciqla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb)
367062306a36Sopenharmony_ci{
367162306a36Sopenharmony_ci	struct srb_iocb *aio = &sp->u.iocb_cmd;
367262306a36Sopenharmony_ci	scsi_qla_host_t *vha = sp->vha;
367362306a36Sopenharmony_ci	struct req_que *req = sp->qpair->req;
367462306a36Sopenharmony_ci	srb_t *orig_sp = sp->cmd_sp;
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci	memset(abt_iocb, 0, sizeof(struct abort_entry_24xx));
367762306a36Sopenharmony_ci	abt_iocb->entry_type = ABORT_IOCB_TYPE;
367862306a36Sopenharmony_ci	abt_iocb->entry_count = 1;
367962306a36Sopenharmony_ci	abt_iocb->handle = make_handle(req->id, sp->handle);
368062306a36Sopenharmony_ci	if (sp->fcport) {
368162306a36Sopenharmony_ci		abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
368262306a36Sopenharmony_ci		abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
368362306a36Sopenharmony_ci		abt_iocb->port_id[1] = sp->fcport->d_id.b.area;
368462306a36Sopenharmony_ci		abt_iocb->port_id[2] = sp->fcport->d_id.b.domain;
368562306a36Sopenharmony_ci	}
368662306a36Sopenharmony_ci	abt_iocb->handle_to_abort =
368762306a36Sopenharmony_ci		make_handle(le16_to_cpu(aio->u.abt.req_que_no),
368862306a36Sopenharmony_ci			    aio->u.abt.cmd_hndl);
368962306a36Sopenharmony_ci	abt_iocb->vp_index = vha->vp_idx;
369062306a36Sopenharmony_ci	abt_iocb->req_que_no = aio->u.abt.req_que_no;
369162306a36Sopenharmony_ci
369262306a36Sopenharmony_ci	/* need to pass original sp */
369362306a36Sopenharmony_ci	if (orig_sp)
369462306a36Sopenharmony_ci		qla_nvme_abort_set_option(abt_iocb, orig_sp);
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_ci	/* Send the command to the firmware */
369762306a36Sopenharmony_ci	wmb();
369862306a36Sopenharmony_ci}
369962306a36Sopenharmony_ci
370062306a36Sopenharmony_cistatic void
370162306a36Sopenharmony_ciqla2x00_mb_iocb(srb_t *sp, struct mbx_24xx_entry *mbx)
370262306a36Sopenharmony_ci{
370362306a36Sopenharmony_ci	int i, sz;
370462306a36Sopenharmony_ci
370562306a36Sopenharmony_ci	mbx->entry_type = MBX_IOCB_TYPE;
370662306a36Sopenharmony_ci	mbx->handle = sp->handle;
370762306a36Sopenharmony_ci	sz = min(ARRAY_SIZE(mbx->mb), ARRAY_SIZE(sp->u.iocb_cmd.u.mbx.out_mb));
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ci	for (i = 0; i < sz; i++)
371062306a36Sopenharmony_ci		mbx->mb[i] = sp->u.iocb_cmd.u.mbx.out_mb[i];
371162306a36Sopenharmony_ci}
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_cistatic void
371462306a36Sopenharmony_ciqla2x00_ctpthru_cmd_iocb(srb_t *sp, struct ct_entry_24xx *ct_pkt)
371562306a36Sopenharmony_ci{
371662306a36Sopenharmony_ci	sp->u.iocb_cmd.u.ctarg.iocb = ct_pkt;
371762306a36Sopenharmony_ci	qla24xx_prep_ms_iocb(sp->vha, &sp->u.iocb_cmd.u.ctarg);
371862306a36Sopenharmony_ci	ct_pkt->handle = sp->handle;
371962306a36Sopenharmony_ci}
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_cistatic void qla2x00_send_notify_ack_iocb(srb_t *sp,
372262306a36Sopenharmony_ci	struct nack_to_isp *nack)
372362306a36Sopenharmony_ci{
372462306a36Sopenharmony_ci	struct imm_ntfy_from_isp *ntfy = sp->u.iocb_cmd.u.nack.ntfy;
372562306a36Sopenharmony_ci
372662306a36Sopenharmony_ci	nack->entry_type = NOTIFY_ACK_TYPE;
372762306a36Sopenharmony_ci	nack->entry_count = 1;
372862306a36Sopenharmony_ci	nack->ox_id = ntfy->ox_id;
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_ci	nack->u.isp24.handle = sp->handle;
373162306a36Sopenharmony_ci	nack->u.isp24.nport_handle = ntfy->u.isp24.nport_handle;
373262306a36Sopenharmony_ci	if (le16_to_cpu(ntfy->u.isp24.status) == IMM_NTFY_ELS) {
373362306a36Sopenharmony_ci		nack->u.isp24.flags = ntfy->u.isp24.flags &
373462306a36Sopenharmony_ci			cpu_to_le16(NOTIFY24XX_FLAGS_PUREX_IOCB);
373562306a36Sopenharmony_ci	}
373662306a36Sopenharmony_ci	nack->u.isp24.srr_rx_id = ntfy->u.isp24.srr_rx_id;
373762306a36Sopenharmony_ci	nack->u.isp24.status = ntfy->u.isp24.status;
373862306a36Sopenharmony_ci	nack->u.isp24.status_subcode = ntfy->u.isp24.status_subcode;
373962306a36Sopenharmony_ci	nack->u.isp24.fw_handle = ntfy->u.isp24.fw_handle;
374062306a36Sopenharmony_ci	nack->u.isp24.exchange_address = ntfy->u.isp24.exchange_address;
374162306a36Sopenharmony_ci	nack->u.isp24.srr_rel_offs = ntfy->u.isp24.srr_rel_offs;
374262306a36Sopenharmony_ci	nack->u.isp24.srr_ui = ntfy->u.isp24.srr_ui;
374362306a36Sopenharmony_ci	nack->u.isp24.srr_flags = 0;
374462306a36Sopenharmony_ci	nack->u.isp24.srr_reject_code = 0;
374562306a36Sopenharmony_ci	nack->u.isp24.srr_reject_code_expl = 0;
374662306a36Sopenharmony_ci	nack->u.isp24.vp_index = ntfy->u.isp24.vp_index;
374762306a36Sopenharmony_ci
374862306a36Sopenharmony_ci	if (ntfy->u.isp24.status_subcode == ELS_PLOGI &&
374962306a36Sopenharmony_ci	    (le16_to_cpu(ntfy->u.isp24.flags) & NOTIFY24XX_FLAGS_FCSP) &&
375062306a36Sopenharmony_ci	    sp->vha->hw->flags.edif_enabled) {
375162306a36Sopenharmony_ci		ql_dbg(ql_dbg_disc, sp->vha, 0x3074,
375262306a36Sopenharmony_ci		    "%s PLOGI NACK sent with FC SECURITY bit, hdl=%x, loopid=%x, to pid %06x\n",
375362306a36Sopenharmony_ci		    sp->name, sp->handle, sp->fcport->loop_id,
375462306a36Sopenharmony_ci		    sp->fcport->d_id.b24);
375562306a36Sopenharmony_ci		nack->u.isp24.flags |= cpu_to_le16(NOTIFY_ACK_FLAGS_FCSP);
375662306a36Sopenharmony_ci	}
375762306a36Sopenharmony_ci}
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_ci/*
376062306a36Sopenharmony_ci * Build NVME LS request
376162306a36Sopenharmony_ci */
376262306a36Sopenharmony_cistatic void
376362306a36Sopenharmony_ciqla_nvme_ls(srb_t *sp, struct pt_ls4_request *cmd_pkt)
376462306a36Sopenharmony_ci{
376562306a36Sopenharmony_ci	struct srb_iocb *nvme;
376662306a36Sopenharmony_ci
376762306a36Sopenharmony_ci	nvme = &sp->u.iocb_cmd;
376862306a36Sopenharmony_ci	cmd_pkt->entry_type = PT_LS4_REQUEST;
376962306a36Sopenharmony_ci	cmd_pkt->entry_count = 1;
377062306a36Sopenharmony_ci	cmd_pkt->timeout = cpu_to_le16(nvme->u.nvme.timeout_sec);
377162306a36Sopenharmony_ci	cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
377262306a36Sopenharmony_ci
377362306a36Sopenharmony_ci	if (sp->unsol_rsp) {
377462306a36Sopenharmony_ci		cmd_pkt->control_flags =
377562306a36Sopenharmony_ci				cpu_to_le16(CF_LS4_RESPONDER << CF_LS4_SHIFT);
377662306a36Sopenharmony_ci		cmd_pkt->nport_handle = nvme->u.nvme.nport_handle;
377762306a36Sopenharmony_ci		cmd_pkt->exchange_address = nvme->u.nvme.exchange_address;
377862306a36Sopenharmony_ci	} else {
377962306a36Sopenharmony_ci		cmd_pkt->control_flags =
378062306a36Sopenharmony_ci				cpu_to_le16(CF_LS4_ORIGINATOR << CF_LS4_SHIFT);
378162306a36Sopenharmony_ci		cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
378262306a36Sopenharmony_ci		cmd_pkt->rx_dseg_count = cpu_to_le16(1);
378362306a36Sopenharmony_ci		cmd_pkt->rx_byte_count = nvme->u.nvme.rsp_len;
378462306a36Sopenharmony_ci		cmd_pkt->dsd[1].length  = nvme->u.nvme.rsp_len;
378562306a36Sopenharmony_ci		put_unaligned_le64(nvme->u.nvme.rsp_dma, &cmd_pkt->dsd[1].address);
378662306a36Sopenharmony_ci	}
378762306a36Sopenharmony_ci
378862306a36Sopenharmony_ci	cmd_pkt->tx_dseg_count = cpu_to_le16(1);
378962306a36Sopenharmony_ci	cmd_pkt->tx_byte_count = nvme->u.nvme.cmd_len;
379062306a36Sopenharmony_ci	cmd_pkt->dsd[0].length = nvme->u.nvme.cmd_len;
379162306a36Sopenharmony_ci	put_unaligned_le64(nvme->u.nvme.cmd_dma, &cmd_pkt->dsd[0].address);
379262306a36Sopenharmony_ci}
379362306a36Sopenharmony_ci
379462306a36Sopenharmony_cistatic void
379562306a36Sopenharmony_ciqla25xx_ctrlvp_iocb(srb_t *sp, struct vp_ctrl_entry_24xx *vce)
379662306a36Sopenharmony_ci{
379762306a36Sopenharmony_ci	int map, pos;
379862306a36Sopenharmony_ci
379962306a36Sopenharmony_ci	vce->entry_type = VP_CTRL_IOCB_TYPE;
380062306a36Sopenharmony_ci	vce->handle = sp->handle;
380162306a36Sopenharmony_ci	vce->entry_count = 1;
380262306a36Sopenharmony_ci	vce->command = cpu_to_le16(sp->u.iocb_cmd.u.ctrlvp.cmd);
380362306a36Sopenharmony_ci	vce->vp_count = cpu_to_le16(1);
380462306a36Sopenharmony_ci
380562306a36Sopenharmony_ci	/*
380662306a36Sopenharmony_ci	 * index map in firmware starts with 1; decrement index
380762306a36Sopenharmony_ci	 * this is ok as we never use index 0
380862306a36Sopenharmony_ci	 */
380962306a36Sopenharmony_ci	map = (sp->u.iocb_cmd.u.ctrlvp.vp_index - 1) / 8;
381062306a36Sopenharmony_ci	pos = (sp->u.iocb_cmd.u.ctrlvp.vp_index - 1) & 7;
381162306a36Sopenharmony_ci	vce->vp_idx_map[map] |= 1 << pos;
381262306a36Sopenharmony_ci}
381362306a36Sopenharmony_ci
381462306a36Sopenharmony_cistatic void
381562306a36Sopenharmony_ciqla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio)
381662306a36Sopenharmony_ci{
381762306a36Sopenharmony_ci	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
381862306a36Sopenharmony_ci	logio->control_flags =
381962306a36Sopenharmony_ci	    cpu_to_le16(LCF_COMMAND_PRLO|LCF_IMPL_PRLO);
382062306a36Sopenharmony_ci
382162306a36Sopenharmony_ci	logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
382262306a36Sopenharmony_ci	logio->port_id[0] = sp->fcport->d_id.b.al_pa;
382362306a36Sopenharmony_ci	logio->port_id[1] = sp->fcport->d_id.b.area;
382462306a36Sopenharmony_ci	logio->port_id[2] = sp->fcport->d_id.b.domain;
382562306a36Sopenharmony_ci	logio->vp_index = sp->fcport->vha->vp_idx;
382662306a36Sopenharmony_ci}
382762306a36Sopenharmony_ci
382862306a36Sopenharmony_cistatic int qla_get_iocbs_resource(struct srb *sp)
382962306a36Sopenharmony_ci{
383062306a36Sopenharmony_ci	bool get_exch;
383162306a36Sopenharmony_ci	bool push_it_through = false;
383262306a36Sopenharmony_ci
383362306a36Sopenharmony_ci	if (!ql2xenforce_iocb_limit) {
383462306a36Sopenharmony_ci		sp->iores.res_type = RESOURCE_NONE;
383562306a36Sopenharmony_ci		return 0;
383662306a36Sopenharmony_ci	}
383762306a36Sopenharmony_ci	sp->iores.res_type = RESOURCE_NONE;
383862306a36Sopenharmony_ci
383962306a36Sopenharmony_ci	switch (sp->type) {
384062306a36Sopenharmony_ci	case SRB_TM_CMD:
384162306a36Sopenharmony_ci	case SRB_PRLI_CMD:
384262306a36Sopenharmony_ci	case SRB_ADISC_CMD:
384362306a36Sopenharmony_ci		push_it_through = true;
384462306a36Sopenharmony_ci		fallthrough;
384562306a36Sopenharmony_ci	case SRB_LOGIN_CMD:
384662306a36Sopenharmony_ci	case SRB_ELS_CMD_RPT:
384762306a36Sopenharmony_ci	case SRB_ELS_CMD_HST:
384862306a36Sopenharmony_ci	case SRB_ELS_CMD_HST_NOLOGIN:
384962306a36Sopenharmony_ci	case SRB_CT_CMD:
385062306a36Sopenharmony_ci	case SRB_NVME_LS:
385162306a36Sopenharmony_ci	case SRB_ELS_DCMD:
385262306a36Sopenharmony_ci		get_exch = true;
385362306a36Sopenharmony_ci		break;
385462306a36Sopenharmony_ci
385562306a36Sopenharmony_ci	case SRB_FXIOCB_DCMD:
385662306a36Sopenharmony_ci	case SRB_FXIOCB_BCMD:
385762306a36Sopenharmony_ci		sp->iores.res_type = RESOURCE_NONE;
385862306a36Sopenharmony_ci		return 0;
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci	case SRB_SA_UPDATE:
386162306a36Sopenharmony_ci	case SRB_SA_REPLACE:
386262306a36Sopenharmony_ci	case SRB_MB_IOCB:
386362306a36Sopenharmony_ci	case SRB_ABT_CMD:
386462306a36Sopenharmony_ci	case SRB_NACK_PLOGI:
386562306a36Sopenharmony_ci	case SRB_NACK_PRLI:
386662306a36Sopenharmony_ci	case SRB_NACK_LOGO:
386762306a36Sopenharmony_ci	case SRB_LOGOUT_CMD:
386862306a36Sopenharmony_ci	case SRB_CTRL_VP:
386962306a36Sopenharmony_ci	case SRB_MARKER:
387062306a36Sopenharmony_ci	default:
387162306a36Sopenharmony_ci		push_it_through = true;
387262306a36Sopenharmony_ci		get_exch = false;
387362306a36Sopenharmony_ci	}
387462306a36Sopenharmony_ci
387562306a36Sopenharmony_ci	sp->iores.res_type |= RESOURCE_IOCB;
387662306a36Sopenharmony_ci	sp->iores.iocb_cnt = 1;
387762306a36Sopenharmony_ci	if (get_exch) {
387862306a36Sopenharmony_ci		sp->iores.res_type |= RESOURCE_EXCH;
387962306a36Sopenharmony_ci		sp->iores.exch_cnt = 1;
388062306a36Sopenharmony_ci	}
388162306a36Sopenharmony_ci	if (push_it_through)
388262306a36Sopenharmony_ci		sp->iores.res_type |= RESOURCE_FORCE;
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci	return qla_get_fw_resources(sp->qpair, &sp->iores);
388562306a36Sopenharmony_ci}
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_cistatic void
388862306a36Sopenharmony_ciqla_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk)
388962306a36Sopenharmony_ci{
389062306a36Sopenharmony_ci	mrk->entry_type = MARKER_TYPE;
389162306a36Sopenharmony_ci	mrk->modifier = sp->u.iocb_cmd.u.tmf.modifier;
389262306a36Sopenharmony_ci	mrk->handle = make_handle(sp->qpair->req->id, sp->handle);
389362306a36Sopenharmony_ci	if (sp->u.iocb_cmd.u.tmf.modifier != MK_SYNC_ALL) {
389462306a36Sopenharmony_ci		mrk->nport_handle = cpu_to_le16(sp->u.iocb_cmd.u.tmf.loop_id);
389562306a36Sopenharmony_ci		int_to_scsilun(sp->u.iocb_cmd.u.tmf.lun, (struct scsi_lun *)&mrk->lun);
389662306a36Sopenharmony_ci		host_to_fcp_swap(mrk->lun, sizeof(mrk->lun));
389762306a36Sopenharmony_ci		mrk->vp_index = sp->u.iocb_cmd.u.tmf.vp_index;
389862306a36Sopenharmony_ci	}
389962306a36Sopenharmony_ci}
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ciint
390262306a36Sopenharmony_ciqla2x00_start_sp(srb_t *sp)
390362306a36Sopenharmony_ci{
390462306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
390562306a36Sopenharmony_ci	scsi_qla_host_t *vha = sp->vha;
390662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
390762306a36Sopenharmony_ci	struct qla_qpair *qp = sp->qpair;
390862306a36Sopenharmony_ci	void *pkt;
390962306a36Sopenharmony_ci	unsigned long flags;
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_ci	if (vha->hw->flags.eeh_busy)
391262306a36Sopenharmony_ci		return -EIO;
391362306a36Sopenharmony_ci
391462306a36Sopenharmony_ci	spin_lock_irqsave(qp->qp_lock_ptr, flags);
391562306a36Sopenharmony_ci	rval = qla_get_iocbs_resource(sp);
391662306a36Sopenharmony_ci	if (rval) {
391762306a36Sopenharmony_ci		spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
391862306a36Sopenharmony_ci		return -EAGAIN;
391962306a36Sopenharmony_ci	}
392062306a36Sopenharmony_ci
392162306a36Sopenharmony_ci	pkt = __qla2x00_alloc_iocbs(sp->qpair, sp);
392262306a36Sopenharmony_ci	if (!pkt) {
392362306a36Sopenharmony_ci		rval = -EAGAIN;
392462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x700c,
392562306a36Sopenharmony_ci		    "qla2x00_alloc_iocbs failed.\n");
392662306a36Sopenharmony_ci		goto done;
392762306a36Sopenharmony_ci	}
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_ci	switch (sp->type) {
393062306a36Sopenharmony_ci	case SRB_LOGIN_CMD:
393162306a36Sopenharmony_ci		IS_FWI2_CAPABLE(ha) ?
393262306a36Sopenharmony_ci		    qla24xx_login_iocb(sp, pkt) :
393362306a36Sopenharmony_ci		    qla2x00_login_iocb(sp, pkt);
393462306a36Sopenharmony_ci		break;
393562306a36Sopenharmony_ci	case SRB_PRLI_CMD:
393662306a36Sopenharmony_ci		qla24xx_prli_iocb(sp, pkt);
393762306a36Sopenharmony_ci		break;
393862306a36Sopenharmony_ci	case SRB_LOGOUT_CMD:
393962306a36Sopenharmony_ci		IS_FWI2_CAPABLE(ha) ?
394062306a36Sopenharmony_ci		    qla24xx_logout_iocb(sp, pkt) :
394162306a36Sopenharmony_ci		    qla2x00_logout_iocb(sp, pkt);
394262306a36Sopenharmony_ci		break;
394362306a36Sopenharmony_ci	case SRB_ELS_CMD_RPT:
394462306a36Sopenharmony_ci	case SRB_ELS_CMD_HST:
394562306a36Sopenharmony_ci		qla24xx_els_iocb(sp, pkt);
394662306a36Sopenharmony_ci		break;
394762306a36Sopenharmony_ci	case SRB_ELS_CMD_HST_NOLOGIN:
394862306a36Sopenharmony_ci		qla_els_pt_iocb(sp->vha, pkt,  &sp->u.bsg_cmd.u.els_arg);
394962306a36Sopenharmony_ci		((struct els_entry_24xx *)pkt)->handle = sp->handle;
395062306a36Sopenharmony_ci		break;
395162306a36Sopenharmony_ci	case SRB_CT_CMD:
395262306a36Sopenharmony_ci		IS_FWI2_CAPABLE(ha) ?
395362306a36Sopenharmony_ci		    qla24xx_ct_iocb(sp, pkt) :
395462306a36Sopenharmony_ci		    qla2x00_ct_iocb(sp, pkt);
395562306a36Sopenharmony_ci		break;
395662306a36Sopenharmony_ci	case SRB_ADISC_CMD:
395762306a36Sopenharmony_ci		IS_FWI2_CAPABLE(ha) ?
395862306a36Sopenharmony_ci		    qla24xx_adisc_iocb(sp, pkt) :
395962306a36Sopenharmony_ci		    qla2x00_adisc_iocb(sp, pkt);
396062306a36Sopenharmony_ci		break;
396162306a36Sopenharmony_ci	case SRB_TM_CMD:
396262306a36Sopenharmony_ci		IS_QLAFX00(ha) ?
396362306a36Sopenharmony_ci		    qlafx00_tm_iocb(sp, pkt) :
396462306a36Sopenharmony_ci		    qla24xx_tm_iocb(sp, pkt);
396562306a36Sopenharmony_ci		break;
396662306a36Sopenharmony_ci	case SRB_FXIOCB_DCMD:
396762306a36Sopenharmony_ci	case SRB_FXIOCB_BCMD:
396862306a36Sopenharmony_ci		qlafx00_fxdisc_iocb(sp, pkt);
396962306a36Sopenharmony_ci		break;
397062306a36Sopenharmony_ci	case SRB_NVME_LS:
397162306a36Sopenharmony_ci		qla_nvme_ls(sp, pkt);
397262306a36Sopenharmony_ci		break;
397362306a36Sopenharmony_ci	case SRB_ABT_CMD:
397462306a36Sopenharmony_ci		IS_QLAFX00(ha) ?
397562306a36Sopenharmony_ci			qlafx00_abort_iocb(sp, pkt) :
397662306a36Sopenharmony_ci			qla24xx_abort_iocb(sp, pkt);
397762306a36Sopenharmony_ci		break;
397862306a36Sopenharmony_ci	case SRB_ELS_DCMD:
397962306a36Sopenharmony_ci		qla24xx_els_logo_iocb(sp, pkt);
398062306a36Sopenharmony_ci		break;
398162306a36Sopenharmony_ci	case SRB_CT_PTHRU_CMD:
398262306a36Sopenharmony_ci		qla2x00_ctpthru_cmd_iocb(sp, pkt);
398362306a36Sopenharmony_ci		break;
398462306a36Sopenharmony_ci	case SRB_MB_IOCB:
398562306a36Sopenharmony_ci		qla2x00_mb_iocb(sp, pkt);
398662306a36Sopenharmony_ci		break;
398762306a36Sopenharmony_ci	case SRB_NACK_PLOGI:
398862306a36Sopenharmony_ci	case SRB_NACK_PRLI:
398962306a36Sopenharmony_ci	case SRB_NACK_LOGO:
399062306a36Sopenharmony_ci		qla2x00_send_notify_ack_iocb(sp, pkt);
399162306a36Sopenharmony_ci		break;
399262306a36Sopenharmony_ci	case SRB_CTRL_VP:
399362306a36Sopenharmony_ci		qla25xx_ctrlvp_iocb(sp, pkt);
399462306a36Sopenharmony_ci		break;
399562306a36Sopenharmony_ci	case SRB_PRLO_CMD:
399662306a36Sopenharmony_ci		qla24xx_prlo_iocb(sp, pkt);
399762306a36Sopenharmony_ci		break;
399862306a36Sopenharmony_ci	case SRB_SA_UPDATE:
399962306a36Sopenharmony_ci		qla24xx_sa_update_iocb(sp, pkt);
400062306a36Sopenharmony_ci		break;
400162306a36Sopenharmony_ci	case SRB_SA_REPLACE:
400262306a36Sopenharmony_ci		qla24xx_sa_replace_iocb(sp, pkt);
400362306a36Sopenharmony_ci		break;
400462306a36Sopenharmony_ci	case SRB_MARKER:
400562306a36Sopenharmony_ci		qla_marker_iocb(sp, pkt);
400662306a36Sopenharmony_ci		break;
400762306a36Sopenharmony_ci	default:
400862306a36Sopenharmony_ci		break;
400962306a36Sopenharmony_ci	}
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_ci	if (sp->start_timer) {
401262306a36Sopenharmony_ci		/* ref: TMR timer ref
401362306a36Sopenharmony_ci		 * this code should be just before start_iocbs function
401462306a36Sopenharmony_ci		 * This will make sure that caller function don't to do
401562306a36Sopenharmony_ci		 * kref_put even on failure
401662306a36Sopenharmony_ci		 */
401762306a36Sopenharmony_ci		kref_get(&sp->cmd_kref);
401862306a36Sopenharmony_ci		add_timer(&sp->u.iocb_cmd.timer);
401962306a36Sopenharmony_ci	}
402062306a36Sopenharmony_ci
402162306a36Sopenharmony_ci	wmb();
402262306a36Sopenharmony_ci	qla2x00_start_iocbs(vha, qp->req);
402362306a36Sopenharmony_cidone:
402462306a36Sopenharmony_ci	if (rval)
402562306a36Sopenharmony_ci		qla_put_fw_resources(sp->qpair, &sp->iores);
402662306a36Sopenharmony_ci	spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
402762306a36Sopenharmony_ci	return rval;
402862306a36Sopenharmony_ci}
402962306a36Sopenharmony_ci
403062306a36Sopenharmony_cistatic void
403162306a36Sopenharmony_ciqla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha,
403262306a36Sopenharmony_ci				struct cmd_bidir *cmd_pkt, uint32_t tot_dsds)
403362306a36Sopenharmony_ci{
403462306a36Sopenharmony_ci	uint16_t avail_dsds;
403562306a36Sopenharmony_ci	struct dsd64 *cur_dsd;
403662306a36Sopenharmony_ci	uint32_t req_data_len = 0;
403762306a36Sopenharmony_ci	uint32_t rsp_data_len = 0;
403862306a36Sopenharmony_ci	struct scatterlist *sg;
403962306a36Sopenharmony_ci	int index;
404062306a36Sopenharmony_ci	int entry_count = 1;
404162306a36Sopenharmony_ci	struct bsg_job *bsg_job = sp->u.bsg_job;
404262306a36Sopenharmony_ci
404362306a36Sopenharmony_ci	/*Update entry type to indicate bidir command */
404462306a36Sopenharmony_ci	put_unaligned_le32(COMMAND_BIDIRECTIONAL, &cmd_pkt->entry_type);
404562306a36Sopenharmony_ci
404662306a36Sopenharmony_ci	/* Set the transfer direction, in this set both flags
404762306a36Sopenharmony_ci	 * Also set the BD_WRAP_BACK flag, firmware will take care
404862306a36Sopenharmony_ci	 * assigning DID=SID for outgoing pkts.
404962306a36Sopenharmony_ci	 */
405062306a36Sopenharmony_ci	cmd_pkt->wr_dseg_count = cpu_to_le16(bsg_job->request_payload.sg_cnt);
405162306a36Sopenharmony_ci	cmd_pkt->rd_dseg_count = cpu_to_le16(bsg_job->reply_payload.sg_cnt);
405262306a36Sopenharmony_ci	cmd_pkt->control_flags = cpu_to_le16(BD_WRITE_DATA | BD_READ_DATA |
405362306a36Sopenharmony_ci							BD_WRAP_BACK);
405462306a36Sopenharmony_ci
405562306a36Sopenharmony_ci	req_data_len = rsp_data_len = bsg_job->request_payload.payload_len;
405662306a36Sopenharmony_ci	cmd_pkt->wr_byte_count = cpu_to_le32(req_data_len);
405762306a36Sopenharmony_ci	cmd_pkt->rd_byte_count = cpu_to_le32(rsp_data_len);
405862306a36Sopenharmony_ci	cmd_pkt->timeout = cpu_to_le16(qla2x00_get_async_timeout(vha) + 2);
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_ci	vha->bidi_stats.transfer_bytes += req_data_len;
406162306a36Sopenharmony_ci	vha->bidi_stats.io_count++;
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_ci	vha->qla_stats.output_bytes += req_data_len;
406462306a36Sopenharmony_ci	vha->qla_stats.output_requests++;
406562306a36Sopenharmony_ci
406662306a36Sopenharmony_ci	/* Only one dsd is available for bidirectional IOCB, remaining dsds
406762306a36Sopenharmony_ci	 * are bundled in continuation iocb
406862306a36Sopenharmony_ci	 */
406962306a36Sopenharmony_ci	avail_dsds = 1;
407062306a36Sopenharmony_ci	cur_dsd = &cmd_pkt->fcp_dsd;
407162306a36Sopenharmony_ci
407262306a36Sopenharmony_ci	index = 0;
407362306a36Sopenharmony_ci
407462306a36Sopenharmony_ci	for_each_sg(bsg_job->request_payload.sg_list, sg,
407562306a36Sopenharmony_ci				bsg_job->request_payload.sg_cnt, index) {
407662306a36Sopenharmony_ci		cont_a64_entry_t *cont_pkt;
407762306a36Sopenharmony_ci
407862306a36Sopenharmony_ci		/* Allocate additional continuation packets */
407962306a36Sopenharmony_ci		if (avail_dsds == 0) {
408062306a36Sopenharmony_ci			/* Continuation type 1 IOCB can accomodate
408162306a36Sopenharmony_ci			 * 5 DSDS
408262306a36Sopenharmony_ci			 */
408362306a36Sopenharmony_ci			cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req);
408462306a36Sopenharmony_ci			cur_dsd = cont_pkt->dsd;
408562306a36Sopenharmony_ci			avail_dsds = 5;
408662306a36Sopenharmony_ci			entry_count++;
408762306a36Sopenharmony_ci		}
408862306a36Sopenharmony_ci		append_dsd64(&cur_dsd, sg);
408962306a36Sopenharmony_ci		avail_dsds--;
409062306a36Sopenharmony_ci	}
409162306a36Sopenharmony_ci	/* For read request DSD will always goes to continuation IOCB
409262306a36Sopenharmony_ci	 * and follow the write DSD. If there is room on the current IOCB
409362306a36Sopenharmony_ci	 * then it is added to that IOCB else new continuation IOCB is
409462306a36Sopenharmony_ci	 * allocated.
409562306a36Sopenharmony_ci	 */
409662306a36Sopenharmony_ci	for_each_sg(bsg_job->reply_payload.sg_list, sg,
409762306a36Sopenharmony_ci				bsg_job->reply_payload.sg_cnt, index) {
409862306a36Sopenharmony_ci		cont_a64_entry_t *cont_pkt;
409962306a36Sopenharmony_ci
410062306a36Sopenharmony_ci		/* Allocate additional continuation packets */
410162306a36Sopenharmony_ci		if (avail_dsds == 0) {
410262306a36Sopenharmony_ci			/* Continuation type 1 IOCB can accomodate
410362306a36Sopenharmony_ci			 * 5 DSDS
410462306a36Sopenharmony_ci			 */
410562306a36Sopenharmony_ci			cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req);
410662306a36Sopenharmony_ci			cur_dsd = cont_pkt->dsd;
410762306a36Sopenharmony_ci			avail_dsds = 5;
410862306a36Sopenharmony_ci			entry_count++;
410962306a36Sopenharmony_ci		}
411062306a36Sopenharmony_ci		append_dsd64(&cur_dsd, sg);
411162306a36Sopenharmony_ci		avail_dsds--;
411262306a36Sopenharmony_ci	}
411362306a36Sopenharmony_ci	/* This value should be same as number of IOCB required for this cmd */
411462306a36Sopenharmony_ci	cmd_pkt->entry_count = entry_count;
411562306a36Sopenharmony_ci}
411662306a36Sopenharmony_ci
411762306a36Sopenharmony_ciint
411862306a36Sopenharmony_ciqla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds)
411962306a36Sopenharmony_ci{
412062306a36Sopenharmony_ci
412162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
412262306a36Sopenharmony_ci	unsigned long flags;
412362306a36Sopenharmony_ci	uint32_t handle;
412462306a36Sopenharmony_ci	uint16_t req_cnt;
412562306a36Sopenharmony_ci	uint16_t cnt;
412662306a36Sopenharmony_ci	uint32_t *clr_ptr;
412762306a36Sopenharmony_ci	struct cmd_bidir *cmd_pkt = NULL;
412862306a36Sopenharmony_ci	struct rsp_que *rsp;
412962306a36Sopenharmony_ci	struct req_que *req;
413062306a36Sopenharmony_ci	int rval = EXT_STATUS_OK;
413162306a36Sopenharmony_ci
413262306a36Sopenharmony_ci	rval = QLA_SUCCESS;
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_ci	rsp = ha->rsp_q_map[0];
413562306a36Sopenharmony_ci	req = vha->req;
413662306a36Sopenharmony_ci
413762306a36Sopenharmony_ci	/* Send marker if required */
413862306a36Sopenharmony_ci	if (vha->marker_needed != 0) {
413962306a36Sopenharmony_ci		if (qla2x00_marker(vha, ha->base_qpair,
414062306a36Sopenharmony_ci			0, 0, MK_SYNC_ALL) != QLA_SUCCESS)
414162306a36Sopenharmony_ci			return EXT_STATUS_MAILBOX;
414262306a36Sopenharmony_ci		vha->marker_needed = 0;
414362306a36Sopenharmony_ci	}
414462306a36Sopenharmony_ci
414562306a36Sopenharmony_ci	/* Acquire ring specific lock */
414662306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
414762306a36Sopenharmony_ci
414862306a36Sopenharmony_ci	handle = qla2xxx_get_next_handle(req);
414962306a36Sopenharmony_ci	if (handle == 0) {
415062306a36Sopenharmony_ci		rval = EXT_STATUS_BUSY;
415162306a36Sopenharmony_ci		goto queuing_error;
415262306a36Sopenharmony_ci	}
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_ci	/* Calculate number of IOCB required */
415562306a36Sopenharmony_ci	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
415662306a36Sopenharmony_ci
415762306a36Sopenharmony_ci	/* Check for room on request queue. */
415862306a36Sopenharmony_ci	if (req->cnt < req_cnt + 2) {
415962306a36Sopenharmony_ci		if (IS_SHADOW_REG_CAPABLE(ha)) {
416062306a36Sopenharmony_ci			cnt = *req->out_ptr;
416162306a36Sopenharmony_ci		} else {
416262306a36Sopenharmony_ci			cnt = rd_reg_dword_relaxed(req->req_q_out);
416362306a36Sopenharmony_ci			if (qla2x00_check_reg16_for_disconnect(vha, cnt))
416462306a36Sopenharmony_ci				goto queuing_error;
416562306a36Sopenharmony_ci		}
416662306a36Sopenharmony_ci
416762306a36Sopenharmony_ci		if  (req->ring_index < cnt)
416862306a36Sopenharmony_ci			req->cnt = cnt - req->ring_index;
416962306a36Sopenharmony_ci		else
417062306a36Sopenharmony_ci			req->cnt = req->length -
417162306a36Sopenharmony_ci				(req->ring_index - cnt);
417262306a36Sopenharmony_ci	}
417362306a36Sopenharmony_ci	if (req->cnt < req_cnt + 2) {
417462306a36Sopenharmony_ci		rval = EXT_STATUS_BUSY;
417562306a36Sopenharmony_ci		goto queuing_error;
417662306a36Sopenharmony_ci	}
417762306a36Sopenharmony_ci
417862306a36Sopenharmony_ci	cmd_pkt = (struct cmd_bidir *)req->ring_ptr;
417962306a36Sopenharmony_ci	cmd_pkt->handle = make_handle(req->id, handle);
418062306a36Sopenharmony_ci
418162306a36Sopenharmony_ci	/* Zero out remaining portion of packet. */
418262306a36Sopenharmony_ci	/* tagged queuing modifier -- default is TSK_SIMPLE (0).*/
418362306a36Sopenharmony_ci	clr_ptr = (uint32_t *)cmd_pkt + 2;
418462306a36Sopenharmony_ci	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
418562306a36Sopenharmony_ci
418662306a36Sopenharmony_ci	/* Set NPORT-ID  (of vha)*/
418762306a36Sopenharmony_ci	cmd_pkt->nport_handle = cpu_to_le16(vha->self_login_loop_id);
418862306a36Sopenharmony_ci	cmd_pkt->port_id[0] = vha->d_id.b.al_pa;
418962306a36Sopenharmony_ci	cmd_pkt->port_id[1] = vha->d_id.b.area;
419062306a36Sopenharmony_ci	cmd_pkt->port_id[2] = vha->d_id.b.domain;
419162306a36Sopenharmony_ci
419262306a36Sopenharmony_ci	qla25xx_build_bidir_iocb(sp, vha, cmd_pkt, tot_dsds);
419362306a36Sopenharmony_ci	cmd_pkt->entry_status = (uint8_t) rsp->id;
419462306a36Sopenharmony_ci	/* Build command packet. */
419562306a36Sopenharmony_ci	req->current_outstanding_cmd = handle;
419662306a36Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
419762306a36Sopenharmony_ci	sp->handle = handle;
419862306a36Sopenharmony_ci	req->cnt -= req_cnt;
419962306a36Sopenharmony_ci
420062306a36Sopenharmony_ci	/* Send the command to the firmware */
420162306a36Sopenharmony_ci	wmb();
420262306a36Sopenharmony_ci	qla2x00_start_iocbs(vha, req);
420362306a36Sopenharmony_ciqueuing_error:
420462306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
420562306a36Sopenharmony_ci
420662306a36Sopenharmony_ci	return rval;
420762306a36Sopenharmony_ci}
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci/**
421062306a36Sopenharmony_ci * qla_start_scsi_type6() - Send a SCSI command to the ISP
421162306a36Sopenharmony_ci * @sp: command to send to the ISP
421262306a36Sopenharmony_ci *
421362306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero.
421462306a36Sopenharmony_ci */
421562306a36Sopenharmony_cistatic int
421662306a36Sopenharmony_ciqla_start_scsi_type6(srb_t *sp)
421762306a36Sopenharmony_ci{
421862306a36Sopenharmony_ci	int		nseg;
421962306a36Sopenharmony_ci	unsigned long   flags;
422062306a36Sopenharmony_ci	uint32_t	*clr_ptr;
422162306a36Sopenharmony_ci	uint32_t	handle;
422262306a36Sopenharmony_ci	struct cmd_type_6 *cmd_pkt;
422362306a36Sopenharmony_ci	uint16_t	cnt;
422462306a36Sopenharmony_ci	uint16_t	req_cnt;
422562306a36Sopenharmony_ci	uint16_t	tot_dsds;
422662306a36Sopenharmony_ci	struct req_que *req = NULL;
422762306a36Sopenharmony_ci	struct rsp_que *rsp;
422862306a36Sopenharmony_ci	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
422962306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->fcport->vha;
423062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
423162306a36Sopenharmony_ci	struct qla_qpair *qpair = sp->qpair;
423262306a36Sopenharmony_ci	uint16_t more_dsd_lists = 0;
423362306a36Sopenharmony_ci	struct dsd_dma *dsd_ptr;
423462306a36Sopenharmony_ci	uint16_t i;
423562306a36Sopenharmony_ci	__be32 *fcp_dl;
423662306a36Sopenharmony_ci	uint8_t additional_cdb_len;
423762306a36Sopenharmony_ci	struct ct6_dsd *ctx;
423862306a36Sopenharmony_ci
423962306a36Sopenharmony_ci	/* Acquire qpair specific lock */
424062306a36Sopenharmony_ci	spin_lock_irqsave(&qpair->qp_lock, flags);
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_ci	/* Setup qpair pointers */
424362306a36Sopenharmony_ci	req = qpair->req;
424462306a36Sopenharmony_ci	rsp = qpair->rsp;
424562306a36Sopenharmony_ci
424662306a36Sopenharmony_ci	/* So we know we haven't pci_map'ed anything yet */
424762306a36Sopenharmony_ci	tot_dsds = 0;
424862306a36Sopenharmony_ci
424962306a36Sopenharmony_ci	/* Send marker if required */
425062306a36Sopenharmony_ci	if (vha->marker_needed != 0) {
425162306a36Sopenharmony_ci		if (__qla2x00_marker(vha, qpair, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) {
425262306a36Sopenharmony_ci			spin_unlock_irqrestore(&qpair->qp_lock, flags);
425362306a36Sopenharmony_ci			return QLA_FUNCTION_FAILED;
425462306a36Sopenharmony_ci		}
425562306a36Sopenharmony_ci		vha->marker_needed = 0;
425662306a36Sopenharmony_ci	}
425762306a36Sopenharmony_ci
425862306a36Sopenharmony_ci	handle = qla2xxx_get_next_handle(req);
425962306a36Sopenharmony_ci	if (handle == 0)
426062306a36Sopenharmony_ci		goto queuing_error;
426162306a36Sopenharmony_ci
426262306a36Sopenharmony_ci	/* Map the sg table so we have an accurate count of sg entries needed */
426362306a36Sopenharmony_ci	if (scsi_sg_count(cmd)) {
426462306a36Sopenharmony_ci		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
426562306a36Sopenharmony_ci				  scsi_sg_count(cmd), cmd->sc_data_direction);
426662306a36Sopenharmony_ci		if (unlikely(!nseg))
426762306a36Sopenharmony_ci			goto queuing_error;
426862306a36Sopenharmony_ci	} else {
426962306a36Sopenharmony_ci		nseg = 0;
427062306a36Sopenharmony_ci	}
427162306a36Sopenharmony_ci
427262306a36Sopenharmony_ci	tot_dsds = nseg;
427362306a36Sopenharmony_ci
427462306a36Sopenharmony_ci	/* eventhough driver only need 1 T6 IOCB, FW still convert DSD to Continueation IOCB */
427562306a36Sopenharmony_ci	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_ci	sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
427862306a36Sopenharmony_ci	sp->iores.exch_cnt = 1;
427962306a36Sopenharmony_ci	sp->iores.iocb_cnt = req_cnt;
428062306a36Sopenharmony_ci
428162306a36Sopenharmony_ci	if (qla_get_fw_resources(sp->qpair, &sp->iores))
428262306a36Sopenharmony_ci		goto queuing_error;
428362306a36Sopenharmony_ci
428462306a36Sopenharmony_ci	more_dsd_lists = qla24xx_calc_dsd_lists(tot_dsds);
428562306a36Sopenharmony_ci	if ((more_dsd_lists + qpair->dsd_inuse) >= NUM_DSD_CHAIN) {
428662306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3028,
428762306a36Sopenharmony_ci		       "Num of DSD list %d is than %d for cmd=%p.\n",
428862306a36Sopenharmony_ci		       more_dsd_lists + qpair->dsd_inuse, NUM_DSD_CHAIN, cmd);
428962306a36Sopenharmony_ci		goto queuing_error;
429062306a36Sopenharmony_ci	}
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ci	if (more_dsd_lists <= qpair->dsd_avail)
429362306a36Sopenharmony_ci		goto sufficient_dsds;
429462306a36Sopenharmony_ci	else
429562306a36Sopenharmony_ci		more_dsd_lists -= qpair->dsd_avail;
429662306a36Sopenharmony_ci
429762306a36Sopenharmony_ci	for (i = 0; i < more_dsd_lists; i++) {
429862306a36Sopenharmony_ci		dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC);
429962306a36Sopenharmony_ci		if (!dsd_ptr) {
430062306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x3029,
430162306a36Sopenharmony_ci			    "Failed to allocate memory for dsd_dma for cmd=%p.\n", cmd);
430262306a36Sopenharmony_ci			goto queuing_error;
430362306a36Sopenharmony_ci		}
430462306a36Sopenharmony_ci		INIT_LIST_HEAD(&dsd_ptr->list);
430562306a36Sopenharmony_ci
430662306a36Sopenharmony_ci		dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool,
430762306a36Sopenharmony_ci			GFP_ATOMIC, &dsd_ptr->dsd_list_dma);
430862306a36Sopenharmony_ci		if (!dsd_ptr->dsd_addr) {
430962306a36Sopenharmony_ci			kfree(dsd_ptr);
431062306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x302a,
431162306a36Sopenharmony_ci			    "Failed to allocate memory for dsd_addr for cmd=%p.\n", cmd);
431262306a36Sopenharmony_ci			goto queuing_error;
431362306a36Sopenharmony_ci		}
431462306a36Sopenharmony_ci		list_add_tail(&dsd_ptr->list, &qpair->dsd_list);
431562306a36Sopenharmony_ci		qpair->dsd_avail++;
431662306a36Sopenharmony_ci	}
431762306a36Sopenharmony_ci
431862306a36Sopenharmony_cisufficient_dsds:
431962306a36Sopenharmony_ci	req_cnt = 1;
432062306a36Sopenharmony_ci
432162306a36Sopenharmony_ci	if (req->cnt < (req_cnt + 2)) {
432262306a36Sopenharmony_ci		if (IS_SHADOW_REG_CAPABLE(ha)) {
432362306a36Sopenharmony_ci			cnt = *req->out_ptr;
432462306a36Sopenharmony_ci		} else {
432562306a36Sopenharmony_ci			cnt = (uint16_t)rd_reg_dword_relaxed(req->req_q_out);
432662306a36Sopenharmony_ci			if (qla2x00_check_reg16_for_disconnect(vha, cnt))
432762306a36Sopenharmony_ci				goto queuing_error;
432862306a36Sopenharmony_ci		}
432962306a36Sopenharmony_ci
433062306a36Sopenharmony_ci		if (req->ring_index < cnt)
433162306a36Sopenharmony_ci			req->cnt = cnt - req->ring_index;
433262306a36Sopenharmony_ci		else
433362306a36Sopenharmony_ci			req->cnt = req->length - (req->ring_index - cnt);
433462306a36Sopenharmony_ci		if (req->cnt < (req_cnt + 2))
433562306a36Sopenharmony_ci			goto queuing_error;
433662306a36Sopenharmony_ci	}
433762306a36Sopenharmony_ci
433862306a36Sopenharmony_ci	ctx = &sp->u.scmd.ct6_ctx;
433962306a36Sopenharmony_ci
434062306a36Sopenharmony_ci	memset(ctx, 0, sizeof(struct ct6_dsd));
434162306a36Sopenharmony_ci	ctx->fcp_cmnd = dma_pool_zalloc(ha->fcp_cmnd_dma_pool,
434262306a36Sopenharmony_ci		GFP_ATOMIC, &ctx->fcp_cmnd_dma);
434362306a36Sopenharmony_ci	if (!ctx->fcp_cmnd) {
434462306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x3031,
434562306a36Sopenharmony_ci		    "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd);
434662306a36Sopenharmony_ci		goto queuing_error;
434762306a36Sopenharmony_ci	}
434862306a36Sopenharmony_ci
434962306a36Sopenharmony_ci	/* Initialize the DSD list and dma handle */
435062306a36Sopenharmony_ci	INIT_LIST_HEAD(&ctx->dsd_list);
435162306a36Sopenharmony_ci	ctx->dsd_use_cnt = 0;
435262306a36Sopenharmony_ci
435362306a36Sopenharmony_ci	if (cmd->cmd_len > 16) {
435462306a36Sopenharmony_ci		additional_cdb_len = cmd->cmd_len - 16;
435562306a36Sopenharmony_ci		if (cmd->cmd_len % 4 ||
435662306a36Sopenharmony_ci		    cmd->cmd_len > QLA_CDB_BUF_SIZE) {
435762306a36Sopenharmony_ci			/*
435862306a36Sopenharmony_ci			 * SCSI command bigger than 16 bytes must be
435962306a36Sopenharmony_ci			 * multiple of 4 or too big.
436062306a36Sopenharmony_ci			 */
436162306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x3033,
436262306a36Sopenharmony_ci			    "scsi cmd len %d not multiple of 4 for cmd=%p.\n",
436362306a36Sopenharmony_ci			    cmd->cmd_len, cmd);
436462306a36Sopenharmony_ci			goto queuing_error_fcp_cmnd;
436562306a36Sopenharmony_ci		}
436662306a36Sopenharmony_ci		ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4;
436762306a36Sopenharmony_ci	} else {
436862306a36Sopenharmony_ci		additional_cdb_len = 0;
436962306a36Sopenharmony_ci		ctx->fcp_cmnd_len = 12 + 16 + 4;
437062306a36Sopenharmony_ci	}
437162306a36Sopenharmony_ci
437262306a36Sopenharmony_ci	/* Build command packet. */
437362306a36Sopenharmony_ci	req->current_outstanding_cmd = handle;
437462306a36Sopenharmony_ci	req->outstanding_cmds[handle] = sp;
437562306a36Sopenharmony_ci	sp->handle = handle;
437662306a36Sopenharmony_ci	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
437762306a36Sopenharmony_ci	req->cnt -= req_cnt;
437862306a36Sopenharmony_ci
437962306a36Sopenharmony_ci	cmd_pkt = (struct cmd_type_6 *)req->ring_ptr;
438062306a36Sopenharmony_ci	cmd_pkt->handle = make_handle(req->id, handle);
438162306a36Sopenharmony_ci
438262306a36Sopenharmony_ci	/* tagged queuing modifier -- default is TSK_SIMPLE (0). */
438362306a36Sopenharmony_ci	clr_ptr = (uint32_t *)cmd_pkt + 2;
438462306a36Sopenharmony_ci	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
438562306a36Sopenharmony_ci	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
438662306a36Sopenharmony_ci
438762306a36Sopenharmony_ci	/* Set NPORT-ID and LUN number */
438862306a36Sopenharmony_ci	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
438962306a36Sopenharmony_ci	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
439062306a36Sopenharmony_ci	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
439162306a36Sopenharmony_ci	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
439262306a36Sopenharmony_ci	cmd_pkt->vp_index = sp->vha->vp_idx;
439362306a36Sopenharmony_ci
439462306a36Sopenharmony_ci	/* Build IOCB segments */
439562306a36Sopenharmony_ci	qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds);
439662306a36Sopenharmony_ci
439762306a36Sopenharmony_ci	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
439862306a36Sopenharmony_ci	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_ci	/* build FCP_CMND IU */
440162306a36Sopenharmony_ci	int_to_scsilun(cmd->device->lun, &ctx->fcp_cmnd->lun);
440262306a36Sopenharmony_ci	ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;
440362306a36Sopenharmony_ci
440462306a36Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE)
440562306a36Sopenharmony_ci		ctx->fcp_cmnd->additional_cdb_len |= 1;
440662306a36Sopenharmony_ci	else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
440762306a36Sopenharmony_ci		ctx->fcp_cmnd->additional_cdb_len |= 2;
440862306a36Sopenharmony_ci
440962306a36Sopenharmony_ci	/* Populate the FCP_PRIO. */
441062306a36Sopenharmony_ci	if (ha->flags.fcp_prio_enabled)
441162306a36Sopenharmony_ci		ctx->fcp_cmnd->task_attribute |=
441262306a36Sopenharmony_ci		    sp->fcport->fcp_prio << 3;
441362306a36Sopenharmony_ci
441462306a36Sopenharmony_ci	memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
441562306a36Sopenharmony_ci
441662306a36Sopenharmony_ci	fcp_dl = (__be32 *)(ctx->fcp_cmnd->cdb + 16 +
441762306a36Sopenharmony_ci	    additional_cdb_len);
441862306a36Sopenharmony_ci	*fcp_dl = htonl((uint32_t)scsi_bufflen(cmd));
441962306a36Sopenharmony_ci
442062306a36Sopenharmony_ci	cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len);
442162306a36Sopenharmony_ci	put_unaligned_le64(ctx->fcp_cmnd_dma,
442262306a36Sopenharmony_ci			   &cmd_pkt->fcp_cmnd_dseg_address);
442362306a36Sopenharmony_ci
442462306a36Sopenharmony_ci	sp->flags |= SRB_FCP_CMND_DMA_VALID;
442562306a36Sopenharmony_ci	cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
442662306a36Sopenharmony_ci	/* Set total data segment count. */
442762306a36Sopenharmony_ci	cmd_pkt->entry_count = (uint8_t)req_cnt;
442862306a36Sopenharmony_ci
442962306a36Sopenharmony_ci	wmb();
443062306a36Sopenharmony_ci	/* Adjust ring index. */
443162306a36Sopenharmony_ci	req->ring_index++;
443262306a36Sopenharmony_ci	if (req->ring_index == req->length) {
443362306a36Sopenharmony_ci		req->ring_index = 0;
443462306a36Sopenharmony_ci		req->ring_ptr = req->ring;
443562306a36Sopenharmony_ci	} else {
443662306a36Sopenharmony_ci		req->ring_ptr++;
443762306a36Sopenharmony_ci	}
443862306a36Sopenharmony_ci
443962306a36Sopenharmony_ci	sp->qpair->cmd_cnt++;
444062306a36Sopenharmony_ci	sp->flags |= SRB_DMA_VALID;
444162306a36Sopenharmony_ci
444262306a36Sopenharmony_ci	/* Set chip new ring index. */
444362306a36Sopenharmony_ci	wrt_reg_dword(req->req_q_in, req->ring_index);
444462306a36Sopenharmony_ci
444562306a36Sopenharmony_ci	/* Manage unprocessed RIO/ZIO commands in response queue. */
444662306a36Sopenharmony_ci	if (vha->flags.process_response_queue &&
444762306a36Sopenharmony_ci	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
444862306a36Sopenharmony_ci		qla24xx_process_response_queue(vha, rsp);
444962306a36Sopenharmony_ci
445062306a36Sopenharmony_ci	spin_unlock_irqrestore(&qpair->qp_lock, flags);
445162306a36Sopenharmony_ci
445262306a36Sopenharmony_ci	return QLA_SUCCESS;
445362306a36Sopenharmony_ci
445462306a36Sopenharmony_ciqueuing_error_fcp_cmnd:
445562306a36Sopenharmony_ci	dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma);
445662306a36Sopenharmony_ci
445762306a36Sopenharmony_ciqueuing_error:
445862306a36Sopenharmony_ci	if (tot_dsds)
445962306a36Sopenharmony_ci		scsi_dma_unmap(cmd);
446062306a36Sopenharmony_ci
446162306a36Sopenharmony_ci	qla_put_fw_resources(sp->qpair, &sp->iores);
446262306a36Sopenharmony_ci
446362306a36Sopenharmony_ci	if (sp->u.scmd.crc_ctx) {
446462306a36Sopenharmony_ci		mempool_free(sp->u.scmd.crc_ctx, ha->ctx_mempool);
446562306a36Sopenharmony_ci		sp->u.scmd.crc_ctx = NULL;
446662306a36Sopenharmony_ci	}
446762306a36Sopenharmony_ci
446862306a36Sopenharmony_ci	spin_unlock_irqrestore(&qpair->qp_lock, flags);
446962306a36Sopenharmony_ci
447062306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
447162306a36Sopenharmony_ci}
4472