]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.25/patches.drivers/qla4xxx-sles11-update
Updated xen patches taken from suse.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.drivers / qla4xxx-sles11-update
diff --git a/src/patches/suse-2.6.27.25/patches.drivers/qla4xxx-sles11-update b/src/patches/suse-2.6.27.25/patches.drivers/qla4xxx-sles11-update
new file mode 100644 (file)
index 0000000..060ad64
--- /dev/null
@@ -0,0 +1,3160 @@
+From: Hannes Reinecke <hare@suse.de>
+Subject: qla4xxx driver fixes for SLES11
+Date: Tue Oct 7 12:59:55 2008 +0200:
+References: bnc#432976
+
+The upstream qla4xxx driver requires some fixes for SLES11.
+
+Signed-off-by: David Wagner <david.wagner@qlogic.com>
+Signed-off-by: Hannes Reinecke <hare@suse.de>
+
+diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig
+index 69cbff3..4eda26a 100644
+--- a/drivers/scsi/qla4xxx/Kconfig
++++ b/drivers/scsi/qla4xxx/Kconfig
+@@ -1,7 +1,7 @@
+ config SCSI_QLA_ISCSI
+       tristate "QLogic ISP4XXX host adapter family support"
+-      depends on PCI && SCSI && NET
++      depends on PCI && SCSI
+       select SCSI_ISCSI_ATTRS
+       ---help---
+-      This driver supports the QLogic 40xx (ISP4XXX) iSCSI host
++      This driver supports the QLogic 40xx (ISP4XXX) iSCSI host 
+       adapter family.
+diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
+index fcc184c..171a342 100644
+--- a/drivers/scsi/qla4xxx/ql4_dbg.c
++++ b/drivers/scsi/qla4xxx/ql4_dbg.c
+@@ -6,10 +6,162 @@
+  */
+ #include "ql4_def.h"
++#include "ql4_version.h"
+ #include "ql4_glbl.h"
+ #include "ql4_dbg.h"
+ #include "ql4_inline.h"
++#include <scsi/scsi_dbg.h>
++
++static void qla4xxx_print_srb_info(struct srb * srb)
++{
++      printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags);
++      printk("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n",
++             __func__, srb->cmd, (unsigned long) srb->dma_handle);
++      printk("%s: fw_ddb_index = %d, lun = %d\n",
++             __func__, srb->fw_ddb_index, srb->cmd->device->lun);
++      printk("%s: iocb_tov = %d\n",
++             __func__, srb->iocb_tov);
++      printk("%s: cc_stat = 0x%x\n", __func__, srb->cc_stat);
++}
++
++void qla4xxx_print_scsi_cmd(struct scsi_cmnd *cmd)
++{
++      printk("SCSI Command = 0x%p, Handle=0x%p\n", cmd, cmd->host_scribble);
++      printk("  b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n",
++             cmd->device->channel, cmd->device->id, cmd->device->lun,
++             cmd->cmd_len);
++      scsi_print_command(cmd);
++      qla4xxx_print_srb_info((struct srb *) cmd->SCp.ptr);
++}
++
++void __dump_registers(struct scsi_qla_host *ha)
++{
++      uint8_t i;
++      for (i = 0; i < MBOX_REG_COUNT; i++) {
++              printk(KERN_INFO "0x%02X mailbox[%d]      = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg, mailbox[i]), i,
++                     readw(&ha->reg->mailbox[i]));
++      }
++      printk(KERN_INFO "0x%02X flash_address   = 0x%08X\n",
++             (uint8_t) offsetof(struct isp_reg, flash_address),
++             readw(&ha->reg->flash_address));
++      printk(KERN_INFO "0x%02X flash_data      = 0x%08X\n",
++             (uint8_t) offsetof(struct isp_reg, flash_data),
++             readw(&ha->reg->flash_data));
++      printk(KERN_INFO "0x%02X ctrl_status     = 0x%08X\n",
++             (uint8_t) offsetof(struct isp_reg, ctrl_status),
++             readw(&ha->reg->ctrl_status));
++      if (is_qla4010(ha)) {
++              printk(KERN_INFO "0x%02X nvram           = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram),
++                     readw(&ha->reg->u1.isp4010.nvram));
++      }
++
++      else if (is_qla4022(ha) | is_qla4032(ha)) {
++              printk(KERN_INFO "0x%02X intr_mask       = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u1.isp4022.intr_mask),
++                     readw(&ha->reg->u1.isp4022.intr_mask));
++              printk(KERN_INFO "0x%02X nvram           = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram),
++                     readw(&ha->reg->u1.isp4022.nvram));
++              printk(KERN_INFO "0x%02X semaphore       = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u1.isp4022.semaphore),
++                     readw(&ha->reg->u1.isp4022.semaphore));
++      }
++      printk(KERN_INFO "0x%02X req_q_in        = 0x%08X\n",
++             (uint8_t) offsetof(struct isp_reg, req_q_in),
++             readw(&ha->reg->req_q_in));
++      printk(KERN_INFO "0x%02X rsp_q_out       = 0x%08X\n",
++             (uint8_t) offsetof(struct isp_reg, rsp_q_out),
++             readw(&ha->reg->rsp_q_out));
++      if (is_qla4010(ha)) {
++              printk(KERN_INFO "0x%02X ext_hw_conf     = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u2.isp4010.ext_hw_conf),
++                     readw(&ha->reg->u2.isp4010.ext_hw_conf));
++              printk(KERN_INFO "0x%02X port_ctrl       = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u2.isp4010.port_ctrl),
++                     readw(&ha->reg->u2.isp4010.port_ctrl));
++              printk(KERN_INFO "0x%02X port_status     = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u2.isp4010.port_status),
++                     readw(&ha->reg->u2.isp4010.port_status));
++              printk(KERN_INFO "0x%02X req_q_out       = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u2.isp4010.req_q_out),
++                     readw(&ha->reg->u2.isp4010.req_q_out));
++              printk(KERN_INFO "0x%02X gp_out          = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out),
++                     readw(&ha->reg->u2.isp4010.gp_out));
++              printk(KERN_INFO "0x%02X gp_in           = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in),
++                     readw(&ha->reg->u2.isp4010.gp_in));
++              printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u2.isp4010.port_err_status),
++                     readw(&ha->reg->u2.isp4010.port_err_status));
++      }
++
++      else if (is_qla4022(ha) | is_qla4032(ha)) {
++              printk(KERN_INFO "Page 0 Registers:\n");
++              printk(KERN_INFO "0x%02X ext_hw_conf     = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u2.isp4022.p0.ext_hw_conf),
++                     readw(&ha->reg->u2.isp4022.p0.ext_hw_conf));
++              printk(KERN_INFO "0x%02X port_ctrl       = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u2.isp4022.p0.port_ctrl),
++                     readw(&ha->reg->u2.isp4022.p0.port_ctrl));
++              printk(KERN_INFO "0x%02X port_status     = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u2.isp4022.p0.port_status),
++                     readw(&ha->reg->u2.isp4022.p0.port_status));
++              printk(KERN_INFO "0x%02X gp_out          = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u2.isp4022.p0.gp_out),
++                     readw(&ha->reg->u2.isp4022.p0.gp_out));
++              printk(KERN_INFO "0x%02X gp_in           = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in),
++                     readw(&ha->reg->u2.isp4022.p0.gp_in));
++              printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u2.isp4022.p0.port_err_status),
++                     readw(&ha->reg->u2.isp4022.p0.port_err_status));
++              printk(KERN_INFO "Page 1 Registers:\n");
++              writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
++                     &ha->reg->ctrl_status);
++              printk(KERN_INFO "0x%02X req_q_out       = 0x%08X\n",
++                     (uint8_t) offsetof(struct isp_reg,
++                                        u2.isp4022.p1.req_q_out),
++                     readw(&ha->reg->u2.isp4022.p1.req_q_out));
++              writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
++                     &ha->reg->ctrl_status);
++      }
++}
++
++void qla4xxx_dump_mbox_registers(struct scsi_qla_host *ha)
++{
++      unsigned long flags = 0;
++      int i = 0;
++      spin_lock_irqsave(&ha->hardware_lock, flags);
++      for (i = 1; i < MBOX_REG_COUNT; i++)
++              printk(KERN_INFO "  Mailbox[%d] = %08x\n", i,
++                     readw(&ha->reg->mailbox[i]));
++      spin_unlock_irqrestore(&ha->hardware_lock, flags);
++}
++
++void qla4xxx_dump_registers(struct scsi_qla_host *ha)
++{
++      unsigned long flags = 0;
++      spin_lock_irqsave(&ha->hardware_lock, flags);
++      __dump_registers(ha);
++      spin_unlock_irqrestore(&ha->hardware_lock, flags);
++}
++
+ void qla4xxx_dump_buffer(void *b, uint32_t size)
+ {
+       uint32_t cnt;
+@@ -30,4 +182,3 @@ void qla4xxx_dump_buffer(void *b, uint32_t size)
+       if (cnt % 16)
+               printk(KERN_DEBUG "\n");
+ }
+-
+diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h
+index d861c3b..20dfe4a 100644
+--- a/drivers/scsi/qla4xxx/ql4_dbg.h
++++ b/drivers/scsi/qla4xxx/ql4_dbg.h
+@@ -12,6 +12,7 @@
+ /* #define QL_DEBUG_LEVEL_3  */               /* Output function tracing */
+ /* #define QL_DEBUG_LEVEL_4  */
+ /* #define QL_DEBUG_LEVEL_5  */
++/* #define QL_DEBUG_LEVEL_6  */
+ /* #define QL_DEBUG_LEVEL_9  */
+ #define QL_DEBUG_LEVEL_2      /* ALways enable error messagess */
+@@ -22,14 +23,14 @@
+ #endif
+ #if defined(QL_DEBUG_LEVEL_2)
+-#define DEBUG2(x)      do {if(ql4xextended_error_logging == 2) x;} while (0);
++#define DEBUG2(x)      do {if(extended_error_logging == 2) x;} while (0);
+ #define DEBUG2_3(x)   do {x;} while (0);
+ #else                         /*  */
+ #define DEBUG2(x)     do {} while (0);
+ #endif                                /*  */
+ #if defined(QL_DEBUG_LEVEL_3)
+-#define DEBUG3(x)      do {if(ql4xextended_error_logging == 3) x;} while (0);
++#define DEBUG3(x)      do {if(extended_error_logging == 3) x;} while (0);
+ #else                         /*  */
+ #define DEBUG3(x)     do {} while (0);
+ #if !defined(QL_DEBUG_LEVEL_2)
+@@ -48,6 +49,12 @@
+ #define DEBUG5(x)     do {} while (0);
+ #endif                                /*  */
++#if defined(QL_DEBUG_LEVEL_6)
++#define DEBUG6(x)     do {x;} while (0);
++#else                         /*  */
++#define DEBUG6(x)     do {} while (0);
++#endif                                /*  */
++
+ #if defined(QL_DEBUG_LEVEL_9)
+ #define DEBUG9(x)     do {x;} while (0);
+ #else                         /*  */
+diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
+index d6be076..52d36b2 100644
+--- a/drivers/scsi/qla4xxx/ql4_def.h
++++ b/drivers/scsi/qla4xxx/ql4_def.h
+@@ -90,10 +90,10 @@
+  ***********************************/
+ #define MAX_HBAS              16
+ #define MAX_BUSES             1
+-#define MAX_TARGETS           (MAX_PRST_DEV_DB_ENTRIES +  MAX_DEV_DB_ENTRIES)
++#define MAX_TARGETS           MAX_DEV_DB_ENTRIES
+ #define MAX_LUNS              0xffff
+ #define MAX_AEN_ENTRIES               256 /* should be > EXT_DEF_MAX_AEN_QUEUE */
+-#define MAX_DDB_ENTRIES               (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
++#define MAX_DDB_ENTRIES               MAX_DEV_DB_ENTRIES
+ #define MAX_PDU_ENTRIES               32
+ #define INVALID_ENTRY         0xFFFF
+ #define MAX_CMDS_TO_RISC      1024
+@@ -121,8 +121,9 @@
+ #define MAX_REQS_SERVICED_PER_INTR    16
+ #define ISCSI_IPADDR_SIZE             4       /* IP address size */
+-#define ISCSI_ALIAS_SIZE              32      /* ISCSI Alias name size */
+-#define ISCSI_NAME_SIZE                       0xE0    /* ISCSI Name size */
++#define ISCSI_ALIAS_SIZE              32      /* ISCSI Alais name size */
++#define ISCSI_NAME_SIZE                       0xE0    /* ISCSI Name size -
++                                               * usually a string */
+ #define LSDW(x) ((u32)((u64)(x)))
+ #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16))
+@@ -158,6 +159,7 @@ struct srb {
+       struct ddb_entry        *ddb;
+       uint16_t flags;         /* (1) Status flags. */
++#define SRB_SCSI_PASSTHRU     BIT_2   /* for scsi passthru cmds */
+ #define SRB_DMA_VALID         BIT_3   /* DMA Buffer mapped. */
+ #define SRB_GOT_SENSE         BIT_4   /* sense data recieved. */
+       uint8_t state;          /* (1) Status flags. */
+@@ -182,25 +184,12 @@ struct srb {
+       uint16_t iocb_tov;
+       uint16_t iocb_cnt;      /* Number of used iocbs */
+       uint16_t cc_stat;
+-      u_long r_start;         /* Time we recieve a cmd from OS */
+-      u_long u_start;         /* Time when we handed the cmd to F/W */
++      uint32_t dma_len;
+ };
+-/*
+- * Asynchronous Event Queue structure
+- */
+-struct aen {
+-        uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
+-};
+-
+-struct ql4_aen_log {
+-        int count;
+-        struct aen entry[MAX_AEN_ENTRIES];
+-};
+-
+-/*
+- * Device Database (DDB) structure
+- */
++      /*
++       * Device Database (DDB) structure
++       */
+ struct ddb_entry {
+       struct list_head list;  /* ddb list */
+       struct scsi_qla_host *ha;
+@@ -262,9 +251,19 @@ struct ddb_entry {
+ #define DF_RELOGIN            0       /* Relogin to device */
+ #define DF_NO_RELOGIN         1       /* Do not relogin if IOCTL
+                                        * logged it out */
+-#define DF_ISNS_DISCOVERED    2       /* Device was discovered via iSNS */
+-#define DF_FO_MASKED          3
++#define DF_SCAN_ISSUED                2
++
++/*
++ * Asynchronous Event Queue structure
++ */
++struct aen {
++      uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
++};
++struct ql4_aen_log {
++      int count;
++      struct aen entry[MAX_AEN_ENTRIES];
++};
+ #include "ql4_fw.h"
+ #include "ql4_nvram.h"
+@@ -273,16 +272,29 @@ struct ddb_entry {
+  * Linux Host Adapter structure
+  */
+ struct scsi_qla_host {
++      struct klist_node node;
++      uint16_t instance;
++      uint16_t rsvd0;
++
++      /* exported functions */
++      int (*ql4cmd)(struct scsi_qla_host *ha, struct srb * srb);
++      int (*ql4mbx)(struct scsi_qla_host *ha, uint8_t inCount,
++              uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts);
++
+       /* Linux adapter configuration data */
++      struct Scsi_Host *host; /* pointer to host data */
++      uint32_t tot_ddbs;
+       unsigned long flags;
++#define AF_ISNS_CMD_DONE           13 /* 0x00002000 */
+ #define AF_ONLINE                     0 /* 0x00000001 */
+ #define AF_INIT_DONE                  1 /* 0x00000002 */
+ #define AF_MBOX_COMMAND                       2 /* 0x00000004 */
+ #define AF_MBOX_COMMAND_DONE          3 /* 0x00000008 */
+-#define AF_INTERRUPTS_ON              6 /* 0x00000040 */
++#define AF_INTERRUPTS_ON              6 /* 0x00000040 Not Used */
+ #define AF_GET_CRASH_RECORD           7 /* 0x00000080 */
+ #define AF_LINK_UP                    8 /* 0x00000100 */
++#define AF_TOPCAT_CHIP_PRESENT                9 /* 0x00000200 */
+ #define AF_IRQ_ATTACHED                       10 /* 0x00000400 */
+ #define AF_DISABLE_ACB_COMPLETE               11 /* 0x00000800 */
+@@ -297,9 +309,6 @@ struct scsi_qla_host {
+ #define DPC_AEN                               9 /* 0x00000200 */
+ #define DPC_GET_DHCP_IP_ADDR          15 /* 0x00008000 */
+-      struct Scsi_Host *host; /* pointer to host data */
+-      uint32_t tot_ddbs;
+-
+       uint16_t        iocb_cnt;
+       uint16_t        iocb_hiwat;
+@@ -324,6 +333,7 @@ struct scsi_qla_host {
+       /* NVRAM registers */
+       struct eeprom_data *nvram;
+       spinlock_t hardware_lock ____cacheline_aligned;
++      spinlock_t list_lock;
+       uint32_t   eeprom_cmd_data;
+       /* Counters for general statistics */
+@@ -348,7 +358,6 @@ struct scsi_qla_host {
+       uint32_t firmware_version[2];
+       uint32_t patch_number;
+       uint32_t build_number;
+-      uint32_t board_id;
+       /* --- From Init_FW --- */
+       /* init_cb_t *init_cb; */
+@@ -368,6 +377,7 @@ struct scsi_qla_host {
+       /* --- From GetFwState --- */
+       uint32_t firmware_state;
++      uint32_t board_id;
+       uint32_t addl_fw_state;
+       /* Linux kernel thread */
+@@ -390,6 +400,10 @@ struct scsi_qla_host {
+       uint16_t free_srb_q_count;
+       uint16_t num_srbs_allocated;
++      /* Active array */
++      struct srb *active_srb_array[MAX_SRBS];
++      uint16_t current_active_index;
++
+       /* DMA Memory Block */
+       void *queues;
+       dma_addr_t queues_dma;
+@@ -418,12 +432,20 @@ struct scsi_qla_host {
+       uint16_t aen_out;
+       struct aen aen_q[MAX_AEN_ENTRIES];
+-      struct ql4_aen_log aen_log;/* tracks all aens */
++      /* pdu variables */
++      uint16_t pdu_count;     /* Number of available aen_q entries */
++      uint16_t pdu_in;        /* Current indexes */
++      uint16_t pdu_out;
++      uint16_t pdu_active;
++      struct pdu_entry *free_pdu_top;
++      struct pdu_entry *free_pdu_bottom;
++      struct pdu_entry pdu_queue[MAX_PDU_ENTRIES];
+       /* This mutex protects several threads to do mailbox commands
+        * concurrently.
+        */
+       struct mutex  mbox_sem;
++      wait_queue_head_t mailbox_wait_queue;
+       /* temporary mailbox status registers */
+       volatile uint8_t mbox_status_count;
+@@ -434,7 +456,11 @@ struct scsi_qla_host {
+       /* Map ddb_list entry by FW ddb index */
+       struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES];
+-
++      struct ql4_aen_log aen_log;
++      void (*ql4getaenlog)(struct scsi_qla_host *ha, struct ql4_aen_log *aenl);
++#define QL_INDICES_PER_ENTRY  32
++#define QL_OSINDEX_ENTRIES    (MAX_DDB_ENTRIES/QL_INDICES_PER_ENTRY)
++      volatile uint32_t os_map[QL_OSINDEX_ENTRIES];
+ };
+ static inline int is_qla4010(struct scsi_qla_host *ha)
+@@ -512,6 +538,20 @@ static inline void __iomem * isp_gp_out(struct scsi_qla_host *ha)
+               &ha->reg->u2.isp4022.p0.gp_out);
+ }
++static inline void __iomem * isp_probe_mux_addr(struct scsi_qla_host *ha)
++{
++      return (is_qla4010(ha) ?
++              &ha->reg->u2.isp4010.probe_mux_addr :
++              &ha->reg->u2.isp4022.p0.probe_mux_addr);
++}
++
++static inline void __iomem * isp_probe_mux_data(struct scsi_qla_host *ha)
++{
++      return (is_qla4010(ha) ?
++              &ha->reg->u2.isp4010.probe_mux_data :
++              &ha->reg->u2.isp4022.p0.probe_mux_data);
++}
++
+ static inline int eeprom_ext_hw_conf_offset(struct scsi_qla_host *ha)
+ {
+       return (is_qla4010(ha) ?
+@@ -590,5 +630,6 @@ static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a)
+ #define PROCESS_ALL_AENS       0
+ #define FLUSH_DDB_CHANGED_AENS         1
+ #define RELOGIN_DDB_CHANGED_AENS 2
++#define PROCESS_FOR_PROBE      3
+ #endif        /*_QLA4XXX_H */
+diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
+index 1b667a7..3fb3658 100644
+--- a/drivers/scsi/qla4xxx/ql4_fw.h
++++ b/drivers/scsi/qla4xxx/ql4_fw.h
+@@ -27,7 +27,11 @@ struct port_ctrl_stat_regs {
+       __le32 rsrvd1[32];      /* 0x60-0xdf */
+       __le32 gp_out;          /* 0xe0 */
+       __le32 gp_in;           /* 0xe4 */
+-      __le32 rsrvd2[5];       /* 0xe8-0xfb */
++      __le32 probe_mux_addr;  /* 0xe8 */
++      __le32 probe_mux_data;  /* 0xec */
++      __le32 stats_index;     /* 0xf0 */
++      __le32 stats_read_data_inc;     /* 0xf4 */
++      __le32 stats_read_data_noinc;   /* 0xf8 */
+       __le32 port_err_status; /* 0xfc */
+ };
+@@ -61,7 +65,9 @@ struct isp_reg {
+       __le32 req_q_in;    /* SCSI Request Queue Producer Index */
+       __le32 rsp_q_out;   /* SCSI Completion Queue Consumer Index */
+-      __le32 reserved2[4];    /* 0x40 */
++      __le32 reserved2[2];    /* 0x40 */
++      __le32 arc_madi_cmd;
++      __le32 arc_madi_data;
+       union {
+               struct {
+@@ -79,7 +85,10 @@ struct isp_reg {
+                       __le32 gp_out; /* 0xe0 */
+                       __le32 gp_in;
+-                      __le32 reserved5[5];
++                      __le32 probe_mux_addr;
++                      __le32 probe_mux_data;
++
++                      __le32 reserved5[3];
+                       __le32 port_err_status; /* 0xfc */
+               } __attribute__ ((packed)) isp4010;
+@@ -216,7 +225,6 @@ union external_hw_config_reg {
+ #define MBOX_CMD_ABOUT_FW                     0x0009
+ #define MBOX_CMD_PING                         0x000B
+ #define MBOX_CMD_LUN_RESET                    0x0016
+-#define MBOX_CMD_TARGET_WARM_RESET            0x0017
+ #define MBOX_CMD_GET_MANAGEMENT_DATA          0x001E
+ #define MBOX_CMD_GET_FW_STATUS                        0x001F
+ #define MBOX_CMD_SET_ISNS_SERVICE             0x0021
+@@ -431,8 +439,9 @@ struct init_fw_ctrl_blk {
+ struct dev_db_entry {
+       uint16_t options;       /* 00-01 */
+-#define DDB_OPT_DISC_SESSION  0x10
+-#define DDB_OPT_TARGET              0x02 /* device is a target */
++#define DDB_OPT_DISC_SESSION  0x10
++#define DDB_OPT_TARGET                0x02 /* device is a target */
++#define DDB_OPT_IPV6_DEVICE   0x100
+       uint16_t exec_throttle; /* 02-03 */
+       uint16_t exec_count;    /* 04-05 */
+@@ -672,14 +681,13 @@ struct continuation_t1_entry {
+ #define ET_CONTINUE   ET_CONT_T1
+ /* Marker entry structure*/
+-struct qla4_marker_entry {
++struct marker_entry {
+       struct qla4_header hdr; /* 00-03 */
+       uint32_t system_defined; /* 04-07 */
+       uint16_t target;        /* 08-09 */
+       uint16_t modifier;      /* 0A-0B */
+-#define MM_LUN_RESET          0
+-#define MM_TGT_WARM_RESET     1
++#define MM_LUN_RESET       0
+       uint16_t flags;         /* 0C-0D */
+       uint16_t reserved1;     /* 0E-0F */
+@@ -733,6 +741,15 @@ struct status_entry {
+ };
++struct pdu_entry {
++      uint8_t *Buff;
++      uint32_t BuffLen;
++      uint32_t SendBuffLen;
++      uint32_t RecvBuffLen;
++      struct pdu_entry *Next;
++      dma_addr_t DmaBuff;
++};
++
+ struct passthru0 {
+       struct qla4_header hdr;                /* 00-03 */
+       uint32_t handle;        /* 04-07 */
+diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
+index 96ebfb0..f948b9a 100644
+--- a/drivers/scsi/qla4xxx/ql4_glbl.h
++++ b/drivers/scsi/qla4xxx/ql4_glbl.h
+@@ -12,6 +12,7 @@ struct iscsi_cls_conn;
+ void qla4xxx_hw_reset(struct scsi_qla_host *ha);
+ int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a);
++int qla4xxx_conn_start(struct iscsi_cls_conn *conn);
+ int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port);
+ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb);
+ int qla4xxx_initialize_adapter(struct scsi_qla_host * ha,
+@@ -27,8 +28,6 @@ int qla4xxx_relogin_device(struct scsi_qla_host * ha,
+                          struct ddb_entry * ddb_entry);
+ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
+                     int lun);
+-int qla4xxx_reset_target(struct scsi_qla_host * ha,
+-                       struct ddb_entry * ddb_entry);
+ int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
+                     uint32_t offset, uint32_t len);
+ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha);
+@@ -56,25 +55,35 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
+ u16 rd_nvram_word(struct scsi_qla_host * ha, int offset);
+ void qla4xxx_get_crash_record(struct scsi_qla_host * ha);
+ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
+-int qla4xxx_add_sess(struct ddb_entry *);
++int qla4xxx_add_sess(struct ddb_entry *, int);
+ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry);
++int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
++                                 uint16_t fw_ddb_index,
++                                 uint16_t connection_id,
++                                 uint16_t option);
++int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
++                               uint16_t fw_ddb_index);
+ int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha);
+ int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
+ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
+                                      uint32_t intr_status);
+ int qla4xxx_init_rings(struct scsi_qla_host * ha);
+-struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
+-                                      uint32_t index);
++void qla4xxx_dump_buffer(void *b, uint32_t size);
++struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index);
+ void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
+ int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
+ int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha,
+-                              uint32_t fw_ddb_index, uint32_t state);
+-void qla4xxx_dump_buffer(void *b, uint32_t size);
++                              uint32_t fw_ddb_index, uint32_t state, uint32_t probe);
++
++int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
++                          uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts);
+ int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
+-      struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod);
++      struct ddb_entry *ddb_entry, int lun);
++
++
+-extern int ql4xextended_error_logging;
++extern int extended_error_logging;
+ extern int ql4xdiscoverywait;
+ extern int ql4xdontresethba;
+ extern int ql4_mod_unload;
+-#endif /* _QLA4x_GBL_H */
++#endif                                /* _QLA4x_GBL_H */
+diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
+index 109c5f5..6e83198 100644
+--- a/drivers/scsi/qla4xxx/ql4_init.c
++++ b/drivers/scsi/qla4xxx/ql4_init.c
+@@ -5,12 +5,20 @@
+  * See LICENSE.qla4xxx for copyright and licensing details.
+  */
+-#include <scsi/iscsi_if.h>
+ #include "ql4_def.h"
++#include "ql4_version.h"
+ #include "ql4_glbl.h"
+ #include "ql4_dbg.h"
+ #include "ql4_inline.h"
++/* link auto negotiation normally takes roughly 2s.   */
++/* If we don't have link in 3 times that period quit. */
++#define        QLA4XXX_LINK_UP_DELAY   6
++
++/*
++ * QLogic ISP4xxx Hardware Support Function Prototypes.
++ */
++
+ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+                                           uint32_t fw_ddb_index);
+@@ -44,7 +52,7 @@ static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
+ }
+ /**
+- * qla4xxx_free_ddb - deallocate ddb
++ * qla4xxx_free_ddb - deallocate ddb  
+  * @ha: pointer to host adapter structure.
+  * @ddb_entry: pointer to device database entry
+  *
+@@ -58,8 +66,7 @@ static void qla4xxx_free_ddb(struct scsi_qla_host *ha,
+       list_del_init(&ddb_entry->list);
+       /* Remove device pointer from index mapping arrays */
+-      ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] =
+-              (struct ddb_entry *) INVALID_ENTRY;
++      ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = NULL;
+       ha->tot_ddbs--;
+       /* Free memory and scsi-ml struct for device entry */
+@@ -95,6 +102,7 @@ void qla4xxx_free_ddb_list(struct scsi_qla_host *ha)
+  **/
+ int qla4xxx_init_rings(struct scsi_qla_host *ha)
+ {
++      uint16_t i;
+       unsigned long flags = 0;
+       /* Initialize request queue. */
+@@ -123,6 +131,10 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha)
+       writel(0, &ha->reg->rsp_q_out);
+       readl(&ha->reg->rsp_q_out);
++      /* Initialize active array */
++      for (i = 0; i < MAX_SRBS; i++)
++              ha->active_srb_array[i] = NULL;
++
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       return QLA_SUCCESS;
+@@ -183,6 +195,16 @@ static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha)
+  **/
+ static int qla4xxx_init_local_data(struct scsi_qla_host *ha)
+ {
++      int i;
++
++      /* Initialize passthru PDU list */
++      for (i = 0; i < (MAX_PDU_ENTRIES - 1); i++)
++              ha->pdu_queue[i].Next = &ha->pdu_queue[i + 1];
++      ha->free_pdu_top = &ha->pdu_queue[0];
++      ha->free_pdu_bottom = &ha->pdu_queue[MAX_PDU_ENTRIES - 1];
++      ha->free_pdu_bottom->Next = NULL;
++      ha->pdu_active = 0;
++
+       /* Initilize aen queue */
+       ha->aen_q_count = MAX_AEN_ENTRIES;
+@@ -263,12 +285,10 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
+                             "seconds expired= %d\n", ha->host_no, __func__,
+                             ha->firmware_state, ha->addl_fw_state,
+                             timeout_count));
+-              if (is_qla4032(ha) &&
+-                      !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) &&
++              if (!(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) &&
+                       (timeout_count < ADAPTER_INIT_TOV - 5)) {
+                       break;
+               }
+-
+               msleep(1000);
+       }                       /* end of for */
+@@ -276,7 +296,8 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
+               DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n",
+                             ha->host_no, __func__));
+-      if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)  {
++      if ((ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)||
++              !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP))  {
+               DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to"
+                             " grab an IP address from DHCP server\n",
+                             ha->host_no, __func__));
+@@ -307,145 +328,27 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha)
+       return qla4xxx_get_firmware_status(ha);
+ }
+-static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
+-                                              uint32_t fw_ddb_index,
+-                                              uint32_t *new_tgt)
++static void qla4xxx_fill_ddb(struct ddb_entry *ddb_entry,
++              struct dev_db_entry *fw_ddb_entry)
+ {
+-      struct dev_db_entry *fw_ddb_entry = NULL;
+-      dma_addr_t fw_ddb_entry_dma;
+-      struct ddb_entry *ddb_entry = NULL;
+-      int found = 0;
+-      uint32_t device_state;
+-
+-      *new_tgt = 0;
+-      /* Make sure the dma buffer is valid */
+-      fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
+-                                        sizeof(*fw_ddb_entry),
+-                                        &fw_ddb_entry_dma, GFP_KERNEL);
+-      if (fw_ddb_entry == NULL) {
+-              DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+-                            ha->host_no, __func__));
+-              return NULL;
+-      }
+-
+-      if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
+-                                  fw_ddb_entry_dma, NULL, NULL,
+-                                  &device_state, NULL, NULL, NULL) ==
+-          QLA_ERROR) {
+-              DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
+-                            "fw_ddb_index %d\n", ha->host_no, __func__,
+-                            fw_ddb_index));
+-              return NULL;
+-      }
+-
+-      /* Allocate DDB if not already allocated. */
+-      DEBUG2(printk("scsi%ld: %s: Looking for ddb[%d]\n", ha->host_no,
+-                    __func__, fw_ddb_index));
+-      list_for_each_entry(ddb_entry, &ha->ddb_list, list) {
+-              if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsi_name,
+-                         ISCSI_NAME_SIZE) == 0) {
+-                      found++;
+-                      break;
+-              }
+-      }
+-
+-      if (!found) {
+-              DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating "
+-                            "new ddb\n", ha->host_no, __func__,
+-                            fw_ddb_index));
+-              *new_tgt = 1;
+-              ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
+-      }
+-
+-      /* if not found allocate new ddb */
+-      dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
+-                        fw_ddb_entry_dma);
+-
+-      return ddb_entry;
+-}
+-
+-/**
+- * qla4xxx_update_ddb_entry - update driver's internal ddb
+- * @ha: pointer to host adapter structure.
+- * @ddb_entry: pointer to device database structure to be filled
+- * @fw_ddb_index: index of the ddb entry in fw ddb table
+- *
+- * This routine updates the driver's internal device database entry
+- * with information retrieved from the firmware's device database
+- * entry for the specified device. The ddb_entry->fw_ddb_index field
+- * must be initialized prior to       calling this routine
+- *
+- **/
+-static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
+-                                  struct ddb_entry *ddb_entry,
+-                                  uint32_t fw_ddb_index)
+-{
+-      struct dev_db_entry *fw_ddb_entry = NULL;
+-      dma_addr_t fw_ddb_entry_dma;
+-      int status = QLA_ERROR;
+-
+-      if (ddb_entry == NULL) {
+-              DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no,
+-                            __func__));
+-              goto exit_update_ddb;
+-      }
+-
+-      /* Make sure the dma buffer is valid */
+-      fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
+-                                        sizeof(*fw_ddb_entry),
+-                                        &fw_ddb_entry_dma, GFP_KERNEL);
+-      if (fw_ddb_entry == NULL) {
+-              DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+-                            ha->host_no, __func__));
+-
+-              goto exit_update_ddb;
+-      }
+-
+-      if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
+-                                  fw_ddb_entry_dma, NULL, NULL,
+-                                  &ddb_entry->fw_ddb_device_state, NULL,
+-                                  &ddb_entry->tcp_source_port_num,
+-                                  &ddb_entry->connection_id) ==
+-          QLA_ERROR) {
+-              DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
+-                            "fw_ddb_index %d\n", ha->host_no, __func__,
+-                            fw_ddb_index));
+-
+-              goto exit_update_ddb;
+-      }
+-
+-      status = QLA_SUCCESS;
+       ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid);
+       ddb_entry->task_mgmt_timeout =
+               le16_to_cpu(fw_ddb_entry->def_timeout);
+       ddb_entry->CmdSn = 0;
+       ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exec_throttle);
++
+       ddb_entry->default_relogin_timeout =
+               le16_to_cpu(fw_ddb_entry->def_timeout);
+-      ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
+-
+-      /* Update index in case it changed */
+-      ddb_entry->fw_ddb_index = fw_ddb_index;
+-      ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
++      ddb_entry->default_time2wait =
++              le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
+       ddb_entry->port = le16_to_cpu(fw_ddb_entry->port);
+       ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
+       memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],
+-             min(sizeof(ddb_entry->iscsi_name),
+-                 sizeof(fw_ddb_entry->iscsi_name)));
++              min(sizeof(ddb_entry->iscsi_name),
++              sizeof(fw_ddb_entry->iscsi_name)));
+       memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0],
+-             min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr)));
+-
+-      DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n",
+-                    ha->host_no, __func__, fw_ddb_index,
+-                    ddb_entry->fw_ddb_device_state, status));
+-
+- exit_update_ddb:
+-      if (fw_ddb_entry)
+-              dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+-                                fw_ddb_entry, fw_ddb_entry_dma);
+-
+-      return status;
++              min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr)));
+ }
+ /**
+@@ -478,6 +381,12 @@ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+       atomic_set(&ddb_entry->relogin_timer, 0);
+       atomic_set(&ddb_entry->relogin_retry_count, 0);
+       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);
++
+       list_add_tail(&ddb_entry->list, &ha->ddb_list);
+       ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
+       ha->tot_ddbs++;
+@@ -490,7 +399,7 @@ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+  * @ha: Pointer to host adapter structure.
+  *
+  * This routine searches for all valid firmware ddb entries and builds
+- * an internal ddb list. Ddbs that are considered valid are those with
++ * an internal ddb list. Ddbs that are considered valid are those with 
+  * a device state of SESSION_ACTIVE.
+  **/
+ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
+@@ -501,90 +410,116 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
+       uint32_t ddb_state;
+       uint32_t conn_err, err_code;
+       struct ddb_entry *ddb_entry;
+-      uint32_t new_tgt;
++      struct dev_db_entry *fw_ddb_entry = NULL;
++      dma_addr_t fw_ddb_entry_dma;
++      uint16_t src_port, conn_id;
++      uint32_t ipv6_device;
+       dev_info(&ha->pdev->dev, "Initializing DDBs ...\n");
++
++      fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
++                      &fw_ddb_entry_dma, GFP_KERNEL);
++
++      if (fw_ddb_entry == NULL) {
++              DEBUG2(dev_info(&ha->pdev->dev, "%s: DMA alloc failed\n",
++                      __func__));
++              return QLA_ERROR;
++      }
++
+       for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES;
+            fw_ddb_index = next_fw_ddb_index) {
+               /* First, let's see if a device exists here */
+-              if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL,
+-                                          &next_fw_ddb_index, &ddb_state,
+-                                          &conn_err, NULL, NULL) ==
+-                  QLA_ERROR) {
+-                      DEBUG2(printk("scsi%ld: %s: get_ddb_entry, "
+-                                    "fw_ddb_index %d failed", ha->host_no,
+-                                    __func__, fw_ddb_index));
+-                      return QLA_ERROR;
++              if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
++                      fw_ddb_entry_dma, NULL, &next_fw_ddb_index,
++                      &ddb_state, &conn_err, &src_port,
++                      &conn_id) == QLA_ERROR) {
++                      DEBUG2(dev_info(&ha->pdev->dev, "%s: get_ddb_entry,"
++                              " fw_ddb_index %d failed", __func__,
++                              fw_ddb_index));
++                      goto exit_ddb_list;
+               }
+-              DEBUG2(printk("scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, "
+-                            "next_fw_ddb_index=%d.\n", ha->host_no, __func__,
++              DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] ddbstate=0x%x, "
++                            "next_fw_ddb_index=%d.\n", __func__,
+                             fw_ddb_index, ddb_state, next_fw_ddb_index));
+               /* Issue relogin, if necessary. */
+               if (ddb_state == DDB_DS_SESSION_FAILED ||
+                   ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) {
++                      ipv6_device = le16_to_cpu(fw_ddb_entry->options) &
++                                      DDB_OPT_IPV6_DEVICE;
+                       /* Try and login to device */
+-                      DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n",
+-                                    ha->host_no, __func__, fw_ddb_index));
++                      DEBUG2(dev_info(&ha->pdev->dev, "%s: Login DDB[%d]\n",
++                              __func__, fw_ddb_index));
+                       err_code = ((conn_err & 0x00ff0000) >> 16);
+                       if (err_code == 0x1c || err_code == 0x06) {
+-                              DEBUG2(printk("scsi%ld: %s send target "
+-                                            "completed "
+-                                            "or access denied failure\n",
+-                                            ha->host_no, __func__));
+-                      } else {
++                              DEBUG2(dev_info(&ha->pdev->dev,
++                                      ": %s send target completed or access"
++                                      " denied failure\n", __func__));
++                      } else if ((!ipv6_device &&
++                                      *((uint32_t *)fw_ddb_entry->ip_addr)) ||
++                                      ipv6_device) {
+                               qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0);
+                               if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index,
+-                                      NULL, 0, NULL, &next_fw_ddb_index,
+-                                      &ddb_state, &conn_err, NULL, NULL)
+-                                      == QLA_ERROR) {
+-                                      DEBUG2(printk("scsi%ld: %s:"
+-                                              "get_ddb_entry %d failed\n",
+-                                              ha->host_no,
++                                      fw_ddb_entry, fw_ddb_entry_dma, NULL,
++                                      &next_fw_ddb_index, &ddb_state,
++                                      &conn_err, &src_port,
++                                      &conn_id) == QLA_ERROR) {
++                                      DEBUG2(dev_info(&ha->pdev->dev,
++                                              "%s: get_fwddb %d failed\n",
+                                               __func__, fw_ddb_index));
+-                                      return QLA_ERROR;
++                                      goto exit_ddb_list;
+                               }
+                       }
+               }
+-              if (ddb_state != DDB_DS_SESSION_ACTIVE)
+-                      goto next_one;
+-              /*
+-               * if fw_ddb with session active state found,
+-               * add to ddb_list
+-               */
+-              DEBUG2(printk("scsi%ld: %s: DDB[%d] added to list\n",
+-                            ha->host_no, __func__, fw_ddb_index));
+-
+-              /* Add DDB to internal our ddb list. */
+-              ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt);
+-              if (ddb_entry == NULL) {
+-                      DEBUG2(printk("scsi%ld: %s: Unable to allocate memory "
+-                                    "for device at fw_ddb_index %d\n",
+-                                    ha->host_no, __func__, fw_ddb_index));
+-                      return QLA_ERROR;
+-              }
+-              /* Fill in the device structure */
+-              if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
+-                  QLA_ERROR) {
+-                      ha->fw_ddb_index_map[fw_ddb_index] =
+-                              (struct ddb_entry *)INVALID_ENTRY;
+-
+-
+-                      DEBUG2(printk("scsi%ld: %s: update_ddb_entry failed "
+-                                    "for fw_ddb_index %d.\n",
+-                                    ha->host_no, __func__, fw_ddb_index));
+-                      return QLA_ERROR;
++              if (!(le16_to_cpu(fw_ddb_entry->options) & DDB_OPT_DISC_SESSION) &&
++                      (ddb_state != DDB_DS_UNASSIGNED) &&
++                      (strlen(fw_ddb_entry->iscsi_name) != 0)){
++                      ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
++                      if (ddb_entry == NULL) {
++                              DEBUG2(dev_info(&ha->pdev->dev,"%s alloc_ddb %d "
++                                      "failed\n", __func__, fw_ddb_index));
++                              goto exit_ddb_list;
++                      }
++                      ddb_entry->fw_ddb_index = fw_ddb_index;
++                      ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
++                      ddb_entry->tcp_source_port_num = src_port;
++                      ddb_entry->connection_id = conn_id;
++                      qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry);
++                      ddb_entry->fw_ddb_device_state = ddb_state;
++                      
++                      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);
++                      } else {
++                              atomic_set(&ddb_entry->state, DDB_STATE_MISSING);
++                              dev_info(&ha->pdev->dev,
++                                      "scsi%ld: %s: ddb[%d] os[%d] marked MISSING\n",
++                                      ha->host_no, __func__, ddb_entry->fw_ddb_index,
++                                      ddb_entry->os_target_id);
++                      }
++                      DEBUG6(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d State %04x"
++                              " ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", __func__,
++                              fw_ddb_index, ddb_entry->os_target_id, ddb_state, conn_err,
++                              fw_ddb_entry->ip_addr[0], fw_ddb_entry->ip_addr[1],
++                              fw_ddb_entry->ip_addr[2], fw_ddb_entry->ip_addr[3],
++                              le16_to_cpu(fw_ddb_entry->port),
++                              fw_ddb_entry->iscsi_name));
+               }
+-next_one:
+               /* We know we've reached the last device when
+                * next_fw_ddb_index is 0 */
+               if (next_fw_ddb_index == 0)
+                       break;
+       }
++exit_ddb_list:
++      dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
++              fw_ddb_entry_dma);
+       dev_info(&ha->pdev->dev, "DDB list done..\n");
+       return status;
+@@ -682,15 +617,18 @@ static int qla4_scan_for_relogin(struct scsi_qla_host *ha,
+ static int qla4xxx_devices_ready(struct scsi_qla_host *ha)
+ {
+       int error;
+-      unsigned long discovery_wtime;
++      unsigned long discovery_wtime = 0;
+       struct qla4_relog_scan rs;
+-      discovery_wtime = jiffies + (ql4xdiscoverywait * HZ);
+-
+       DEBUG(printk("Waiting (%d) for devices ...\n", ql4xdiscoverywait));
+       do {
+               /* poll for AEN. */
+               qla4xxx_get_firmware_state(ha);
++
++              if(!(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) &&
++                      (discovery_wtime > QLA4XXX_LINK_UP_DELAY))
++                      break;
++
+               if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) {
+                       /* Set time-between-relogin timer */
+                       qla4xxx_process_aen(ha, RELOGIN_DDB_CHANGED_AENS);
+@@ -708,7 +646,8 @@ static int qla4xxx_devices_ready(struct scsi_qla_host *ha)
+               }
+               msleep(2000);
+-      } while (!time_after_eq(jiffies, discovery_wtime));
++              discovery_wtime += 2;
++      } while (discovery_wtime < ql4xdiscoverywait);
+       DEBUG3(qla4xxx_get_conn_event_log(ha));
+@@ -750,13 +689,13 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha)
+               qla4xxx_free_ddb_list(ha);
+       for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++)
+-              ha->fw_ddb_index_map[fw_ddb_index] =
+-                      (struct ddb_entry *)INVALID_ENTRY;
++              ha->fw_ddb_index_map[fw_ddb_index] = NULL;
+       ha->tot_ddbs = 0;
+       qla4xxx_flush_AENS(ha);
++
+       /*
+        * First perform device discovery for active
+        * fw ddb indexes and build
+@@ -773,7 +712,7 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha)
+        * the aens here will catch them.
+        */
+       if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
+-              qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
++              qla4xxx_process_aen(ha, PROCESS_FOR_PROBE);
+       return status;
+ }
+@@ -789,19 +728,37 @@ int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha)
+ {
+       int status = QLA_SUCCESS;
+       struct ddb_entry *ddb_entry, *detemp;
++      struct dev_db_entry *fw_ddb_entry = NULL;
++      dma_addr_t fw_ddb_entry_dma;
++
++      fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
++                              sizeof(*fw_ddb_entry), &fw_ddb_entry_dma,
++                              GFP_KERNEL);
++      if (fw_ddb_entry == NULL)
++              return QLA_ERROR;
+       /* Update the device information for all devices. */
+       list_for_each_entry_safe(ddb_entry, detemp, &ha->ddb_list, list) {
+-              qla4xxx_update_ddb_entry(ha, ddb_entry,
+-                                       ddb_entry->fw_ddb_index);
+-              if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
+-                      atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
+-                      DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked "
+-                                     "ONLINE\n", ha->host_no, __func__,
+-                                     ddb_entry->fw_ddb_index));
+-              } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
+-                      qla4xxx_mark_device_missing(ha, ddb_entry);
++              if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
++                      fw_ddb_entry, fw_ddb_entry_dma, NULL, NULL,
++                      &ddb_entry->fw_ddb_device_state, NULL,
++                      &ddb_entry->tcp_source_port_num,
++                      &ddb_entry->connection_id) == QLA_SUCCESS) {
++
++                      qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry);
++
++                      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);
++                      } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
++                              qla4xxx_mark_device_missing(ha, ddb_entry);
++              }
+       }
++      dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
++              fw_ddb_entry, fw_ddb_entry_dma);
+       return status;
+ }
+@@ -884,12 +841,11 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
+ static void qla4x00_pci_config(struct scsi_qla_host *ha)
+ {
+       uint16_t w;
+-      int status;
+       dev_info(&ha->pdev->dev, "Configuring PCI space...\n");
+       pci_set_master(ha->pdev);
+-      status = pci_set_mwi(ha->pdev);
++      pci_set_mwi(ha->pdev);
+       /*
+        * We want to respect framework's setting of PCI configuration space
+        * command register and also want to make sure that all bits of
+@@ -1007,7 +963,7 @@ int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
+  * qla4xxx_start_firmware - starts qla4xxx firmware
+  * @ha: Pointer to host adapter structure.
+  *
+- * This routine performs the necessary steps to start the firmware for
++ * This routine performs the neccessary steps to start the firmware for
+  * the QLA4010 adapter.
+  **/
+ static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
+@@ -1127,7 +1083,7 @@ static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
+  * @renew_ddb_list: Indicates what to do with the adapter's ddb list
+  *    after adapter recovery has completed.
+  *    0=preserve ddb list, 1=destroy and rebuild ddb list
+- *
++ * 
+  * This routine parforms all of the steps necessary to initialize the adapter.
+  *
+  **/
+@@ -1211,51 +1167,81 @@ exit_init_hba:
+  * This routine processes adds a device as a result of an 8014h AEN.
+  **/
+ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha,
+-                                         uint32_t fw_ddb_index)
++                                 uint32_t fw_ddb_index, uint32_t probe)
+ {
+-      struct ddb_entry * ddb_entry;
+-      uint32_t new_tgt;
++      struct dev_db_entry *fw_ddb_entry = NULL;
++      dma_addr_t fw_ddb_entry_dma;
++      uint16_t src_port, conn_id;
++      struct ddb_entry *ddb_entry = NULL;
++      uint32_t ddb_state, found = 0;
+-      /* First allocate a device structure */
+-      ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt);
+-      if (ddb_entry == NULL) {
+-              DEBUG2(printk(KERN_WARNING
+-                            "scsi%ld: Unable to allocate memory to add "
+-                            "fw_ddb_index %d\n", ha->host_no, fw_ddb_index));
++      fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
++                              &fw_ddb_entry_dma, GFP_KERNEL);
++
++      if (fw_ddb_entry == NULL) {
++              DEBUG2(dev_info(&ha->pdev->dev, "%s dmaalloc failed\n", __func__));
+               return;
+       }
+-      if (!new_tgt && (ddb_entry->fw_ddb_index != fw_ddb_index)) {
++      if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
++              fw_ddb_entry_dma, NULL, NULL, &ddb_state, NULL, &src_port,
++              &conn_id) == QLA_ERROR) {
++              DEBUG2(dev_info(&ha->pdev->dev, "%s getddb %d failed\n",
++                      __func__, fw_ddb_index));
++              return;
++      }
++
++      list_for_each_entry(ddb_entry, &ha->ddb_list, list) {
++              if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsi_name,
++                      ISCSI_NAME_SIZE) == 0) {
++                      found = 1;
++
++                      DEBUG6(dev_info(&ha->pdev->dev, "%s found target ddb = 0x%p"
++                              " sess 0x%p conn 0x%p state 0x%x nidx 0x%x oidx 0x%x\n",
++                              __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn,
++                              ddb_entry->state, fw_ddb_index, ddb_entry->fw_ddb_index));
++                      break;
++              }
++      }
++
++      if (!found)
++              ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
++      else if (ddb_entry->fw_ddb_index != fw_ddb_index) {
+               /* Target has been bound to a new fw_ddb_index */
+               qla4xxx_free_ddb(ha, ddb_entry);
+               ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
+-              if (ddb_entry == NULL) {
+-                      DEBUG2(printk(KERN_WARNING
+-                              "scsi%ld: Unable to allocate memory"
+-                              " to add fw_ddb_index %d\n",
+-                              ha->host_no, fw_ddb_index));
+-                      return;
+-              }
+       }
+-      if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
+-                                  QLA_ERROR) {
+-              ha->fw_ddb_index_map[fw_ddb_index] =
+-                                      (struct ddb_entry *)INVALID_ENTRY;
+-              DEBUG2(printk(KERN_WARNING
+-                            "scsi%ld: failed to add new device at index "
+-                            "[%d]\n Unable to retrieve fw ddb entry\n",
+-                            ha->host_no, fw_ddb_index));
+-              qla4xxx_free_ddb(ha, ddb_entry);
+-              return;
++
++      if (ddb_entry == NULL) {
++              DEBUG2(dev_info(&ha->pdev->dev, "%s NULL DDB %d\n",
++                      __func__, fw_ddb_index));
++              goto exit_dyn_add;
+       }
+-      if (qla4xxx_add_sess(ddb_entry)) {
+-              DEBUG2(printk(KERN_WARNING
++      ddb_entry->fw_ddb_index = fw_ddb_index;
++      ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
++      ddb_entry->tcp_source_port_num = src_port;
++      ddb_entry->connection_id = conn_id;
++      qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry);
++      ddb_entry->fw_ddb_device_state = ddb_state;
++
++      if (!probe) {
++              if (qla4xxx_add_sess(ddb_entry, 1)) {
++                      DEBUG2(printk(KERN_WARNING
+                             "scsi%ld: failed to add new device at index "
+                             "[%d]\n Unable to add connection and session\n",
+                             ha->host_no, fw_ddb_index));
+-              qla4xxx_free_ddb(ha, ddb_entry);
++                      qla4xxx_free_ddb(ha, ddb_entry);
++              }
+       }
++
++      DEBUG6(dev_info(&ha->pdev->dev, "%s added ddb 0x%p sess 0x%p conn 0x%p"
++              " state 0x%x\n", __func__, ddb_entry, ddb_entry->sess,
++              ddb_entry->conn, ddb_entry->state));
++exit_dyn_add:
++      dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
++              fw_ddb_entry_dma);
++      return;
+ }
+ /**
+@@ -1267,11 +1253,13 @@ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha,
+  * This routine processes a Decive Database Changed AEN Event.
+  **/
+ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
+-                              uint32_t fw_ddb_index, uint32_t state)
++              uint32_t fw_ddb_index, uint32_t state, uint32_t probe)
+ {
+       struct ddb_entry * ddb_entry;
+       uint32_t old_fw_ddb_device_state;
++      DEBUG6(dev_info(&ha->pdev->dev, "%s idx %d nstate 0x%x\n",
++              __func__, fw_ddb_index, state));
+       /* check for out of range index */
+       if (fw_ddb_index >= MAX_DDB_ENTRIES)
+               return QLA_ERROR;
+@@ -1281,9 +1269,12 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
+       /* Device does not currently exist in our database. */
+       if (ddb_entry == NULL) {
+               if (state == DDB_DS_SESSION_ACTIVE)
+-                      qla4xxx_add_device_dynamically(ha, fw_ddb_index);
++                      qla4xxx_add_device_dynamically(ha, fw_ddb_index, probe);
+               return QLA_SUCCESS;
+       }
++      DEBUG6(dev_info(&ha->pdev->dev, "%s ddb_entry 0x%p ostate 0x%x"
++              " sess 0x%p conn 0x%p\n", __func__, ddb_entry,
++              ddb_entry->state, ddb_entry->sess, ddb_entry->conn));
+       /* Device already exists in our database. */
+       old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state;
+@@ -1297,25 +1288,43 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
+       }
+       ddb_entry->fw_ddb_device_state = state;
++
++      if (probe)
++              return QLA_SUCCESS;
++
+       /* Device is back online. */
+       if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
+-              atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
+               atomic_set(&ddb_entry->port_down_timer,
+                          ha->port_down_retry_count);
++              atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
+               atomic_set(&ddb_entry->relogin_retry_count, 0);
+               atomic_set(&ddb_entry->relogin_timer, 0);
+               clear_bit(DF_RELOGIN, &ddb_entry->flags);
+               clear_bit(DF_NO_RELOGIN, &ddb_entry->flags);
+-              iscsi_unblock_session(ddb_entry->sess);
+-              iscsi_session_event(ddb_entry->sess,
+-                                  ISCSI_KEVENT_CREATE_SESSION);
+-              /*
+-               * Change the lun state to READY in case the lun TIMEOUT before
+-               * the device came back.
+-               */
++
++              DEBUG6(dev_info(&ha->pdev->dev, "%s conn startddb_entry 0x%p"
++                      " sess 0x%p conn 0x%p\n",
++                      __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn)); 
++
++              qla4xxx_conn_start(ddb_entry->conn);
++
++              DEBUG6(dev_info(&ha->pdev->dev, "%s conn start done "
++                      "ddb_entry 0x%p sess 0x%p conn 0x%p\n",
++                      __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn));
++
++              if (!test_bit(DF_SCAN_ISSUED, &ddb_entry->flags)) {
++                      scsi_scan_target(&ddb_entry->sess->dev, 0,
++                              ddb_entry->sess->target_id,
++                              SCAN_WILD_CARD, 0);
++                      set_bit(DF_SCAN_ISSUED, &ddb_entry->flags);
++              }
+       } else {
+               /* Device went away, try to relogin. */
+               /* Mark device missing */
++              DEBUG6(dev_info(&ha->pdev->dev, "%s mark missing ddb_entry 0x%p"
++                      " sess 0x%p conn 0x%p\n", __func__, ddb_entry,
++                      ddb_entry->sess, ddb_entry->conn));
++
+               if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
+                       qla4xxx_mark_device_missing(ha, ddb_entry);
+               /*
+@@ -1325,8 +1334,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
+                */
+               if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED &&
+                   !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
+-                  !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) &&
+-                  !test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) {
++                  !test_bit(DF_NO_RELOGIN, &ddb_entry->flags)) {
+                       /*
+                        * This triggers a relogin.  After the relogin_timer
+                        * expires, the relogin gets scheduled.  We must wait a
+diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h
+index 6375eb0..3cf28aa 100644
+--- a/drivers/scsi/qla4xxx/ql4_inline.h
++++ b/drivers/scsi/qla4xxx/ql4_inline.h
+@@ -24,8 +24,7 @@ qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index)
+       struct ddb_entry *ddb_entry = NULL;
+       if ((fw_ddb_index < MAX_DDB_ENTRIES) &&
+-          (ha->fw_ddb_index_map[fw_ddb_index] !=
+-              (struct ddb_entry *) INVALID_ENTRY)) {
++          (ha->fw_ddb_index_map[fw_ddb_index] != NULL)) {
+               ddb_entry = ha->fw_ddb_index_map[fw_ddb_index];
+       }
+diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
+index 912a674..d387386 100644
+--- a/drivers/scsi/qla4xxx/ql4_iocb.c
++++ b/drivers/scsi/qla4xxx/ql4_iocb.c
+@@ -6,11 +6,12 @@
+  */
+ #include "ql4_def.h"
++#include "ql4_version.h"
+ #include "ql4_glbl.h"
+ #include "ql4_dbg.h"
+ #include "ql4_inline.h"
+-
++#define VMWARE_CMD_TIMEOUT    30
+ #include <scsi/scsi_tcq.h>
+ /**
+@@ -67,9 +68,9 @@ static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
+  * This routine issues a marker IOCB.
+  **/
+ int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
+-      struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod)
++                           struct ddb_entry *ddb_entry, int lun)
+ {
+-      struct qla4_marker_entry *marker_entry;
++      struct marker_entry *marker_entry;
+       unsigned long flags = 0;
+       uint8_t status = QLA_SUCCESS;
+@@ -87,7 +88,7 @@ int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
+       marker_entry->hdr.entryType = ET_MARKER;
+       marker_entry->hdr.entryCount = 1;
+       marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index);
+-      marker_entry->modifier = cpu_to_le16(mrkr_mod);
++      marker_entry->modifier = cpu_to_le16(MM_LUN_RESET);
+       int_to_scsilun(lun, &marker_entry->lun);
+       wmb();
+@@ -160,6 +161,13 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb,
+       avail_dsds = COMMAND_SEG;
+       cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]);
++      if (srb->flags & SRB_SCSI_PASSTHRU) {
++              cur_dsd->base.addrLow = cpu_to_le32(LSDW(srb->dma_handle));
++              cur_dsd->base.addrHigh = cpu_to_le32(MSDW(srb->dma_handle));
++              cur_dsd->count = cpu_to_le32(srb->dma_len);
++              return;
++      }
++
+       scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+               dma_addr_t sle_dma;
+@@ -204,6 +212,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
+       unsigned long flags;
+       uint16_t cnt;
++      uint16_t i;
+       uint32_t index;
+       char tag[2];
+@@ -215,7 +224,22 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
+       /* Acquire hardware specific lock */
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+-      index = (uint32_t)cmd->request->tag;
++      index = ha->current_active_index;
++      for (i = 0; i < MAX_SRBS; i++) {
++              index++;
++              if (index == MAX_SRBS)
++                      index = 1;
++              if (ha->active_srb_array[index] == 0) {
++                      ha->current_active_index = index;
++                      break;
++              }
++      }
++      if (i >= MAX_SRBS) {
++              printk(KERN_INFO "scsi%ld: %s: NO more SRB entries used "
++                     "iocbs=%d, \n reqs remaining=%d\n", ha->host_no,
++                     __func__, ha->iocb_cnt, ha->req_q_count);
++              goto queuing_error;
++      }
+       /* Calculate the number of request entries needed. */
+       nseg = scsi_dma_map(cmd);
+@@ -258,8 +282,8 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
+       /* Set data transfer direction control flags
+        * NOTE: Look at data_direction bits iff there is data to be
+-       *       transferred, as the data direction bit is sometimed filled
+-       *       in when there is no data to be transferred */
++       *       transferred, as the data direction bit is sometimed filled
++       *       in when there is no data to be transferred */
+       cmd_entry->control_flags = CF_NO_DATA;
+       if (scsi_bufflen(cmd)) {
+               if (cmd->sc_data_direction == DMA_TO_DEVICE)
+@@ -286,7 +310,6 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
+                       break;
+               }
+-
+       /* Advance request queue pointer */
+       ha->request_in++;
+       if (ha->request_in == REQUEST_QUEUE_DEPTH) {
+@@ -313,6 +336,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
+       }
+       srb->cmd->host_scribble = (unsigned char *)srb;
++      ha->active_srb_array[index] = srb;
+       /* update counters */
+       srb->state = SRB_ACTIVE_STATE;
+@@ -331,6 +355,9 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
+       return QLA_SUCCESS;
+ queuing_error:
++      if (srb->flags & SRB_SCSI_PASSTHRU)
++              return QLA_ERROR;
++
+       if (tot_dsds)
+               scsi_dma_unmap(cmd);
+@@ -338,4 +365,3 @@ queuing_error:
+       return QLA_ERROR;
+ }
+-
+diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
+index 799120f..dfe985b 100644
+--- a/drivers/scsi/qla4xxx/ql4_isr.c
++++ b/drivers/scsi/qla4xxx/ql4_isr.c
+@@ -6,6 +6,7 @@
+  */
+ #include "ql4_def.h"
++#include "ql4_version.h"
+ #include "ql4_glbl.h"
+ #include "ql4_dbg.h"
+ #include "ql4_inline.h"
+@@ -27,11 +28,6 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
+       srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));
+       if (!srb) {
+-              /* FIXMEdg: Don't we need to reset ISP in this case??? */
+-              DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid "
+-                            "handle 0x%x, sp=%p. This cmd may have already "
+-                            "been completed.\n", ha->host_no, __func__,
+-                            le32_to_cpu(sts_entry->handle), srb));
+               dev_warn(&ha->pdev->dev, "%s invalid status entry:"
+                       " handle=0x%0x\n", __func__, sts_entry->handle);
+               set_bit(DPC_RESET_HA, &ha->dpc_flags);
+@@ -40,12 +36,9 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
+       cmd = srb->cmd;
+       if (cmd == NULL) {
+-              DEBUG2(printk("scsi%ld: %s: Command already returned back to "
+-                            "OS pkt->handle=%d srb=%p srb->state:%d\n",
+-                            ha->host_no, __func__, sts_entry->handle,
+-                            srb, srb->state));
+-              dev_warn(&ha->pdev->dev, "Command is NULL:"
+-                      " already returned to OS (srb=%p)\n", srb);
++              dev_warn(&ha->pdev->dev, "%s Command is NULL: srb=%p"
++                      " sts_handle=0x%0x srb_state=0x%0x\n", __func__,
++                      srb, sts_entry->handle, srb->state);
+               return;
+       }
+@@ -61,27 +54,15 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
+       scsi_status = sts_entry->scsiStatus;
+       switch (sts_entry->completionStatus) {
+       case SCS_COMPLETE:
+-
+               if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {
+                       cmd->result = DID_ERROR << 16;
+                       break;
+               }
+-
+-              if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) {
++              if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) {
+                       scsi_set_resid(cmd, residual);
+                       if (!scsi_status && ((scsi_bufflen(cmd) - residual) <
+-                              cmd->underflow)) {
+-
++                                 cmd->underflow)) {
+                               cmd->result = DID_ERROR << 16;
+-
+-                              DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
+-                                      "Mid-layer Data underrun0, "
+-                                      "xferlen = 0x%x, "
+-                                      "residual = 0x%x\n", ha->host_no,
+-                                      cmd->device->channel,
+-                                      cmd->device->id,
+-                                      cmd->device->lun, __func__,
+-                                      scsi_bufflen(cmd), residual));
+                               break;
+                       }
+               }
+@@ -218,13 +202,13 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
+                                * will return DID_ERROR.
+                                */
+                               DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
+-                                      "Mid-layer Data underrun1, "
+-                                      "xferlen = 0x%x, "
+-                                      "residual = 0x%x\n", ha->host_no,
+-                                      cmd->device->channel,
+-                                      cmd->device->id,
+-                                      cmd->device->lun, __func__,
+-                                      scsi_bufflen(cmd), residual));
++                                      "Mid-layer Data underrun len = 0x%x, "
++                                      "resid = 0x%x, compstat = 0x%x\n",
++                                      ha->host_no, cmd->device->channel,
++                                      cmd->device->id, cmd->device->lun,
++                                      __func__, scsi_bufflen(cmd),
++                                      residual,
++                                      sts_entry->completionStatus));
+                               cmd->result = DID_ERROR << 16;
+                       } else {
+@@ -414,6 +398,15 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
+       } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
+               /* Immediately process the AENs that don't require much work.
+                * Only queue the database_changed AENs */
++
++              dev_info(&ha->pdev->dev, "%s mbx0 0x%08x mbx1 0x%08x"
++                      " mbx2 0x%08x mbx3 0x%08x mbx4 0x%08x mbx5 0x%08x "
++                      "mbx6 0x%08x mbx7 0x%08x\n", __func__,
++                      readl(&ha->reg->mailbox[0]), readl(&ha->reg->mailbox[1]),
++                      readl(&ha->reg->mailbox[2]), readl(&ha->reg->mailbox[3]),
++                      readl(&ha->reg->mailbox[4]), readl(&ha->reg->mailbox[5]),
++                      readl(&ha->reg->mailbox[6]), readl(&ha->reg->mailbox[7]));
++
+               if (ha->aen_log.count < MAX_AEN_ENTRIES) {
+                       for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
+                               ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] =
+@@ -480,9 +473,9 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
+                       mbox_stat2 = readl(&ha->reg->mailbox[2]);
+                       mbox_stat3 = readl(&ha->reg->mailbox[3]);
+-                      if ((mbox_stat3 == 5) && (mbox_stat2 == 3))
++                      if ((mbox_stat3 == 5) && (mbox_stat2 == 3)) 
+                               set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
+-                      else if ((mbox_stat3 == 2) && (mbox_stat2 == 5))
++                      else if ((mbox_stat3 == 2) && (mbox_stat2 == 5)) 
+                               set_bit(DPC_RESET_HA, &ha->dpc_flags);
+                       break;
+@@ -604,6 +597,7 @@ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
+  **/
+ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id)
+ {
++
+       struct scsi_qla_host *ha;
+       uint32_t intr_status;
+       unsigned long flags = 0;
+@@ -714,7 +708,17 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
+       int i;
+       unsigned long flags;
++      DEBUG6(dev_info(&ha->pdev->dev, "%s proc_aen 0x%x\n",
++              __func__, process_aen));
++
+       spin_lock_irqsave(&ha->hardware_lock, flags);
++      if (process_aen == FLUSH_DDB_CHANGED_AENS) {
++              ha->aen_q_count = MAX_AEN_ENTRIES;
++              ha->aen_out = ha->aen_in = 0;
++              spin_unlock_irqrestore(&ha->hardware_lock, flags);
++              return;
++      }
++
+       while (ha->aen_out != ha->aen_in) {
+               aen = &ha->aen_q[ha->aen_out];
+               /* copy aen information to local structure */
+@@ -727,60 +731,46 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
+               if (ha->aen_out == MAX_AEN_ENTRIES)
+                       ha->aen_out = 0;
+-              spin_unlock_irqrestore(&ha->hardware_lock, flags);
++              DEBUG6(dev_info(&ha->pdev->dev, "%s mbx0 0x%x mbx1 0x%x mbx2 "
++                      "0x%x mbx3 0x%x ddb 0x%p\n", __func__, mbox_sts[0],
++                      mbox_sts[1], mbox_sts[2], mbox_sts[3],
++                      qla4xxx_lookup_ddb_by_fw_index(ha, mbox_sts[2])));
+-              DEBUG2(printk("qla4xxx(%ld): AEN[%d]=0x%08x, mbx1=0x%08x mbx2=0x%08x"
+-                      " mbx3=0x%08x mbx4=0x%08x\n", ha->host_no,
+-                      (ha->aen_out ? (ha->aen_out-1): (MAX_AEN_ENTRIES-1)),
+-                      mbox_sts[0], mbox_sts[1], mbox_sts[2],
+-                      mbox_sts[3], mbox_sts[4]));
++              if (process_aen == RELOGIN_DDB_CHANGED_AENS) {
++                      /* for use during init time, we only want to
++                       * relogin non-active ddbs */
++                      struct ddb_entry *ddb_entry;
+-              switch (mbox_sts[0]) {
+-              case MBOX_ASTS_DATABASE_CHANGED:
+-                      if (process_aen == FLUSH_DDB_CHANGED_AENS) {
+-                              DEBUG2(printk("scsi%ld: AEN[%d] %04x, index "
+-                                            "[%d] state=%04x FLUSHED!\n",
+-                                            ha->host_no, ha->aen_out,
+-                                            mbox_sts[0], mbox_sts[2],
+-                                            mbox_sts[3]));
+-                              break;
+-                      } else if (process_aen == RELOGIN_DDB_CHANGED_AENS) {
+-                              /* for use during init time, we only want to
+-                               * relogin non-active ddbs */
+-                              struct ddb_entry *ddb_entry;
+-
+-                              ddb_entry =
+-                                      /* FIXME: name length? */
+-                                      qla4xxx_lookup_ddb_by_fw_index(ha,
+-                                                                     mbox_sts[2]);
+-                              if (!ddb_entry)
+-                                      break;
+-
+-                              ddb_entry->dev_scan_wait_to_complete_relogin =
+-                                      0;
++                      ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, mbox_sts[2]);
++
++                      if (ddb_entry) {
++
++                              DEBUG6(dev_info(&ha->pdev->dev, "%s ddb 0x%p "
++                                      "sess 0x%p conn 0x%p state 0x%x\n",
++                                      __func__, ddb_entry, ddb_entry->sess,
++                                      ddb_entry->conn, ddb_entry->state));
++
++                              ddb_entry->dev_scan_wait_to_complete_relogin = 0;
+                               ddb_entry->dev_scan_wait_to_start_relogin =
+                                       jiffies +
+-                                      ((ddb_entry->default_time2wait +
+-                                        4) * HZ);
++                                      ((ddb_entry->default_time2wait + 4) * HZ);
+                               DEBUG2(printk("scsi%ld: ddb index [%d] initate"
+-                                            " RELOGIN after %d seconds\n",
+-                                            ha->host_no,
+-                                            ddb_entry->fw_ddb_index,
+-                                            ddb_entry->default_time2wait +
+-                                            4));
+-                              break;
++                                    " RELOGIN after %d seconds\n", ha->host_no,
++                                      ddb_entry->fw_ddb_index,
++                                      ddb_entry->default_time2wait + 4));
+                       }
+-
++              } else if (mbox_sts[0] == MBOX_ASTS_DATABASE_CHANGED) {
++                      spin_unlock_irqrestore(&ha->hardware_lock, flags);
+                       if (mbox_sts[1] == 0) { /* Global DB change. */
+                               qla4xxx_reinitialize_ddb_list(ha);
+                       } else if (mbox_sts[1] == 1) {  /* Specific device. */
+                               qla4xxx_process_ddb_changed(ha, mbox_sts[2],
+-                                                          mbox_sts[3]);
++                                      mbox_sts[3],
++                                      ((process_aen == PROCESS_FOR_PROBE) ? 1 : 0 ));
+                       }
+-                      break;
++                      spin_lock_irqsave(&ha->hardware_lock, flags);
+               }
+-              spin_lock_irqsave(&ha->hardware_lock, flags);
+       }
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ }
+diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
+index c577d79..dbd7218 100644
+--- a/drivers/scsi/qla4xxx/ql4_mbx.c
++++ b/drivers/scsi/qla4xxx/ql4_mbx.c
+@@ -6,6 +6,7 @@
+  */
+ #include "ql4_def.h"
++#include "ql4_version.h"
+ #include "ql4_glbl.h"
+ #include "ql4_dbg.h"
+ #include "ql4_inline.h"
+@@ -23,9 +24,9 @@
+  * If outCount is 0, this routine completes successfully WITHOUT waiting
+  * for the mailbox command to complete.
+  **/
+-static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+-                                 uint8_t outCount, uint32_t *mbx_cmd,
+-                                 uint32_t *mbx_sts)
++int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
++                          uint8_t outCount, uint32_t *mbx_cmd,
++                          uint32_t *mbx_sts)
+ {
+       int status = QLA_ERROR;
+       uint8_t i;
+@@ -39,9 +40,9 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+                             "pointer\n", ha->host_no, __func__));
+               return status;
+       }
++
+       /* Mailbox code active */
+       wait_count = MBOX_TOV * 100;
+-
+       while (wait_count--) {
+               mutex_lock(&ha->mbox_sem);
+               if (!test_bit(AF_MBOX_COMMAND, &ha->flags)) {
+@@ -87,8 +88,6 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+       readl(&ha->reg->ctrl_status);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+-      /* Wait for completion */
+-
+       /*
+        * If we don't want status, don't wait for the mailbox command to
+        * complete.  For example, MBOX_CMD_RESET_FW doesn't return status,
+@@ -98,6 +97,8 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+               status = QLA_SUCCESS;
+               goto mbox_exit;
+       }
++      /* Wait for completion */
++      set_current_state(TASK_UNINTERRUPTIBLE);
+       /* Wait for command to complete */
+       wait_count = jiffies + MBOX_TOV * HZ;
+       while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
+@@ -119,6 +120,7 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               msleep(10);
+       }
++      set_current_state(TASK_RUNNING);
+       /* Check for mailbox timeout. */
+       if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) {
+@@ -172,6 +174,86 @@ mbox_exit:
+       return status;
+ }
++
++/**
++ * qla4xxx_issue_iocb - issue mailbox iocb command
++ * @ha: adapter state pointer.
++ * @buffer: buffer pointer.
++ * @phys_addr: physical address of buffer.
++ * @size: size of buffer.
++ *
++ * Issues iocbs via mailbox commands.
++ * TARGET_QUEUE_LOCK must be released.
++ * ADAPTER_STATE_LOCK must be released.
++ **/
++int
++qla4xxx_issue_iocb(struct scsi_qla_host * ha, void *buffer,
++                 dma_addr_t phys_addr, size_t size)
++{
++      uint32_t mbox_cmd[MBOX_REG_COUNT];
++      uint32_t mbox_sts[MBOX_REG_COUNT];
++      int status;
++
++      memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++      memset(&mbox_sts, 0, sizeof(mbox_sts));
++
++      mbox_cmd[0] = MBOX_CMD_EXECUTE_IOCB_A64;
++      mbox_cmd[1] = 0;
++      mbox_cmd[2] = LSDW(phys_addr);
++      mbox_cmd[3] = MSDW(phys_addr);
++
++      status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
++      return status;
++}
++
++int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
++                                 uint16_t fw_ddb_index,
++                                 uint16_t connection_id,
++                                 uint16_t option)
++{
++      uint32_t mbox_cmd[MBOX_REG_COUNT];
++      uint32_t mbox_sts[MBOX_REG_COUNT];
++
++      memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++      memset(&mbox_sts, 0, sizeof(mbox_sts));
++
++      mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT;
++      mbox_cmd[1] = fw_ddb_index;
++      mbox_cmd[2] = connection_id;
++      mbox_cmd[3] = LOGOUT_OPTION_RELOGIN;
++
++      if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], &mbox_sts[0]) !=
++          QLA_SUCCESS) {
++              DEBUG2(printk("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT "
++                            "option %04x failed sts %04X %04X",
++                            ha->host_no, __func__,
++                            option, mbox_sts[0], mbox_sts[1]));
++              if (mbox_sts[0] == 0x4005)
++                      DEBUG2(printk("%s reason %04X\n", __func__,
++                                    mbox_sts[1]));
++      }
++      return QLA_SUCCESS;
++}
++
++int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
++                               uint16_t fw_ddb_index)
++{
++      uint32_t mbox_cmd[MBOX_REG_COUNT];
++      uint32_t mbox_sts[MBOX_REG_COUNT];
++
++      memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++      memset(&mbox_sts, 0, sizeof(mbox_sts));
++
++      mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY;
++      mbox_cmd[1] = fw_ddb_index;
++
++      if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
++          QLA_SUCCESS)
++              return QLA_ERROR;
++
++      return QLA_SUCCESS;
++}
++
+ /**
+  * qla4xxx_initialize_fw_cb - initializes firmware control block.
+  * @ha: Pointer to host adapter structure.
+@@ -450,15 +532,16 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
+                             mbox_sts[1]));
+               goto exit_get_fwddb;
+       }
++
+       if (fw_ddb_entry) {
+-              dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d "
+-                         "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n",
++              DEBUG6(dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d Next %d "
++                         "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", __func__,
+                          fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3],
+                          mbox_sts[4], mbox_sts[5], fw_ddb_entry->ip_addr[0],
+                          fw_ddb_entry->ip_addr[1], fw_ddb_entry->ip_addr[2],
+                          fw_ddb_entry->ip_addr[3],
+                          le16_to_cpu(fw_ddb_entry->port),
+-                         fw_ddb_entry->iscsi_name);
++                         fw_ddb_entry->iscsi_name));
+       }
+       if (num_valid_ddb_entries)
+               *num_valid_ddb_entries = mbox_sts[2];
+@@ -518,6 +601,31 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
+       return qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
+ }
++int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
++                                  uint16_t fw_ddb_index)
++{
++      int status = QLA_ERROR;
++      uint32_t mbox_cmd[MBOX_REG_COUNT];
++      uint32_t mbox_sts[MBOX_REG_COUNT];
++
++      /* Do not wait for completion. The firmware will send us an
++       * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
++       */
++      memset(&mbox_cmd, 0, sizeof(mbox_cmd));
++      memset(&mbox_sts, 0, sizeof(mbox_sts));
++
++      mbox_cmd[0] = MBOX_CMD_CONN_OPEN_SESS_LOGIN;
++      mbox_cmd[1] = (uint32_t) fw_ddb_index;
++      mbox_cmd[6] = 1;
++
++      status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 0, &mbox_cmd[0], &mbox_sts[0]);
++      DEBUG2(printk("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n",
++                    __func__, fw_ddb_index, status, mbox_sts[0],
++                    mbox_sts[1]);)
++
++              return status;
++}
++
+ /**
+  * qla4xxx_get_crash_record - retrieves crash record.
+  * @ha: Pointer to host adapter structure.
+@@ -642,7 +750,7 @@ void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha)
+       DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n",
+                     ha->host_no, num_valid_entries));
+-      if (ql4xextended_error_logging == 3) {
++      if (extended_error_logging == 3) {
+               if (oldest_entry == 0) {
+                       /* Circular Buffer has not wrapped around */
+                       for (i=0; i < num_valid_entries; i++) {
+@@ -713,45 +821,6 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
+       return status;
+ }
+-/**
+- * qla4xxx_reset_target - issues target Reset
+- * @ha: Pointer to host adapter structure.
+- * @db_entry: Pointer to device database entry
+- * @un_entry: Pointer to lun entry structure
+- *
+- * This routine performs a TARGET RESET on the specified target.
+- * The caller must ensure that the ddb_entry pointers
+- * are valid before calling this routine.
+- **/
+-int qla4xxx_reset_target(struct scsi_qla_host *ha,
+-                       struct ddb_entry *ddb_entry)
+-{
+-      uint32_t mbox_cmd[MBOX_REG_COUNT];
+-      uint32_t mbox_sts[MBOX_REG_COUNT];
+-      int status = QLA_SUCCESS;
+-
+-      DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no,
+-                    ddb_entry->os_target_id));
+-
+-      /*
+-       * Send target reset command to ISP, so that the ISP will return all
+-       * outstanding requests with RESET status
+-       */
+-      memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+-      memset(&mbox_sts, 0, sizeof(mbox_sts));
+-
+-      mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET;
+-      mbox_cmd[1] = ddb_entry->fw_ddb_index;
+-      mbox_cmd[5] = 0x01;     /* Immediate Command Enable */
+-
+-      qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+-                              &mbox_sts[0]);
+-      if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
+-          mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
+-              status = QLA_ERROR;
+-
+-      return status;
+-}
+ int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
+                     uint32_t offset, uint32_t len)
+@@ -782,8 +851,8 @@ int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
+  * qla4xxx_get_fw_version - gets firmware version
+  * @ha: Pointer to host adapter structure.
+  *
+- * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may
+- * hold an address for data.  Make sure that we write 0 to those mailboxes,
++ * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may 
++ * hold an address for data.  Make sure that we write 0 to those mailboxes, 
+  * if unused.
+  **/
+ int qla4xxx_get_fw_version(struct scsi_qla_host * ha)
+@@ -835,7 +904,7 @@ static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha,
+       return QLA_SUCCESS;
+ }
+-static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
++int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
+ {
+       uint32_t mbox_cmd[MBOX_REG_COUNT];
+       uint32_t mbox_sts[MBOX_REG_COUNT];
+@@ -889,14 +958,14 @@ int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port)
+       if (ret_val != QLA_SUCCESS)
+               goto qla4xxx_send_tgts_exit;
+-      memset(fw_ddb_entry->iscsi_alias, 0,
++      memset((void *)fw_ddb_entry->iscsi_alias, 0,
+              sizeof(fw_ddb_entry->iscsi_alias));
+-      memset(fw_ddb_entry->iscsi_name, 0,
++      memset((void *)fw_ddb_entry->iscsi_name, 0,
+              sizeof(fw_ddb_entry->iscsi_name));
+-      memset(fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr));
+-      memset(fw_ddb_entry->tgt_addr, 0,
++      memset((void *)fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr));
++      memset((void *)fw_ddb_entry->tgt_addr, 0,
+              sizeof(fw_ddb_entry->tgt_addr));
+       fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET);
+diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c
+index 7fe0482..67cfd0a 100644
+--- a/drivers/scsi/qla4xxx/ql4_nvram.c
++++ b/drivers/scsi/qla4xxx/ql4_nvram.c
+@@ -6,6 +6,7 @@
+  */
+ #include "ql4_def.h"
++#include "ql4_version.h"
+ #include "ql4_glbl.h"
+ #include "ql4_dbg.h"
+ #include "ql4_inline.h"
+diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h
+index b47b4fc..08e2aed 100644
+--- a/drivers/scsi/qla4xxx/ql4_nvram.h
++++ b/drivers/scsi/qla4xxx/ql4_nvram.h
+@@ -134,7 +134,9 @@ struct eeprom_data {
+                       u16 phyConfig;  /* x36 */
+ #define        PHY_CONFIG_PHY_ADDR_MASK             0x1f
+ #define        PHY_CONFIG_ENABLE_FW_MANAGEMENT_MASK 0x20
+-                      u16 reserved_56;        /* x38 */
++                      u16 topcat;     /* x38 */
++#define TOPCAT_PRESENT                0x0100
++#define TOPCAT_MASK           0xFF00
+ #define EEPROM_UNUSED_1_SIZE   2
+                       u8 unused_1[EEPROM_UNUSED_1_SIZE]; /* x3A */
+diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
+index 4255b36..a62188b 100644
+--- a/drivers/scsi/qla4xxx/ql4_os.c
++++ b/drivers/scsi/qla4xxx/ql4_os.c
+@@ -1,6 +1,6 @@
+ /*
+  * QLogic iSCSI HBA Driver
+- * Copyright (c)  2003-2006 QLogic Corporation
++ * Copyright (c)      2003-2006 QLogic Corporation
+  *
+  * See LICENSE.qla4xxx for copyright and licensing details.
+  */
+@@ -9,6 +9,7 @@
+ #include <scsi/scsi_tcq.h>
+ #include <scsi/scsicam.h>
++#include <linux/klist.h>
+ #include "ql4_def.h"
+ #include "ql4_version.h"
+ #include "ql4_glbl.h"
+@@ -18,7 +19,18 @@
+ /*
+  * Driver version
+  */
+-static char qla4xxx_version_str[40];
++char qla4xxx_version_str[40];
++EXPORT_SYMBOL_GPL(qla4xxx_version_str);
++
++/*
++ * List of host adapters
++ */
++struct klist qla4xxx_hostlist;
++
++struct klist *qla4xxx_hostlist_ptr = &qla4xxx_hostlist;
++EXPORT_SYMBOL_GPL(qla4xxx_hostlist_ptr);
++
++static atomic_t qla4xxx_hba_count;
+ /*
+  * SRB allocation cache
+@@ -38,16 +50,13 @@ MODULE_PARM_DESC(ql4xdontresethba,
+                " default it will reset hba :0"
+                " set to 1 to avoid resetting HBA");
+-int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */
+-module_param(ql4xextended_error_logging, int, S_IRUGO | S_IRUSR);
+-MODULE_PARM_DESC(ql4xextended_error_logging,
++int extended_error_logging = 0; /* 0 = off, 1 = log errors */
++module_param(extended_error_logging, int, S_IRUGO | S_IRUSR);
++MODULE_PARM_DESC(extended_error_logging,
+                "Option to enable extended error logging, "
+                "Default is 0 - no logging, 1 - debug logging");
+ int ql4_mod_unload = 0;
+-
+-#define QL4_DEF_QDEPTH 32
+-
+ /*
+  * SCSI host template entry points
+  */
+@@ -73,12 +82,9 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
+ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
+                               void (*done) (struct scsi_cmnd *));
+ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
+-static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
+ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
+ static int qla4xxx_slave_alloc(struct scsi_device *device);
+ static int qla4xxx_slave_configure(struct scsi_device *device);
+-static void qla4xxx_slave_destroy(struct scsi_device *sdev);
+-static void qla4xxx_scan_start(struct Scsi_Host *shost);
+ static struct scsi_host_template qla4xxx_driver_template = {
+       .module                 = THIS_MODULE,
+@@ -87,15 +93,10 @@ static struct scsi_host_template qla4xxx_driver_template = {
+       .queuecommand           = qla4xxx_queuecommand,
+       .eh_device_reset_handler = qla4xxx_eh_device_reset,
+-      .eh_target_reset_handler = qla4xxx_eh_target_reset,
+       .eh_host_reset_handler  = qla4xxx_eh_host_reset,
+       .slave_configure        = qla4xxx_slave_configure,
+       .slave_alloc            = qla4xxx_slave_alloc,
+-      .slave_destroy          = qla4xxx_slave_destroy,
+-
+-      .scan_finished          = iscsi_scan_finished,
+-      .scan_start             = qla4xxx_scan_start,
+       .this_id                = -1,
+       .cmd_per_lun            = 3,
+@@ -108,13 +109,10 @@ static struct scsi_host_template qla4xxx_driver_template = {
+ static struct iscsi_transport qla4xxx_iscsi_transport = {
+       .owner                  = THIS_MODULE,
+       .name                   = DRIVER_NAME,
+-      .caps                   = CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD |
+-                                CAP_DATA_PATH_OFFLOAD,
+-      .param_mask             = ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS |
+-                                ISCSI_TARGET_NAME | ISCSI_TPGT,
+-      .host_param_mask        = ISCSI_HOST_HWADDRESS |
+-                                ISCSI_HOST_IPADDRESS |
+-                                ISCSI_HOST_INITIATOR_NAME,
++      .param_mask             = ISCSI_CONN_PORT |
++                                ISCSI_CONN_ADDRESS |
++                                ISCSI_TARGET_NAME |
++                                ISCSI_TPGT,
+       .tgt_dscvr              = qla4xxx_tgt_dscvr,
+       .get_conn_param         = qla4xxx_conn_get_param,
+       .get_session_param      = qla4xxx_sess_get_param,
+@@ -129,19 +127,16 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)
+       struct ddb_entry *ddb_entry = session->dd_data;
+       struct scsi_qla_host *ha = ddb_entry->ha;
+-      if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
+-              atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
++      atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
+-              DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count "
+-                            "of (%d) secs exhausted, marking device DEAD.\n",
+-                            ha->host_no, __func__, ddb_entry->fw_ddb_index,
+-                            ha->port_down_retry_count));
++      dev_info(&ha->pdev->dev, "%s: ddb[%d] os[%d] marked DEAD"
++              " - retry count of (%d)\n", __func__,
++              ddb_entry->fw_ddb_index, ddb_entry->os_target_id,
++              ha->port_down_retry_count);
+-              DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc "
+-                            "flags = 0x%lx\n",
+-                            ha->host_no, __func__, ha->dpc_flags));
+-              queue_work(ha->dpc_thread, &ha->dpc_work);
+-      }
++      DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = "
++                              "0x%lx\n", ha->host_no, __func__, ha->dpc_flags));
++      queue_work(ha->dpc_thread, &ha->dpc_work);
+ }
+ static int qla4xxx_host_get_param(struct Scsi_Host *shost,
+@@ -151,16 +146,13 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost,
+       int len;
+       switch (param) {
+-      case ISCSI_HOST_PARAM_HWADDRESS:
+-              len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN);
+-              break;
+       case ISCSI_HOST_PARAM_IPADDRESS:
+-              len = sprintf(buf, "%d.%d.%d.%d\n", ha->ip_address[0],
+-                            ha->ip_address[1], ha->ip_address[2],
+-                            ha->ip_address[3]);
++              len = sprintf(buf, "%d.%d.%d.%d", ha->ip_address[0],
++                              ha->ip_address[1], ha->ip_address[2],
++                              ha->ip_address[3]);
+               break;
+       case ISCSI_HOST_PARAM_INITIATOR_NAME:
+-              len = sprintf(buf, "%s\n", ha->name_string);
++              len = sprintf(buf, "%s", ha->name_string);
+               break;
+       default:
+               return -ENOSYS;
+@@ -169,6 +161,38 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost,
+       return len;
+ }
++int qla4xxx_conn_start(struct iscsi_cls_conn *conn)
++{
++      struct iscsi_cls_session *session;
++      struct ddb_entry *ddb_entry;
++
++      session = iscsi_dev_to_session(conn->dev.parent);
++      ddb_entry = session->dd_data;
++
++      DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n",
++                              ddb_entry->ha->host_no, __func__,
++                              ddb_entry->fw_ddb_index));
++      iscsi_unblock_session(session);
++      return 0;
++}
++
++static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag)
++{
++      struct iscsi_cls_session *session;
++      struct ddb_entry *ddb_entry;
++
++      session = iscsi_dev_to_session(conn->dev.parent);
++      ddb_entry = session->dd_data;
++
++      DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n",
++                              ddb_entry->ha->host_no, __func__,
++                              ddb_entry->fw_ddb_index));
++      if (flag == STOP_CONN_RECOVER)
++              iscsi_block_session(session);
++      else
++              printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
++}
++
+ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
+                                 enum iscsi_param param, char *buf)
+ {
+@@ -177,11 +201,11 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
+       switch (param) {
+       case ISCSI_PARAM_TARGET_NAME:
+-              len = snprintf(buf, PAGE_SIZE - 1, "%s\n",
+-                             ddb_entry->iscsi_name);
++              len = snprintf(buf, PAGE_SIZE - 1, "%s",
++                                       ddb_entry->iscsi_name);
+               break;
+       case ISCSI_PARAM_TPGT:
+-              len = sprintf(buf, "%u\n", ddb_entry->tpgt);
++              len = sprintf(buf, "%u", ddb_entry->tpgt);
+               break;
+       default:
+               return -ENOSYS;
+@@ -202,12 +226,12 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
+       switch (param) {
+       case ISCSI_PARAM_CONN_PORT:
+-              len = sprintf(buf, "%hu\n", ddb_entry->port);
++              len = sprintf(buf, "%u", (uint32_t)ddb_entry->port);
+               break;
+       case ISCSI_PARAM_CONN_ADDRESS:
+               /* TODO: what are the ipv6 bits */
+-              len = sprintf(buf, "%u.%u.%u.%u\n",
+-                            NIPQUAD(ddb_entry->ip_addr));
++              len = sprintf(buf, "%u.%u.%u.%u",
++                                      NIPQUAD(ddb_entry->ip_addr));
+               break;
+       default:
+               return -ENOSYS;
+@@ -257,17 +281,15 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry)
+               return;
+       if (ddb_entry->conn) {
+-              atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
+               iscsi_remove_session(ddb_entry->sess);
+       }
+       iscsi_free_session(ddb_entry->sess);
+ }
+-int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
++int qla4xxx_add_sess(struct ddb_entry *ddb_entry, int scan)
+ {
+       int err;
+-      ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
+       err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index);
+       if (err) {
+               DEBUG2(printk(KERN_ERR "Could not add session.\n"));
+@@ -281,7 +303,11 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
+               return -ENOMEM;
+       }
+-      /* finally ready to go */
++      ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
++      if (scan)
++              scsi_scan_target(&ddb_entry->sess->dev, 0,
++                               ddb_entry->sess->target_id,
++                               SCAN_WILD_CARD, 0);
+       iscsi_unblock_session(ddb_entry->sess);
+       return 0;
+ }
+@@ -292,7 +318,7 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha)
+       struct iscsi_cls_session *sess;
+       sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport,
+-                                 sizeof(struct ddb_entry));
++                      sizeof(struct ddb_entry));
+       if (!sess)
+               return NULL;
+@@ -303,18 +329,6 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha)
+       return ddb_entry;
+ }
+-static void qla4xxx_scan_start(struct Scsi_Host *shost)
+-{
+-      struct scsi_qla_host *ha = shost_priv(shost);
+-      struct ddb_entry *ddb_entry, *ddbtemp;
+-
+-      /* finish setup of sessions that were already setup in firmware */
+-      list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) {
+-              if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE)
+-                      qla4xxx_add_sess(ddb_entry);
+-      }
+-}
+-
+ /*
+  * Timer routines
+  */
+@@ -323,7 +337,7 @@ static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func,
+                               unsigned long interval)
+ {
+       DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n",
+-                   __func__, ha->host->host_no));
++                        __func__, ha->host->host_no));
+       init_timer(&ha->timer);
+       ha->timer.expires = jiffies + interval * HZ;
+       ha->timer.data = (unsigned long)ha;
+@@ -349,11 +363,11 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
+                                struct ddb_entry *ddb_entry)
+ {
+       atomic_set(&ddb_entry->state, DDB_STATE_MISSING);
+-      DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n",
+-                    ha->host_no, ddb_entry->bus, ddb_entry->target,
+-                    ddb_entry->fw_ddb_index));
+-      iscsi_block_session(ddb_entry->sess);
+-      iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED);
++
++      dev_info(&ha->pdev->dev, "%s: ddb[%d] os[%d] marked MISSING\n",
++               __func__, ddb_entry->fw_ddb_index, ddb_entry->os_target_id);
++
++      qla4xxx_conn_stop(ddb_entry->conn, STOP_CONN_RECOVER);
+ }
+ static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
+@@ -393,10 +407,10 @@ void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb)
+ {
+       struct scsi_cmnd *cmd = srb->cmd;
+-      qla4xxx_srb_free_dma(ha, srb);
+-
+-      mempool_free(srb, ha->srb_mempool);
+-
++      if (!(srb->flags & SRB_SCSI_PASSTHRU)) {
++              qla4xxx_srb_free_dma(ha, srb);
++              mempool_free(srb, ha->srb_mempool);
++      }
+       cmd->scsi_done(cmd);
+ }
+@@ -404,7 +418,7 @@ void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb)
+  * qla4xxx_queuecommand - scsi layer issues scsi command to driver.
+  * @cmd: Pointer to Linux's SCSI command structure
+  * @done_fn: Function that the driver calls to notify the SCSI mid-layer
+- *    that the command has been processed.
++ *     that the command has been processed.
+  *
+  * Remarks:
+  * This routine is invoked by Linux to send a SCSI command to the driver.
+@@ -419,30 +433,20 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
+ {
+       struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+       struct ddb_entry *ddb_entry = cmd->device->hostdata;
+-      struct iscsi_cls_session *sess = ddb_entry->sess;
+       struct srb *srb;
+       int rval;
+-      if (!sess) {
+-              cmd->result = DID_IMM_RETRY << 16;
+-              goto qc_fail_command;
+-      }
+-
+-      rval = iscsi_session_chkready(sess);
+-      if (rval) {
+-              cmd->result = rval;
+-              goto qc_fail_command;
+-      }
+-
+       if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
+               if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) {
+                       cmd->result = DID_NO_CONNECT << 16;
+                       goto qc_fail_command;
+               }
+-              return SCSI_MLQUEUE_TARGET_BUSY;
++              goto qc_host_busy;
+       }
+-      if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags))
++      if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
++              test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
++              test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags))
+               goto qc_host_busy;
+       spin_unlock_irq(ha->host->host_lock);
+@@ -596,7 +600,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
+                       if (atomic_read(&ddb_entry->retry_relogin_timer) !=
+                           INVALID_ENTRY) {
+                               if (atomic_read(&ddb_entry->retry_relogin_timer)
+-                                              == 0) {
++                                              == 0) {
+                                       atomic_set(&ddb_entry->
+                                               retry_relogin_timer,
+                                               INVALID_ENTRY);
+@@ -669,7 +673,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
+            test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
+            test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
+            test_bit(DPC_AEN, &ha->dpc_flags)) &&
+-           ha->dpc_thread) {
++          ha->dpc_thread) {
+               DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
+                             " - dpc flags = 0x%lx\n",
+                             ha->host_no, __func__, ha->dpc_flags));
+@@ -694,7 +698,6 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
+       uint32_t index = 0;
+       int stat = QLA_SUCCESS;
+       unsigned long flags;
+-      struct scsi_cmnd *cmd;
+       int wait_cnt = WAIT_CMD_TOV;    /*
+                                        * Initialized for 30 seconds as we
+                                        * expect all commands to retuned
+@@ -704,15 +707,14 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
+       while (wait_cnt) {
+               spin_lock_irqsave(&ha->hardware_lock, flags);
+               /* Find a command that hasn't completed. */
+-              for (index = 0; index < ha->host->can_queue; index++) {
+-                      cmd = scsi_host_find_tag(ha->host, index);
+-                      if (cmd != NULL)
++              for (index = 1; index < MAX_SRBS; index++) {
++                      if (ha->active_srb_array[index] != NULL)
+                               break;
+               }
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               /* If No Commands are pending, wait is complete */
+-              if (index == ha->host->can_queue) {
++              if (index == MAX_SRBS) {
+                       break;
+               }
+@@ -738,7 +740,6 @@ void qla4xxx_hw_reset(struct scsi_qla_host *ha)
+       DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__));
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+-
+       /*
+        * If the SCSI Reset Interrupt bit is set, clear it.
+        * Otherwise, the Soft Reset won't work.
+@@ -865,9 +866,9 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
+       unsigned long flags;
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+-      for (i = 0; i < ha->host->can_queue; i++) {
+-              srb = qla4xxx_del_from_active_array(ha, i);
+-              if (srb != NULL) {
++      for (i = 1; i < MAX_SRBS; i++) {
++              if ((srb = ha->active_srb_array[i]) != NULL) {
++                      qla4xxx_del_from_active_array(ha, i);
+                       srb->cmd->result = DID_RESET << 16;
+                       qla4xxx_srb_compl(ha, srb);
+               }
+@@ -879,19 +880,13 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
+ /**
+  * qla4xxx_recover_adapter - recovers adapter after a fatal error
+  * @ha: Pointer to host adapter structure.
+- * @renew_ddb_list: Indicates what to do with the adapter's ddb list
+- *
+- * renew_ddb_list value can be 0=preserve ddb list, 1=destroy and rebuild
+- * ddb list.
+  **/
+-static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
+-                              uint8_t renew_ddb_list)
++static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) 
+ {
+       int status;
+       /* Stall incoming I/O until we are done */
+       clear_bit(AF_ONLINE, &ha->flags);
+-
+       DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no,
+                     __func__));
+@@ -909,7 +904,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
+        * returns with ISP interrupts enabled.
+        */
+       if (status == QLA_SUCCESS) {
+-              DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
++              DEBUG2(printk(KERN_ERR "scsi%ld: %s - Performing soft reset..\n",
+                             ha->host_no, __func__));
+               qla4xxx_flush_active_srbs(ha);
+               if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
+@@ -929,7 +924,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
+               /* If successful, AF_ONLINE flag set in
+                * qla4xxx_initialize_adapter */
+-              status = qla4xxx_initialize_adapter(ha, renew_ddb_list);
++              status = qla4xxx_initialize_adapter(ha, PRESERVE_DDB_LIST);
+       }
+       /* Failed adapter initialization?
+@@ -990,7 +985,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
+  * @data: in our case pointer to adapter structure
+  *
+  * This routine is a task that is schedule by the interrupt handler
+- * to perform the background processing for interrupts.  We put it
++ * to perform the background processing for interrupts.       We put it
+  * on a task queue that is consumed whenever the scheduler runs; that's
+  * so you can do anything (i.e. put the process to sleep etc).  In fact,
+  * the mid-level tries to sleep when it reaches the driver threshold
+@@ -1004,7 +999,8 @@ static void qla4xxx_do_dpc(struct work_struct *work)
+       int status = QLA_ERROR;
+       DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
+-              "flags = 0x%08lx, dpc_flags = 0x%08lx ctrl_stat = 0x%08x\n",
++              "ha->flags=0x%08lx ha->dpc_flags=0x%08lx"
++              " ctrl_status=0x%08x\n",
+               ha->host_no, __func__, ha->flags, ha->dpc_flags,
+               readw(&ha->reg->ctrl_status)));
+@@ -1017,8 +1013,8 @@ static void qla4xxx_do_dpc(struct work_struct *work)
+           test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
+           test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) {
+               if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
+-                      test_bit(DPC_RESET_HA, &ha->dpc_flags))
+-                      qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
++                  test_bit(DPC_RESET_HA, &ha->dpc_flags))
++                      qla4xxx_recover_adapter(ha);
+               if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
+                       uint8_t wait_time = RESET_INTR_TOV;
+@@ -1036,7 +1032,7 @@ static void qla4xxx_do_dpc(struct work_struct *work)
+                       qla4xxx_flush_active_srbs(ha);
+                       if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) {
+                               qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+-                              status = qla4xxx_initialize_adapter(ha,
++                              status = qla4xxx_initialize_adapter(ha, 
+                                               PRESERVE_DDB_LIST);
+                       }
+                       clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
+@@ -1070,8 +1066,8 @@ static void qla4xxx_do_dpc(struct work_struct *work)
+                        */
+                       if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+                               printk(KERN_WARNING "scsi%ld: %s: "
+-                                     "need to reset hba\n",
+-                                     ha->host_no, __func__);
++                                               "need to reset hba\n",
++                                               ha->host_no, __func__);
+                               break;
+                       }
+               }
+@@ -1110,7 +1106,6 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
+       qla4xxx_mem_free(ha);
+       pci_disable_device(ha->pdev);
+-
+ }
+ /***
+@@ -1147,7 +1142,6 @@ static int qla4xxx_iospace_config(struct scsi_qla_host *ha)
+       if (!(mmio_flags & IORESOURCE_MEM)) {
+               dev_err(&ha->pdev->dev,
+                       "region #0 not an MMIO resource, aborting\n");
+-
+               goto iospace_error_exit;
+       }
+       if (mmio_len < MIN_IOBASE_LEN) {
+@@ -1179,6 +1173,14 @@ iospace_error_exit:
+       return -ENOMEM;
+ }
++static void ql4_get_aen_log(struct scsi_qla_host *ha, struct ql4_aen_log *aenl)
++{
++      if (aenl) {
++              memcpy(aenl, &ha->aen_log, sizeof (ha->aen_log));
++              ha->aen_log.count = 0;
++      }
++}
++
+ /**
+  * qla4xxx_probe_adapter - callback function to probe HBA
+  * @pdev: pointer to pci_dev structure
+@@ -1194,6 +1196,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
+       int ret = -ENODEV, status;
+       struct Scsi_Host *host;
+       struct scsi_qla_host *ha;
++      struct ddb_entry *ddb_entry, *ddbtemp;
+       uint8_t init_retry_count = 0;
+       char buf[34];
+@@ -1211,18 +1214,22 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
+       ha = (struct scsi_qla_host *) host->hostdata;
+       memset(ha, 0, sizeof(*ha));
+-      /* Save the information from PCI BIOS.  */
++      /* Save the information from PCI BIOS. */
+       ha->pdev = pdev;
+       ha->host = host;
+       ha->host_no = host->host_no;
++      ha->ql4mbx = qla4xxx_mailbox_command;
++      ha->ql4cmd = qla4xxx_send_command_to_isp;
++      ha->ql4getaenlog = ql4_get_aen_log;
++
+       /* Configure PCI I/O space. */
+       ret = qla4xxx_iospace_config(ha);
+       if (ret)
+               goto probe_failed;
+       dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n",
+-                 pdev->device, pdev->irq, ha->reg);
++               pdev->device, pdev->irq, ha->reg);
+       qla4xxx_config_dma_addressing(ha);
+@@ -1233,11 +1240,12 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
+       mutex_init(&ha->mbox_sem);
+       spin_lock_init(&ha->hardware_lock);
++      spin_lock_init(&ha->list_lock);
+       /* Allocate dma buffers */
+       if (qla4xxx_mem_alloc(ha)) {
+               dev_warn(&ha->pdev->dev,
+-                         "[ERROR] Failed to allocate memory for adapter\n");
++                       "[ERROR] Failed to allocate memory for adapter\n");
+               ret = -ENOMEM;
+               goto probe_failed;
+@@ -1250,8 +1258,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
+        */
+       status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
+       while (status == QLA_ERROR && init_retry_count++ < MAX_INIT_RETRIES) {
+-              DEBUG2(printk("scsi: %s: retrying adapter initialization "
+-                            "(%d)\n", __func__, init_retry_count));
++              DEBUG2(printk(KERN_ERR "scsi%ld: %s: retrying adapter initialization "
++                                      "(%d)\n", ha->host_no, __func__, init_retry_count));
+               qla4xxx_soft_reset(ha);
+               status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
+       }
+@@ -1267,15 +1275,9 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
+       host->max_lun = MAX_LUNS - 1;
+       host->max_id = MAX_TARGETS;
+       host->max_cmd_len = IOCB_MAX_CDB_LEN;
+-      host->can_queue = MAX_SRBS ;
++      host->can_queue = REQUEST_QUEUE_DEPTH + 128;
+       host->transportt = qla4xxx_scsi_transport;
+-        ret = scsi_init_shared_tag_map(host, MAX_SRBS);
+-        if (ret) {
+-                dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed\n");
+-                goto probe_failed;
+-        }
+-
+       /* Startup the kernel thread for this host adapter. */
+       DEBUG2(printk("scsi: %s: Starting kernel thread for "
+                     "qla4xxx_dpc\n", __func__));
+@@ -1287,9 +1289,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
+               goto probe_failed;
+       }
+       INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
+-
+       ret = request_irq(pdev->irq, qla4xxx_intr_handler,
+-                        IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha);
++                      IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha);
+       if (ret) {
+               dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d"
+                       " already in use.\n", pdev->irq);
+@@ -1312,15 +1313,39 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
+       if (ret)
+               goto probe_failed;
++      /* Update transport device information for all devices. */
++      list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) {
++
++              if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE)
++                      set_bit(DF_SCAN_ISSUED, &ddb_entry->flags);
++
++              if (qla4xxx_add_sess(ddb_entry,
++                      test_bit(DF_SCAN_ISSUED, &ddb_entry->flags)))
++                      goto remove_host;
++              if (!test_bit(DF_SCAN_ISSUED, &ddb_entry->flags))
++                      qla4xxx_mark_device_missing(ha, ddb_entry);
++      }
++
+       printk(KERN_INFO
+              " QLogic iSCSI HBA Driver version: %s\n"
+-             "  QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
+-             qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
++             "  QLogic ISP%04x @ %s, pdev = %p host#=%ld, fw=%02d.%02d.%02d.%02d\n",
++             qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), pdev,
+              ha->host_no, ha->firmware_version[0], ha->firmware_version[1],
+              ha->patch_number, ha->build_number);
+-      scsi_scan_host(host);
++
++      /* Insert new entry into the list of adapters. */
++      klist_add_tail(&ha->node, &qla4xxx_hostlist);
++      ha->instance = atomic_inc_return(&qla4xxx_hba_count) - 1;
++
++      DEBUG2(printk("qla4xxx: listhead=%p, done adding ha=%p i=%d\n",
++                    &qla4xxx_hostlist, &ha->node, ha->instance));
++
+       return 0;
++remove_host:
++      qla4xxx_free_ddb_list(ha);
++      scsi_remove_host(host);
++
+ probe_failed:
+       qla4xxx_free_adapter(ha);
+       scsi_host_put(ha->host);
+@@ -1346,6 +1371,9 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
+       while (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags))
+               ssleep(1);
++      klist_remove(&ha->node);
++      atomic_dec(&qla4xxx_hba_count);
++
+       /* remove devs from iscsi_sessions to scsi_devices */
+       qla4xxx_free_ddb_list(ha);
+@@ -1374,7 +1402,7 @@ static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
+               if (pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
+                       dev_dbg(&ha->pdev->dev,
+                                 "Failed to set 64 bit PCI consistent mask; "
+-                                 "using 32 bit.\n");
++                                "using 32 bit.\n");
+                       retval = pci_set_consistent_dma_mask(ha->pdev,
+                                                            DMA_32BIT_MASK);
+               }
+@@ -1385,23 +1413,22 @@ static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
+ static int qla4xxx_slave_alloc(struct scsi_device *sdev)
+ {
+       struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target);
+-      struct ddb_entry *ddb = sess->dd_data;
+-      sdev->hostdata = ddb;
+-      sdev->tagged_supported = 1;
+-      scsi_activate_tcq(sdev, QL4_DEF_QDEPTH);
+-      return 0;
++      if (sess) {
++              sdev->hostdata = sess->dd_data;
++              return 0;
++      }
++      return FAILED;
+ }
+ static int qla4xxx_slave_configure(struct scsi_device *sdev)
+ {
+-      sdev->tagged_supported = 1;
+-      return 0;
+-}
++      if (sdev->tagged_supported)
++              scsi_activate_tcq(sdev, 32);
++      else
++              scsi_deactivate_tcq(sdev, 32);
+-static void qla4xxx_slave_destroy(struct scsi_device *sdev)
+-{
+-      scsi_deactivate_tcq(sdev, 1);
++      return 0;
+ }
+ /**
+@@ -1414,12 +1441,14 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev)
+ struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index)
+ {
+       struct srb *srb = NULL;
+-      struct scsi_cmnd *cmd;
+-      if (!(cmd = scsi_host_find_tag(ha->host, index)))
++      /* validate handle and remove from active array */
++      if (index >= MAX_SRBS)
+               return srb;
+-      if (!(srb = (struct srb *)cmd->host_scribble))
++      srb = ha->active_srb_array[index];
++      ha->active_srb_array[index] = NULL;
++      if (!srb)
+               return srb;
+       /* update counters */
+@@ -1467,24 +1496,18 @@ static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,
+  **/
+ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
+ {
+-      unsigned long wait_online;
+-
+-      wait_online = jiffies + (30 * HZ);
+-      while (time_before(jiffies, wait_online)) {
++      unsigned long wait_online = 60;
++      while (wait_online--) {
+               if (adapter_up(ha))
+                       return QLA_SUCCESS;
+-              else if (ha->retry_reset_ha_cnt == 0)
+-                      return QLA_ERROR;
+-
+-              msleep(2000);
++              ssleep(2);
+       }
+-
+       return QLA_ERROR;
+ }
+ /**
+- * qla4xxx_eh_wait_for_commands - wait for active cmds to finish.
++ * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish.
+  * @ha: pointer to to HBA
+  * @t: target id
+  * @l: lun id
+@@ -1492,26 +1515,33 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
+  * This function waits for all outstanding commands to a lun to complete. It
+  * returns 0 if all pending commands are returned and 1 otherwise.
+  **/
+-static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
+-                                      struct scsi_target *stgt,
+-                                      struct scsi_device *sdev)
++static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha,
++                                               int t, int l)
+ {
+       int cnt;
+-      int status = 0;
++      int status;
++      struct srb *sp;
+       struct scsi_cmnd *cmd;
+       /*
+-       * Waiting for all commands for the designated target or dev
+-       * in the active array
++       * Waiting for all commands for the designated target in the active
++       * array
+        */
+-      for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
+-              cmd = scsi_host_find_tag(ha->host, cnt);
+-              if (cmd && stgt == scsi_target(cmd->device) &&
+-                  (!sdev || sdev == cmd->device)) {
+-                      if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
+-                              status++;
+-                              break;
++      status = 0;
++      for (cnt = 1; cnt < MAX_SRBS; cnt++) {
++              spin_lock(&ha->hardware_lock);
++              sp = ha->active_srb_array[cnt];
++              if (sp) {
++                      cmd = sp->cmd;
++                      spin_unlock(&ha->hardware_lock);
++                      if (cmd->device->id == t && cmd->device->lun == l) {
++                              if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
++                                      status++;
++                                      break;
++                              }
+                       }
++              } else {
++                      spin_unlock(&ha->hardware_lock);
+               }
+       }
+       return status;
+@@ -1528,47 +1558,49 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
+ {
+       struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+       struct ddb_entry *ddb_entry = cmd->device->hostdata;
+-      struct srb *sp;
+       int ret = FAILED, stat;
+-      sp = (struct srb *) cmd->SCp.ptr;
+-      if (!sp || !ddb_entry)
++      if (!ddb_entry)
+               return ret;
+       dev_info(&ha->pdev->dev,
+-                 "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no,
+-                 cmd->device->channel, cmd->device->id, cmd->device->lun);
++               "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no,
++               cmd->device->channel, cmd->device->id, cmd->device->lun);
+-      DEBUG2(printk(KERN_INFO
+-                    "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
+-                    "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
+-                    cmd, jiffies, cmd->request->timeout / HZ,
+-                    ha->dpc_flags, cmd->result, cmd->allowed));
++      if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
++              dev_info(&ha->pdev->dev, "%s: HBA OFFLINE: FAILED\n", __func__);
++              return FAILED;
++      }
+-      /* FIXME: wait for hba to go online */
+       stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
+       if (stat != QLA_SUCCESS) {
+               dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat);
+               goto eh_dev_reset_done;
+       }
+-      if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
+-                                       cmd->device)) {
+-              dev_info(&ha->pdev->dev,
+-                         "DEVICE RESET FAILED - waiting for "
+-                         "commands.\n");
+-              goto eh_dev_reset_done;
++      /*
++       * If we are coming down the EH path, wait for all commands to complete
++       * for the device.
++       */
++      if (cmd->device->host->shost_state == SHOST_RECOVERY) {
++              if (qla4xxx_eh_wait_for_active_target_commands(ha,
++                                                             cmd->device->id,
++                                                             cmd->device->
++                                                             lun)) {
++                      dev_info(&ha->pdev->dev,
++                               "DEVICE RESET FAILED - waiting for "
++                               "commands.\n");
++                      goto eh_dev_reset_done;
++              }
+       }
+-
+-      /* Send marker. */
+-      if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
+-              MM_LUN_RESET) != QLA_SUCCESS)
++      if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun)
++              != QLA_SUCCESS)
+               goto eh_dev_reset_done;
+       dev_info(&ha->pdev->dev,
+-                 "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
+-                 ha->host_no, cmd->device->channel, cmd->device->id,
+-                 cmd->device->lun);
++               "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
++               ha->host_no, cmd->device->channel, cmd->device->id,
++               cmd->device->lun);
+       ret = SUCCESS;
+@@ -1578,59 +1610,6 @@ eh_dev_reset_done:
+ }
+ /**
+- * qla4xxx_eh_target_reset - callback for target reset.
+- * @cmd: Pointer to Linux's SCSI command structure
+- *
+- * This routine is called by the Linux OS to reset the target.
+- **/
+-static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
+-{
+-      struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+-      struct ddb_entry *ddb_entry = cmd->device->hostdata;
+-      int stat;
+-
+-      if (!ddb_entry)
+-              return FAILED;
+-
+-      starget_printk(KERN_INFO, scsi_target(cmd->device),
+-                     "WARM TARGET RESET ISSUED.\n");
+-
+-      DEBUG2(printk(KERN_INFO
+-                    "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, "
+-                    "to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
+-                    ha->host_no, cmd, jiffies, cmd->request->timeout / HZ,
+-                    ha->dpc_flags, cmd->result, cmd->allowed));
+-
+-      stat = qla4xxx_reset_target(ha, ddb_entry);
+-      if (stat != QLA_SUCCESS) {
+-              starget_printk(KERN_INFO, scsi_target(cmd->device),
+-                             "WARM TARGET RESET FAILED.\n");
+-              return FAILED;
+-      }
+-
+-      if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
+-                                       NULL)) {
+-              starget_printk(KERN_INFO, scsi_target(cmd->device),
+-                             "WARM TARGET DEVICE RESET FAILED - "
+-                             "waiting for commands.\n");
+-              return FAILED;
+-      }
+-
+-      /* Send marker. */
+-      if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
+-              MM_TGT_WARM_RESET) != QLA_SUCCESS) {
+-              starget_printk(KERN_INFO, scsi_target(cmd->device),
+-                             "WARM TARGET DEVICE RESET FAILED - "
+-                             "marker iocb failed.\n");
+-              return FAILED;
+-      }
+-
+-      starget_printk(KERN_INFO, scsi_target(cmd->device),
+-                     "WARM TARGET RESET SUCCEEDED.\n");
+-      return SUCCESS;
+-}
+-
+-/**
+  * qla4xxx_eh_host_reset - kernel callback
+  * @cmd: Pointer to Linux's SCSI command structure
+  *
+@@ -1644,27 +1623,19 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
+       ha = (struct scsi_qla_host *) cmd->device->host->hostdata;
+-      dev_info(&ha->pdev->dev,
+-                 "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no,
+-                 cmd->device->channel, cmd->device->id, cmd->device->lun);
++      dev_info(&ha->pdev->dev, "%s: ADAPTER RESET ISSUED.\n", __func__);
+       if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
+-              DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host.  Adapter "
+-                            "DEAD.\n", ha->host_no, cmd->device->channel,
+-                            __func__));
+-
++              dev_info(&ha->pdev->dev, "%s: HBA OFFLINE: FAILED\n", __func__);
+               return FAILED;
+       }
+-      /* make sure the dpc thread is stopped while we reset the hba */
+-      clear_bit(AF_ONLINE, &ha->flags);
+-      flush_workqueue(ha->dpc_thread);
+-
+-      if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS)
++      if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS) {
+               return_status = SUCCESS;
++      }
+       dev_info(&ha->pdev->dev, "HOST RESET %s.\n",
+-                 return_status == FAILED ? "FAILED" : "SUCCEDED");
++               return_status == FAILED ? "FAILED" : "SUCCEDED");
+       return return_status;
+ }
+@@ -1704,9 +1675,11 @@ static int __init qla4xxx_module_init(void)
+ {
+       int ret;
++      atomic_set(&qla4xxx_hba_count, 0);
++      klist_init(&qla4xxx_hostlist, NULL, NULL);
+       /* Allocate cache for SRBs. */
+       srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
+-                                     SLAB_HWCACHE_ALIGN, NULL);
++                      SLAB_HWCACHE_ALIGN, NULL);
+       if (srb_cachep == NULL) {
+               printk(KERN_ERR
+                      "%s: Unable to allocate SRB cache..."
+@@ -1717,7 +1690,7 @@ static int __init qla4xxx_module_init(void)
+       /* Derive version string. */
+       strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION);
+-      if (ql4xextended_error_logging)
++      if (extended_error_logging)
+               strcat(qla4xxx_version_str, "-debug");
+       qla4xxx_scsi_transport =
+@@ -1727,13 +1700,13 @@ static int __init qla4xxx_module_init(void)
+               goto release_srb_cache;
+       }
++      printk(KERN_INFO "QLogic iSCSI HBA Driver\n");
+       ret = pci_register_driver(&qla4xxx_pci_driver);
+       if (ret)
+               goto unregister_transport;
+       printk(KERN_INFO "QLogic iSCSI HBA Driver\n");
+       return 0;
+-
+ unregister_transport:
+       iscsi_unregister_transport(&qla4xxx_iscsi_transport);
+ release_srb_cache:
+diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
+index ab984cb..1cbfcbb 100644
+--- a/drivers/scsi/qla4xxx/ql4_version.h
++++ b/drivers/scsi/qla4xxx/ql4_version.h
+@@ -5,5 +5,6 @@
+  * See LICENSE.qla4xxx for copyright and licensing details.
+  */
+-#define QLA4XXX_DRIVER_VERSION        "5.01.00-k8"
++#define QLA4XXX_DRIVER_VERSION   "5.01.00-k8_sles11-01"
++