Commit 576bfde8 authored by Joe Carnuccio's avatar Joe Carnuccio Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: Add deferred queue for processing ABTS and RDP

This patch adds deferred queue for processing aborts and RDP in the driver.

Link: https://lore.kernel.org/r/20200212214436.25532-14-hmadhani@marvell.com


Signed-off-by: default avatarJoe Carnuccio <joe.carnuccio@cavium.com>
Signed-off-by: default avatarHimanshu Madhani <hmadhani@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 09e382bc
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -4474,6 +4474,15 @@ struct active_regions {
#define QLA_SET_DATA_RATE_NOLR	1
#define QLA_SET_DATA_RATE_LR	2 /* Set speed and initiate LR */

struct purex_item {
	struct list_head list;
	struct scsi_qla_host *vha;
	void (*process_item)(struct scsi_qla_host *vha, void *pkt);
	struct {
		uint8_t iocb[64];
	} iocb;
};

/*
 * Qlogic scsi host structure
 */
@@ -4664,7 +4673,11 @@ typedef struct scsi_qla_host {
	uint16_t ql2xexchoffld;
	uint16_t ql2xiniexchg;

	void	*purex_data;
	struct purex_list {
		struct list_head head;
		spinlock_t lock;
	} purex_list;

	struct name_list_extended gnl;
	/* Count of active session/fcport */
	int fcport_count;
+87 −4
Original line number Diff line number Diff line
@@ -727,7 +727,7 @@ struct ct_entry_24xx {
 * ISP queue - PUREX IOCB entry structure definition
 */
#define PUREX_IOCB_TYPE		0x51	/* CT Pass Through IOCB entry */
typedef struct purex_entry_24xx {
struct purex_entry_24xx {
	uint8_t entry_type;		/* Entry type. */
	uint8_t entry_count;		/* Entry count. */
	uint8_t sys_define;		/* System defined. */
@@ -763,9 +763,7 @@ typedef struct purex_entry_24xx {
	uint32_t param;

	uint8_t els_frame_payload[20];
} purex_entry_24xx_t;

#define PUREX_ENTRY_SIZE	(sizeof(purex_entry_24xx_t))
};

/*
 * ISP queue - ELS Pass-Through entry structure definition.
@@ -1000,6 +998,91 @@ struct abort_entry_24xx {
	uint8_t reserved_2[12];
};

#define ABTS_RCV_TYPE		0x54
#define ABTS_RSP_TYPE		0x55
struct abts_entry_24xx {
	uint8_t entry_type;
	uint8_t entry_count;
	uint8_t handle_count;
	uint8_t entry_status;

	uint32_t handle;		/* type 0x55 only */

	uint16_t comp_status;		/* type 0x55 only */
	uint16_t nport_handle;		/* type 0x54 only */

	uint16_t control_flags;		/* type 0x55 only */
	uint8_t vp_idx;
	uint8_t sof_type;		/* sof_type is upper nibble */

	uint32_t rx_xch_addr;

	uint8_t d_id[3];
	uint8_t r_ctl;

	uint8_t s_id[3];
	uint8_t cs_ctl;

	uint8_t f_ctl[3];
	uint8_t type;

	uint16_t seq_cnt;
	uint8_t df_ctl;
	uint8_t seq_id;

	uint16_t rx_id;
	uint16_t ox_id;

	uint32_t param;

	union {
		struct {
			uint32_t subcode3;
			uint32_t rsvd;
			uint32_t subcode1;
			uint32_t subcode2;
		} error;
		struct {
			uint16_t rsrvd1;
			uint8_t last_seq_id;
			uint8_t seq_id_valid;
			uint16_t aborted_rx_id;
			uint16_t aborted_ox_id;
			uint16_t high_seq_cnt;
			uint16_t low_seq_cnt;
		} ba_acc;
		struct {
			uint8_t vendor_unique;
			uint8_t explanation;
			uint8_t reason;
		} ba_rjt;
	} payload;

	uint32_t rx_xch_addr_to_abort;
} __packed;

/* ABTS payload explanation values */
#define BA_RJT_EXP_NO_ADDITIONAL	0
#define BA_RJT_EXP_INV_OX_RX_ID		3
#define BA_RJT_EXP_SEQ_ABORTED		5

/* ABTS payload reason values */
#define BA_RJT_RSN_INV_CMD_CODE		1
#define BA_RJT_RSN_LOGICAL_ERROR	3
#define BA_RJT_RSN_LOGICAL_BUSY		5
#define BA_RJT_RSN_PROTOCOL_ERROR	7
#define BA_RJT_RSN_UNABLE_TO_PERFORM	9
#define BA_RJT_RSN_VENDOR_SPECIFIC	0xff

/* FC_F values */
#define FC_TYPE_BLD		0x000		/* Basic link data */
#define FC_F_CTL_RSP_CNTXT	0x800000	/* Responder of exchange */
#define FC_F_CTL_LAST_SEQ	0x100000	/* Last sequence */
#define FC_F_CTL_END_SEQ	0x80000		/* Last sequence */
#define FC_F_CTL_SEQ_INIT	0x010000	/* Sequence initiative */
#define FC_ROUTING_BLD		0x80		/* Basic link data frame */
#define FC_R_CTL_BLD_BA_ACC	0x04		/* BA_ACC (basic accept) */

/*
 * ISP I/O Register Set structure definitions.
 */
+2 −0
Original line number Diff line number Diff line
@@ -230,6 +230,7 @@ void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *,
int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *);
int qla24xx_post_relogin_work(struct scsi_qla_host *vha);
void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *);
void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt);

/*
 * Global Functions in qla_mid.c source file.
@@ -928,6 +929,7 @@ void qlt_remove_target_resources(struct qla_hw_data *);
void qlt_clr_qp_table(struct scsi_qla_host *vha);
void qlt_set_mode(struct scsi_qla_host *);
int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode);
extern void qla24xx_process_purex_list(struct purex_list *);

/* nvme.c */
void qla_nvme_unregister_remote_port(struct fc_port *fcport);
+150 −4
Original line number Diff line number Diff line
@@ -31,13 +31,144 @@ const char *const port_state_str[] = {
	"ONLINE"
};

static void qla24xx_purex_iocb(scsi_qla_host_t *vha, struct req_que *req,
	struct sts_entry_24xx *pkt)
static void qla24xx_purex_iocb(scsi_qla_host_t *vha, void *pkt,
	void (*process_item)(struct scsi_qla_host *vha, void *pkt))
{
	memcpy(vha->purex_data, pkt, PUREX_ENTRY_SIZE);
	struct purex_list *list = &vha->purex_list;
	struct purex_item *item;
	ulong flags;

	item = kzalloc(sizeof(*item), GFP_KERNEL);
	if (!item) {
		ql_log(ql_log_warn, vha, 0x5092,
		    ">> Failed allocate purex list item.\n");
		return;
	}

	item->vha = vha;
	item->process_item = process_item;
	memcpy(&item->iocb, pkt, sizeof(item->iocb));

	spin_lock_irqsave(&list->lock, flags);
	list_add_tail(&item->list, &list->head);
	spin_unlock_irqrestore(&list->lock, flags);

	set_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags);
}

static void
qla24xx_process_abts(struct scsi_qla_host *vha, void *pkt)
{
	struct abts_entry_24xx *abts = pkt;
	struct qla_hw_data *ha = vha->hw;
	struct els_entry_24xx *rsp_els;
	struct abts_entry_24xx *abts_rsp;
	dma_addr_t dma;
	uint32_t fctl;
	int rval;

	ql_dbg(ql_dbg_init, vha, 0x0286, "%s: entered.\n", __func__);

	ql_log(ql_log_warn, vha, 0x0287,
	    "Processing ABTS xchg=%#x oxid=%#x rxid=%#x seqid=%#x seqcnt=%#x\n",
	    abts->rx_xch_addr_to_abort, abts->ox_id, abts->rx_id,
	    abts->seq_id, abts->seq_cnt);
	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0287,
	    "-------- ABTS RCV -------\n");
	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0287,
	    (uint8_t *)abts, sizeof(*abts));

	rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els), &dma,
	    GFP_KERNEL);
	if (!rsp_els) {
		ql_log(ql_log_warn, vha, 0x0287,
		    "Failed allocate dma buffer ABTS/ELS RSP.\n");
		return;
	}

	/* terminate exchange */
	memset(rsp_els, 0, sizeof(*rsp_els));
	rsp_els->entry_type = ELS_IOCB_TYPE;
	rsp_els->entry_count = 1;
	rsp_els->nport_handle = ~0;
	rsp_els->rx_xchg_address = abts->rx_xch_addr_to_abort;
	rsp_els->control_flags = EPD_RX_XCHG;
	ql_dbg(ql_dbg_init, vha, 0x0283,
	    "Sending ELS Response to terminate exchange %#x...\n",
	    abts->rx_xch_addr_to_abort);
	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
	    "-------- ELS RSP -------\n");
	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
	    (uint8_t *)rsp_els, sizeof(*rsp_els));
	rval = qla2x00_issue_iocb(vha, rsp_els, dma, 0);
	if (rval) {
		ql_log(ql_log_warn, vha, 0x0288,
		    "%s: iocb failed to execute -> %x\n", __func__, rval);
	} else if (rsp_els->comp_status) {
		ql_log(ql_log_warn, vha, 0x0289,
		    "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n",
		    __func__, rsp_els->comp_status,
		    rsp_els->error_subcode_1, rsp_els->error_subcode_2);
	} else {
		ql_dbg(ql_dbg_init, vha, 0x028a,
		    "%s: abort exchange done.\n", __func__);
	}

	/* send ABTS response */
	abts_rsp = (void *)rsp_els;
	memset(abts_rsp, 0, sizeof(*abts_rsp));
	abts_rsp->entry_type = ABTS_RSP_TYPE;
	abts_rsp->entry_count = 1;
	abts_rsp->nport_handle = abts->nport_handle;
	abts_rsp->vp_idx = abts->vp_idx;
	abts_rsp->sof_type = abts->sof_type & 0xf0;
	abts_rsp->rx_xch_addr = abts->rx_xch_addr;
	abts_rsp->d_id[0] = abts->s_id[0];
	abts_rsp->d_id[1] = abts->s_id[1];
	abts_rsp->d_id[2] = abts->s_id[2];
	abts_rsp->r_ctl = FC_ROUTING_BLD | FC_R_CTL_BLD_BA_ACC;
	abts_rsp->s_id[0] = abts->d_id[0];
	abts_rsp->s_id[1] = abts->d_id[1];
	abts_rsp->s_id[2] = abts->d_id[2];
	abts_rsp->cs_ctl = abts->cs_ctl;
	/* include flipping bit23 in fctl */
	fctl = ~(abts->f_ctl[2] | 0x7F) << 16 |
	    FC_F_CTL_LAST_SEQ | FC_F_CTL_END_SEQ | FC_F_CTL_SEQ_INIT;
	abts_rsp->f_ctl[0] = fctl >> 0 & 0xff;
	abts_rsp->f_ctl[1] = fctl >> 8 & 0xff;
	abts_rsp->f_ctl[2] = fctl >> 16 & 0xff;
	abts_rsp->type = FC_TYPE_BLD;
	abts_rsp->rx_id = abts->rx_id;
	abts_rsp->ox_id = abts->ox_id;
	abts_rsp->payload.ba_acc.aborted_rx_id = abts->rx_id;
	abts_rsp->payload.ba_acc.aborted_ox_id = abts->ox_id;
	abts_rsp->payload.ba_acc.high_seq_cnt = ~0;
	abts_rsp->rx_xch_addr_to_abort = abts->rx_xch_addr_to_abort;
	ql_dbg(ql_dbg_init, vha, 0x028b,
	    "Sending BA ACC response to ABTS %#x...\n",
	    abts->rx_xch_addr_to_abort);
	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x028b,
	    "-------- ELS RSP -------\n");
	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x028b,
	    (uint8_t *)abts_rsp, sizeof(*abts_rsp));
	rval = qla2x00_issue_iocb(vha, abts_rsp, dma, 0);
	if (rval) {
		ql_log(ql_log_warn, vha, 0x028c,
		    "%s: iocb failed to execute -> %x\n", __func__, rval);
	} else if (abts_rsp->comp_status) {
		ql_log(ql_log_warn, vha, 0x028d,
		    "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n",
		    __func__, abts_rsp->comp_status,
		    abts_rsp->payload.error.subcode1,
		    abts_rsp->payload.error.subcode2);
	} else {
		ql_dbg(ql_dbg_init, vha, 0x028ea,
		    "%s: done.\n", __func__);
	}

	dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els), rsp_els, dma);
}

/**
 * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
 * @irq: interrupt number
@@ -3097,6 +3228,11 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
			qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
			break;
		case ABTS_RECV_24XX:
			if (qla_ini_mode_enabled(vha)) {
				qla24xx_purex_iocb(vha, pkt,
				    qla24xx_process_abts);
				break;
			}
			if (IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
			    IS_QLA28XX(ha)) {
				/* ensure that the ATIO queue is empty */
@@ -3142,8 +3278,18 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
			    (struct vp_ctrl_entry_24xx *)pkt);
			break;
		case PUREX_IOCB_TYPE:
			qla24xx_purex_iocb(vha, rsp->req, pkt);
		{
			struct purex_entry_24xx *purex = (void *)pkt;

			if (purex->els_frame_payload[3] != ELS_COMMAND_RDP) {
				ql_dbg(ql_dbg_init, vha, 0x5091,
				    "Discarding ELS Request opcode %#x...\n",
				    purex->els_frame_payload[3]);
				break;
			}
			qla24xx_purex_iocb(vha, pkt, qla24xx_process_purex_rdp);
			break;
		}
		default:
			/* Type Not Supported. */
			ql_dbg(ql_dbg_async, vha, 0x5042,
+7 −0
Original line number Diff line number Diff line
@@ -361,6 +361,13 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
		}
	}

	if (test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags)) {
		if (atomic_read(&vha->loop_state) == LOOP_READY) {
			qla24xx_process_purex_list(&vha->purex_list);
			clear_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags);
		}
	}

	if (test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) {
		ql_dbg(ql_dbg_dpc, vha, 0x4016,
		    "FCPort update scheduled.\n");
Loading