Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad0a0b01 authored by Quinn Tran's avatar Quinn Tran Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: Fix Firmware dump size for Extended login and Exchange Offload



This patch adjusts and reallocates fw_dump memory for target mode
to save for extended login and exchange offload buffers into
dump captured.

Signed-off-by: default avatarQuinn Tran <quinn.tran@cavium.com>
Signed-off-by: default avatarHimanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent bbead493
Loading
Loading
Loading
Loading
+110 −99
Original line number Diff line number Diff line
@@ -2593,70 +2593,27 @@ qla24xx_chip_diag(scsi_qla_host_t *vha)
	return rval;
}

void
qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
static void
qla2x00_alloc_offload_mem(scsi_qla_host_t *vha)
{
	int rval;
	uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
	    eft_size, fce_size, mq_size;
	dma_addr_t tc_dma;
	void *tc;
	struct qla_hw_data *ha = vha->hw;
	struct req_que *req = ha->req_q_map[0];
	struct rsp_que *rsp = ha->rsp_q_map[0];

	if (ha->fw_dump) {
	if (ha->eft) {
		ql_dbg(ql_dbg_init, vha, 0x00bd,
		    "Firmware dump already allocated.\n");
		    "%s: Offload Mem is already allocated.\n",
		    __func__);
		return;
	}

	ha->fw_dumped = 0;
	ha->fw_dump_cap_flags = 0;
	dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
	req_q_size = rsp_q_size = 0;

	if (IS_QLA27XX(ha))
		goto try_fce;

	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
		fixed_size = sizeof(struct qla2100_fw_dump);
	} else if (IS_QLA23XX(ha)) {
		fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
		mem_size = (ha->fw_memory_size - 0x11000 + 1) *
		    sizeof(uint16_t);
	} else if (IS_FWI2_CAPABLE(ha)) {
		if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
			fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem);
		else if (IS_QLA81XX(ha))
			fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
		else if (IS_QLA25XX(ha))
			fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem);
		else
			fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);

		mem_size = (ha->fw_memory_size - 0x100000 + 1) *
		    sizeof(uint32_t);
		if (ha->mqenable) {
			if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
				mq_size = sizeof(struct qla2xxx_mq_chain);
			/*
			 * Allocate maximum buffer size for all queues.
			 * Resizing must be done at end-of-dump processing.
			 */
			mq_size += ha->max_req_queues *
			    (req->length * sizeof(request_t));
			mq_size += ha->max_rsp_queues *
			    (rsp->length * sizeof(response_t));
		}
		if (ha->tgt.atio_ring)
			mq_size += ha->tgt.atio_q_length * sizeof(request_t);
	if (IS_FWI2_CAPABLE(ha)) {
		/* Allocate memory for Fibre Channel Event Buffer. */
		if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
		    !IS_QLA27XX(ha))
			goto try_eft;

try_fce:
		if (ha->fce)
			dma_free_coherent(&ha->pdev->dev,
			    FCE_SIZE, ha->fce, ha->fce_dma);
@@ -2684,7 +2641,6 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
		ql_dbg(ql_dbg_init, vha, 0x00c0,
		    "Allocate (%d KB) for FCE...\n", FCE_SIZE / 1024);

		fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE;
		ha->flags.fce_enabled = 1;
		ha->fce_dma = tc_dma;
		ha->fce = tc;
@@ -2701,7 +2657,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
			ql_log(ql_log_warn, vha, 0x00c1,
			    "Unable to allocate (%d KB) for EFT.\n",
			    EFT_SIZE / 1024);
			goto cont_alloc;
			goto eft_err;
		}

		rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS);
@@ -2710,17 +2666,76 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
			    "Unable to initialize EFT (%d).\n", rval);
			dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
			    tc_dma);
			goto cont_alloc;
			goto eft_err;
		}
		ql_dbg(ql_dbg_init, vha, 0x00c3,
		    "Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024);

		eft_size = EFT_SIZE;
		ha->eft_dma = tc_dma;
		ha->eft = tc;
	}

cont_alloc:
eft_err:
	return;
}

void
qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
{
	uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
	    eft_size, fce_size, mq_size;
	struct qla_hw_data *ha = vha->hw;
	struct req_que *req = ha->req_q_map[0];
	struct rsp_que *rsp = ha->rsp_q_map[0];
	struct qla2xxx_fw_dump *fw_dump;

	dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
	req_q_size = rsp_q_size = 0;

	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
		fixed_size = sizeof(struct qla2100_fw_dump);
	} else if (IS_QLA23XX(ha)) {
		fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
		mem_size = (ha->fw_memory_size - 0x11000 + 1) *
		    sizeof(uint16_t);
	} else if (IS_FWI2_CAPABLE(ha)) {
		if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
			fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem);
		else if (IS_QLA81XX(ha))
			fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
		else if (IS_QLA25XX(ha))
			fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem);
		else
			fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);

		mem_size = (ha->fw_memory_size - 0x100000 + 1) *
		    sizeof(uint32_t);
		if (ha->mqenable) {
			if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
				mq_size = sizeof(struct qla2xxx_mq_chain);
			/*
			 * Allocate maximum buffer size for all queues.
			 * Resizing must be done at end-of-dump processing.
			 */
			mq_size += ha->max_req_queues *
			    (req->length * sizeof(request_t));
			mq_size += ha->max_rsp_queues *
			    (rsp->length * sizeof(response_t));
		}
		if (ha->tgt.atio_ring)
			mq_size += ha->tgt.atio_q_length * sizeof(request_t);
		/* Allocate memory for Fibre Channel Event Buffer. */
		if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
		    !IS_QLA27XX(ha))
			goto try_eft;

		fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE;
try_eft:
		ql_dbg(ql_dbg_init, vha, 0x00c3,
		    "Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024);
		eft_size = EFT_SIZE;
	}

	if (IS_QLA27XX(ha)) {
		if (!ha->fw_dump_template) {
			ql_log(ql_log_warn, vha, 0x00ba,
@@ -2748,30 +2763,21 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
			ha->exlogin_size;

allocate:
	ha->fw_dump = vmalloc(dump_size);
	if (!ha->fw_dump) {
	if (!ha->fw_dump_len || dump_size != ha->fw_dump_len) {
		fw_dump = vmalloc(dump_size);
		if (!fw_dump) {
			ql_log(ql_log_warn, vha, 0x00c4,
			    "Unable to allocate (%d KB) for firmware dump.\n",
			    dump_size / 1024);
		} else {
			if (ha->fw_dump)
				vfree(ha->fw_dump);
			ha->fw_dump = fw_dump;

		if (ha->fce) {
			dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
			    ha->fce_dma);
			ha->fce = NULL;
			ha->fce_dma = 0;
		}

		if (ha->eft) {
			dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
			    ha->eft_dma);
			ha->eft = NULL;
			ha->eft_dma = 0;
		}
		return;
	}
			ha->fw_dump_len = dump_size;
			ql_dbg(ql_dbg_init, vha, 0x00c5,
	    "Allocated (%d KB) for firmware dump.\n", dump_size / 1024);
			    "Allocated (%d KB) for firmware dump.\n",
			    dump_size / 1024);

			if (IS_QLA27XX(ha))
				return;
@@ -2794,6 +2800,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
			ha->fw_dump->header_size =
				htonl(offsetof(struct qla2xxx_fw_dump, isp));
		}
	}
}

static int
qla81xx_mpi_sync(scsi_qla_host_t *vha)
@@ -3118,9 +3126,12 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
				if (rval != QLA_SUCCESS)
					goto failed;

				if (!fw_major_version && ql2xallocfwdump
				    && !(IS_P3P_TYPE(ha)))
				if (!fw_major_version && !(IS_P3P_TYPE(ha)))
					qla2x00_alloc_offload_mem(vha);

				if (ql2xallocfwdump && !(IS_P3P_TYPE(ha)))
					qla2x00_alloc_fw_dump(vha);

			} else {
				goto failed;
			}
+37 −3
Original line number Diff line number Diff line
@@ -526,7 +526,8 @@ qla27xx_fwdt_entry_t268(struct scsi_qla_host *vha,
{
	ql_dbg(ql_dbg_misc, vha, 0xd20c,
	    "%s: gethb(%x) [%lx]\n", __func__, ent->t268.buf_type, *len);
	if (ent->t268.buf_type == T268_BUF_TYPE_EXTD_TRACE) {
	switch (ent->t268.buf_type) {
	case T268_BUF_TYPE_EXTD_TRACE:
		if (vha->hw->eft) {
			if (buf) {
				ent->t268.buf_size = EFT_SIZE;
@@ -538,10 +539,43 @@ qla27xx_fwdt_entry_t268(struct scsi_qla_host *vha,
			    "%s: missing eft\n", __func__);
			qla27xx_skip_entry(ent, buf);
		}
		break;
	case T268_BUF_TYPE_EXCH_BUFOFF:
		if (vha->hw->exchoffld_buf) {
			if (buf) {
				ent->t268.buf_size = vha->hw->exchoffld_size;
				ent->t268.start_addr =
					vha->hw->exchoffld_buf_dma;
			}
			qla27xx_insertbuf(vha->hw->exchoffld_buf,
			    vha->hw->exchoffld_size, buf, len);
		} else {
			ql_dbg(ql_dbg_misc, vha, 0xd028,
			    "%s: missing exch offld\n", __func__);
			qla27xx_skip_entry(ent, buf);
		}
		break;
	case T268_BUF_TYPE_EXTD_LOGIN:
		if (vha->hw->exlogin_buf) {
			if (buf) {
				ent->t268.buf_size = vha->hw->exlogin_size;
				ent->t268.start_addr =
					vha->hw->exlogin_buf_dma;
			}
			qla27xx_insertbuf(vha->hw->exlogin_buf,
			    vha->hw->exlogin_size, buf, len);
		} else {
		ql_dbg(ql_dbg_misc, vha, 0xd02b,
			ql_dbg(ql_dbg_misc, vha, 0xd028,
			    "%s: missing ext login\n", __func__);
			qla27xx_skip_entry(ent, buf);
		}
		break;

	default:
		ql_dbg(ql_dbg_async, vha, 0xd02b,
		    "%s: unknown buffer %x\n", __func__, ent->t268.buf_type);
		qla27xx_skip_entry(ent, buf);
		break;
	}

	return false;