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

Commit 09ff701a authored by Sarang Radke's avatar Sarang Radke Committed by James Bottomley
Browse files

[SCSI] qla2xxx: Add APEX support.



Allows priority setting for FCP_CMNDs.

Signed-off-by: default avatarGiridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 6e98016c
Loading
Loading
Loading
Loading
+163 −0
Original line number Diff line number Diff line
@@ -35,6 +35,166 @@ done:
	return sp;
}

int
qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
{
	int i, ret, num_valid;
	uint8_t *bcode;
	struct qla_fcp_prio_entry *pri_entry;

	ret = 1;
	num_valid = 0;
	bcode = (uint8_t *)pri_cfg;

	if (bcode[0x0] != 'H' || bcode[0x1] != 'Q' || bcode[0x2] != 'O' ||
			bcode[0x3] != 'S') {
		return 0;
	}
	if (flag != 1)
		return ret;

	pri_entry = &pri_cfg->entry[0];
	for (i = 0; i < pri_cfg->num_entries; i++) {
		if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID)
			num_valid++;
		pri_entry++;
	}

	if (num_valid == 0)
		ret = 0;

	return ret;
}

static int
qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job)
{
	struct Scsi_Host *host = bsg_job->shost;
	scsi_qla_host_t *vha = shost_priv(host);
	struct qla_hw_data *ha = vha->hw;
	int ret = 0;
	uint32_t len;
	uint32_t oper;

	bsg_job->reply->reply_payload_rcv_len = 0;

	if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
		test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
		test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
		ret = -EBUSY;
		goto exit_fcp_prio_cfg;
	}

	/* Get the sub command */
	oper = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];

	/* Only set config is allowed if config memory is not allocated */
	if (!ha->fcp_prio_cfg && (oper != QLFC_FCP_PRIO_SET_CONFIG)) {
		ret = -EINVAL;
		goto exit_fcp_prio_cfg;
	}
	switch (oper) {
	case QLFC_FCP_PRIO_DISABLE:
		if (ha->flags.fcp_prio_enabled) {
			ha->flags.fcp_prio_enabled = 0;
			ha->fcp_prio_cfg->attributes &=
				~FCP_PRIO_ATTR_ENABLE;
			qla24xx_update_all_fcp_prio(vha);
			bsg_job->reply->result = DID_OK;
		} else {
			ret = -EINVAL;
			bsg_job->reply->result = (DID_ERROR << 16);
			goto exit_fcp_prio_cfg;
		}
		break;

	case QLFC_FCP_PRIO_ENABLE:
		if (!ha->flags.fcp_prio_enabled) {
			if (ha->fcp_prio_cfg) {
				ha->flags.fcp_prio_enabled = 1;
				ha->fcp_prio_cfg->attributes |=
				    FCP_PRIO_ATTR_ENABLE;
				qla24xx_update_all_fcp_prio(vha);
				bsg_job->reply->result = DID_OK;
			} else {
				ret = -EINVAL;
				bsg_job->reply->result = (DID_ERROR << 16);
				goto exit_fcp_prio_cfg;
			}
		}
		break;

	case QLFC_FCP_PRIO_GET_CONFIG:
		len = bsg_job->reply_payload.payload_len;
		if (!len || len > FCP_PRIO_CFG_SIZE) {
			ret = -EINVAL;
			bsg_job->reply->result = (DID_ERROR << 16);
			goto exit_fcp_prio_cfg;
		}

		bsg_job->reply->result = DID_OK;
		bsg_job->reply->reply_payload_rcv_len =
			sg_copy_from_buffer(
			bsg_job->reply_payload.sg_list,
			bsg_job->reply_payload.sg_cnt, ha->fcp_prio_cfg,
			len);

		break;

	case QLFC_FCP_PRIO_SET_CONFIG:
		len = bsg_job->request_payload.payload_len;
		if (!len || len > FCP_PRIO_CFG_SIZE) {
			bsg_job->reply->result = (DID_ERROR << 16);
			ret = -EINVAL;
			goto exit_fcp_prio_cfg;
		}

		if (!ha->fcp_prio_cfg) {
			ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE);
			if (!ha->fcp_prio_cfg) {
				qla_printk(KERN_WARNING, ha,
					"Unable to allocate memory "
					"for fcp prio config data (%x).\n",
					FCP_PRIO_CFG_SIZE);
				bsg_job->reply->result = (DID_ERROR << 16);
				ret = -ENOMEM;
				goto exit_fcp_prio_cfg;
			}
		}

		memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE);
		sg_copy_to_buffer(bsg_job->request_payload.sg_list,
		bsg_job->request_payload.sg_cnt, ha->fcp_prio_cfg,
			FCP_PRIO_CFG_SIZE);

		/* validate fcp priority data */
		if (!qla24xx_fcp_prio_cfg_valid(
			(struct qla_fcp_prio_cfg *)
			ha->fcp_prio_cfg, 1)) {
			bsg_job->reply->result = (DID_ERROR << 16);
			ret = -EINVAL;
			/* If buffer was invalidatic int
			 * fcp_prio_cfg is of no use
			 */
			vfree(ha->fcp_prio_cfg);
			ha->fcp_prio_cfg = NULL;
			goto exit_fcp_prio_cfg;
		}

		ha->flags.fcp_prio_enabled = 0;
		if (ha->fcp_prio_cfg->attributes & FCP_PRIO_ATTR_ENABLE)
			ha->flags.fcp_prio_enabled = 1;
		qla24xx_update_all_fcp_prio(vha);
		bsg_job->reply->result = DID_OK;
		break;
	default:
		ret = -EINVAL;
		break;
	}
exit_fcp_prio_cfg:
	bsg_job->job_done(bsg_job);
	return ret;
}
static int
qla2x00_process_els(struct fc_bsg_job *bsg_job)
{
@@ -948,6 +1108,9 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
	case QL_VND_IIDMA:
		return qla24xx_iidma(bsg_job);

	case QL_VND_FCP_PRIO_CFG_CMD:
		return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job);

	default:
		bsg_job->reply->result = (DID_ERROR << 16);
		bsg_job->job_done(bsg_job);
+7 −0
Original line number Diff line number Diff line
@@ -1580,6 +1580,8 @@ typedef struct fc_port {
	uint16_t loop_id;
	uint16_t old_loop_id;

	uint8_t fcp_prio;

	uint8_t fabric_port_name[WWN_SIZE];
	uint16_t fp_speed;

@@ -2296,6 +2298,7 @@ struct qla_hw_data {
		uint32_t	eeh_busy		:1;
		uint32_t	cpu_affinity_enabled	:1;
		uint32_t	disable_msix_handshake	:1;
		uint32_t	fcp_prio_enabled	:1;
	} flags;

	/* This spinlock is used to protect "io transactions", you must
@@ -2599,6 +2602,7 @@ struct qla_hw_data {
	uint32_t        flt_region_nvram;
	uint32_t        flt_region_npiv_conf;
	uint32_t	flt_region_gold_fw;
	uint32_t	flt_region_fcp_prio;

	/* Needed for BEACON */
	uint16_t        beacon_blink_led;
@@ -2627,6 +2631,9 @@ struct qla_hw_data {
	struct isp_operations *isp_ops;
	struct workqueue_struct *wq;
	struct qlfc_fw fw_buf;

	/* FCP_CMND priority support */
	struct qla_fcp_prio_cfg *fcp_prio_cfg;
};

/*
+59 −0
Original line number Diff line number Diff line
@@ -841,6 +841,8 @@ struct device_reg_24xx {
#define FA_HW_EVENT_ENTRY_SIZE	4
#define FA_NPIV_CONF0_ADDR	0x5C000
#define FA_NPIV_CONF1_ADDR	0x5D000
#define FA_FCP_PRIO0_ADDR	0x10000
#define FA_FCP_PRIO1_ADDR	0x12000

/*
 * Flash Error Log Event Codes.
@@ -1274,6 +1276,8 @@ struct qla_flt_header {
#define FLT_REG_NPIV_CONF_0	0x29
#define FLT_REG_NPIV_CONF_1	0x2a
#define FLT_REG_GOLD_FW		0x2f
#define FLT_REG_FCP_PRIO_0	0x87
#define FLT_REG_FCP_PRIO_1	0x88

struct qla_flt_region {
	uint32_t code;
@@ -1750,6 +1754,61 @@ struct ex_init_cb_81xx {
#define FARX_ACCESS_FLASH_CONF_81XX	0x7FFD0000
#define FARX_ACCESS_FLASH_DATA_81XX	0x7F800000

/* FCP priority config defines *************************************/
/* operations */
#define QLFC_FCP_PRIO_DISABLE           0x0
#define QLFC_FCP_PRIO_ENABLE            0x1
#define QLFC_FCP_PRIO_GET_CONFIG        0x2
#define QLFC_FCP_PRIO_SET_CONFIG        0x3

struct qla_fcp_prio_entry {
	uint16_t flags;         /* Describes parameter(s) in FCP        */
	/* priority entry that are valid        */
#define FCP_PRIO_ENTRY_VALID            0x1
#define FCP_PRIO_ENTRY_TAG_VALID        0x2
#define FCP_PRIO_ENTRY_SPID_VALID       0x4
#define FCP_PRIO_ENTRY_DPID_VALID       0x8
#define FCP_PRIO_ENTRY_LUNB_VALID       0x10
#define FCP_PRIO_ENTRY_LUNE_VALID       0x20
#define FCP_PRIO_ENTRY_SWWN_VALID       0x40
#define FCP_PRIO_ENTRY_DWWN_VALID       0x80
	uint8_t  tag;           /* Priority value                   */
	uint8_t  reserved;      /* Reserved for future use          */
	uint32_t src_pid;       /* Src port id. high order byte     */
				/* unused; -1 (wild card)           */
	uint32_t dst_pid;       /* Src port id. high order byte     */
	/* unused; -1 (wild card)           */
	uint16_t lun_beg;       /* 1st lun num of lun range.        */
				/* -1 (wild card)                   */
	uint16_t lun_end;       /* 2nd lun num of lun range.        */
				/* -1 (wild card)                   */
	uint8_t  src_wwpn[8];   /* Source WWPN: -1 (wild card)      */
	uint8_t  dst_wwpn[8];   /* Destination WWPN: -1 (wild card) */
};

struct qla_fcp_prio_cfg {
	uint8_t  signature[4];  /* "HQOS" signature of config data  */
	uint16_t version;       /* 1: Initial version               */
	uint16_t length;        /* config data size in num bytes    */
	uint16_t checksum;      /* config data bytes checksum       */
	uint16_t num_entries;   /* Number of entries                */
	uint16_t size_of_entry; /* Size of each entry in num bytes  */
	uint8_t  attributes;    /* enable/disable, persistence      */
#define FCP_PRIO_ATTR_DISABLE   0x0
#define FCP_PRIO_ATTR_ENABLE    0x1
#define FCP_PRIO_ATTR_PERSIST   0x2
	uint8_t  reserved;      /* Reserved for future use          */
#define FCP_PRIO_CFG_HDR_SIZE   0x10
	struct qla_fcp_prio_entry entry[1];     /* fcp priority entries  */
#define FCP_PRIO_CFG_ENTRY_SIZE 0x20
};

#define FCP_PRIO_CFG_SIZE       (32*1024) /* fcp prio data per port*/

/* 25XX Support ****************************************************/
#define FA_FCP_PRIO0_ADDR_25	0x3C000
#define FA_FCP_PRIO1_ADDR_25	0x3E000

/* 81XX Flash locations -- occupies second 2MB region. */
#define FA_BOOT_CODE_ADDR_81	0x80000
#define FA_RISC_CODE_ADDR_81	0xA0000
+8 −1
Original line number Diff line number Diff line
@@ -328,6 +328,9 @@ extern int
qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t);

extern int qla2x00_get_data_rate(scsi_qla_host_t *);
extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t,
	uint16_t *);

/*
 * Global Function Prototypes in qla_isr.c source file.
 */
@@ -384,6 +387,7 @@ extern int qla2xxx_get_flash_info(scsi_qla_host_t *);
extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);

extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *);
extern int qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *);

/*
 * Global Function Prototypes in qla_dbg.c source file.
@@ -430,7 +434,10 @@ extern void qla2x00_init_host_attr(scsi_qla_host_t *);
extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *);
extern int qla2x00_echo_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *);
extern int qla2x00_echo_test(scsi_qla_host_t *,
	struct msg_echo_lb *, uint16_t *);
extern int qla24xx_update_all_fcp_prio(scsi_qla_host_t *);
extern int qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *, uint8_t);

/*
 * Global Function Prototypes in qla_dfs.c source file.
+168 −0
Original line number Diff line number Diff line
@@ -349,6 +349,12 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
		}
	}

	if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) {
		if (qla24xx_read_fcp_prio_cfg(vha))
			qla_printk(KERN_ERR, ha,
			"Unable to read FCP priority data.\n");
	}

	return (rval);
}

@@ -4905,3 +4911,165 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha)
	ha->fw_options[2] |= BIT_9;
	qla2x00_set_fw_options(vha, ha->fw_options);
}

/*
 * qla24xx_get_fcp_prio
 *	Gets the fcp cmd priority value for the logged in port.
 *	Looks for a match of the port descriptors within
 *	each of the fcp prio config entries. If a match is found,
 *	the tag (priority) value is returned.
 *
 * Input:
 *	ha = adapter block po
 *	fcport = port structure pointer.
 *
 * Return:
 * 	non-zero (if found)
 * 	0 (if not found)
 *
 * Context:
 * 	Kernel context
 */
uint8_t
qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
{
	int i, entries;
	uint8_t pid_match, wwn_match;
	uint8_t priority;
	uint32_t pid1, pid2;
	uint64_t wwn1, wwn2;
	struct qla_fcp_prio_entry *pri_entry;
	struct qla_hw_data *ha = vha->hw;

	if (!ha->fcp_prio_cfg || !ha->flags.fcp_prio_enabled)
		return 0;

	priority = 0;
	entries = ha->fcp_prio_cfg->num_entries;
	pri_entry = &ha->fcp_prio_cfg->entry[0];

	for (i = 0; i < entries; i++) {
		pid_match = wwn_match = 0;

		if (!(pri_entry->flags & FCP_PRIO_ENTRY_VALID)) {
			pri_entry++;
			continue;
		}

		/* check source pid for a match */
		if (pri_entry->flags & FCP_PRIO_ENTRY_SPID_VALID) {
			pid1 = pri_entry->src_pid & INVALID_PORT_ID;
			pid2 = vha->d_id.b24 & INVALID_PORT_ID;
			if (pid1 == INVALID_PORT_ID)
				pid_match++;
			else if (pid1 == pid2)
				pid_match++;
		}

		/* check destination pid for a match */
		if (pri_entry->flags & FCP_PRIO_ENTRY_DPID_VALID) {
			pid1 = pri_entry->dst_pid & INVALID_PORT_ID;
			pid2 = fcport->d_id.b24 & INVALID_PORT_ID;
			if (pid1 == INVALID_PORT_ID)
				pid_match++;
			else if (pid1 == pid2)
				pid_match++;
		}

		/* check source WWN for a match */
		if (pri_entry->flags & FCP_PRIO_ENTRY_SWWN_VALID) {
			wwn1 = wwn_to_u64(vha->port_name);
			wwn2 = wwn_to_u64(pri_entry->src_wwpn);
			if (wwn2 == (uint64_t)-1)
				wwn_match++;
			else if (wwn1 == wwn2)
				wwn_match++;
		}

		/* check destination WWN for a match */
		if (pri_entry->flags & FCP_PRIO_ENTRY_DWWN_VALID) {
			wwn1 = wwn_to_u64(fcport->port_name);
			wwn2 = wwn_to_u64(pri_entry->dst_wwpn);
			if (wwn2 == (uint64_t)-1)
				wwn_match++;
			else if (wwn1 == wwn2)
				wwn_match++;
		}

		if (pid_match == 2 || wwn_match == 2) {
			/* Found a matching entry */
			if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID)
				priority = pri_entry->tag;
			break;
		}

		pri_entry++;
	}

	return priority;
}

/*
 * qla24xx_update_fcport_fcp_prio
 *	Activates fcp priority for the logged in fc port
 *
 * Input:
 *	ha = adapter block pointer.
 *	fcp = port structure pointer.
 *
 * Return:
 *	QLA_SUCCESS or QLA_FUNCTION_FAILED
 *
 * Context:
 *	Kernel context.
 */
int
qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *ha, fc_port_t *fcport)
{
	int ret;
	uint8_t priority;
	uint16_t mb[5];

	if (atomic_read(&fcport->state) == FCS_UNCONFIGURED ||
		fcport->port_type != FCT_TARGET ||
		fcport->loop_id == FC_NO_LOOP_ID)
		return QLA_FUNCTION_FAILED;

	priority = qla24xx_get_fcp_prio(ha, fcport);
	ret = qla24xx_set_fcp_prio(ha, fcport->loop_id, priority, mb);
	if (ret == QLA_SUCCESS)
		fcport->fcp_prio = priority;
	else
		DEBUG2(printk(KERN_WARNING
			"scsi(%ld): Unable to activate fcp priority, "
			" ret=0x%x\n", ha->host_no, ret));

	return  ret;
}

/*
 * qla24xx_update_all_fcp_prio
 *	Activates fcp priority for all the logged in ports
 *
 * Input:
 *	ha = adapter block pointer.
 *
 * Return:
 *	QLA_SUCCESS or QLA_FUNCTION_FAILED
 *
 * Context:
 *	Kernel context.
 */
int
qla24xx_update_all_fcp_prio(scsi_qla_host_t *vha)
{
	int ret;
	fc_port_t *fcport;

	ret = QLA_FUNCTION_FAILED;
	/* We need to set priority for all logged in ports */
	list_for_each_entry(fcport, &vha->vp_fcports, list)
		ret = qla24xx_update_fcport_fcp_prio(vha, fcport);

	return ret;
}
Loading