[SCSI] qla4xxx: set device state as per Link UP and LINK DOWN

Link Down -> Mark all devices missing
 Previously, the driver took no action on a Link Down,
 and waited for the I/O on a dead connection to timeout
 in the firmware before marking the DDB missing.

Link Up -> Mark all devices online
 F/W will do auto login to all the devices only once.
 After that its the responsibility of the driver to
 relogin to devices whenever there is :
        * Any sort of connection failure or
        * KATO expires indicating target has logged out or
        * I/O times out etc.

Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Signed-off-by: Karen Higgins <karen.higgins@qlogic.com>
Signed-off-by: Ravi Anand <ravi.anand@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 2ccad36..d6c8b42 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -685,6 +685,7 @@
 	     test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
 	     test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
 	     test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
+	     test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||
 	     test_bit(DPC_AEN, &ha->dpc_flags)) &&
 	     ha->dpc_thread) {
 		DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
@@ -1069,6 +1070,54 @@
 	if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
 		qla4xxx_get_dhcp_ip_address(ha);
 
+	/* ---- link change? --- */
+	if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) {
+		if (!test_bit(AF_LINK_UP, &ha->flags)) {
+			/* ---- link down? --- */
+			list_for_each_entry_safe(ddb_entry, dtemp,
+						 &ha->ddb_list, list) {
+				if (atomic_read(&ddb_entry->state) ==
+						DDB_STATE_ONLINE)
+					qla4xxx_mark_device_missing(ha,
+							ddb_entry);
+			}
+		} else {
+			/* ---- link up? --- *
+			 * F/W will auto login to all devices ONLY ONCE after
+			 * link up during driver initialization and runtime
+			 * fatal error recovery.  Therefore, the driver must
+			 * manually relogin to devices when recovering from
+			 * connection failures, logouts, expired KATO, etc. */
+
+			list_for_each_entry_safe(ddb_entry, dtemp,
+							&ha->ddb_list, list) {
+				if ((atomic_read(&ddb_entry->state) ==
+						 DDB_STATE_MISSING) ||
+				    (atomic_read(&ddb_entry->state) ==
+						 DDB_STATE_DEAD)) {
+					if (ddb_entry->fw_ddb_device_state ==
+					    DDB_DS_SESSION_ACTIVE) {
+						atomic_set(&ddb_entry->state,
+							   DDB_STATE_ONLINE);
+						dev_info(&ha->pdev->dev,
+						    "scsi%ld: %s: ddb[%d]"
+						    " os[%d] marked"
+						    " ONLINE\n",
+						    ha->host_no, __func__,
+						    ddb_entry->fw_ddb_index,
+						    ddb_entry->os_target_id);
+
+						iscsi_unblock_session(
+						    ddb_entry->sess);
+					} else
+						qla4xxx_relogin_device(
+						    ha, ddb_entry);
+				}
+
+			}
+		}
+	}
+
 	/* ---- relogin device? --- */
 	if (adapter_up(ha) &&
 	    test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) {