Commit 62e9dd17 authored by Shyam Sundar's avatar Shyam Sundar Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: Change in PUREX to handle FPIN ELS requests

SAN Congestion Management generates ELS pkts whose size can vary and be >
64 bytes. Change the PUREX handling code to support non-standard ELS pkt
size.

Link: https://lore.kernel.org/r/20200630102229.29660-2-njavali@marvell.com


Reviewed-by: default avatarHimanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: default avatarShyam Sundar <ssundar@marvell.com>
Signed-off-by: default avatarArun Easi <aeasi@marvell.com>
Signed-off-by: default avatarNilesh Javali <njavali@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent e7019c95
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_bsg_fc.h>

#include <uapi/scsi/fc/fc_els.h>

/* Big endian Fibre Channel S_ID (source ID) or D_ID (destination ID). */
typedef struct {
	uint8_t domain;
@@ -1304,7 +1306,6 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs)
#define RNID_TYPE_ASIC_TEMP	0xC

#define ELS_CMD_MAP_SIZE	32
#define ELS_COMMAND_RDP		0x18

/*
 * Firmware state codes from get firmware state mailbox command
@@ -4522,10 +4523,19 @@ struct active_regions {
#define QLA_SET_DATA_RATE_NOLR	1
#define QLA_SET_DATA_RATE_LR	2 /* Set speed and initiate LR */

#define QLA_DEFAULT_PAYLOAD_SIZE	64
/*
 * This item might be allocated with a size > sizeof(struct purex_item).
 * The "size" variable gives the size of the payload (which
 * is variable) starting at "iocb".
 */
struct purex_item {
	struct list_head list;
	struct scsi_qla_host *vha;
	void (*process_item)(struct scsi_qla_host *vha, void *pkt);
	void (*process_item)(struct scsi_qla_host *vha,
			     struct purex_item *pkt);
	atomic_t in_use;
	uint16_t size;
	struct {
		uint8_t iocb[64];
	} iocb;
@@ -4725,6 +4735,7 @@ typedef struct scsi_qla_host {
		struct list_head head;
		spinlock_t lock;
	} purex_list;
	struct purex_item default_item;

	struct name_list_extended gnl;
	/* Count of active session/fcport */
+2 −1
Original line number Diff line number Diff line
@@ -229,7 +229,8 @@ 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);
void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
			       struct purex_item *pkt);

/*
 * Global Functions in qla_mid.c source file.
+85 −31
Original line number Diff line number Diff line
@@ -31,35 +31,11 @@ const char *const port_state_str[] = {
	"ONLINE"
};

static void qla24xx_purex_iocb(scsi_qla_host_t *vha, void *pkt,
	void (*process_item)(struct scsi_qla_host *vha, void *pkt))
{
	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)
qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
{
	struct abts_entry_24xx *abts = pkt;
	struct abts_entry_24xx *abts =
	    (struct abts_entry_24xx *)&pkt->iocb;
	struct qla_hw_data *ha = vha->hw;
	struct els_entry_24xx *rsp_els;
	struct abts_entry_24xx *abts_rsp;
@@ -789,6 +765,74 @@ qla27xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
	}
}

struct purex_item *
qla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size)
{
	struct purex_item *item = NULL;
	uint8_t item_hdr_size = sizeof(*item);

	if (size > QLA_DEFAULT_PAYLOAD_SIZE) {
		item = kzalloc(item_hdr_size +
		    (size - QLA_DEFAULT_PAYLOAD_SIZE), GFP_ATOMIC);
	} else {
		if (atomic_inc_return(&vha->default_item.in_use) == 1) {
			item = &vha->default_item;
			goto initialize_purex_header;
		} else {
			item = kzalloc(item_hdr_size, GFP_ATOMIC);
		}
	}
	if (!item) {
		ql_log(ql_log_warn, vha, 0x5092,
		       ">> Failed allocate purex list item.\n");

		return NULL;
	}

initialize_purex_header:
	item->vha = vha;
	item->size = size;
	return item;
}

static void
qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
			 void (*process_item)(struct scsi_qla_host *vha,
					      struct purex_item *pkt))
{
	struct purex_list *list = &vha->purex_list;
	ulong flags;

	pkt->process_item = process_item;

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

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

/**
 * qla24xx_copy_std_pkt() - Copy over purex ELS which is
 * contained in a single IOCB.
 * purex packet.
 * @vha: SCSI driver HA context
 * @pkt: ELS packet
 */
struct purex_item
*qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt)
{
	struct purex_item *item;

	item = qla24xx_alloc_purex_item(vha,
					QLA_DEFAULT_PAYLOAD_SIZE);
	if (!item)
		return item;

	memcpy(&item->iocb, pkt, sizeof(item->iocb));
	return item;
}

/**
 * qla2x00_async_event() - Process aynchronous events.
 * @vha: SCSI driver HA context
@@ -3229,6 +3273,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
{
	struct sts_entry_24xx *pkt;
	struct qla_hw_data *ha = vha->hw;
	struct purex_item *pure_item;

	if (!ha->flags.fw_started)
		return;
@@ -3280,7 +3325,11 @@ process_err:
			break;
		case ABTS_RECV_24XX:
			if (qla_ini_mode_enabled(vha)) {
				qla24xx_purex_iocb(vha, pkt,
				pure_item = qla24xx_copy_std_pkt(vha, pkt);
				if (!pure_item)
					break;

				qla24xx_queue_purex_item(vha, pure_item,
							 qla24xx_process_abts);
				break;
			}
@@ -3332,13 +3381,18 @@ process_err:
		{
			struct purex_entry_24xx *purex = (void *)pkt;

			if (purex->els_frame_payload[3] != ELS_COMMAND_RDP) {
			if (purex->els_frame_payload[3] != ELS_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);
			pure_item = qla24xx_copy_std_pkt(vha, pkt);
			if (!pure_item)
				break;

			qla24xx_queue_purex_item(vha, pure_item,
						 qla24xx_process_purex_rdp);
			break;
		}
		default:
+17 −5
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ static struct rom_cmd {
	{ MBC_IOCB_COMMAND_A64 },
	{ MBC_GET_ADAPTER_LOOP_ID },
	{ MBC_READ_SFP },
	{ MBC_SET_RNID_PARAMS },
	{ MBC_GET_RNID_PARAMS },
	{ MBC_GET_SET_ZIO_THRESHOLD },
};
@@ -4866,6 +4867,7 @@ qla24xx_get_port_login_templ(scsi_qla_host_t *vha, dma_addr_t buf_dma,
	return rval;
}

#define PUREX_CMD_COUNT	2
int
qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha)
{
@@ -4874,12 +4876,12 @@ qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha)
	mbx_cmd_t *mcp = &mc;
	uint8_t *els_cmd_map;
	dma_addr_t els_cmd_map_dma;
	uint cmd_opcode = ELS_COMMAND_RDP;
	uint index = cmd_opcode / 8;
	uint bit = cmd_opcode % 8;
	uint8_t cmd_opcode[PUREX_CMD_COUNT];
	uint8_t i, index, purex_bit;
	struct qla_hw_data *ha = vha->hw;

	if (!IS_QLA25XX(ha) && !IS_QLA2031(ha) && !IS_QLA27XX(ha))
	if (!IS_QLA25XX(ha) && !IS_QLA2031(ha) &&
	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
		return QLA_SUCCESS;

	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1197,
@@ -4893,7 +4895,17 @@ qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha)
		return QLA_MEMORY_ALLOC_FAILED;
	}

	els_cmd_map[index] |= 1 << bit;
	memset(els_cmd_map, 0, ELS_CMD_MAP_SIZE);

	/* List of Purex ELS */
	cmd_opcode[0] = ELS_FPIN;
	cmd_opcode[1] = ELS_RDP;

	for (i = 0; i < PUREX_CMD_COUNT; i++) {
		index = cmd_opcode[i] / 8;
		purex_bit = cmd_opcode[i] % 8;
		els_cmd_map[index] |= 1 << purex_bit;
	}

	mcp->mb[0] = MBC_SET_RNID_PARAMS;
	mcp->mb[1] = RNID_TYPE_ELS_CMD << 8;
+15 −4
Original line number Diff line number Diff line
@@ -5893,10 +5893,12 @@ qla25xx_rdp_port_speed_currently(struct qla_hw_data *ha)
 * vha:	SCSI qla host
 * purex: RDP request received by HBA
 */
void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt)
void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
			       struct purex_item *item)
{
	struct qla_hw_data *ha = vha->hw;
	struct purex_entry_24xx *purex = pkt;
	struct purex_entry_24xx *purex =
	    (struct purex_entry_24xx *)&item->iocb;
	dma_addr_t rsp_els_dma;
	dma_addr_t rsp_payload_dma;
	dma_addr_t stat_dma;
@@ -6306,6 +6308,15 @@ dealloc:
		    rsp_els, rsp_els_dma);
}

void
qla24xx_free_purex_item(struct purex_item *item)
{
	if (item == &item->vha->default_item)
		memset(&item->vha->default_item, 0, sizeof(struct purex_item));
	else
		kfree(item);
}

void qla24xx_process_purex_list(struct purex_list *list)
{
	struct list_head head = LIST_HEAD_INIT(head);
@@ -6318,8 +6329,8 @@ void qla24xx_process_purex_list(struct purex_list *list)

	list_for_each_entry_safe(item, next, &head, list) {
		list_del(&item->list);
		item->process_item(item->vha, &item->iocb);
		kfree(item);
		item->process_item(item->vha, item);
		qla24xx_free_purex_item(item);
	}
}

Loading