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

Commit 41dc529a authored by Quinn Tran's avatar Quinn Tran Committed by Nicholas Bellinger
Browse files

qla2xxx: Improve RSCN handling in driver



Current code blindly does State Change Registration when
the link is up. Move SCR behind fabric scan, so that arbitrated
loop scan would not get erroneous error message.

Some of the other improvements are as follows

- Add session deletion for TPRLO and send acknowledgment for TPRLO.
- Enable FW option to move ABTS, RIDA & PUREX from RSPQ to ATIOQ.
- Save NPort ID early in link init.
- Move ABTS & RIDA to ATIOQ helps in keeping command ordering and
  link up sequence ordering.
- Save Nport ID and update VP map so that SCSI CMD/ATIO won't be dropped.
- fcport alloc does the initializes memory to zero. Remove memset to
  zero since It might corrupt link list.
- Turn off Registration for State Change MB in loop mode.

Signed-off-by: default avatarQuinn Tran <quinn.tran@cavium.com>
Signed-off-by: default avatarHimanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: default avatarBart Van Assche <bart.vanassche@sandisk.com>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 0ca55938
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -2226,6 +2226,13 @@ enum fcport_mgt_event {
	FCME_DELETE_DONE,
};

enum rscn_addr_format {
	RSCN_PORT_ADDR,
	RSCN_AREA_ADDR,
	RSCN_DOM_ADDR,
	RSCN_FAB_ADDR,
};

/*
 * Fibre channel port structure.
 */
@@ -3956,7 +3963,7 @@ typedef struct scsi_qla_host {
#define FCOE_CTX_RESET_NEEDED	18	/* Initiate FCoE context reset */
#define MPI_RESET_NEEDED	19	/* Initiate MPI FW reset */
#define ISP_QUIESCE_NEEDED	20	/* Driver need some quiescence */
#define SCR_PENDING		21	/* SCR in target mode */
#define FREE_BIT 21
#define PORT_UPDATE_NEEDED	22
#define FX00_RESET_RECOVERY	23
#define FX00_TARGET_SCAN	24
@@ -4010,7 +4017,9 @@ typedef struct scsi_qla_host {
	/* list of commands waiting on workqueue */
	struct list_head	qla_cmd_list;
	struct list_head	qla_sess_op_cmd_list;
	struct list_head	unknown_atio_list;
	spinlock_t		cmd_list_lock;
	struct delayed_work	unknown_atio_work;

	/* Counter to detect races between ELS and RSCN events */
	atomic_t		generation_tick;
+62 −13
Original line number Diff line number Diff line
@@ -1301,27 +1301,76 @@ struct vp_config_entry_24xx {
};

#define VP_RPT_ID_IOCB_TYPE	0x32	/* Report ID Acquisition entry. */
enum VP_STATUS {
	VP_STAT_COMPL,
	VP_STAT_FAIL,
	VP_STAT_ID_CHG,
	VP_STAT_SNS_TO,				/* timeout */
	VP_STAT_SNS_RJT,
	VP_STAT_SCR_TO,				/* timeout */
	VP_STAT_SCR_RJT,
};

enum VP_FLAGS {
	VP_FLAGS_CON_FLOOP = 1,
	VP_FLAGS_CON_P2P = 2,
	VP_FLAGS_CON_FABRIC = 3,
	VP_FLAGS_NAME_VALID = BIT_5,
};

struct vp_rpt_id_entry_24xx {
	uint8_t entry_type;		/* Entry type. */
	uint8_t entry_count;		/* Entry count. */
	uint8_t sys_define;		/* System defined. */
	uint8_t entry_status;		/* Entry Status. */

	uint32_t handle;		/* System handle. */

	uint16_t vp_count;		/* Format 0 -- | VP setup | VP acq |. */
					/* Format 1 -- | VP count |. */
	uint16_t vp_idx;		/* Format 0 -- Reserved. */
					/* Format 1 -- VP status and index. */
	uint32_t resv1;
	uint8_t vp_acquired;
	uint8_t vp_setup;
	uint8_t vp_idx;		/* Format 0=reserved */
	uint8_t vp_status;	/* Format 0=reserved */

	uint8_t port_id[3];
	uint8_t format;

	union {
		struct {
			/* format 0 loop */
			uint8_t vp_idx_map[16];
			uint8_t reserved_4[32];
		} f0;
		struct {
			/* format 1 fabric */
			uint8_t vpstat1_subcode; /* vp_status=1 subcode */
			uint8_t flags;
			uint16_t fip_flags;
			uint8_t rsv2[12];

	uint8_t reserved_4[24];
			uint8_t ls_rjt_vendor;
			uint8_t ls_rjt_explanation;
			uint8_t ls_rjt_reason;
			uint8_t rsv3[5];

			uint8_t port_name[8];
			uint8_t node_name[8];
			uint16_t bbcr;
			uint8_t reserved_5[6];
		} f1;
		struct { /* format 2: N2N direct connect */
		    uint8_t vpstat1_subcode;
		    uint8_t flags;
		    uint16_t rsv6;
		    uint8_t rsv2[12];

		    uint8_t ls_rjt_vendor;
		    uint8_t ls_rjt_explanation;
		    uint8_t ls_rjt_reason;
		    uint8_t rsv3[5];

		    uint8_t port_name[8];
		    uint8_t node_name[8];
		    uint32_t remote_nport_id;
		    uint32_t reserved_5;
		} f2;
	} u;
};

#define VF_EVFP_IOCB_TYPE       0x26    /* Exchange Virtual Fabric Parameters entry. */
+2 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ extern int ql2xmdenable;
extern int ql2xexlogins;
extern int ql2xexchoffld;
extern int ql2xfwholdabts;
extern int ql2xmvasynctoatio;

extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -844,5 +845,6 @@ extern void qlt_schedule_sess_for_deletion_lock(struct fc_port *);
extern struct fc_port *qlt_find_sess_invalidate_other(scsi_qla_host_t *,
	uint64_t wwn, port_id_t port_id, uint16_t loop_id, struct fc_port **);
void qla24xx_delete_sess_fn(struct work_struct *);
void qlt_unknown_atio_work_fn(struct work_struct *);

#endif /* _QLA_GBL_H */
+3 −1
Original line number Diff line number Diff line
@@ -2914,8 +2914,10 @@ int qla24xx_async_gidpn(scsi_qla_host_t *vha, fc_port_t *fcport)
int qla24xx_post_gidpn_work(struct scsi_qla_host *vha, fc_port_t *fcport)
{
	struct qla_work_evt *e;
	int ls;

	if ((atomic_read(&vha->loop_state) != LOOP_READY) ||
	ls = atomic_read(&vha->loop_state);
	if (((ls != LOOP_READY) && (ls != LOOP_UP)) ||
		test_bit(UNLOADING, &vha->dpc_flags))
		return 0;

+125 −25
Original line number Diff line number Diff line
@@ -1071,10 +1071,10 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha,
	qla24xx_fcport_handle_login(vha, fcport);
}

void qla2x00_fcport_event_handler(scsi_qla_host_t *vha,
	struct event_arg *ea)
void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
{
	fc_port_t *fcport;
	fc_port_t *fcport, *f, *tf;
	uint32_t id = 0, mask, rid;
	int rc;

	switch (ea->event) {
@@ -1087,7 +1087,8 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha,
	case FCME_RSCN:
		if (test_bit(UNLOADING, &vha->dpc_flags))
			return;

		switch (ea->id.b.rsvd_1) {
		case RSCN_PORT_ADDR:
			fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1);
			if (!fcport) {
				/* cable moved */
@@ -1103,6 +1104,40 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha,
				qla24xx_handle_rscn_event(fcport, ea);
			}
			break;
		case RSCN_AREA_ADDR:
		case RSCN_DOM_ADDR:
			if (ea->id.b.rsvd_1 == RSCN_AREA_ADDR) {
				mask = 0xffff00;
				ql_log(ql_dbg_async, vha, 0xffff,
					   "RSCN: Area 0x%06x was affected\n",
					   ea->id.b24);
			} else {
				mask = 0xff0000;
				ql_log(ql_dbg_async, vha, 0xffff,
					   "RSCN: Domain 0x%06x was affected\n",
					   ea->id.b24);
			}

			rid = ea->id.b24 & mask;
			list_for_each_entry_safe(f, tf, &vha->vp_fcports,
			    list) {
				id = f->d_id.b24 & mask;
				if (rid == id) {
					ea->fcport = f;
					qla24xx_handle_rscn_event(f, ea);
				}
			}
			break;
		case RSCN_FAB_ADDR:
		default:
			ql_log(ql_log_warn, vha, 0xffff,
				"RSCN: Fabric was affected. Addr format %d\n",
				ea->id.b.rsvd_1);
			qla2x00_mark_all_devices_lost(vha, 1);
			set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
			set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
		}
		break;
	case FCME_GIDPN_DONE:
		qla24xx_handle_gidpn_event(vha, ea);
		break;
@@ -2947,6 +2982,21 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
			__func__, ha->fw_options[2]);
	}

	/* Move PUREX, ABTS RX & RIDA to ATIOQ */
	if (ql2xmvasynctoatio) {
		if (qla_tgt_mode_enabled(vha) ||
		    qla_dual_mode_enabled(vha))
			ha->fw_options[2] |= BIT_11;
		else
			ha->fw_options[2] &= ~BIT_11;
	}

	ql_dbg(ql_dbg_init, vha, 0xffff,
		"%s, add FW options 1-3 = 0x%04x 0x%04x 0x%04x mode %x\n",
		__func__, ha->fw_options[1], ha->fw_options[2],
		ha->fw_options[3], vha->host->active_mode);
	qla2x00_set_fw_options(vha, ha->fw_options);

	/* Update Serial Link options. */
	if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
		return;
@@ -3953,10 +4003,11 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)

	} else if (ha->current_topology == ISP_CFG_N) {
		clear_bit(RSCN_UPDATE, &flags);

	} else if (ha->current_topology == ISP_CFG_NL) {
		clear_bit(RSCN_UPDATE, &flags);
		set_bit(LOCAL_LOOP_UPDATE, &flags);
	} else if (!vha->flags.online ||
	    (test_bit(ABORT_ISP_ACTIVE, &flags))) {

		set_bit(RSCN_UPDATE, &flags);
		set_bit(LOCAL_LOOP_UPDATE, &flags);
	}
@@ -4058,6 +4109,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
	uint16_t	loop_id;
	uint8_t		domain, area, al_pa;
	struct qla_hw_data *ha = vha->hw;
	unsigned long flags;

	found_devs = 0;
	new_fcport = NULL;
@@ -4098,7 +4150,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
			    "Marking port lost loop_id=0x%04x.\n",
			    fcport->loop_id);

			qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST);
			qla2x00_mark_device_lost(vha, fcport, 0, 0);
		}
	}

@@ -4129,13 +4181,14 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
		if (loop_id > LAST_LOCAL_LOOP_ID)
			continue;

		memset(new_fcport, 0, sizeof(fc_port_t));
		memset(new_fcport->port_name, 0, WWN_SIZE);

		/* Fill in member data. */
		new_fcport->d_id.b.domain = domain;
		new_fcport->d_id.b.area = area;
		new_fcport->d_id.b.al_pa = al_pa;
		new_fcport->loop_id = loop_id;

		rval2 = qla2x00_get_port_database(vha, new_fcport, 0);
		if (rval2 != QLA_SUCCESS) {
			ql_dbg(ql_dbg_disc, vha, 0x201a,
@@ -4148,6 +4201,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
			continue;
		}

		spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
		/* Check for matching device in port list. */
		found = 0;
		fcport = NULL;
@@ -4163,6 +4217,12 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
			memcpy(fcport->node_name, new_fcport->node_name,
			    WWN_SIZE);

			if (!fcport->login_succ) {
				vha->fcport_count++;
				fcport->login_succ = 1;
				fcport->disc_state = DSC_LOGIN_COMPLETE;
			}

			found++;
			break;
		}
@@ -4173,16 +4233,28 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)

			/* Allocate a new replacement fcport. */
			fcport = new_fcport;
			if (!fcport->login_succ) {
				vha->fcport_count++;
				fcport->login_succ = 1;
				fcport->disc_state = DSC_LOGIN_COMPLETE;
			}

			spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);

			new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);

			if (new_fcport == NULL) {
				ql_log(ql_log_warn, vha, 0x201c,
				    "Failed to allocate memory for fcport.\n");
				rval = QLA_MEMORY_ALLOC_FAILED;
				goto cleanup_allocation;
			}
			spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
			new_fcport->flags &= ~FCF_FABRIC_DEVICE;
		}

		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);

		/* Base iIDMA settings on HBA port speed. */
		fcport->fp_speed = ha->link_data_rate;

@@ -4371,6 +4443,16 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
	}
	vha->device_flags |= SWITCH_FOUND;


	if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) {
		rval = qla2x00_send_change_request(vha, 0x3, 0);
		if (rval != QLA_SUCCESS)
			ql_log(ql_log_warn, vha, 0x121,
				"Failed to enable receiving of RSCN requests: 0x%x.\n",
				rval);
	}


	do {
		qla2x00_mgmt_svr_login(vha);

@@ -6116,6 +6198,7 @@ uint8_t qla27xx_find_valid_image(struct scsi_qla_host *vha)

	for (chksum = 0; cnt--; wptr++)
		chksum += le32_to_cpu(*wptr);

	if (chksum) {
		ql_dbg(ql_dbg_init, vha, 0x018c,
		    "Checksum validation failed for primary image (0x%x)\n",
@@ -7128,6 +7211,10 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
		vha->flags.process_response_queue = 1;
	}

	 /* enable RIDA Format2 */
	if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha))
		icb->firmware_options_3 |= BIT_0;

	if (rval) {
		ql_log(ql_log_warn, vha, 0x0076,
		    "NVRAM configuration failed.\n");
@@ -7252,13 +7339,26 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha)
			__func__, ha->fw_options[2]);
	}

	if (!ql2xetsenable)
		goto out;
	/* Move PUREX, ABTS RX & RIDA to ATIOQ */
	if (ql2xmvasynctoatio) {
		if (qla_tgt_mode_enabled(vha) ||
		    qla_dual_mode_enabled(vha))
			ha->fw_options[2] |= BIT_11;
		else
			ha->fw_options[2] &= ~BIT_11;
	}

	if (ql2xetsenable) {
		/* Enable ETS Burst. */
		memset(ha->fw_options, 0, sizeof(ha->fw_options));
		ha->fw_options[2] |= BIT_9;
out:
	}

	ql_dbg(ql_dbg_init, vha, 0xffff,
		"%s, add FW options 1-3 = 0x%04x 0x%04x 0x%04x mode %x\n",
		__func__, ha->fw_options[1], ha->fw_options[2],
		ha->fw_options[3], vha->host->active_mode);

	qla2x00_set_fw_options(vha, ha->fw_options);
}

Loading