Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3574

kernel-2.6.18-194.11.1.el5.src.rpm

From: Marcus Barrow <mbarrow@redhat.com>
Date: Thu, 2 Jul 2009 12:22:47 -0400
Subject: [scsi] qla2xxx: prevent I/O stoppage
Message-id: 20090702162247.6351.79590.sendpatchset@file.bos.redhat.com
O-Subject: [rhel 5.4 patch] [V2] qla2xxx - prevent I/O stoppage.
Bugzilla: 507620
RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com>

BZ 507620 - qla2xxx - properly handle event notification in FCoE environment

Version 2 of this patch. Addresses Pete Zaitcev's request to put common
code in a sub-routine and remove a duplicate debugging printk.

This patch corrects a problem found by partners in FCoE environments.

The driver's state engine does not properly handle this situation for
FCoE and this will cause I/O to stop without resuming.

Applies and builds cleanly with 2.6.18-154. Tested by QLogic and partners.
This work will be submitted upstream.

Correctly handle 'global port-unavailable' AEN.

Treat a global port-unavailable PORT_UPDATE (8014h) AEN as a
loop-down event.  For this case, within the FCoE domain, the
'logical' interface has been terminated, but the driver will
not receive the classic LOOP_DOWN AEN.

diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index c576cad..9b21639 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -109,6 +109,7 @@ extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
 
 extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
 
+extern void qla2x00_set_loop_down(scsi_qla_host_t *, uint16_t *);
 extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int);
 extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int);
 
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 069d3a6..882ee92 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -481,30 +481,7 @@ skip_rio:
 		break;
 
 	case MBA_LOOP_DOWN:		/* Loop Down Event */
-		DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN (%x).\n",
-		    ha->host_no, mb[1]));
-		qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x).\n", mb[1]);
-		DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
-			"(%x %x %x).\n", ha->host_no, mb[1], mb[2], mb[3]));
-		qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x %x %x).\n",
-			mb[1], mb[2], mb[3]);
-
-		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
-			atomic_set(&ha->loop_state, LOOP_DOWN);
-			atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
-			ha->device_flags |= DFLG_NO_CABLE;
-			qla2x00_mark_all_devices_lost(ha, 1);
-		}
-
-		if (ha->parent) {
-			atomic_set(&ha->vp_state, VP_FAILED);
-			atomic_set(&ha->vport_last_state,
-			    atomic_read(&ha->vport_state));
-			atomic_set(&ha->vport_state, FC_VPORT_FAILED);
-		}
-
-		ha->flags.management_server_logged_in = 0;
-		ha->link_data_rate = PORT_SPEED_UNKNOWN;
+		qla2x00_set_loop_down( ha, mb );
 		if (ql2xfdmienable)
 			set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
 		break;
@@ -602,6 +579,17 @@ skip_rio:
 		break;
 
 	case MBA_PORT_UPDATE:		/* Port database update */
+                /* Only handle SCNs for our Vport index. */
+                if (mb[1] != 0xffff &&
+                    ha->vp_idx && ha->vp_idx != (mb[3] & 0xff))
+                        break;
+
+                /* Global event -- port logout or port unavailable. */
+                if (mb[1] == 0xffff && mb[2] == 0x7) {
+			qla2x00_set_loop_down( ha, mb );
+			break;
+                }
+
 		/*
 		 * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET
 		 * event etc. earlier indicating loop is down) then process
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 16eb173..519ac68 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2139,6 +2139,32 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
 		fc_remote_port_delete(rport);
 }
 
+void
+qla2x00_set_loop_down(scsi_qla_host_t *ha, uint16_t *mb)
+{
+	DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
+	    "(%x %x %x).\n", ha->host_no, mb[1], mb[2], mb[3]));
+	qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x %x %x).\n",
+	    mb[1], mb[2], mb[3]);
+
+	if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
+		atomic_set(&ha->loop_state, LOOP_DOWN);
+		atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
+		ha->device_flags |= DFLG_NO_CABLE;
+		qla2x00_mark_all_devices_lost(ha, 1);
+	}
+
+	if (ha->parent) {
+		atomic_set(&ha->vp_state, VP_FAILED);
+		atomic_set(&ha->vport_last_state,
+		    atomic_read(&ha->vport_state));
+		atomic_set(&ha->vport_state, FC_VPORT_FAILED);
+	}
+
+	ha->flags.management_server_logged_in = 0;
+	ha->link_data_rate = PORT_SPEED_UNKNOWN;
+}
+
 /*
  * qla2x00_mark_device_lost Updates fcport state when device goes offline.
  *