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

Commit faef62d1 authored by Armen Baloyan's avatar Armen Baloyan Committed by James Bottomley
Browse files

[SCSI] qla2xxx: Fix Task Management command asynchronous handling



- Fix interpreting the wrong IOCB type for task management
functions in the response path.
- Merge the task management function handling for various adapters.

Signed-off-by: default avatarArmen Baloyan <armen.baloyan@qlogic.com>
Signed-off-by: default avatarSaurav Kashyap <saurav.kashyap@qlogic.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 43a9c38b
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -34,6 +34,7 @@
 * |                              |                    | 0x5047,0x5052  |
 * |                              |                    | 0x5047,0x5052  |
 * |                              |                    | 0x5084,0x5075	|
 * |                              |                    | 0x5084,0x5075	|
 * |                              |                    | 0x503d,0x5044  |
 * |                              |                    | 0x503d,0x5044  |
 * |                              |                    | 0x507b		|
 * | Timer Routines               |       0x6012       |                |
 * | Timer Routines               |       0x6012       |                |
 * | User Space Interactions      |       0x70e2       | 0x7018,0x702e  |
 * | User Space Interactions      |       0x70e2       | 0x7018,0x702e  |
 * |				  |		       | 0x7020,0x7024  |
 * |				  |		       | 0x7020,0x7024  |
+44 −35
Original line number Original line Diff line number Diff line
@@ -271,56 +271,46 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
}
}


static void
static void
qla2x00_async_tm_cmd_done(void *data, void *ptr, int res)
qla2x00_tmf_iocb_timeout(void *data)
{
{
	srb_t *sp = (srb_t *)ptr;
	srb_t *sp = (srb_t *)data;
	struct srb_iocb *iocb = &sp->u.iocb_cmd;
	struct srb_iocb *tmf = &sp->u.iocb_cmd;
	struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
	uint32_t flags;
	uint16_t lun;
	int rval;

	if (!test_bit(UNLOADING, &vha->dpc_flags)) {
		flags = iocb->u.tmf.flags;
		lun = (uint16_t)iocb->u.tmf.lun;

		/* Issue Marker IOCB */
		rval = qla2x00_marker(vha, vha->hw->req_q_map[0],
			vha->hw->rsp_q_map[0], sp->fcport->loop_id, lun,
			flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);


		if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
	tmf->u.tmf.comp_status = CS_TIMEOUT;
			ql_dbg(ql_dbg_taskm, vha, 0x8030,
	complete(&tmf->u.tmf.comp);
			    "TM IOCB failed (%x).\n", rval);
		}
}
}
	sp->free(sp->fcport->vha, sp);

static void
qla2x00_tmf_sp_done(void *data, void *ptr, int res)
{
	srb_t *sp = (srb_t *)ptr;
	struct srb_iocb *tmf = &sp->u.iocb_cmd;
	complete(&tmf->u.tmf.comp);
}
}


int
int
qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t tm_flags, uint32_t lun,
qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
	uint32_t tag)
	uint32_t tag)
{
{
	struct scsi_qla_host *vha = fcport->vha;
	struct scsi_qla_host *vha = fcport->vha;
	struct srb_iocb *tm_iocb;
	srb_t *sp;
	srb_t *sp;
	struct srb_iocb *tcf;
	int rval = QLA_FUNCTION_FAILED;
	int rval;


	rval = QLA_FUNCTION_FAILED;
	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
	if (!sp)
	if (!sp)
		goto done;
		goto done;


	tm_iocb = &sp->u.iocb_cmd;
	sp->type = SRB_TM_CMD;
	sp->type = SRB_TM_CMD;
	sp->name = "tmf";
	sp->name = "tmf";
	qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
	qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha));

	tm_iocb->u.tmf.flags = flags;
	tcf = &sp->u.iocb_cmd;
	tm_iocb->u.tmf.lun = lun;
	tcf->u.tmf.flags = tm_flags;
	tm_iocb->u.tmf.data = tag;
	tcf->u.tmf.lun = lun;
	sp->done = qla2x00_tmf_sp_done;
	tcf->u.tmf.data = tag;
	tm_iocb->timeout = qla2x00_tmf_iocb_timeout;
	tcf->timeout = qla2x00_async_iocb_timeout;
	init_completion(&tm_iocb->u.tmf.comp);
	sp->done = qla2x00_async_tm_cmd_done;


	rval = qla2x00_start_sp(sp);
	rval = qla2x00_start_sp(sp);
	if (rval != QLA_SUCCESS)
	if (rval != QLA_SUCCESS)
@@ -330,10 +320,29 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t tm_flags, uint32_t lun,
	    "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n",
	    "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n",
	    sp->handle, fcport->loop_id, fcport->d_id.b.domain,
	    sp->handle, fcport->loop_id, fcport->d_id.b.domain,
	    fcport->d_id.b.area, fcport->d_id.b.al_pa);
	    fcport->d_id.b.area, fcport->d_id.b.al_pa);
	return rval;

	wait_for_completion(&tm_iocb->u.tmf.comp);

	rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ?
	    QLA_SUCCESS : QLA_FUNCTION_FAILED;

	if ((rval != QLA_SUCCESS) || tm_iocb->u.tmf.data) {
		ql_dbg(ql_dbg_taskm, vha, 0x8030,
		    "TM IOCB failed (%x).\n", rval);
	}

	if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) {
		flags = tm_iocb->u.tmf.flags;
		lun = (uint16_t)tm_iocb->u.tmf.lun;

		/* Issue Marker IOCB */
		qla2x00_marker(vha, vha->hw->req_q_map[0],
		    vha->hw->rsp_q_map[0], sp->fcport->loop_id, lun,
		    flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
	}


done_free_sp:
done_free_sp:
	sp->free(fcport->vha, sp);
	sp->free(vha, sp);
done:
done:
	return rval;
	return rval;
}
}
+22 −24
Original line number Original line Diff line number Diff line
@@ -1498,8 +1498,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
}
}


static void
static void
qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
    struct tsk_mgmt_entry *tsk)
{
{
	const char func[] = "TMF-IOCB";
	const char func[] = "TMF-IOCB";
	const char *type;
	const char *type;
@@ -1507,7 +1506,6 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
	srb_t *sp;
	srb_t *sp;
	struct srb_iocb *iocb;
	struct srb_iocb *iocb;
	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
	int error = 1;


	sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
	sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
	if (!sp)
	if (!sp)
@@ -1516,21 +1514,21 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
	iocb = &sp->u.iocb_cmd;
	iocb = &sp->u.iocb_cmd;
	type = sp->name;
	type = sp->name;
	fcport = sp->fcport;
	fcport = sp->fcport;
	iocb->u.tmf.data = QLA_SUCCESS;


	if (sts->entry_status) {
	if (sts->entry_status) {
		ql_log(ql_log_warn, fcport->vha, 0x5038,
		ql_log(ql_log_warn, fcport->vha, 0x5038,
		    "Async-%s error - hdl=%x entry-status(%x).\n",
		    "Async-%s error - hdl=%x entry-status(%x).\n",
		    type, sp->handle, sts->entry_status);
		    type, sp->handle, sts->entry_status);
		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
	} else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
	} else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
		ql_log(ql_log_warn, fcport->vha, 0x5039,
		ql_log(ql_log_warn, fcport->vha, 0x5039,
		    "Async-%s error - hdl=%x completion status(%x).\n",
		    "Async-%s error - hdl=%x completion status(%x).\n",
		    type, sp->handle, sts->comp_status);
		    type, sp->handle, sts->comp_status);
	} else if (!(le16_to_cpu(sts->scsi_status) &
		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
	} else if ((le16_to_cpu(sts->scsi_status) &
	    SS_RESPONSE_INFO_LEN_VALID)) {
	    SS_RESPONSE_INFO_LEN_VALID)) {
		ql_log(ql_log_warn, fcport->vha, 0x503a,
		if (le32_to_cpu(sts->rsp_data_len) < 4) {
		    "Async-%s error - hdl=%x no response info(%x).\n",
		    type, sp->handle, sts->scsi_status);
	} else if (le32_to_cpu(sts->rsp_data_len) < 4) {
			ql_log(ql_log_warn, fcport->vha, 0x503b,
			ql_log(ql_log_warn, fcport->vha, 0x503b,
			    "Async-%s error - hdl=%x not enough response(%d).\n",
			    "Async-%s error - hdl=%x not enough response(%d).\n",
			    type, sp->handle, sts->rsp_data_len);
			    type, sp->handle, sts->rsp_data_len);
@@ -1538,15 +1536,13 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
			ql_log(ql_log_warn, fcport->vha, 0x503c,
			ql_log(ql_log_warn, fcport->vha, 0x503c,
			    "Async-%s error - hdl=%x response(%x).\n",
			    "Async-%s error - hdl=%x response(%x).\n",
			    type, sp->handle, sts->data[3]);
			    type, sp->handle, sts->data[3]);
	} else {
		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
		error = 0;
		}
	}
	}


	if (error) {
	if (iocb->u.tmf.data != QLA_SUCCESS)
		iocb->u.tmf.data = error;
		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5055,
		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5055,
		    (uint8_t *)sts, sizeof(*sts));
		    (uint8_t *)sts, sizeof(*sts));
	}


	sp->done(vha, sp, 0);
	sp->done(vha, sp, 0);
}
}
@@ -2026,6 +2022,12 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
		return;
		return;
	}
	}


	/* Task Management completion. */
	if (sp->type == SRB_TM_CMD) {
		qla24xx_tm_iocb_entry(vha, req, pkt);
		return;
	}

	/* Fast path completion. */
	/* Fast path completion. */
	if (comp_status == CS_COMPLETE && scsi_status == 0) {
	if (comp_status == CS_COMPLETE && scsi_status == 0) {
		qla2x00_process_completed_request(vha, req, handle);
		qla2x00_process_completed_request(vha, req, handle);
@@ -2475,10 +2477,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
			qla24xx_logio_entry(vha, rsp->req,
			qla24xx_logio_entry(vha, rsp->req,
			    (struct logio_entry_24xx *)pkt);
			    (struct logio_entry_24xx *)pkt);
			break;
			break;
		case TSK_MGMT_IOCB_TYPE:
			qla24xx_tm_iocb_entry(vha, rsp->req,
			    (struct tsk_mgmt_entry *)pkt);
			break;
                case CT_IOCB_TYPE:
                case CT_IOCB_TYPE:
			qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
			qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
			break;
			break;
+2 −64
Original line number Original line Diff line number Diff line
@@ -685,78 +685,16 @@ qlafx00_disable_intrs(struct qla_hw_data *ha)
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
}


static void
qlafx00_tmf_iocb_timeout(void *data)
{
	srb_t *sp = (srb_t *)data;
	struct srb_iocb *tmf = &sp->u.iocb_cmd;

	tmf->u.tmf.comp_status = cpu_to_le16((uint16_t)CS_TIMEOUT);
	complete(&tmf->u.tmf.comp);
}

static void
qlafx00_tmf_sp_done(void *data, void *ptr, int res)
{
	srb_t *sp = (srb_t *)ptr;
	struct srb_iocb *tmf = &sp->u.iocb_cmd;

	complete(&tmf->u.tmf.comp);
}

static int
qlafx00_async_tm_cmd(fc_port_t *fcport, uint32_t flags,
		     uint32_t lun, uint32_t tag)
{
	scsi_qla_host_t *vha = fcport->vha;
	struct srb_iocb *tm_iocb;
	srb_t *sp;
	int rval = QLA_FUNCTION_FAILED;

	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
	if (!sp)
		goto done;

	tm_iocb = &sp->u.iocb_cmd;
	sp->type = SRB_TM_CMD;
	sp->name = "tmf";
	qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha));
	tm_iocb->u.tmf.flags = flags;
	tm_iocb->u.tmf.lun = lun;
	tm_iocb->u.tmf.data = tag;
	sp->done = qlafx00_tmf_sp_done;
	tm_iocb->timeout = qlafx00_tmf_iocb_timeout;
	init_completion(&tm_iocb->u.tmf.comp);

	rval = qla2x00_start_sp(sp);
	if (rval != QLA_SUCCESS)
		goto done_free_sp;

	ql_dbg(ql_dbg_async, vha, 0x507b,
	    "Task management command issued target_id=%x\n",
	    fcport->tgt_id);

	wait_for_completion(&tm_iocb->u.tmf.comp);

	rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ?
	    QLA_SUCCESS : QLA_FUNCTION_FAILED;

done_free_sp:
	sp->free(vha, sp);
done:
	return rval;
}

int
int
qlafx00_abort_target(fc_port_t *fcport, unsigned int l, int tag)
qlafx00_abort_target(fc_port_t *fcport, unsigned int l, int tag)
{
{
	return qlafx00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
	return qla2x00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
}
}


int
int
qlafx00_lun_reset(fc_port_t *fcport, unsigned int l, int tag)
qlafx00_lun_reset(fc_port_t *fcport, unsigned int l, int tag)
{
{
	return qlafx00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
	return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
}
}


int
int