Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 9 May 2007 03:32:16 +0000 (20:32 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 9 May 2007 03:32:16 +0000 (20:32 -0700)
* master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (58 commits)
  [SCSI] zfcp: clear boxed flag on unit reopen.
  [SCSI] zfcp: clear adapter failed flag if an fsf request times out.
  [SCSI] zfcp: rework request ID management.
  [SCSI] zfcp: Fix deadlock between zfcp ERP and SCSI
  [SCSI] zfcp: Locking for req_no and req_seq_no
  [SCSI] zfcp: print S_ID and D_ID with 3 bytes
  [SCSI] ipr: Use PCI-E reset API for new ipr adapter
  [SCSI] qla2xxx: Update version number to 8.01.07-k7.
  [SCSI] qla2xxx: Add MSI support.
  [SCSI] qla2xxx: Correct pci_set_msi() usage semantics.
  [SCSI] qla2xxx: Attempt to stop firmware only if it had been previously executed.
  [SCSI] qla2xxx: Honor NVRAM port-down-retry-count settings.
  [SCSI] qla2xxx: Error-out during probe() if we're unable to complete HBA initialization.
  [SCSI] zfcp: Stop system after memory corruption
  [SCSI] mesh: cleanup variable usage in interrupt handler
  [SCSI] megaraid: replace yield() with cond_resched()
  [SCSI] megaraid: fix warnings when CONFIG_PROC_FS=n
  [SCSI] aacraid: correct SUN products to README
  [SCSI] aacraid: superfluous adapter reset for IBM 8 series ServeRAID controllers
  [SCSI] aacraid: kexec fix (reset interrupt handler)
  ...

53 files changed:
Documentation/feature-removal-schedule.txt
Documentation/scsi/aacraid.txt
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_scsi.c
drivers/scsi/aacraid/comminit.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/dpcsup.c
drivers/scsi/aacraid/rx.c
drivers/scsi/ch.c
drivers/scsi/dpt_i2o.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_disc.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/megaraid.c
drivers/scsi/megaraid.h
drivers/scsi/megaraid/megaraid_mm.c
drivers/scsi/mesh.c
drivers/scsi/qla1280.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/qla4xxx/ql4_dbg.c
drivers/scsi/qla4xxx/ql4_glbl.h
drivers/scsi/qla4xxx/ql4_init.c
drivers/scsi/qla4xxx/ql4_iocb.c
drivers/scsi/qla4xxx/ql4_mbx.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/tmscsim.c
drivers/scsi/tmscsim.h
include/scsi/libsas.h

index 2291ff620d93e2e220823dd3da8094b60ef709fa..676b7981adb771d5185c5bedd4c286ebc81d66f3 100644 (file)
@@ -59,6 +59,15 @@ Who: Dan Dennedy <dan@dennedy.org>, Stefan Richter <stefanr@s5r6.in-berlin.de>
 
 ---------------------------
 
+What:  old NCR53C9x driver
+When:  October 2007
+Why:   Replaced by the much better esp_scsi driver.  Actual low-level
+       driver can ported over almost trivially.
+Who:   David Miller <davem@davemloft.net>
+       Christoph Hellwig <hch@lst.de>
+
+---------------------------
+
 What:  Video4Linux API 1 ioctls and video_decoder.h from Video devices.
 When:  December 2006
 Why:   V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
index 2368e7e4a8cfa9d64c27c0b9932c79e5e3f378f0..ce3cb42507bd1edd5c0495af1a1ba6edb1b764a8 100644 (file)
@@ -98,8 +98,8 @@ Supported Cards/Chipsets
        9005:0285:9005:02b0             (Sunrise Lake ARK)
        9005:0285:9005:02b1     Adaptec (Voodoo 8 internal 8 external)
        9005:0285:108e:7aac     SUN     STK RAID REM (Voodoo44 Coyote)
-       9005:0285:108e:0286     SUN     SG-XPCIESAS-R-IN (Cougar)
-       9005:0285:108e:0287     SUN     SG-XPCIESAS-R-EX (Prometheus)
+       9005:0285:108e:0286     SUN     STK RAID INT (Cougar)
+       9005:0285:108e:0287     SUN     STK RAID EXT (Prometheus)
 
 People
 -------------------------
index 1f9554e0801392e043ff2ac1e120ed44c8da7644..324899c96efe2dcf4b15597d245c5306ceead9f6 100644 (file)
@@ -118,97 +118,32 @@ _zfcp_hex_dump(char *addr, int count)
 
 #define ZFCP_LOG_AREA                  ZFCP_LOG_AREA_FSF
 
-static int zfcp_reqlist_init(struct zfcp_adapter *adapter)
+static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter)
 {
-       int i;
+       int idx;
 
        adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head),
                                    GFP_KERNEL);
-
        if (!adapter->req_list)
                return -ENOMEM;
 
-       for (i=0; i<REQUEST_LIST_SIZE; i++)
-               INIT_LIST_HEAD(&adapter->req_list[i]);
-
+       for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
+               INIT_LIST_HEAD(&adapter->req_list[idx]);
        return 0;
 }
 
 static void zfcp_reqlist_free(struct zfcp_adapter *adapter)
 {
-       struct zfcp_fsf_req *request, *tmp;
-       unsigned int i;
-
-       for (i=0; i<REQUEST_LIST_SIZE; i++) {
-               if (list_empty(&adapter->req_list[i]))
-                       continue;
-
-               list_for_each_entry_safe(request, tmp,
-                                        &adapter->req_list[i], list)
-                       list_del(&request->list);
-       }
-
        kfree(adapter->req_list);
 }
 
-void zfcp_reqlist_add(struct zfcp_adapter *adapter,
-                     struct zfcp_fsf_req *fsf_req)
-{
-       unsigned int i;
-
-       i = fsf_req->req_id % REQUEST_LIST_SIZE;
-       list_add_tail(&fsf_req->list, &adapter->req_list[i]);
-}
-
-void zfcp_reqlist_remove(struct zfcp_adapter *adapter, unsigned long req_id)
-{
-       struct zfcp_fsf_req *request, *tmp;
-       unsigned int i, counter;
-       u64 dbg_tmp[2];
-
-       i = req_id % REQUEST_LIST_SIZE;
-       BUG_ON(list_empty(&adapter->req_list[i]));
-
-       counter = 0;
-       list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) {
-               if (request->req_id == req_id) {
-                       dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active);
-                       dbg_tmp[1] = (u64) counter;
-                       debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16);
-                       list_del(&request->list);
-                       break;
-               }
-               counter++;
-       }
-}
-
-struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *adapter,
-                                          unsigned long req_id)
-{
-       struct zfcp_fsf_req *request, *tmp;
-       unsigned int i;
-
-       /* 0 is reserved as an invalid req_id */
-       if (req_id == 0)
-               return NULL;
-
-       i = req_id % REQUEST_LIST_SIZE;
-
-       list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list)
-               if (request->req_id == req_id)
-                       return request;
-
-       return NULL;
-}
-
 int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
 {
-       unsigned int i;
+       unsigned int idx;
 
-       for (i=0; i<REQUEST_LIST_SIZE; i++)
-               if (!list_empty(&adapter->req_list[i]))
+       for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
+               if (!list_empty(&adapter->req_list[idx]))
                        return 0;
-
        return 1;
 }
 
@@ -913,6 +848,8 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
        unit->sysfs_device.release = zfcp_sysfs_unit_release;
        dev_set_drvdata(&unit->sysfs_device, unit);
 
+       init_waitqueue_head(&unit->scsi_scan_wq);
+
        /* mark unit unusable as long as sysfs registration is not complete */
        atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
 
@@ -1104,7 +1041,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
 
        /* initialize list of fsf requests */
        spin_lock_init(&adapter->req_list_lock);
-       retval = zfcp_reqlist_init(adapter);
+       retval = zfcp_reqlist_alloc(adapter);
        if (retval) {
                ZFCP_LOG_INFO("request list initialization failed\n");
                goto failed_low_mem_buffers;
@@ -1165,6 +1102,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
        zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
  sysfs_failed:
        dev_set_drvdata(&ccw_device->dev, NULL);
+       zfcp_reqlist_free(adapter);
  failed_low_mem_buffers:
        zfcp_free_low_mem_buffers(adapter);
        if (qdio_free(ccw_device) != 0)
@@ -1497,7 +1435,7 @@ zfcp_fsf_incoming_els_plogi(struct zfcp_adapter *adapter,
 
        if (!port || (port->wwpn != (*(wwn_t *) &els_plogi->serv_param.wwpn))) {
                ZFCP_LOG_DEBUG("ignored incoming PLOGI for nonexisting port "
-                              "with d_id 0x%08x on adapter %s\n",
+                              "with d_id 0x%06x on adapter %s\n",
                               status_buffer->d_id,
                               zfcp_get_busid_by_adapter(adapter));
        } else {
@@ -1522,7 +1460,7 @@ zfcp_fsf_incoming_els_logo(struct zfcp_adapter *adapter,
 
        if (!port || (port->wwpn != els_logo->nport_wwpn)) {
                ZFCP_LOG_DEBUG("ignored incoming LOGO for nonexisting port "
-                              "with d_id 0x%08x on adapter %s\n",
+                              "with d_id 0x%06x on adapter %s\n",
                               status_buffer->d_id,
                               zfcp_get_busid_by_adapter(adapter));
        } else {
@@ -1704,7 +1642,7 @@ static void zfcp_ns_gid_pn_handler(unsigned long data)
        /* looks like a valid d_id */
         port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
        atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status);
-       ZFCP_LOG_DEBUG("adapter %s:  wwpn=0x%016Lx ---> d_id=0x%08x\n",
+       ZFCP_LOG_DEBUG("adapter %s:  wwpn=0x%016Lx ---> d_id=0x%06x\n",
                       zfcp_get_busid_by_port(port), port->wwpn, port->d_id);
        goto out;
 
index 32933ed54b8a05dbe3534ac90395bbbf3d1ee283..22649639230b25fc8a326ab0eb3938070a9fdb26 100644 (file)
@@ -637,6 +637,7 @@ do { \
 #define ZFCP_STATUS_UNIT_SHARED                        0x00000004
 #define ZFCP_STATUS_UNIT_READONLY              0x00000008
 #define ZFCP_STATUS_UNIT_REGISTERED            0x00000010
+#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING     0x00000020
 
 /* FSF request status (this does not have a common part) */
 #define ZFCP_STATUS_FSFREQ_NOT_INIT            0x00000000
@@ -980,6 +981,10 @@ struct zfcp_unit {
         struct scsi_device     *device;        /* scsi device struct pointer */
        struct zfcp_erp_action erp_action;     /* pending error recovery */
         atomic_t               erp_counter;
+       wait_queue_head_t      scsi_scan_wq;   /* can be used to wait until
+                                                 all scsi_scan_target
+                                                 requests have been
+                                                 completed. */
 };
 
 /* FSF request */
@@ -1084,6 +1089,42 @@ extern void _zfcp_hex_dump(char *, int);
 #define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter))
 #define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port))
 
+/*
+ * Helper functions for request ID management.
+ */
+static inline int zfcp_reqlist_hash(unsigned long req_id)
+{
+       return req_id % REQUEST_LIST_SIZE;
+}
+
+static inline void zfcp_reqlist_add(struct zfcp_adapter *adapter,
+                                   struct zfcp_fsf_req *fsf_req)
+{
+       unsigned int idx;
+
+       idx = zfcp_reqlist_hash(fsf_req->req_id);
+       list_add_tail(&fsf_req->list, &adapter->req_list[idx]);
+}
+
+static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter,
+                                      struct zfcp_fsf_req *fsf_req)
+{
+       list_del(&fsf_req->list);
+}
+
+static inline struct zfcp_fsf_req *
+zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id)
+{
+       struct zfcp_fsf_req *request;
+       unsigned int idx;
+
+       idx = zfcp_reqlist_hash(req_id);
+       list_for_each_entry(request, &adapter->req_list[idx], list)
+               if (request->req_id == req_id)
+                       return request;
+       return NULL;
+}
+
 /*
  *  functions needed for reference/usage counting
  */
index c1f2d4b14c2b4517071d5e8fc6a8d5358a9b7347..aef66bc2b6cac79dff1219b44a287f666a8a4087 100644 (file)
@@ -179,7 +179,7 @@ static void zfcp_close_fsf(struct zfcp_adapter *adapter)
 static void zfcp_fsf_request_timeout_handler(unsigned long data)
 {
        struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
-       zfcp_erp_adapter_reopen(adapter, 0);
+       zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
 }
 
 void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
@@ -342,9 +342,9 @@ zfcp_erp_adisc(struct zfcp_port *port)
        adisc->wwpn = fc_host_port_name(adapter->scsi_host);
        adisc->wwnn = fc_host_node_name(adapter->scsi_host);
        adisc->nport_id = fc_host_port_id(adapter->scsi_host);
-       ZFCP_LOG_INFO("ADISC request from s_id 0x%08x to d_id 0x%08x "
+       ZFCP_LOG_INFO("ADISC request from s_id 0x%06x to d_id 0x%06x "
                      "(wwpn=0x%016Lx, wwnn=0x%016Lx, "
-                     "hard_nport_id=0x%08x, nport_id=0x%08x)\n",
+                     "hard_nport_id=0x%06x, nport_id=0x%06x)\n",
                      adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn,
                      (wwn_t) adisc->wwnn, adisc->hard_nport_id,
                      adisc->nport_id);
@@ -352,7 +352,7 @@ zfcp_erp_adisc(struct zfcp_port *port)
        retval = zfcp_fsf_send_els(send_els);
        if (retval != 0) {
                ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port "
-                               "0x%08x on adapter %s\n", send_els->d_id,
+                               "0x%06x on adapter %s\n", send_els->d_id,
                                zfcp_get_busid_by_adapter(adapter));
                goto freemem;
        }
@@ -398,7 +398,7 @@ zfcp_erp_adisc_handler(unsigned long data)
        if (send_els->status != 0) {
                ZFCP_LOG_NORMAL("ELS request rejected/timed out, "
                                "force physical port reopen "
-                               "(adapter %s, port d_id=0x%08x)\n",
+                               "(adapter %s, port d_id=0x%06x)\n",
                                zfcp_get_busid_by_adapter(adapter), d_id);
                debug_text_event(adapter->erp_dbf, 3, "forcreop");
                if (zfcp_erp_port_forced_reopen(port, 0))
@@ -411,9 +411,9 @@ zfcp_erp_adisc_handler(unsigned long data)
 
        adisc = zfcp_sg_to_address(send_els->resp);
 
-       ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id "
-                     "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
-                     "hard_nport_id=0x%08x, nport_id=0x%08x)\n",
+       ZFCP_LOG_INFO("ADISC response from d_id 0x%06x to s_id "
+                     "0x%06x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
+                     "hard_nport_id=0x%06x, nport_id=0x%06x)\n",
                      d_id, fc_host_port_id(adapter->scsi_host),
                      (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn,
                      adisc->hard_nport_id, adisc->nport_id);
@@ -847,8 +847,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
        if (erp_action->fsf_req) {
                /* take lock to ensure that request is not deleted meanwhile */
                spin_lock(&adapter->req_list_lock);
-               if (zfcp_reqlist_ismember(adapter,
-                                           erp_action->fsf_req->req_id)) {
+               if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) {
                        /* fsf_req still exists */
                        debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
                        debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
@@ -1377,7 +1376,7 @@ zfcp_erp_port_failed(struct zfcp_port *port)
 
        if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status))
                ZFCP_LOG_NORMAL("port erp failed (adapter %s, "
-                               "port d_id=0x%08x)\n",
+                               "port d_id=0x%06x)\n",
                                zfcp_get_busid_by_port(port), port->d_id);
        else
                ZFCP_LOG_NORMAL("port erp failed (adapter %s, wwpn=0x%016Lx)\n",
@@ -1591,6 +1590,62 @@ zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result)
        return result;
 }
 
+struct zfcp_erp_add_work {
+       struct zfcp_unit  *unit;
+       struct work_struct work;
+};
+
+/**
+ * zfcp_erp_scsi_scan
+ * @data: pointer to a struct zfcp_erp_add_work
+ *
+ * Registers a logical unit with the SCSI stack.
+ */
+static void zfcp_erp_scsi_scan(struct work_struct *work)
+{
+       struct zfcp_erp_add_work *p =
+               container_of(work, struct zfcp_erp_add_work, work);
+       struct zfcp_unit *unit = p->unit;
+       struct fc_rport *rport = unit->port->rport;
+       scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
+                        unit->scsi_lun, 0);
+       atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
+       wake_up(&unit->scsi_scan_wq);
+       zfcp_unit_put(unit);
+       kfree(p);
+}
+
+/**
+ * zfcp_erp_schedule_work
+ * @unit: pointer to unit which should be registered with SCSI stack
+ *
+ * Schedules work which registers a unit with the SCSI stack
+ */
+static void
+zfcp_erp_schedule_work(struct zfcp_unit *unit)
+{
+       struct zfcp_erp_add_work *p;
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (!p) {
+               ZFCP_LOG_NORMAL("error: Out of resources. Could not register "
+                               "the FCP-LUN 0x%Lx connected to "
+                               "the port with WWPN 0x%Lx connected to "
+                               "the adapter %s with the SCSI stack.\n",
+                               unit->fcp_lun,
+                               unit->port->wwpn,
+                               zfcp_get_busid_by_unit(unit));
+               return;
+       }
+
+       zfcp_unit_get(unit);
+       memset(p, 0, sizeof(*p));
+       atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
+       INIT_WORK(&p->work, zfcp_erp_scsi_scan);
+       p->unit = unit;
+       schedule_work(&p->work);
+}
+
 /*
  * function:   
  *
@@ -2401,7 +2456,7 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action)
                                retval = ZFCP_ERP_FAILED;
                        }
                } else {
-                       ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> "
+                       ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> "
                                       "trying open\n", port->wwpn, port->d_id);
                        retval = zfcp_erp_port_strategy_open_port(erp_action);
                }
@@ -2441,7 +2496,7 @@ zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action)
        case ZFCP_ERP_STEP_UNINITIALIZED:
        case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
        case ZFCP_ERP_STEP_PORT_CLOSING:
-               ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> trying open\n",
+               ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> trying open\n",
                               port->wwpn, port->d_id);
                retval = zfcp_erp_port_strategy_open_port(erp_action);
                break;
@@ -3092,9 +3147,9 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
                    && port->rport) {
                        atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED,
                                        &unit->status);
-                       scsi_scan_target(&port->rport->dev, 0,
-                                        port->rport->scsi_target_id,
-                                        unit->scsi_lun, 0);
+                       if (atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
+                                            &unit->status) == 0)
+                               zfcp_erp_schedule_work(unit);
                }
                zfcp_unit_put(unit);
                break;
@@ -3121,7 +3176,7 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
                                                zfcp_get_busid_by_port(port),
                                                port->wwpn);
                        else {
-                               scsi_flush_work(adapter->scsi_host);
+                               scsi_target_unblock(&port->rport->dev);
                                port->rport->maxframe_size = port->maxframe_size;
                                port->rport->supported_classes =
                                        port->supported_classes;
index 01386ac688a27887e32cd75dfa336a2c4611f5d9..991d45667a44d0453f06d0134d1345a8a5509d2a 100644 (file)
@@ -184,10 +184,6 @@ extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *,
                                      unsigned long);
 extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
                                         struct scsi_cmnd *);
-extern void zfcp_reqlist_add(struct zfcp_adapter *, struct zfcp_fsf_req *);
-extern void zfcp_reqlist_remove(struct zfcp_adapter *, unsigned long);
-extern struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *,
-                                                 unsigned long);
 extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
 
 #endif /* ZFCP_EXT_H */
index 4c0a59afd5c85bda51083b6cab01588c11268363..a8b02542ac2da30aaaf9a953153d41e419c18da0 100644 (file)
@@ -828,7 +828,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
 
        if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) {
                ZFCP_LOG_NORMAL("bug: Reopen port indication received for"
-                               "nonexisting port with d_id 0x%08x on "
+                               "nonexisting port with d_id 0x%06x on "
                                "adapter %s. Ignored.\n",
                                status_buffer->d_id & ZFCP_DID_MASK,
                                zfcp_get_busid_by_adapter(adapter));
@@ -853,7 +853,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
                                &status_buffer->status_subtype, sizeof (u32));
                ZFCP_LOG_NORMAL("bug: Undefined status subtype received "
                                "for a reopen indication on port with "
-                               "d_id 0x%08x on the adapter %s. "
+                               "d_id 0x%06x on the adapter %s. "
                                "Ignored. (debug info 0x%x)\n",
                                status_buffer->d_id,
                                zfcp_get_busid_by_adapter(adapter),
@@ -1156,7 +1156,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
        }
 
        ZFCP_LOG_DEBUG("Abort FCP Command request initiated "
-                      "(adapter%s, port d_id=0x%08x, "
+                      "(adapter%s, port d_id=0x%06x, "
                       "unit x%016Lx, old_req_id=0x%lx)\n",
                       zfcp_get_busid_by_adapter(adapter),
                       unit->port->d_id,
@@ -1554,7 +1554,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
 
        case FSF_ACCESS_DENIED:
                ZFCP_LOG_NORMAL("access denied, cannot send generic service "
-                               "command (adapter %s, port d_id=0x%08x)\n",
+                               "command (adapter %s, port d_id=0x%06x)\n",
                                zfcp_get_busid_by_port(port), port->d_id);
                for (counter = 0; counter < 2; counter++) {
                        subtable = header->fsf_status_qual.halfword[counter * 2];
@@ -1576,7 +1576,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
 
         case FSF_GENERIC_COMMAND_REJECTED:
                ZFCP_LOG_INFO("generic service command rejected "
-                             "(adapter %s, port d_id=0x%08x)\n",
+                             "(adapter %s, port d_id=0x%06x)\n",
                              zfcp_get_busid_by_port(port), port->d_id);
                ZFCP_LOG_INFO("status qualifier:\n");
                ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
@@ -1602,7 +1602,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
 
         case FSF_PORT_BOXED:
                ZFCP_LOG_INFO("port needs to be reopened "
-                             "(adapter %s, port d_id=0x%08x)\n",
+                             "(adapter %s, port d_id=0x%06x)\n",
                              zfcp_get_busid_by_port(port), port->d_id);
                debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
                zfcp_erp_port_boxed(port);
@@ -1683,7 +1683,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
                                  NULL, &lock_flags, &fsf_req);
        if (ret < 0) {
                 ZFCP_LOG_INFO("error: creation of ELS request failed "
-                             "(adapter %s, port d_id: 0x%08x)\n",
+                             "(adapter %s, port d_id: 0x%06x)\n",
                               zfcp_get_busid_by_adapter(adapter), d_id);
                 goto failed_req;
        }
@@ -1708,7 +1708,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
                                                 ZFCP_MAX_SBALS_PER_ELS_REQ);
                 if (bytes <= 0) {
                         ZFCP_LOG_INFO("error: creation of ELS request failed "
-                                     "(adapter %s, port d_id: 0x%08x)\n",
+                                     "(adapter %s, port d_id: 0x%06x)\n",
                                      zfcp_get_busid_by_adapter(adapter), d_id);
                         if (bytes == 0) {
                                 ret = -ENOMEM;
@@ -1725,7 +1725,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
                                                 ZFCP_MAX_SBALS_PER_ELS_REQ);
                 if (bytes <= 0) {
                         ZFCP_LOG_INFO("error: creation of ELS request failed "
-                                     "(adapter %s, port d_id: 0x%08x)\n",
+                                     "(adapter %s, port d_id: 0x%06x)\n",
                                      zfcp_get_busid_by_adapter(adapter), d_id);
                         if (bytes == 0) {
                                 ret = -ENOMEM;
@@ -1739,7 +1739,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
                 /* reject request */
                ZFCP_LOG_INFO("error: microcode does not support chained SBALs"
                               ", ELS request too big (adapter %s, "
-                             "port d_id: 0x%08x)\n",
+                             "port d_id: 0x%06x)\n",
                              zfcp_get_busid_by_adapter(adapter), d_id);
                 ret = -EOPNOTSUPP;
                 goto failed_send;
@@ -1760,13 +1760,13 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
        ret = zfcp_fsf_req_send(fsf_req);
        if (ret) {
                ZFCP_LOG_DEBUG("error: initiation of ELS request failed "
-                              "(adapter %s, port d_id: 0x%08x)\n",
+                              "(adapter %s, port d_id: 0x%06x)\n",
                               zfcp_get_busid_by_adapter(adapter), d_id);
                goto failed_send;
        }
 
        ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: "
-                      "0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
+                      "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
        goto out;
 
  failed_send:
@@ -1859,7 +1859,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
        case FSF_ELS_COMMAND_REJECTED:
                ZFCP_LOG_INFO("ELS has been rejected because command filter "
                              "prohibited sending "
-                             "(adapter: %s, port d_id: 0x%08x)\n",
+                             "(adapter: %s, port d_id: 0x%06x)\n",
                              zfcp_get_busid_by_adapter(adapter), d_id);
 
                break;
@@ -1907,7 +1907,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
 
        case FSF_ACCESS_DENIED:
                ZFCP_LOG_NORMAL("access denied, cannot send ELS command "
-                               "(adapter %s, port d_id=0x%08x)\n",
+                               "(adapter %s, port d_id=0x%06x)\n",
                                zfcp_get_busid_by_adapter(adapter), d_id);
                for (counter = 0; counter < 2; counter++) {
                        subtable = header->fsf_status_qual.halfword[counter * 2];
@@ -2070,7 +2070,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
        ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n"
                        "WWNN 0x%016Lx, "
                        "WWPN 0x%016Lx, "
-                       "S_ID 0x%08x,\n"
+                       "S_ID 0x%06x,\n"
                        "adapter version 0x%x, "
                        "LIC version 0x%x, "
                        "FC link speed %d Gb/s\n",
@@ -3043,6 +3043,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
        queue_designator = &header->fsf_status_qual.fsf_queue_designator;
 
        atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
+                         ZFCP_STATUS_COMMON_ACCESS_BOXED |
                          ZFCP_STATUS_UNIT_SHARED |
                          ZFCP_STATUS_UNIT_READONLY,
                          &unit->status);
@@ -4645,23 +4646,22 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
        fsf_req->adapter = adapter;
        fsf_req->fsf_command = fsf_cmd;
        INIT_LIST_HEAD(&fsf_req->list);
-       
-       /* this is serialized (we are holding req_queue-lock of adapter */
-       if (adapter->req_no == 0)
-               adapter->req_no++;
-       fsf_req->req_id = adapter->req_no++;
-
        init_timer(&fsf_req->timer);
-       zfcp_fsf_req_qtcb_init(fsf_req);
 
        /* initialize waitqueue which may be used to wait on 
           this request completion */
        init_waitqueue_head(&fsf_req->completion_wq);
 
         ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags);
-        if(ret < 0) {
+        if (ret < 0)
                 goto failed_sbals;
-       }
+
+       /* this is serialized (we are holding req_queue-lock of adapter) */
+       if (adapter->req_no == 0)
+               adapter->req_no++;
+       fsf_req->req_id = adapter->req_no++;
+
+       zfcp_fsf_req_qtcb_init(fsf_req);
 
        /*
         * We hold queue_lock here. Check if QDIOUP is set and let request fail
@@ -4788,7 +4788,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req)
                retval = -EIO;
                del_timer(&fsf_req->timer);
                spin_lock(&adapter->req_list_lock);
-               zfcp_reqlist_remove(adapter, fsf_req->req_id);
+               zfcp_reqlist_remove(adapter, fsf_req);
                spin_unlock(&adapter->req_list_lock);
                /* undo changes in request queue made for this request */
                zfcp_qdio_zero_sbals(req_queue->buffer,
index 1e12a78e8edd1c17886a66f5e7bf2b530adf6018..cb08ca3cc0f993bcb6925ea7e007d0df2bdc78d7 100644 (file)
@@ -283,10 +283,10 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device,
 }
 
 /**
- * zfcp_qdio_reqid_check - checks for valid reqids or unsolicited status
+ * zfcp_qdio_reqid_check - checks for valid reqids.
  */
-static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, 
-                                unsigned long req_id)
+static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
+                                 unsigned long req_id)
 {
        struct zfcp_fsf_req *fsf_req;
        unsigned long flags;
@@ -294,23 +294,22 @@ static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
        debug_long_event(adapter->erp_dbf, 4, req_id);
 
        spin_lock_irqsave(&adapter->req_list_lock, flags);
-       fsf_req = zfcp_reqlist_ismember(adapter, req_id);
+       fsf_req = zfcp_reqlist_find(adapter, req_id);
 
-       if (!fsf_req) {
-               spin_unlock_irqrestore(&adapter->req_list_lock, flags);
-               ZFCP_LOG_NORMAL("error: unknown request id (%ld).\n", req_id);
-               zfcp_erp_adapter_reopen(adapter, 0);
-               return -EINVAL;
-       }
+       if (!fsf_req)
+               /*
+                * Unknown request means that we have potentially memory
+                * corruption and must stop the machine immediatly.
+                */
+               panic("error: unknown request id (%ld) on adapter %s.\n",
+                     req_id, zfcp_get_busid_by_adapter(adapter));
 
-       zfcp_reqlist_remove(adapter, req_id);
+       zfcp_reqlist_remove(adapter, fsf_req);
        atomic_dec(&adapter->reqs_active);
        spin_unlock_irqrestore(&adapter->req_list_lock, flags);
 
        /* finish the FSF request */
        zfcp_fsf_req_complete(fsf_req);
-
-       return 0;
 }
 
 /*
@@ -374,27 +373,9 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
 
                        /* look for QDIO request identifiers in SB */
                        buffere = &buffer->element[buffere_index];
-                       retval = zfcp_qdio_reqid_check(adapter,
-                                       (unsigned long) buffere->addr);
-
-                       if (retval) {
-                               ZFCP_LOG_NORMAL("bug: unexpected inbound "
-                                               "packet on adapter %s "
-                                               "(reqid=0x%lx, "
-                                               "first_element=%d, "
-                                               "elements_processed=%d)\n",
-                                               zfcp_get_busid_by_adapter(adapter),
-                                               (unsigned long) buffere->addr,
-                                               first_element,
-                                               elements_processed);
-                               ZFCP_LOG_NORMAL("hex dump of inbound buffer "
-                                               "at address %p "
-                                               "(buffer_index=%d, "
-                                               "buffere_index=%d)\n", buffer,
-                                               buffer_index, buffere_index);
-                               ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
-                                             (char *) buffer, SBAL_SIZE);
-                       }
+                       zfcp_qdio_reqid_check(adapter,
+                                             (unsigned long) buffere->addr);
+
                        /*
                         * A single used SBALE per inbound SBALE has been
                         * implemented by QDIO so far. Hope they will
index 99db02062c3b4af325e8cbfa3b9208d333a867d5..16e2d64658afea075143230bdcc08d9a492a58a8 100644 (file)
@@ -22,6 +22,7 @@
 #define ZFCP_LOG_AREA                  ZFCP_LOG_AREA_SCSI
 
 #include "zfcp_ext.h"
+#include <asm/atomic.h>
 
 static void zfcp_scsi_slave_destroy(struct scsi_device *sdp);
 static int zfcp_scsi_slave_alloc(struct scsi_device *sdp);
@@ -179,6 +180,10 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
        struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
 
        if (unit) {
+               zfcp_erp_wait(unit->port->adapter);
+               wait_event(unit->scsi_scan_wq,
+                          atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
+                                           &unit->status) == 0);
                atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
                sdpnt->hostdata = NULL;
                unit->device = NULL;
@@ -402,8 +407,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 
        /* Check whether corresponding fsf_req is still pending */
        spin_lock(&adapter->req_list_lock);
-       fsf_req = zfcp_reqlist_ismember(adapter, (unsigned long)
-                                       scpnt->host_scribble);
+       fsf_req = zfcp_reqlist_find(adapter,
+                                   (unsigned long) scpnt->host_scribble);
        spin_unlock(&adapter->req_list_lock);
        if (!fsf_req) {
                write_unlock_irqrestore(&adapter->abort_lock, flags);
index 33682ce96a5d683cdc9d6e2687b2e95eaee43f20..3009ad8c407343d209e9b4d0a79639f0dbbfd4fe 100644 (file)
@@ -387,12 +387,11 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
         *      Ok now init the communication subsystem
         */
 
-       dev->queues = kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
+       dev->queues = kzalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
        if (dev->queues == NULL) {
                printk(KERN_ERR "Error could not allocate comm region.\n");
                return NULL;
        }
-       memset(dev->queues, 0, sizeof(struct aac_queue_block));
 
        if (aac_comm_init(dev)<0){
                kfree(dev->queues);
index 5824a757a7531aa9d71801486754cee84027a3f1..9aca57eda943664011d06863c309fd4178a58622 100644 (file)
@@ -1223,13 +1223,11 @@ int aac_check_health(struct aac_dev * aac)
                 * Warning: no sleep allowed while
                 * holding spinlock
                 */
-               hw_fib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
-               fib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
+               hw_fib = kzalloc(sizeof(struct hw_fib), GFP_ATOMIC);
+               fib = kzalloc(sizeof(struct fib), GFP_ATOMIC);
                if (fib && hw_fib) {
                        struct aac_aifcmd * aif;
 
-                       memset(hw_fib, 0, sizeof(struct hw_fib));
-                       memset(fib, 0, sizeof(struct fib));
                        fib->hw_fib_va = hw_fib;
                        fib->dev = aac;
                        aac_fib_init(fib);
index 42c7dcda6d9bd1c9679cddcc8dd01bb0be00ae4c..fcd25f7d0bc636252074d535338d3c9f9e2e81f0 100644 (file)
@@ -248,16 +248,14 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
                 * manage the linked lists.
                 */
                if ((!dev->aif_thread)
-                || (!(fib = kmalloc(sizeof(struct fib),GFP_ATOMIC))))
+                || (!(fib = kzalloc(sizeof(struct fib),GFP_ATOMIC))))
                        return 1;
-               if (!(hw_fib = kmalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
+               if (!(hw_fib = kzalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
                        kfree (fib);
                        return 1;
                }
-               memset(hw_fib, 0, sizeof(struct hw_fib));
                memcpy(hw_fib, (struct hw_fib *)(((ptrdiff_t)(dev->regs.sa)) +
                  (index & ~0x00000002L)), sizeof(struct hw_fib));
-               memset(fib, 0, sizeof(struct fib));
                INIT_LIST_HEAD(&fib->fiblink);
                fib->type = FSAFS_NTC_FIB_CONTEXT;
                fib->size = sizeof(struct fib);
index 0c71315cbf1aec8ed3df4f72bf8bb87d6a7f2cbc..291cd14f4e989737b0f54c289250a6cb006a67e0 100644 (file)
@@ -539,8 +539,10 @@ int _aac_rx_init(struct aac_dev *dev)
        }
 
        /* Failure to reset here is an option ... */
+       dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
+       dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt;
        dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
-       if ((((status & 0xff) != 0xff) || reset_devices) &&
+       if ((((status & 0x0c) != 0x0c) || reset_devices) &&
          !aac_rx_restart_adapter(dev, 0))
                ++restart;
        /*
index 2a2cc6cf1182a9cdaa2ebf0df1c2b9e15b4b37e3..2311019304c00ef22ec4a8b63167a7c65c7dc488 100644 (file)
@@ -319,10 +319,9 @@ ch_readconfig(scsi_changer *ch)
        int     result,id,lun,i;
        u_int   elem;
 
-       buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
+       buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
        if (!buffer)
                return -ENOMEM;
-       memset(buffer,0,512);
        
        memset(cmd,0,sizeof(cmd));
        cmd[0] = MODE_SENSE;
@@ -530,10 +529,9 @@ ch_set_voltag(scsi_changer *ch, u_int elem,
        u_char  *buffer;
        int result;
 
-       buffer = kmalloc(512, GFP_KERNEL);
+       buffer = kzalloc(512, GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
-       memset(buffer,0,512);
 
        dprintk("%s %s voltag: 0x%x => \"%s\"\n",
                clear     ? "clear"     : "set",
@@ -922,11 +920,10 @@ static int ch_probe(struct device *dev)
        if (sd->type != TYPE_MEDIUM_CHANGER)
                return -ENODEV;
     
-       ch = kmalloc(sizeof(*ch), GFP_KERNEL);
+       ch = kzalloc(sizeof(*ch), GFP_KERNEL);
        if (NULL == ch)
                return -ENOMEM;
 
-       memset(ch,0,sizeof(*ch));
        ch->minor = ch_devcount;
        sprintf(ch->name,"ch%d",ch->minor);
        mutex_init(&ch->lock);
index fb6433a56989f5b98d5fccfc9978d9ba51d23ec3..8c7d2bbf9b1a848b90b19a2edd1663e0164c0a2b 100644 (file)
@@ -1308,13 +1308,12 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
                schedule_timeout_uninterruptible(1);
        } while (m == EMPTY_QUEUE);
 
-       status = kmalloc(4, GFP_KERNEL|ADDR32);
+       status = kzalloc(4, GFP_KERNEL|ADDR32);
        if(status == NULL) {
                adpt_send_nop(pHba, m);
                printk(KERN_ERR"IOP reset failed - no free memory.\n");
                return -ENOMEM;
        }
-       memset(status,0,4);
 
        msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
        msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
@@ -1504,21 +1503,19 @@ static int adpt_i2o_parse_lct(adpt_hba* pHba)
                                        continue;
                                }
                                if( pHba->channel[bus_no].device[scsi_id] == NULL){
-                                       pDev =  kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+                                       pDev =  kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
                                        if(pDev == NULL) {
                                                return -ENOMEM;
                                        }
                                        pHba->channel[bus_no].device[scsi_id] = pDev;
-                                       memset(pDev,0,sizeof(struct adpt_device));
                                } else {
                                        for( pDev = pHba->channel[bus_no].device[scsi_id];      
                                                        pDev->next_lun; pDev = pDev->next_lun){
                                        }
-                                       pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+                                       pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
                                        if(pDev->next_lun == NULL) {
                                                return -ENOMEM;
                                        }
-                                       memset(pDev->next_lun,0,sizeof(struct adpt_device));
                                        pDev = pDev->next_lun;
                                }
                                pDev->tid = tid;
@@ -1667,12 +1664,11 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
                reply_size = REPLY_FRAME_SIZE;
        }
        reply_size *= 4;
-       reply = kmalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL);
+       reply = kzalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL);
        if(reply == NULL) {
                printk(KERN_WARNING"%s: Could not allocate reply buffer\n",pHba->name);
                return -ENOMEM;
        }
-       memset(reply,0,REPLY_FRAME_SIZE*4);
        sg_offset = (msg[0]>>4)&0xf;
        msg[2] = 0x40000000; // IOCTL context
        msg[3] = (u32)reply;
@@ -2444,7 +2440,7 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
                                }
                                pDev = pHba->channel[bus_no].device[scsi_id];   
                                if( pDev == NULL){
-                                       pDev =  kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+                                       pDev =  kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
                                        if(pDev == NULL) {
                                                return -ENOMEM;
                                        }
@@ -2453,12 +2449,11 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
                                        while (pDev->next_lun) {
                                                pDev = pDev->next_lun;
                                        }
-                                       pDev = pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+                                       pDev = pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
                                        if(pDev == NULL) {
                                                return -ENOMEM;
                                        }
                                }
-                               memset(pDev,0,sizeof(struct adpt_device));
                                pDev->tid = d->lct_data.tid;
                                pDev->scsi_channel = bus_no;
                                pDev->scsi_id = scsi_id;
index 2c7b77e833f993ff6d14d65820452d87dbaa8351..4baa79e686794ba5915717c2998860b6031fd91b 100644 (file)
@@ -92,6 +92,7 @@ static unsigned int ipr_fastfail = 0;
 static unsigned int ipr_transop_timeout = 0;
 static unsigned int ipr_enable_cache = 1;
 static unsigned int ipr_debug = 0;
+static unsigned int ipr_dual_ioa_raid = 1;
 static DEFINE_SPINLOCK(ipr_driver_lock);
 
 /* This table describes the differences between DMA controller chips */
@@ -158,6 +159,8 @@ module_param_named(enable_cache, ipr_enable_cache, int, 0);
 MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)");
 module_param_named(debug, ipr_debug, int, 0);
 MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)");
+module_param_named(dual_ioa_raid, ipr_dual_ioa_raid, int, 0);
+MODULE_PARM_DESC(dual_ioa_raid, "Enable dual adapter RAID support. Set to 1 to enable. (default: 1)");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(IPR_DRIVER_VERSION);
 
@@ -206,6 +209,8 @@ struct ipr_error_table_t ipr_error_table[] = {
        "8009: Impending cache battery pack failure"},
        {0x02040400, 0, 0,
        "34FF: Disk device format in progress"},
+       {0x02048000, 0, IPR_DEFAULT_LOG_LEVEL,
+       "9070: IOA requested reset"},
        {0x023F0000, 0, 0,
        "Synchronization required"},
        {0x024E0000, 0, 0,
@@ -950,6 +955,53 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd)
        }
 }
 
+/**
+ * strip_and_pad_whitespace - Strip and pad trailing whitespace.
+ * @i:         index into buffer
+ * @buf:               string to modify
+ *
+ * This function will strip all trailing whitespace, pad the end
+ * of the string with a single space, and NULL terminate the string.
+ *
+ * Return value:
+ *     new length of string
+ **/
+static int strip_and_pad_whitespace(int i, char *buf)
+{
+       while (i && buf[i] == ' ')
+               i--;
+       buf[i+1] = ' ';
+       buf[i+2] = '\0';
+       return i + 2;
+}
+
+/**
+ * ipr_log_vpd_compact - Log the passed extended VPD compactly.
+ * @prefix:            string to print at start of printk
+ * @hostrcb:   hostrcb pointer
+ * @vpd:               vendor/product id/sn struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb,
+                               struct ipr_vpd *vpd)
+{
+       char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + IPR_SERIAL_NUM_LEN + 3];
+       int i = 0;
+
+       memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN);
+       i = strip_and_pad_whitespace(IPR_VENDOR_ID_LEN - 1, buffer);
+
+       memcpy(&buffer[i], vpd->vpids.product_id, IPR_PROD_ID_LEN);
+       i = strip_and_pad_whitespace(i + IPR_PROD_ID_LEN - 1, buffer);
+
+       memcpy(&buffer[i], vpd->sn, IPR_SERIAL_NUM_LEN);
+       buffer[IPR_SERIAL_NUM_LEN + i] = '\0';
+
+       ipr_hcam_err(hostrcb, "%s VPID/SN: %s\n", prefix, buffer);
+}
+
 /**
  * ipr_log_vpd - Log the passed VPD to the error log.
  * @vpd:               vendor/product id/sn struct
@@ -973,6 +1025,23 @@ static void ipr_log_vpd(struct ipr_vpd *vpd)
        ipr_err("    Serial Number: %s\n", buffer);
 }
 
+/**
+ * ipr_log_ext_vpd_compact - Log the passed extended VPD compactly.
+ * @prefix:            string to print at start of printk
+ * @hostrcb:   hostrcb pointer
+ * @vpd:               vendor/product id/sn/wwn struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log_ext_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb,
+                                   struct ipr_ext_vpd *vpd)
+{
+       ipr_log_vpd_compact(prefix, hostrcb, &vpd->vpd);
+       ipr_hcam_err(hostrcb, "%s WWN: %08X%08X\n", prefix,
+                    be32_to_cpu(vpd->wwid[0]), be32_to_cpu(vpd->wwid[1]));
+}
+
 /**
  * ipr_log_ext_vpd - Log the passed extended VPD to the error log.
  * @vpd:               vendor/product id/sn/wwn struct
@@ -1287,10 +1356,11 @@ static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
 
        error = &hostrcb->hcam.u.error.u.type_17_error;
        error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+       strstrip(error->failure_reason);
 
-       ipr_err("%s\n", error->failure_reason);
-       ipr_err("Remote Adapter VPD:\n");
-       ipr_log_ext_vpd(&error->vpd);
+       ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason,
+                    be32_to_cpu(hostrcb->hcam.u.error.prc));
+       ipr_log_ext_vpd_compact("Remote IOA", hostrcb, &error->vpd);
        ipr_log_hex_data(ioa_cfg, error->data,
                         be32_to_cpu(hostrcb->hcam.length) -
                         (offsetof(struct ipr_hostrcb_error, u) +
@@ -1312,10 +1382,11 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
 
        error = &hostrcb->hcam.u.error.u.type_07_error;
        error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+       strstrip(error->failure_reason);
 
-       ipr_err("%s\n", error->failure_reason);
-       ipr_err("Remote Adapter VPD:\n");
-       ipr_log_vpd(&error->vpd);
+       ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason,
+                    be32_to_cpu(hostrcb->hcam.u.error.prc));
+       ipr_log_vpd_compact("Remote IOA", hostrcb, &error->vpd);
        ipr_log_hex_data(ioa_cfg, error->data,
                         be32_to_cpu(hostrcb->hcam.length) -
                         (offsetof(struct ipr_hostrcb_error, u) +
@@ -1672,12 +1743,15 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
        u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
 
        list_del(&hostrcb->queue);
        list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
 
        if (!ioasc) {
                ipr_handle_log_data(ioa_cfg, hostrcb);
+               if (fd_ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED)
+                       ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_ABBREV);
        } else if (ioasc != IPR_IOASC_IOA_WAS_RESET) {
                dev_err(&ioa_cfg->pdev->dev,
                        "Host RCB failed with IOASC: 0x%08X\n", ioasc);
@@ -2635,8 +2709,13 @@ static ssize_t ipr_store_diagnostics(struct class_device *class_dev,
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       }
+
        ioa_cfg->errors_logged = 0;
        ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
 
@@ -2958,6 +3037,11 @@ static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg,
        unsigned long lock_flags;
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       }
 
        if (ioa_cfg->ucode_sglist) {
                spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -4656,18 +4740,19 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
        struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
        struct ipr_resource_entry *res = scsi_cmd->device->hostdata;
        u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 masked_ioasc = ioasc & IPR_IOASC_IOASC_MASK;
 
        if (!res) {
                ipr_scsi_eh_done(ipr_cmd);
                return;
        }
 
-       if (!ipr_is_gscsi(res))
+       if (!ipr_is_gscsi(res) && masked_ioasc != IPR_IOASC_HW_DEV_BUS_STATUS)
                ipr_gen_sense(ipr_cmd);
 
        ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
 
-       switch (ioasc & IPR_IOASC_IOASC_MASK) {
+       switch (masked_ioasc) {
        case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST:
                if (ipr_is_naca_model(res))
                        scsi_cmd->result |= (DID_ABORT << 16);
@@ -5363,6 +5448,7 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd)
                        ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb);
        }
 
+       scsi_report_bus_reset(ioa_cfg->host, IPR_VSET_BUS);
        dev_info(&ioa_cfg->pdev->dev, "IOA initialized.\n");
 
        ioa_cfg->reset_retries = 0;
@@ -5798,6 +5884,94 @@ static int ipr_ioafp_mode_sense_page28(struct ipr_cmnd *ipr_cmd)
        return IPR_RC_JOB_RETURN;
 }
 
+/**
+ * ipr_ioafp_mode_select_page24 - Issue Mode Select to IOA
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function enables dual IOA RAID support if possible.
+ *
+ * Return value:
+ *     IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_mode_select_page24(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       struct ipr_mode_pages *mode_pages = &ioa_cfg->vpd_cbs->mode_pages;
+       struct ipr_mode_page24 *mode_page;
+       int length;
+
+       ENTER;
+       mode_page = ipr_get_mode_page(mode_pages, 0x24,
+                                     sizeof(struct ipr_mode_page24));
+
+       if (mode_page)
+               mode_page->flags |= IPR_ENABLE_DUAL_IOA_AF;
+
+       length = mode_pages->hdr.length + 1;
+       mode_pages->hdr.length = 0;
+
+       ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11,
+                             ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages),
+                             length);
+
+       ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+       ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+       LEAVE;
+       return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_mode_sense_page24_failed - Handle failure of IOAFP mode sense
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function handles the failure of a Mode Sense to the IOAFP.
+ * Some adapters do not handle all mode pages.
+ *
+ * Return value:
+ *     IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_mode_sense_page24_failed(struct ipr_cmnd *ipr_cmd)
+{
+       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+       if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) {
+               ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+               return IPR_RC_JOB_CONTINUE;
+       }
+
+       return ipr_reset_cmd_failed(ipr_cmd);
+}
+
+/**
+ * ipr_ioafp_mode_sense_page24 - Issue Page 24 Mode Sense to IOA
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function send a mode sense to the IOA to retrieve
+ * the IOA Advanced Function Control mode page.
+ *
+ * Return value:
+ *     IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_mode_sense_page24(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+       ENTER;
+       ipr_build_mode_sense(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE),
+                            0x24, ioa_cfg->vpd_cbs_dma +
+                            offsetof(struct ipr_misc_cbs, mode_pages),
+                            sizeof(struct ipr_mode_pages));
+
+       ipr_cmd->job_step = ipr_ioafp_mode_select_page24;
+       ipr_cmd->job_step_failed = ipr_reset_mode_sense_page24_failed;
+
+       ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+       LEAVE;
+       return IPR_RC_JOB_RETURN;
+}
+
 /**
  * ipr_init_res_table - Initialize the resource table
  * @ipr_cmd:   ipr command struct
@@ -5866,7 +6040,10 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd)
                }
        }
 
-       ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+       if (ioa_cfg->dual_raid && ipr_dual_ioa_raid)
+               ipr_cmd->job_step = ipr_ioafp_mode_sense_page24;
+       else
+               ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
 
        LEAVE;
        return IPR_RC_JOB_CONTINUE;
@@ -5888,8 +6065,11 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd)
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
        struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
        struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data;
+       struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap;
 
        ENTER;
+       if (cap->cap & IPR_CAP_DUAL_IOA_RAID)
+               ioa_cfg->dual_raid = 1;
        dev_info(&ioa_cfg->pdev->dev, "Adapter firmware version: %02X%02X%02X%02X\n",
                 ucode_vpd->major_release, ucode_vpd->card_type,
                 ucode_vpd->minor_release[0], ucode_vpd->minor_release[1]);
@@ -5972,6 +6152,37 @@ static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page)
        return 0;
 }
 
+/**
+ * ipr_ioafp_cap_inquiry - Send a Page 0xD0 Inquiry to the adapter.
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function sends a Page 0xD0 inquiry to the adapter
+ * to retrieve adapter capabilities.
+ *
+ * Return value:
+ *     IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data;
+       struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap;
+
+       ENTER;
+       ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+       memset(cap, 0, sizeof(*cap));
+
+       if (ipr_inquiry_page_supported(page0, 0xD0)) {
+               ipr_ioafp_inquiry(ipr_cmd, 1, 0xD0,
+                                 ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, cap),
+                                 sizeof(struct ipr_inquiry_cap));
+               return IPR_RC_JOB_RETURN;
+       }
+
+       LEAVE;
+       return IPR_RC_JOB_CONTINUE;
+}
+
 /**
  * ipr_ioafp_page3_inquiry - Send a Page 3 Inquiry to the adapter.
  * @ipr_cmd:   ipr command struct
@@ -5992,7 +6203,7 @@ static int ipr_ioafp_page3_inquiry(struct ipr_cmnd *ipr_cmd)
        if (!ipr_inquiry_page_supported(page0, 1))
                ioa_cfg->cache_state = CACHE_NONE;
 
-       ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+       ipr_cmd->job_step = ipr_ioafp_cap_inquiry;
 
        ipr_ioafp_inquiry(ipr_cmd, 1, 3,
                          ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data),
@@ -6278,6 +6489,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
        struct ipr_hostrcb *hostrcb;
        struct ipr_uc_sdt sdt;
        int rc, length;
+       u32 ioasc;
 
        mailbox = readl(ioa_cfg->ioa_mailbox);
 
@@ -6310,9 +6522,13 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
                                        (__be32 *)&hostrcb->hcam,
                                        min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32));
 
-       if (!rc)
+       if (!rc) {
                ipr_handle_log_data(ioa_cfg, hostrcb);
-       else
+               ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
+               if (ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED &&
+                   ioa_cfg->sdt_state == GET_DUMP)
+                       ioa_cfg->sdt_state = WAIT_FOR_DUMP;
+       } else
                ipr_unit_check_no_data(ioa_cfg);
 
        list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
@@ -6424,6 +6640,48 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
        return rc;
 }
 
+/**
+ * ipr_reset_slot_reset_done - Clear PCI reset to the adapter
+ * @ipr_cmd:   ipr command struct
+ *
+ * Description: This clears PCI reset to the adapter and delays two seconds.
+ *
+ * Return value:
+ *     IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd)
+{
+       ENTER;
+       pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev, pcie_deassert_reset);
+       ipr_cmd->job_step = ipr_reset_bist_done;
+       ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
+       LEAVE;
+       return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_slot_reset - Reset the PCI slot of the adapter.
+ * @ipr_cmd:   ipr command struct
+ *
+ * Description: This asserts PCI reset to the adapter.
+ *
+ * Return value:
+ *     IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       struct pci_dev *pdev = ioa_cfg->pdev;
+
+       ENTER;
+       pci_block_user_cfg_access(pdev);
+       pci_set_pcie_reset_state(pdev, pcie_warm_reset);
+       ipr_cmd->job_step = ipr_reset_slot_reset_done;
+       ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT);
+       LEAVE;
+       return IPR_RC_JOB_RETURN;
+}
+
 /**
  * ipr_reset_allowed - Query whether or not IOA can be reset
  * @ioa_cfg:   ioa config struct
@@ -6463,7 +6721,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd)
                ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
                ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT);
        } else {
-               ipr_cmd->job_step = ipr_reset_start_bist;
+               ipr_cmd->job_step = ioa_cfg->reset;
                rc = IPR_RC_JOB_CONTINUE;
        }
 
@@ -6496,7 +6754,7 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd)
                writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg);
                ipr_cmd->job_step = ipr_reset_wait_to_start_bist;
        } else {
-               ipr_cmd->job_step = ipr_reset_start_bist;
+               ipr_cmd->job_step = ioa_cfg->reset;
        }
 
        ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT;
@@ -6591,12 +6849,14 @@ static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd)
                ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN;
                ipr_cmd->ioarcb.cmd_pkt.cdb[1] = shutdown_type;
 
-               if (shutdown_type == IPR_SHUTDOWN_ABBREV)
-                       timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT;
+               if (shutdown_type == IPR_SHUTDOWN_NORMAL)
+                       timeout = IPR_SHUTDOWN_TIMEOUT;
                else if (shutdown_type == IPR_SHUTDOWN_PREPARE_FOR_NORMAL)
                        timeout = IPR_INTERNAL_TIMEOUT;
+               else if (ioa_cfg->dual_raid && ipr_dual_ioa_raid)
+                       timeout = IPR_DUAL_IOA_ABBR_SHUTDOWN_TO;
                else
-                       timeout = IPR_SHUTDOWN_TIMEOUT;
+                       timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT;
 
                ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, timeout);
 
@@ -6776,8 +7036,11 @@ static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev)
        struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
-       _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
-                                        IPR_SHUTDOWN_NONE);
+       if (ioa_cfg->needs_warm_reset)
+               ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+       else
+               _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
+                                       IPR_SHUTDOWN_NONE);
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
        return PCI_ERS_RESULT_RECOVERED;
 }
@@ -7226,7 +7489,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
        unsigned long ipr_regs_pci;
        void __iomem *ipr_regs;
        int rc = PCIBIOS_SUCCESSFUL;
-       volatile u32 mask, uproc;
+       volatile u32 mask, uproc, interrupts;
 
        ENTER;
 
@@ -7265,6 +7528,14 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
        else
                ioa_cfg->transop_timeout = IPR_OPERATIONAL_TIMEOUT;
 
+       rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &ioa_cfg->revid);
+
+       if (rc != PCIBIOS_SUCCESSFUL) {
+               dev_err(&pdev->dev, "Failed to read PCI revision ID\n");
+               rc = -EIO;
+               goto out_scsi_host_put;
+       }
+
        ipr_regs_pci = pci_resource_start(pdev, 0);
 
        rc = pci_request_regions(pdev, IPR_NAME);
@@ -7333,9 +7604,14 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
         * the card is in an unknown state and needs a hard reset
         */
        mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+       interrupts = readl(ioa_cfg->regs.sense_interrupt_reg);
        uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg);
        if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT))
                ioa_cfg->needs_hard_reset = 1;
+       if (interrupts & IPR_PCII_ERROR_INTERRUPTS)
+               ioa_cfg->needs_hard_reset = 1;
+       if (interrupts & IPR_PCII_IOA_UNIT_CHECKED)
+               ioa_cfg->ioa_unit_checked = 1;
 
        ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
        rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg);
@@ -7346,6 +7622,13 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
                goto cleanup_nolog;
        }
 
+       if ((dev_id->driver_data & IPR_USE_PCI_WARM_RESET) ||
+           (dev_id->device == PCI_DEVICE_ID_IBM_OBSIDIAN_E && !ioa_cfg->revid)) {
+               ioa_cfg->needs_warm_reset = 1;
+               ioa_cfg->reset = ipr_reset_slot_reset;
+       } else
+               ioa_cfg->reset = ipr_reset_start_bist;
+
        spin_lock(&ipr_driver_lock);
        list_add_tail(&ioa_cfg->queue, &ipr_ioa_head);
        spin_unlock(&ipr_driver_lock);
@@ -7428,6 +7711,12 @@ static void __ipr_remove(struct pci_dev *pdev)
        ENTER;
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+       }
+
        ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
 
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
@@ -7551,6 +7840,12 @@ static void ipr_shutdown(struct pci_dev *pdev)
        unsigned long lock_flags = 0;
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       }
+
        ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
        wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
@@ -7577,19 +7872,22 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
-             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0,
+             IPR_USE_LONG_TRANSOP_TIMEOUT },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
              IPR_USE_LONG_TRANSOP_TIMEOUT },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
-             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0,
+             IPR_USE_LONG_TRANSOP_TIMEOUT},
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
              IPR_USE_LONG_TRANSOP_TIMEOUT },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
-             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0, 0 },
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0,
+             IPR_USE_LONG_TRANSOP_TIMEOUT },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0,
              IPR_USE_LONG_TRANSOP_TIMEOUT },
@@ -7597,7 +7895,7 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0,
-             IPR_USE_LONG_TRANSOP_TIMEOUT },
+             IPR_USE_LONG_TRANSOP_TIMEOUT | IPR_USE_PCI_WARM_RESET },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
@@ -7627,6 +7925,7 @@ static struct pci_driver ipr_driver = {
        .remove = ipr_remove,
        .shutdown = ipr_shutdown,
        .err_handler = &ipr_err_handler,
+       .dynids.use_driver_data = 1
 };
 
 /**
index bc53d7cebe0ac645e654b34889e9fb0c4cfbd9f5..d93156671e93d7155505098242f821a46c1ed973 100644 (file)
@@ -37,8 +37,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.3.2"
-#define IPR_DRIVER_DATE "(March 23, 2007)"
+#define IPR_DRIVER_VERSION "2.4.1"
+#define IPR_DRIVER_DATE "(April 24, 2007)"
 
 /*
  * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -91,6 +91,7 @@
  * IOASCs
  */
 #define IPR_IOASC_NR_INIT_CMD_REQUIRED         0x02040200
+#define IPR_IOASC_NR_IOA_RESET_REQUIRED                0x02048000
 #define IPR_IOASC_SYNC_REQUIRED                        0x023f0000
 #define IPR_IOASC_MED_DO_NOT_REALLOC           0x03110C00
 #define IPR_IOASC_HW_SEL_TIMEOUT                       0x04050000
 
 /* Driver data flags */
 #define IPR_USE_LONG_TRANSOP_TIMEOUT           0x00000001
+#define IPR_USE_PCI_WARM_RESET                 0x00000002
 
 #define IPR_DEFAULT_MAX_ERROR_DUMP                     984
 #define IPR_NUM_LOG_HCAMS                              2
 #define IPR_SHUTDOWN_TIMEOUT                   (ipr_fastfail ? 60 * HZ : 10 * 60 * HZ)
 #define IPR_VSET_RW_TIMEOUT                    (ipr_fastfail ? 30 * HZ : 2 * 60 * HZ)
 #define IPR_ABBREV_SHUTDOWN_TIMEOUT            (10 * HZ)
+#define IPR_DUAL_IOA_ABBR_SHUTDOWN_TO  (2 * 60 * HZ)
 #define IPR_DEVICE_RESET_TIMEOUT               (ipr_fastfail ? 10 * HZ : 30 * HZ)
 #define IPR_CANCEL_ALL_TIMEOUT         (ipr_fastfail ? 10 * HZ : 30 * HZ)
 #define IPR_ABORT_TASK_TIMEOUT         (ipr_fastfail ? 10 * HZ : 30 * HZ)
 #define IPR_WAIT_FOR_RESET_TIMEOUT             (2 * HZ)
 #define IPR_CHECK_FOR_RESET_TIMEOUT            (HZ / 10)
 #define IPR_WAIT_FOR_BIST_TIMEOUT              (2 * HZ)
+#define IPR_PCI_RESET_TIMEOUT                  (HZ / 2)
 #define IPR_DUMP_TIMEOUT                       (15 * HZ)
 
 /*
@@ -602,6 +606,12 @@ struct ipr_mode_page28 {
        struct ipr_dev_bus_entry bus[0];
 }__attribute__((packed));
 
+struct ipr_mode_page24 {
+       struct ipr_mode_page_hdr hdr;
+       u8 flags;
+#define IPR_ENABLE_DUAL_IOA_AF 0x80
+}__attribute__((packed));
+
 struct ipr_ioa_vpd {
        struct ipr_std_inq_data std_inq_data;
        u8 ascii_part_num[12];
@@ -624,6 +634,19 @@ struct ipr_inquiry_page3 {
        u8 patch_number[4];
 }__attribute__((packed));
 
+struct ipr_inquiry_cap {
+       u8 peri_qual_dev_type;
+       u8 page_code;
+       u8 reserved1;
+       u8 page_length;
+       u8 ascii_len;
+       u8 reserved2;
+       u8 sis_version[2];
+       u8 cap;
+#define IPR_CAP_DUAL_IOA_RAID          0x80
+       u8 reserved3[15];
+}__attribute__((packed));
+
 #define IPR_INQUIRY_PAGE0_ENTRIES 20
 struct ipr_inquiry_page0 {
        u8 peri_qual_dev_type;
@@ -962,6 +985,7 @@ struct ipr_misc_cbs {
        struct ipr_ioa_vpd ioa_vpd;
        struct ipr_inquiry_page0 page0_data;
        struct ipr_inquiry_page3 page3_data;
+       struct ipr_inquiry_cap cap;
        struct ipr_mode_pages mode_pages;
        struct ipr_supported_device supp_dev;
 };
@@ -1068,6 +1092,10 @@ struct ipr_ioa_cfg {
        u8 allow_cmds:1;
        u8 allow_ml_add_del:1;
        u8 needs_hard_reset:1;
+       u8 dual_raid:1;
+       u8 needs_warm_reset:1;
+
+       u8 revid;
 
        enum ipr_cache_state cache_state;
        u16 type; /* CCIN of the card */
@@ -1161,6 +1189,7 @@ struct ipr_ioa_cfg {
        struct pci_pool *ipr_cmd_pool;
 
        struct ipr_cmnd *reset_cmd;
+       int (*reset) (struct ipr_cmnd *);
 
        struct ata_host ata_host;
        char ipr_cmd_label[8];
index 897a5e2c55e438a806c6e93072547a7386922832..b4b52694497c16312d87ed2d2203e55ad630ff07 100644 (file)
@@ -23,6 +23,8 @@
  *
  */
 
+#include <linux/kthread.h>
+
 #include "sas_internal.h"
 
 #include <scsi/scsi_host.h>
@@ -184,7 +186,7 @@ static int sas_queue_up(struct sas_task *task)
        list_add_tail(&task->list, &core->task_queue);
        core->task_queue_size += 1;
        spin_unlock_irqrestore(&core->task_queue_lock, flags);
-       up(&core->queue_thread_sema);
+       wake_up_process(core->queue_thread);
 
        return 0;
 }
@@ -819,7 +821,7 @@ static void sas_queue(struct sas_ha_struct *sas_ha)
        struct sas_internal *i = to_sas_internal(core->shost->transportt);
 
        spin_lock_irqsave(&core->task_queue_lock, flags);
-       while (!core->queue_thread_kill &&
+       while (!kthread_should_stop() &&
               !list_empty(&core->task_queue)) {
 
                can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
@@ -858,8 +860,6 @@ static void sas_queue(struct sas_ha_struct *sas_ha)
        spin_unlock_irqrestore(&core->task_queue_lock, flags);
 }
 
-static DECLARE_COMPLETION(queue_th_comp);
-
 /**
  * sas_queue_thread -- The Task Collector thread
  * @_sas_ha: pointer to struct sas_ha
@@ -867,40 +867,33 @@ static DECLARE_COMPLETION(queue_th_comp);
 static int sas_queue_thread(void *_sas_ha)
 {
        struct sas_ha_struct *sas_ha = _sas_ha;
-       struct scsi_core *core = &sas_ha->core;
 
-       daemonize("sas_queue_%d", core->shost->host_no);
        current->flags |= PF_NOFREEZE;
 
-       complete(&queue_th_comp);
-
        while (1) {
-               down_interruptible(&core->queue_thread_sema);
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
                sas_queue(sas_ha);
-               if (core->queue_thread_kill)
+               if (kthread_should_stop())
                        break;
        }
 
-       complete(&queue_th_comp);
-
        return 0;
 }
 
 int sas_init_queue(struct sas_ha_struct *sas_ha)
 {
-       int res;
        struct scsi_core *core = &sas_ha->core;
 
        spin_lock_init(&core->task_queue_lock);
        core->task_queue_size = 0;
        INIT_LIST_HEAD(&core->task_queue);
-       init_MUTEX_LOCKED(&core->queue_thread_sema);
 
-       res = kernel_thread(sas_queue_thread, sas_ha, 0);
-       if (res >= 0)
-               wait_for_completion(&queue_th_comp);
-
-       return res < 0 ? res : 0;
+       core->queue_thread = kthread_run(sas_queue_thread, sas_ha,
+                                        "sas_queue_%d", core->shost->host_no);
+       if (IS_ERR(core->queue_thread))
+               return PTR_ERR(core->queue_thread);
+       return 0;
 }
 
 void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
@@ -909,10 +902,7 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
        struct scsi_core *core = &sas_ha->core;
        struct sas_task *task, *n;
 
-       init_completion(&queue_th_comp);
-       core->queue_thread_kill = 1;
-       up(&core->queue_thread_sema);
-       wait_for_completion(&queue_th_comp);
+       kthread_stop(core->queue_thread);
 
        if (!list_empty(&core->task_queue))
                SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n",
index a7de0bca5bdd31efd19b2683e95feaa39e7aadcd..82e8f90c46178472c3cb24243250dea996cdcd46 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -27,10 +27,6 @@ struct lpfc_sli2_slim;
                                           requests */
 #define LPFC_MAX_NS_RETRY      3       /* Number of retry attempts to contact
                                           the NameServer  before giving up. */
-#define LPFC_DFT_HBA_Q_DEPTH   2048    /* max cmds per hba */
-#define LPFC_LC_HBA_Q_DEPTH    1024    /* max cmds per low cost hba */
-#define LPFC_LP101_HBA_Q_DEPTH 128     /* max cmds per low cost hba */
-
 #define LPFC_CMD_PER_LUN       3       /* max outstanding cmds per lun */
 #define LPFC_SG_SEG_CNT                64      /* sg element count per scsi cmnd */
 #define LPFC_IOCB_LIST_CNT     2250    /* list of IOCBs for fast-path usage. */
@@ -244,28 +240,23 @@ struct lpfc_hba {
 #define FC_FABRIC               0x100  /* We are fabric attached */
 #define FC_ESTABLISH_LINK       0x200  /* Reestablish Link */
 #define FC_RSCN_DISCOVERY       0x400  /* Authenticate all devices after RSCN*/
+#define FC_BLOCK_MGMT_IO        0x800   /* Don't allow mgmt mbx or iocb cmds */
 #define FC_LOADING             0x1000  /* HBA in process of loading drvr */
 #define FC_UNLOADING           0x2000  /* HBA in process of unloading drvr */
 #define FC_SCSI_SCAN_TMO        0x4000 /* scsi scan timer running */
 #define FC_ABORT_DISCOVERY      0x8000 /* we want to abort discovery */
 #define FC_NDISC_ACTIVE         0x10000        /* NPort discovery active */
 #define FC_BYPASSED_MODE        0x20000        /* NPort is in bypassed mode */
+#define FC_LOOPBACK_MODE        0x40000        /* NPort is in Loopback mode */
+                                       /* This flag is set while issuing */
+                                       /* INIT_LINK mailbox command */
+#define FC_IGNORE_ERATT         0x80000        /* intr handler should ignore ERATT */
 
        uint32_t fc_topology;   /* link topology, from LINK INIT */
 
        struct lpfc_stats fc_stat;
 
-       /* These are the head/tail pointers for the bind, plogi, adisc, unmap,
-        *  and map lists.  Their counters are immediately following.
-        */
-       struct list_head fc_plogi_list;
-       struct list_head fc_adisc_list;
-       struct list_head fc_reglogin_list;
-       struct list_head fc_prli_list;
-       struct list_head fc_nlpunmap_list;
-       struct list_head fc_nlpmap_list;
-       struct list_head fc_npr_list;
-       struct list_head fc_unused_list;
+       struct list_head fc_nodes;
 
        /* Keep counters for the number of entries in each list. */
        uint16_t fc_plogi_cnt;
@@ -387,13 +378,17 @@ struct lpfc_hba {
 
        mempool_t *mbox_mem_pool;
        mempool_t *nlp_mem_pool;
-       struct list_head freebufList;
-       struct list_head ctrspbuflist;
-       struct list_head rnidrspbuflist;
 
        struct fc_host_statistics link_stats;
 };
 
+static inline void
+lpfc_set_loopback_flag(struct lpfc_hba *phba) {
+       if (phba->cfg_topology == FLAGS_LOCAL_LB)
+               phba->fc_flag |= FC_LOOPBACK_MODE;
+       else
+               phba->fc_flag &= ~FC_LOOPBACK_MODE;
+}
 
 struct rnidrsp {
        void *buf;
index f247e786af99487cda664cae44193adec19af7b3..95fe77e816f80a756b937f6012b8ab989e14ac74 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -20,6 +20,7 @@
  *******************************************************************/
 
 #include <linux/ctype.h>
+#include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
@@ -213,6 +214,7 @@ lpfc_issue_lip(struct Scsi_Host *host)
        int mbxstatus = MBXERR_ERROR;
 
        if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+           (phba->fc_flag & FC_BLOCK_MGMT_IO) ||
            (phba->hba_state != LPFC_HBA_READY))
                return -EPERM;
 
@@ -235,6 +237,7 @@ lpfc_issue_lip(struct Scsi_Host *host)
                                                     phba->fc_ratov * 2);
        }
 
+       lpfc_set_loopback_flag(phba);
        if (mbxstatus == MBX_TIMEOUT)
                pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
        else
@@ -247,19 +250,62 @@ lpfc_issue_lip(struct Scsi_Host *host)
 }
 
 static int
-lpfc_selective_reset(struct lpfc_hba *phba)
+lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
 {
        struct completion online_compl;
+       struct lpfc_sli_ring *pring;
+       struct lpfc_sli *psli;
        int status = 0;
+       int cnt = 0;
+       int i;
 
        init_completion(&online_compl);
        lpfc_workq_post_event(phba, &status, &online_compl,
-                             LPFC_EVT_OFFLINE);
+                             LPFC_EVT_OFFLINE_PREP);
+       wait_for_completion(&online_compl);
+
+       if (status != 0)
+               return -EIO;
+
+       psli = &phba->sli;
+
+       for (i = 0; i < psli->num_rings; i++) {
+               pring = &psli->ring[i];
+               /* The linkdown event takes 30 seconds to timeout. */
+               while (pring->txcmplq_cnt) {
+                       msleep(10);
+                       if (cnt++ > 3000) {
+                               lpfc_printf_log(phba,
+                                       KERN_WARNING, LOG_INIT,
+                                       "%d:0466 Outstanding IO when "
+                                       "bringing Adapter offline\n",
+                                       phba->brd_no);
+                               break;
+                       }
+               }
+       }
+
+       init_completion(&online_compl);
+       lpfc_workq_post_event(phba, &status, &online_compl, type);
        wait_for_completion(&online_compl);
 
        if (status != 0)
                return -EIO;
 
+       return 0;
+}
+
+static int
+lpfc_selective_reset(struct lpfc_hba *phba)
+{
+       struct completion online_compl;
+       int status = 0;
+
+       status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
+
+       if (status != 0)
+               return status;
+
        init_completion(&online_compl);
        lpfc_workq_post_event(phba, &status, &online_compl,
                              LPFC_EVT_ONLINE);
@@ -324,23 +370,19 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
 
        init_completion(&online_compl);
 
-       if(strncmp(buf, "online", sizeof("online") - 1) == 0)
+       if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
                lpfc_workq_post_event(phba, &status, &online_compl,
                                      LPFC_EVT_ONLINE);
-       else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
-               lpfc_workq_post_event(phba, &status, &online_compl,
-                                     LPFC_EVT_OFFLINE);
+               wait_for_completion(&online_compl);
+       } else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
+               status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
        else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0)
-               lpfc_workq_post_event(phba, &status, &online_compl,
-                                     LPFC_EVT_WARM_START);
-       else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
-               lpfc_workq_post_event(phba, &status, &online_compl,
-                                     LPFC_EVT_KILL);
+               status = lpfc_do_offline(phba, LPFC_EVT_WARM_START);
+       else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
+               status = lpfc_do_offline(phba, LPFC_EVT_KILL);
        else
                return -EINVAL;
 
-       wait_for_completion(&online_compl);
-
        if (!status)
                return strlen(buf);
        else
@@ -645,9 +687,7 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
        dev_printk(KERN_NOTICE, &phba->pcidev->dev,
                   "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
 
-       init_completion(&online_compl);
-       lpfc_workq_post_event(phba, &stat1, &online_compl, LPFC_EVT_OFFLINE);
-       wait_for_completion(&online_compl);
+       stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
        if (stat1)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                        "%d:0463 lpfc_soft_wwpn attribute set failed to reinit "
@@ -789,6 +829,18 @@ lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
        return -EINVAL;
 }
 
+static void
+lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
+{
+       struct lpfc_nodelist  *ndlp;
+
+       spin_lock_irq(phba->host->host_lock);
+       list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp)
+               if (ndlp->rport)
+                       ndlp->rport->dev_loss_tmo = phba->cfg_devloss_tmo;
+       spin_unlock_irq(phba->host->host_lock);
+}
+
 static int
 lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
 {
@@ -804,6 +856,7 @@ lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
        if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
                phba->cfg_nodev_tmo = val;
                phba->cfg_devloss_tmo = val;
+               lpfc_update_rport_devloss_tmo(phba);
                return 0;
        }
 
@@ -839,6 +892,7 @@ lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
                phba->cfg_nodev_tmo = val;
                phba->cfg_devloss_tmo = val;
                phba->dev_loss_tmo_changed = 1;
+               lpfc_update_rport_devloss_tmo(phba);
                return 0;
        }
 
@@ -931,9 +985,10 @@ LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
 #       1  = 1 Gigabaud
 #       2  = 2 Gigabaud
 #       4  = 4 Gigabaud
-# Value range is [0,4]. Default value is 0.
+#       8  = 8 Gigabaud
+# Value range is [0,8]. Default value is 0.
 */
-LPFC_ATTR_R(link_speed, 0, 0, 4, "Select link speed");
+LPFC_ATTR_R(link_speed, 0, 0, 8, "Select link speed");
 
 /*
 # lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
@@ -958,7 +1013,7 @@ LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support");
 /*
 # lpfc_cr_delay & lpfc_cr_count: Default values for I/O colaesing
 # cr_delay (msec) or cr_count outstanding commands. cr_delay can take
-# value [0,63]. cr_count can take value [0,255]. Default value of cr_delay
+# value [0,63]. cr_count can take value [1,255]. Default value of cr_delay
 # is 0. Default value of cr_count is 1. The cr_count feature is disabled if
 # cr_delay is set to 0.
 */
@@ -1227,11 +1282,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
        struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
        int rc;
 
-       if (off > sizeof(MAILBOX_t))
+       if (off > MAILBOX_CMD_SIZE)
                return -ERANGE;
 
-       if ((count + off) > sizeof(MAILBOX_t))
-               count = sizeof(MAILBOX_t) - off;
+       if ((count + off) > MAILBOX_CMD_SIZE)
+               count = MAILBOX_CMD_SIZE - off;
 
        if (off % 4 ||  count % 4 || (unsigned long)buf % 4)
                return -EINVAL;
@@ -1307,6 +1362,12 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
                        return -EPERM;
                }
 
+               if (phba->fc_flag & FC_BLOCK_MGMT_IO) {
+                       sysfs_mbox_idle(phba);
+                       spin_unlock_irq(host->host_lock);
+                       return  -EAGAIN;
+               }
+
                if ((phba->fc_flag & FC_OFFLINE_MODE) ||
                    (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){
 
@@ -1326,6 +1387,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
                }
 
                if (rc != MBX_SUCCESS) {
+                       if (rc == MBX_TIMEOUT) {
+                               phba->sysfs_mbox.mbox->mbox_cmpl =
+                                       lpfc_sli_def_mbox_cmpl;
+                               phba->sysfs_mbox.mbox = NULL;
+                       }
                        sysfs_mbox_idle(phba);
                        spin_unlock_irq(host->host_lock);
                        return  (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
@@ -1344,7 +1410,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
 
        phba->sysfs_mbox.offset = off + count;
 
-       if (phba->sysfs_mbox.offset == sizeof(MAILBOX_t))
+       if (phba->sysfs_mbox.offset == MAILBOX_CMD_SIZE)
                sysfs_mbox_idle(phba);
 
        spin_unlock_irq(phba->host->host_lock);
@@ -1358,7 +1424,7 @@ static struct bin_attribute sysfs_mbox_attr = {
                .mode = S_IRUSR | S_IWUSR,
                .owner = THIS_MODULE,
        },
-       .size = sizeof(MAILBOX_t),
+       .size = MAILBOX_CMD_SIZE,
        .read = sysfs_mbox_read,
        .write = sysfs_mbox_write,
 };
@@ -1494,6 +1560,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
                        case LA_4GHZ_LINK:
                                fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
                        break;
+                       case LA_8GHZ_LINK:
+                               fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
+                       break;
                        default:
                                fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
                        break;
@@ -1546,6 +1615,9 @@ lpfc_get_stats(struct Scsi_Host *shost)
        unsigned long seconds;
        int rc = 0;
 
+       if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+               return NULL;
+
        pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!pmboxq)
                return NULL;
@@ -1631,6 +1703,8 @@ lpfc_get_stats(struct Scsi_Host *shost)
        else
                hs->seconds_since_last_reset = seconds - psli->stats_start;
 
+       mempool_free(pmboxq, phba->mbox_mem_pool);
+
        return hs;
 }
 
@@ -1644,6 +1718,9 @@ lpfc_reset_stats(struct Scsi_Host *shost)
        MAILBOX_t *pmb;
        int rc = 0;
 
+       if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+               return;
+
        pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!pmboxq)
                return;
@@ -1699,6 +1776,8 @@ lpfc_reset_stats(struct Scsi_Host *shost)
 
        psli->stats_start = get_seconds();
 
+       mempool_free(pmboxq, phba->mbox_mem_pool);
+
        return;
 }
 
@@ -1706,67 +1785,51 @@ lpfc_reset_stats(struct Scsi_Host *shost)
  * The LPFC driver treats linkdown handling as target loss events so there
  * are no sysfs handlers for link_down_tmo.
  */
-static void
-lpfc_get_starget_port_id(struct scsi_target *starget)
+
+static struct lpfc_nodelist *
+lpfc_get_node_by_target(struct scsi_target *starget)
 {
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
        struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
-       uint32_t did = -1;
-       struct lpfc_nodelist *ndlp = NULL;
+       struct lpfc_nodelist *ndlp;
 
        spin_lock_irq(shost->host_lock);
-       /* Search the mapped list for this target ID */
-       list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-               if (starget->id == ndlp->nlp_sid) {
-                       did = ndlp->nlp_DID;
-                       break;
+       /* Search for this, mapped, target ID */
+       list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
+                   starget->id == ndlp->nlp_sid) {
+                       spin_unlock_irq(shost->host_lock);
+                       return ndlp;
                }
        }
        spin_unlock_irq(shost->host_lock);
+       return NULL;
+}
+
+static void
+lpfc_get_starget_port_id(struct scsi_target *starget)
+{
+       struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
 
-       fc_starget_port_id(starget) = did;
+       fc_starget_port_id(starget) = ndlp ? ndlp->nlp_DID : -1;
 }
 
 static void
 lpfc_get_starget_node_name(struct scsi_target *starget)
 {
-       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-       struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
-       u64 node_name = 0;
-       struct lpfc_nodelist *ndlp = NULL;
-
-       spin_lock_irq(shost->host_lock);
-       /* Search the mapped list for this target ID */
-       list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-               if (starget->id == ndlp->nlp_sid) {
-                       node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn);
-                       break;
-               }
-       }
-       spin_unlock_irq(shost->host_lock);
+       struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
 
-       fc_starget_node_name(starget) = node_name;
+       fc_starget_node_name(starget) =
+               ndlp ? wwn_to_u64(ndlp->nlp_nodename.u.wwn) : 0;
 }
 
 static void
 lpfc_get_starget_port_name(struct scsi_target *starget)
 {
-       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-       struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
-       u64 port_name = 0;
-       struct lpfc_nodelist *ndlp = NULL;
-
-       spin_lock_irq(shost->host_lock);
-       /* Search the mapped list for this target ID */
-       list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-               if (starget->id == ndlp->nlp_sid) {
-                       port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn);
-                       break;
-               }
-       }
-       spin_unlock_irq(shost->host_lock);
+       struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
 
-       fc_starget_port_name(starget) = port_name;
+       fc_starget_port_name(starget) =
+               ndlp ? wwn_to_u64(ndlp->nlp_portname.u.wwn) : 0;
 }
 
 static void
@@ -1895,25 +1958,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
                        sizeof(struct fcp_rsp) +
                        (phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
 
-       switch (phba->pcidev->device) {
-       case PCI_DEVICE_ID_LP101:
-       case PCI_DEVICE_ID_BSMB:
-       case PCI_DEVICE_ID_ZSMB:
-               phba->cfg_hba_queue_depth = LPFC_LP101_HBA_Q_DEPTH;
-               break;
-       case PCI_DEVICE_ID_RFLY:
-       case PCI_DEVICE_ID_PFLY:
-       case PCI_DEVICE_ID_BMID:
-       case PCI_DEVICE_ID_ZMID:
-       case PCI_DEVICE_ID_TFLY:
-               phba->cfg_hba_queue_depth = LPFC_LC_HBA_Q_DEPTH;
-               break;
-       default:
-               phba->cfg_hba_queue_depth = LPFC_DFT_HBA_Q_DEPTH;
-       }
 
-       if (phba->cfg_hba_queue_depth > lpfc_hba_queue_depth)
-               lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
+       lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
 
        return;
 }
index 1251788ce2a36efa58b61c096c18b7350b8b5a66..b8c2a8862d8cbc8dda943a54f0153bfb19ed3f22 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -18,6 +18,8 @@
  * included with this package.                                     *
  *******************************************************************/
 
+typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
+
 struct fc_rport;
 void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
 void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -43,20 +45,24 @@ void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_nlp_list(struct lpfc_hba *, struct lpfc_nodelist *, int);
+void lpfc_dequeue_node(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_nlp_set_state(struct lpfc_hba *, struct lpfc_nodelist *, int);
+void lpfc_drop_node(struct lpfc_hba *, struct lpfc_nodelist *);
 void lpfc_set_disctmo(struct lpfc_hba *);
 int lpfc_can_disctmo(struct lpfc_hba *);
 int lpfc_unreg_rpi(struct lpfc_hba *, struct lpfc_nodelist *);
 int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
                    struct lpfc_iocbq *, struct lpfc_nodelist *);
-int lpfc_nlp_remove(struct lpfc_hba *, struct lpfc_nodelist *);
 void lpfc_nlp_init(struct lpfc_hba *, struct lpfc_nodelist *, uint32_t);
+struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
+int  lpfc_nlp_put(struct lpfc_nodelist *);
 struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_hba *, uint32_t);
 void lpfc_disc_list_loopmap(struct lpfc_hba *);
 void lpfc_disc_start(struct lpfc_hba *);
 void lpfc_disc_flush_list(struct lpfc_hba *);
 void lpfc_disc_timeout(unsigned long);
 
+struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
 struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
 
 int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
@@ -66,8 +72,7 @@ int lpfc_disc_state_machine(struct lpfc_hba *, struct lpfc_nodelist *, void *,
 
 int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *,
                     struct serv_parm *, uint32_t);
-int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp,
-                       int);
+int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp);
 int lpfc_els_abort_flogi(struct lpfc_hba *);
 int lpfc_initial_flogi(struct lpfc_hba *);
 int lpfc_issue_els_plogi(struct lpfc_hba *, uint32_t, uint8_t);
@@ -113,7 +118,10 @@ void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
 int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
 void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
 int lpfc_online(struct lpfc_hba *);
-int lpfc_offline(struct lpfc_hba *);
+void lpfc_block_mgmt_io(struct lpfc_hba *);
+void lpfc_unblock_mgmt_io(struct lpfc_hba *);
+void lpfc_offline_prep(struct lpfc_hba *);
+void lpfc_offline(struct lpfc_hba *);
 
 int lpfc_sli_setup(struct lpfc_hba *);
 int lpfc_sli_queue_setup(struct lpfc_hba *);
@@ -162,8 +170,8 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
 struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
                                             struct lpfc_sli_ring *,
                                             dma_addr_t);
-int lpfc_sli_issue_abort_iotag32(struct lpfc_hba *, struct lpfc_sli_ring *,
-                                struct lpfc_iocbq *);
+int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
+                              struct lpfc_iocbq *);
 int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
                          uint64_t, lpfc_ctx_cmd);
 int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
@@ -172,9 +180,8 @@ int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
 void lpfc_mbox_timeout(unsigned long);
 void lpfc_mbox_timeout_handler(struct lpfc_hba *);
 
-struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t, uint32_t);
-struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, uint32_t,
-                                       struct lpfc_name *);
+struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t);
+struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, struct lpfc_name *);
 
 int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
                         uint32_t timeout);
@@ -193,6 +200,9 @@ void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
 
 /* Function prototypes. */
 const char* lpfc_info(struct Scsi_Host *);
+void lpfc_scan_start(struct Scsi_Host *);
+int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
+
 void lpfc_get_cfgparam(struct lpfc_hba *);
 int lpfc_alloc_sysfs_attr(struct lpfc_hba *);
 void lpfc_free_sysfs_attr(struct lpfc_hba *);
index a51a41b7f15d55566277619d8be5e64d06b31324..34a9e3bb2614058c9ca827be246b65539564e0cb 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -334,21 +334,22 @@ lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
 
        lpfc_set_disctmo(phba);
 
-       Cnt = Size  > FCELSSIZE ? FCELSSIZE : Size;
 
        list_add_tail(&head, &mp->list);
        list_for_each_entry_safe(mp, next_mp, &head, list) {
                mlast = mp;
 
+               Cnt = Size  > FCELSSIZE ? FCELSSIZE : Size;
+
                Size -= Cnt;
 
-               if (!ctptr)
+               if (!ctptr) {
                        ctptr = (uint32_t *) mlast->virt;
-               else
+               else
                        Cnt -= 16;      /* subtract length of CT header */
 
                /* Loop through entire NameServer list of DIDs */
-               while (Cnt) {
+               while (Cnt >= sizeof (uint32_t)) {
 
                        /* Get next DID from NameServer List */
                        CTentry = *ctptr++;
@@ -442,10 +443,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
                        phba->fc_ns_retry++;
                        /* CT command is being retried */
-                       ndlp =
-                           lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
-                                             NameServer_DID);
-                       if (ndlp) {
+                       ndlp = lpfc_findnode_did(phba, NameServer_DID);
+                       if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
                                if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) ==
                                    0) {
                                        goto out;
@@ -729,7 +728,7 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba * phba,
        uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
        uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
 
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
+       ndlp = lpfc_findnode_did(phba, FDMI_DID);
        if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
                /* FDMI rsp failed */
                lpfc_printf_log(phba,
@@ -1039,6 +1038,9 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
                                case LA_4GHZ_LINK:
                                        ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
                                break;
+                               case LA_8GHZ_LINK:
+                                       ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
+                               break;
                                default:
                                        ae->un.PortSpeed =
                                                HBA_PORTSPEED_UNKNOWN;
@@ -1161,7 +1163,7 @@ lpfc_fdmi_tmo_handler(struct lpfc_hba *phba)
 {
        struct lpfc_nodelist *ndlp;
 
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
+       ndlp = lpfc_findnode_did(phba, FDMI_DID);
        if (ndlp) {
                if (init_utsname()->nodename[0] != '\0') {
                        lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
index 9766f909c9c69e02a912eb90686e62d3fdbd4bbf..498059f3f7f43583727fd98d7ea7120a08e686d2 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -31,6 +31,7 @@
 /* worker thread events */
 enum lpfc_work_type {
        LPFC_EVT_ONLINE,
+       LPFC_EVT_OFFLINE_PREP,
        LPFC_EVT_OFFLINE,
        LPFC_EVT_WARM_START,
        LPFC_EVT_KILL,
@@ -68,7 +69,6 @@ struct lpfc_nodelist {
        uint16_t        nlp_maxframe;           /* Max RCV frame size */
        uint8_t         nlp_class_sup;          /* Supported Classes */
        uint8_t         nlp_retry;              /* used for ELS retries */
-       uint8_t         nlp_disc_refcnt;        /* used for DSM */
        uint8_t         nlp_fcp_info;           /* class info, bits 0-3 */
 #define NLP_FCP_2_DEVICE   0x10                        /* FCP-2 device */
 
@@ -79,20 +79,10 @@ struct lpfc_nodelist {
        struct lpfc_work_evt els_retry_evt;
        unsigned long last_ramp_up_time;        /* jiffy of last ramp up */
        unsigned long last_q_full_time;         /* jiffy of last queue full */
+       struct kref     kref;
 };
 
 /* Defines for nlp_flag (uint32) */
-#define NLP_NO_LIST        0x0         /* Indicates immediately free node */
-#define NLP_UNUSED_LIST    0x1         /* Flg to indicate node will be freed */
-#define NLP_PLOGI_LIST     0x2         /* Flg to indicate sent PLOGI */
-#define NLP_ADISC_LIST     0x3         /* Flg to indicate sent ADISC */
-#define NLP_REGLOGIN_LIST  0x4         /* Flg to indicate sent REG_LOGIN */
-#define NLP_PRLI_LIST      0x5         /* Flg to indicate sent PRLI */
-#define NLP_UNMAPPED_LIST  0x6         /* Node is now unmapped */
-#define NLP_MAPPED_LIST    0x7         /* Node is now mapped */
-#define NLP_NPR_LIST       0x8         /* Node is in NPort Recovery state */
-#define NLP_JUST_DQ        0x9         /* just deque ndlp in lpfc_nlp_list */
-#define NLP_LIST_MASK      0xf         /* mask to see what list node is on */
 #define NLP_PLOGI_SND      0x20                /* sent PLOGI request for this entry */
 #define NLP_PRLI_SND       0x40                /* sent PRLI request for this entry */
 #define NLP_ADISC_SND      0x80                /* sent ADISC request for this entry */
@@ -108,20 +98,8 @@ struct lpfc_nodelist {
                                           ACC */
 #define NLP_NPR_ADISC      0x2000000   /* Issue ADISC when dq'ed from
                                           NPR list */
-#define NLP_DELAY_REMOVE   0x4000000   /* Defer removal till end of DSM */
 #define NLP_NODEV_REMOVE   0x8000000   /* Defer removal till discovery ends */
 
-/* Defines for list searchs */
-#define NLP_SEARCH_MAPPED    0x1       /* search mapped */
-#define NLP_SEARCH_UNMAPPED  0x2       /* search unmapped */
-#define NLP_SEARCH_PLOGI     0x4       /* search plogi */
-#define NLP_SEARCH_ADISC     0x8       /* search adisc */
-#define NLP_SEARCH_REGLOGIN  0x10      /* search reglogin */
-#define NLP_SEARCH_PRLI      0x20      /* search prli */
-#define NLP_SEARCH_NPR       0x40      /* search npr */
-#define NLP_SEARCH_UNUSED    0x80      /* search mapped */
-#define NLP_SEARCH_ALL       0xff      /* search all lists */
-
 /* There are 4 different double linked lists nodelist entries can reside on.
  * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
  * when Link Up discovery or Registered State Change Notification (RSCN)
index a5f33a0dd4e7b79fb204cff5553d04c71c76177e..638b3cd677bdd30d68e82523901b50b23ada97b3 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -182,6 +182,7 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
                icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
                icmd->un.elsreq64.remoteID = did;       /* DID */
                icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
+               icmd->ulpTimeout = phba->fc_ratov * 2;
        } else {
                icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64);
                icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
@@ -208,9 +209,9 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
        }
 
        /* Save for completion so we can release these resources */
-       elsiocb->context1 = (uint8_t *) ndlp;
-       elsiocb->context2 = (uint8_t *) pcmd;
-       elsiocb->context3 = (uint8_t *) pbuflist;
+       elsiocb->context1 = lpfc_nlp_get(ndlp);
+       elsiocb->context2 = pcmd;
+       elsiocb->context3 = pbuflist;
        elsiocb->retry = retry;
        elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
 
@@ -222,16 +223,16 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
                /* Xmit ELS command <elsCmd> to remote NPORT <did> */
                lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                                "%d:0116 Xmit ELS command x%x to remote "
-                               "NPORT x%x Data: x%x x%x\n",
+                               "NPORT x%x I/O tag: x%x, HBA state: x%x\n",
                                phba->brd_no, elscmd,
-                               did, icmd->ulpIoTag, phba->hba_state);
+                               did, elsiocb->iotag, phba->hba_state);
        } else {
                /* Xmit ELS response <elsCmd> to remote NPORT <did> */
                lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                                "%d:0117 Xmit ELS response x%x to remote "
-                               "NPORT x%x Data: x%x x%x\n",
+                               "NPORT x%x I/O tag: x%x, size: x%x\n",
                                phba->brd_no, elscmd,
-                               ndlp->nlp_DID, icmd->ulpIoTag, cmdSize);
+                               ndlp->nlp_DID, elsiocb->iotag, cmdSize);
        }
 
        return elsiocb;
@@ -304,7 +305,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
                goto fail_free_mbox;
 
        mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
-       mbox->context2 = ndlp;
+       mbox->context2 = lpfc_nlp_get(ndlp);
 
        rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
        if (rc == MBX_NOT_FINISHED)
@@ -313,6 +314,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
        return 0;
 
  fail_issue_reg_login:
+       lpfc_nlp_put(ndlp);
        mp = (struct lpfc_dmabuf *) mbox->context1;
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
@@ -368,9 +370,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
                        mempool_free(mbox, phba->mbox_mem_pool);
                        goto fail;
                }
-               mempool_free(ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
 
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, PT2PT_RemoteID);
+               ndlp = lpfc_findnode_did(phba, PT2PT_RemoteID);
                if (!ndlp) {
                        /*
                         * Cannot find existing Fabric ndlp, so allocate a
@@ -387,12 +389,11 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
                                sizeof(struct lpfc_name));
                memcpy(&ndlp->nlp_nodename, &sp->nodeName,
                                sizeof(struct lpfc_name));
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
        } else {
                /* This side will wait for the PLOGI */
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
        }
 
        spin_lock_irq(phba->host->host_lock);
@@ -407,8 +408,8 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
 }
 
 static void
-lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
-                   struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                   struct lpfc_iocbq *rspiocb)
 {
        IOCB_t *irsp = &rspiocb->iocb;
        struct lpfc_nodelist *ndlp = cmdiocb->context1;
@@ -418,7 +419,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
 
        /* Check to see if link went down during discovery */
        if (lpfc_els_chk_latt(phba)) {
-               lpfc_nlp_remove(phba, ndlp);
+               lpfc_nlp_put(ndlp);
                goto out;
        }
 
@@ -433,13 +434,12 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
                phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
                spin_unlock_irq(phba->host->host_lock);
 
-               /* If private loop, then allow max outstandting els to be
+               /* If private loop, then allow max outstanding els to be
                 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
                 * alpa map would take too long otherwise.
                 */
                if (phba->alpa_map[0] == 0) {
-                       phba->cfg_discovery_threads =
-                           LPFC_MAX_DISC_THREADS;
+                       phba->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
                }
 
                /* FLOGI failure */
@@ -484,7 +484,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
        }
 
 flogifail:
-       lpfc_nlp_remove(phba, ndlp);
+       lpfc_nlp_put(ndlp);
 
        if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
            (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED &&
@@ -582,24 +582,8 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba)
                icmd = &iocb->iocb;
                if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) {
                        ndlp = (struct lpfc_nodelist *)(iocb->context1);
-                       if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
-                               list_del(&iocb->list);
-                               pring->txcmplq_cnt--;
-
-                               if ((icmd->un.elsreq64.bdl.ulpIoTag32)) {
-                                       lpfc_sli_issue_abort_iotag32
-                                               (phba, pring, iocb);
-                               }
-                               if (iocb->iocb_cmpl) {
-                                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-                                       icmd->un.ulpWord[4] =
-                                           IOERR_SLI_ABORTED;
-                                       spin_unlock_irq(phba->host->host_lock);
-                                       (iocb->iocb_cmpl) (phba, iocb, iocb);
-                                       spin_lock_irq(phba->host->host_lock);
-                               } else
-                                       lpfc_sli_release_iocbq(phba, iocb);
-                       }
+                       if (ndlp && (ndlp->nlp_DID == Fabric_DID))
+                               lpfc_sli_issue_abort_iotag(phba, pring, iocb);
                }
        }
        spin_unlock_irq(phba->host->host_lock);
@@ -608,12 +592,12 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba)
 }
 
 int
-lpfc_initial_flogi(struct lpfc_hba * phba)
+lpfc_initial_flogi(struct lpfc_hba *phba)
 {
        struct lpfc_nodelist *ndlp;
 
        /* First look for the Fabric ndlp */
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, Fabric_DID);
+       ndlp = lpfc_findnode_did(phba, Fabric_DID);
        if (!ndlp) {
                /* Cannot find existing Fabric ndlp, so allocate a new one */
                ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
@@ -621,10 +605,10 @@ lpfc_initial_flogi(struct lpfc_hba * phba)
                        return 0;
                lpfc_nlp_init(phba, ndlp, Fabric_DID);
        } else {
-               lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ);
+               lpfc_dequeue_node(phba, ndlp);
        }
        if (lpfc_issue_els_flogi(phba, ndlp, 0)) {
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
        }
        return 1;
 }
@@ -653,7 +637,7 @@ lpfc_more_plogi(struct lpfc_hba * phba)
 }
 
 static struct lpfc_nodelist *
-lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
+lpfc_plogi_confirm_nport(struct lpfc_hba *phba, struct lpfc_dmabuf *prsp,
                         struct lpfc_nodelist *ndlp)
 {
        struct lpfc_nodelist *new_ndlp;
@@ -670,12 +654,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
 
        lp = (uint32_t *) prsp->virt;
        sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
-       memset(name, 0, sizeof (struct lpfc_name));
+       memset(name, 0, sizeof(struct lpfc_name));
 
-       /* Now we to find out if the NPort we are logging into, matches the WWPN
+       /* Now we find out if the NPort we are logging into, matches the WWPN
         * we have for that ndlp. If not, we have some work to do.
         */
-       new_ndlp = lpfc_findnode_wwpn(phba, NLP_SEARCH_ALL, &sp->portName);
+       new_ndlp = lpfc_findnode_wwpn(phba, &sp->portName);
 
        if (new_ndlp == ndlp)
                return ndlp;
@@ -695,18 +679,15 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
        lpfc_unreg_rpi(phba, new_ndlp);
        new_ndlp->nlp_DID = ndlp->nlp_DID;
        new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
-       new_ndlp->nlp_state = ndlp->nlp_state;
-       lpfc_nlp_list(phba, new_ndlp, ndlp->nlp_flag & NLP_LIST_MASK);
+       lpfc_nlp_set_state(phba, new_ndlp, ndlp->nlp_state);
 
        /* Move this back to NPR list */
-       if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-       }
+       if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
+               lpfc_drop_node(phba, ndlp);
        else {
                lpfc_unreg_rpi(phba, ndlp);
                ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
        }
        return new_ndlp;
 }
@@ -720,13 +701,11 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        struct lpfc_dmabuf *prsp;
        int disc, rc, did, type;
 
-
        /* we pass cmdiocb to state machine which needs rspiocb as well */
        cmdiocb->context_un.rsp_iocb = rspiocb;
 
        irsp = &rspiocb->iocb;
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL,
-                                               irsp->un.elsreq64.remoteID);
+       ndlp = lpfc_findnode_did(phba, irsp->un.elsreq64.remoteID);
        if (!ndlp)
                goto out;
 
@@ -1354,7 +1333,7 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
                                                ndlp->nlp_DID, ELS_CMD_SCR);
        if (!elsiocb) {
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
                return 1;
        }
 
@@ -1373,12 +1352,12 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        spin_lock_irq(phba->host->host_lock);
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
                spin_unlock_irq(phba->host->host_lock);
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
        }
        spin_unlock_irq(phba->host->host_lock);
-       mempool_free( ndlp, phba->nlp_mem_pool);
+       lpfc_nlp_put(ndlp);
        return 0;
 }
 
@@ -1407,7 +1386,7 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
                                                ndlp->nlp_DID, ELS_CMD_RNID);
        if (!elsiocb) {
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
                return 1;
        }
 
@@ -1428,7 +1407,7 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
 
        memcpy(&fp->RportName, &phba->fc_portname, sizeof (struct lpfc_name));
        memcpy(&fp->RnodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
-       if ((ondlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, nportid))) {
+       if ((ondlp = lpfc_findnode_did(phba, nportid))) {
                memcpy(&fp->OportName, &ondlp->nlp_portname,
                       sizeof (struct lpfc_name));
                memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
@@ -1440,12 +1419,12 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        spin_lock_irq(phba->host->host_lock);
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
                spin_unlock_irq(phba->host->host_lock);
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
        }
        spin_unlock_irq(phba->host->host_lock);
-       mempool_free( ndlp, phba->nlp_mem_pool);
+       lpfc_nlp_put(ndlp);
        return 0;
 }
 
@@ -1554,29 +1533,25 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
        case ELS_CMD_PLOGI:
                if(!lpfc_issue_els_plogi(phba, ndlp->nlp_DID, retry)) {
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
                }
                break;
        case ELS_CMD_ADISC:
                if (!lpfc_issue_els_adisc(phba, ndlp, retry)) {
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
                }
                break;
        case ELS_CMD_PRLI:
                if (!lpfc_issue_els_prli(phba, ndlp, retry)) {
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
                }
                break;
        case ELS_CMD_LOGO:
                if (!lpfc_issue_els_logo(phba, ndlp, retry)) {
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_NPR_NODE;
-                       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                }
                break;
        }
@@ -1614,12 +1589,12 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                cmd = *elscmd++;
        }
 
-       if(ndlp)
+       if (ndlp)
                did = ndlp->nlp_DID;
        else {
                /* We should only hit this case for retrying PLOGI */
                did = irsp->un.elsreq64.remoteID;
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+               ndlp = lpfc_findnode_did(phba, did);
                if (!ndlp && (cmd != ELS_CMD_PLOGI))
                        return 1;
        }
@@ -1746,8 +1721,7 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                        ndlp->nlp_flag |= NLP_DELAY_TMO;
 
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_NPR_NODE;
-                       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                        ndlp->nlp_last_elscmd = cmd;
 
                        return 1;
@@ -1759,27 +1733,24 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                case ELS_CMD_PLOGI:
                        if (ndlp) {
                                ndlp->nlp_prev_state = ndlp->nlp_state;
-                               ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                               lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+                               lpfc_nlp_set_state(phba, ndlp,
+                                                  NLP_STE_PLOGI_ISSUE);
                        }
                        lpfc_issue_els_plogi(phba, did, cmdiocb->retry);
                        return 1;
                case ELS_CMD_ADISC:
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
                        lpfc_issue_els_adisc(phba, ndlp, cmdiocb->retry);
                        return 1;
                case ELS_CMD_PRLI:
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
                        lpfc_issue_els_prli(phba, ndlp, cmdiocb->retry);
                        return 1;
                case ELS_CMD_LOGO:
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_NPR_NODE;
-                       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                        lpfc_issue_els_logo(phba, ndlp, cmdiocb->retry);
                        return 1;
                }
@@ -1796,10 +1767,14 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 }
 
 int
-lpfc_els_free_iocb(struct lpfc_hba * phba, struct lpfc_iocbq * elsiocb)
+lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
 {
        struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
 
+       if (elsiocb->context1) {
+               lpfc_nlp_put(elsiocb->context1);
+               elsiocb->context1 = NULL;
+       }
        /* context2  = cmd,  context2->next = rsp, context3 = bpl */
        if (elsiocb->context2) {
                buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
@@ -1843,7 +1818,7 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 
        switch (ndlp->nlp_state) {
        case NLP_STE_UNUSED_NODE:       /* node is just allocated */
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                break;
        case NLP_STE_NPR_NODE:          /* NPort Recovery mode */
                lpfc_unreg_rpi(phba, ndlp);
@@ -1856,8 +1831,8 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 }
 
 static void
-lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
-                 struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                 struct lpfc_iocbq *rspiocb)
 {
        IOCB_t *irsp;
        struct lpfc_nodelist *ndlp;
@@ -1872,14 +1847,14 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 
 
        /* Check to see if link went down during discovery */
-       if ((lpfc_els_chk_latt(phba)) || !ndlp) {
+       if (lpfc_els_chk_latt(phba) || !ndlp) {
                if (mbox) {
                        mp = (struct lpfc_dmabuf *) mbox->context1;
                        if (mp) {
                                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                                kfree(mp);
                        }
-                       mempool_free( mbox, phba->mbox_mem_pool);
+                       mempool_free(mbox, phba->mbox_mem_pool);
                }
                goto out;
        }
@@ -1899,15 +1874,15 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                    && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
                        lpfc_unreg_rpi(phba, ndlp);
                        mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
-                       mbox->context2 = ndlp;
+                       mbox->context2 = lpfc_nlp_get(ndlp);
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_REG_LOGIN_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_REGLOGIN_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE);
                        if (lpfc_sli_issue_mbox(phba, mbox,
                                                (MBX_NOWAIT | MBX_STOP_IOCB))
                            != MBX_NOT_FINISHED) {
                                goto out;
                        }
+                       lpfc_nlp_put(ndlp);
                        /* NOTE: we should have messages for unsuccessful
                           reglogin */
                } else {
@@ -1917,7 +1892,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                               (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
                               (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
                                if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
-                                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                                       lpfc_drop_node(phba, ndlp);
                                        ndlp = NULL;
                                }
                        }
@@ -2012,15 +1987,16 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
                return 1;
        }
 
-       if (newnode)
+       if (newnode) {
+               lpfc_nlp_put(ndlp);
                elsiocb->context1 = NULL;
+       }
 
        /* Xmit ELS ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0128 Xmit ELS ACC response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "%d:0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
+                       "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
@@ -2077,10 +2053,9 @@ lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
 
        /* Xmit ELS RJT <err> response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0129 Xmit ELS RJT x%x response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       rejectError, elsiocb->iocb.ulpIoTag,
+                       "%d:0129 Xmit ELS RJT x%x response tag x%x xri x%x, "
+                       "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+                       phba->brd_no, rejectError, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
@@ -2119,18 +2094,18 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
        if (!elsiocb)
                return 1;
 
+       icmd = &elsiocb->iocb;
+       oldcmd = &oldiocb->iocb;
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+
        /* Xmit ADISC ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0130 Xmit ADISC ACC response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "%d:0130 Xmit ADISC ACC response iotag x%x xri: "
+                       "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
-       icmd = &elsiocb->iocb;
-       oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
        *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -2155,8 +2130,8 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
 }
 
 int
-lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
-                     struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb,
+                     struct lpfc_nodelist *ndlp)
 {
        PRLI *npr;
        lpfc_vpd_t *vpd;
@@ -2178,18 +2153,18 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
        if (!elsiocb)
                return 1;
 
+       icmd = &elsiocb->iocb;
+       oldcmd = &oldiocb->iocb;
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+
        /* Xmit PRLI ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0131 Xmit PRLI ACC response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "%d:0131 Xmit PRLI ACC response tag x%x xri x%x, "
+                       "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
-       icmd = &elsiocb->iocb;
-       oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
        *((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
@@ -2232,9 +2207,8 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
 }
 
 static int
-lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
-                     uint8_t format,
-                     struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format,
+                     struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
 {
        RNID *rn;
        IOCB_t *icmd;
@@ -2259,17 +2233,17 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
        if (!elsiocb)
                return 1;
 
+       icmd = &elsiocb->iocb;
+       oldcmd = &oldiocb->iocb;
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+
        /* Xmit RNID ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                        "%d:0132 Xmit RNID ACC response tag x%x "
-                       "Data: x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "xri x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext);
 
-       icmd = &elsiocb->iocb;
-       oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
        *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -2301,6 +2275,7 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
 
        phba->fc_stat.elsXmitACC++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+       lpfc_nlp_put(ndlp);
        elsiocb->context1 = NULL;  /* Don't need ndlp for cmpl,
                                    * it could be freed */
 
@@ -2315,32 +2290,31 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
 }
 
 int
-lpfc_els_disc_adisc(struct lpfc_hba * phba)
+lpfc_els_disc_adisc(struct lpfc_hba *phba)
 {
        int sentadisc;
        struct lpfc_nodelist *ndlp, *next_ndlp;
 
        sentadisc = 0;
-       /* go thru NPR list and issue any remaining ELS ADISCs */
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                       nlp_listp) {
-               if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
-                       if (ndlp->nlp_flag & NLP_NPR_ADISC) {
-                               ndlp->nlp_flag &= ~NLP_NPR_ADISC;
-                               ndlp->nlp_prev_state = ndlp->nlp_state;
-                               ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-                               lpfc_nlp_list(phba, ndlp,
-                                       NLP_ADISC_LIST);
-                               lpfc_issue_els_adisc(phba, ndlp, 0);
-                               sentadisc++;
-                               phba->num_disc_nodes++;
-                               if (phba->num_disc_nodes >=
-                                   phba->cfg_discovery_threads) {
-                                       spin_lock_irq(phba->host->host_lock);
-                                       phba->fc_flag |= FC_NLP_MORE;
-                                       spin_unlock_irq(phba->host->host_lock);
-                                       break;
-                               }
+       /* go thru NPR nodes and issue any remaining ELS ADISCs */
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+                   (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+                   (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
+                       spin_lock_irq(phba->host->host_lock);
+                       ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+                       spin_unlock_irq(phba->host->host_lock);
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
+                       lpfc_issue_els_adisc(phba, ndlp, 0);
+                       sentadisc++;
+                       phba->num_disc_nodes++;
+                       if (phba->num_disc_nodes >=
+                           phba->cfg_discovery_threads) {
+                               spin_lock_irq(phba->host->host_lock);
+                               phba->fc_flag |= FC_NLP_MORE;
+                               spin_unlock_irq(phba->host->host_lock);
+                               break;
                        }
                }
        }
@@ -2360,24 +2334,22 @@ lpfc_els_disc_plogi(struct lpfc_hba * phba)
 
        sentplogi = 0;
        /* go thru NPR list and issue any remaining ELS PLOGIs */
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                               nlp_listp) {
-               if ((ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
-                  (!(ndlp->nlp_flag & NLP_DELAY_TMO))) {
-                       if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
-                               ndlp->nlp_prev_state = ndlp->nlp_state;
-                               ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                               lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
-                               lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
-                               sentplogi++;
-                               phba->num_disc_nodes++;
-                               if (phba->num_disc_nodes >=
-                                   phba->cfg_discovery_threads) {
-                                       spin_lock_irq(phba->host->host_lock);
-                                       phba->fc_flag |= FC_NLP_MORE;
-                                       spin_unlock_irq(phba->host->host_lock);
-                                       break;
-                               }
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+                   (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+                   (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
+                   (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
+                       lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+                       sentplogi++;
+                       phba->num_disc_nodes++;
+                       if (phba->num_disc_nodes >=
+                           phba->cfg_discovery_threads) {
+                               spin_lock_irq(phba->host->host_lock);
+                               phba->fc_flag |= FC_NLP_MORE;
+                               spin_unlock_irq(phba->host->host_lock);
+                               break;
                        }
                }
        }
@@ -2479,42 +2451,30 @@ lpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did)
 }
 
 static int
-lpfc_rscn_recovery_check(struct lpfc_hba * phba)
+lpfc_rscn_recovery_check(struct lpfc_hba *phba)
 {
-       struct lpfc_nodelist *ndlp = NULL, *next_ndlp;
-       struct list_head *listp;
-       struct list_head *node_list[7];
-       int i;
+       struct lpfc_nodelist *ndlp = NULL;
 
        /* Look at all nodes effected by pending RSCNs and move
-        * them to NPR list.
+        * them to NPR state.
         */
-       node_list[0] = &phba->fc_npr_list;  /* MUST do this list first */
-       node_list[1] = &phba->fc_nlpmap_list;
-       node_list[2] = &phba->fc_nlpunmap_list;
-       node_list[3] = &phba->fc_prli_list;
-       node_list[4] = &phba->fc_reglogin_list;
-       node_list[5] = &phba->fc_adisc_list;
-       node_list[6] = &phba->fc_plogi_list;
-       for (i = 0; i < 7; i++) {
-               listp = node_list[i];
-               if (list_empty(listp))
-                       continue;
 
-               list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
-                       if (!(lpfc_rscn_payload_check(phba, ndlp->nlp_DID)))
-                               continue;
+       list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
+                   lpfc_rscn_payload_check(phba, ndlp->nlp_DID) == 0)
+                       continue;
 
-                       lpfc_disc_state_machine(phba, ndlp, NULL,
+               lpfc_disc_state_machine(phba, ndlp, NULL,
                                        NLP_EVT_DEVICE_RECOVERY);
 
-                       /* Make sure NLP_DELAY_TMO is NOT running
-                        * after a device recovery event.
-                        */
-                       if (ndlp->nlp_flag & NLP_DELAY_TMO)
-                               lpfc_cancel_retry_delay_tmo(phba, ndlp);
-               }
+               /*
+                * Make sure NLP_DELAY_TMO is NOT running after a device
+                * recovery event.
+                */
+               if (ndlp->nlp_flag & NLP_DELAY_TMO)
+                       lpfc_cancel_retry_delay_tmo(phba, ndlp);
        }
+
        return 0;
 }
 
@@ -2639,8 +2599,8 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
 
        /* To process RSCN, first compare RSCN data with NameServer */
        phba->fc_ns_retry = 0;
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, NameServer_DID);
-       if (ndlp) {
+       ndlp = lpfc_findnode_did(phba, NameServer_DID);
+       if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
                /* Good ndlp, issue CT Request to NameServer */
                if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == 0) {
                        /* Wait for NameServer query cmpl before we can
@@ -2650,7 +2610,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
        } else {
                /* If login to NameServer does not exist, issue one */
                /* Good status, issue PLOGI to NameServer */
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+               ndlp = lpfc_findnode_did(phba, NameServer_DID);
                if (ndlp) {
                        /* Wait for NameServer login cmpl before we can
                           continue */
@@ -2664,8 +2624,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
                        lpfc_nlp_init(phba, ndlp, NameServer_DID);
                        ndlp->nlp_type |= NLP_FABRIC;
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
                        lpfc_issue_els_plogi(phba, NameServer_DID, 0);
                        /* Wait for NameServer login cmpl before we can
                           continue */
@@ -2734,8 +2693,9 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba,
                        mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                        rc = lpfc_sli_issue_mbox
                                (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+                       lpfc_set_loopback_flag(phba);
                        if (rc == MBX_NOT_FINISHED) {
-                               mempool_free( mbox, phba->mbox_mem_pool);
+                               mempool_free(mbox, phba->mbox_mem_pool);
                        }
                        return 1;
                } else if (rc > 0) {    /* greater than */
@@ -2800,8 +2760,8 @@ lpfc_els_rcv_rnid(struct lpfc_hba * phba,
 }
 
 static int
-lpfc_els_rcv_lirr(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
-                struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_lirr(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                struct lpfc_nodelist *ndlp)
 {
        struct ls_rjt stat;
 
@@ -2815,7 +2775,7 @@ lpfc_els_rcv_lirr(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 }
 
 static void
-lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
@@ -2838,14 +2798,15 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
        pmb->context2 = NULL;
 
        if (mb->mbxStatus) {
-               mempool_free( pmb, phba->mbox_mem_pool);
+               mempool_free(pmb, phba->mbox_mem_pool);
                return;
        }
 
        cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
-       mempool_free( pmb, phba->mbox_mem_pool);
+       mempool_free(pmb, phba->mbox_mem_pool);
        elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, lpfc_max_els_tries, ndlp,
                                                ndlp->nlp_DID, ELS_CMD_ACC);
+       lpfc_nlp_put(ndlp);
        if (!elsiocb)
                return;
 
@@ -2875,15 +2836,15 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        /* Xmit ELS RPS ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0118 Xmit ELS RPS ACC response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "%d:0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
+                       "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
        elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
        phba->fc_stat.elsXmitACC++;
+
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
        }
@@ -2923,13 +2884,14 @@ lpfc_els_rcv_rps(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                        lpfc_read_lnk_stat(phba, mbox);
                        mbox->context1 =
                            (void *)((unsigned long)cmdiocb->iocb.ulpContext);
-                       mbox->context2 = ndlp;
+                       mbox->context2 = lpfc_nlp_get(ndlp);
                        mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
                        if (lpfc_sli_issue_mbox (phba, mbox,
                            (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) {
                                /* Mbox completion will send ELS Response */
                                return 0;
                        }
+                       lpfc_nlp_put(ndlp);
                        mempool_free(mbox, phba->mbox_mem_pool);
                }
        }
@@ -2984,10 +2946,9 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
 
        /* Xmit ELS RPL ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0120 Xmit ELS RPL ACC response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "%d:0120 Xmit ELS RPL ACC response tag x%x xri x%x, "
+                       "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
@@ -3091,8 +3052,8 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
                        /* Log back into the node before sending the FARP. */
                        if (fp->Rflags & FARP_REQUEST_PLOGI) {
                                ndlp->nlp_prev_state = ndlp->nlp_state;
-                               ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                               lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+                               lpfc_nlp_set_state(phba, ndlp,
+                                                  NLP_STE_PLOGI_ISSUE);
                                lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
                        }
 
@@ -3169,14 +3130,15 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                         */
 
                        list_for_each_entry_safe(ndlp, next_ndlp,
-                               &phba->fc_npr_list, nlp_listp) {
-
+                                                &phba->fc_nodes, nlp_listp) {
+                               if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+                                       continue;
                                if (ndlp->nlp_type & NLP_FABRIC) {
                                        /*
                                         * Clean up old Fabric, Nameserver and
                                         * other NLP_FABRIC logins
                                         */
-                                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                                       lpfc_drop_node(phba, ndlp);
                                } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
                                        /* Fail outstanding I/O now since this
                                         * device is marked for PLOGI
@@ -3193,20 +3155,22 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                /* Discovery not needed,
                 * move the nodes to their original state.
                 */
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                       nlp_listp) {
+               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+                                        nlp_listp) {
+                       if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+                               continue;
 
                        switch (ndlp->nlp_prev_state) {
                        case NLP_STE_UNMAPPED_NODE:
                                ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                               ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-                               lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+                               lpfc_nlp_set_state(phba, ndlp,
+                                                  NLP_STE_UNMAPPED_NODE);
                                break;
 
                        case NLP_STE_MAPPED_NODE:
                                ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                               ndlp->nlp_state = NLP_STE_MAPPED_NODE;
-                               lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+                               lpfc_nlp_set_state(phba, ndlp,
+                                                  NLP_STE_MAPPED_NODE);
                                break;
 
                        default:
@@ -3246,9 +3210,8 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
        struct lpfc_iocbq *tmp_iocb, *piocb;
        IOCB_t *cmd = NULL;
        struct lpfc_dmabuf *pcmd;
-       struct list_head *dlp;
        uint32_t *elscmd;
-       uint32_t els_command;
+       uint32_t els_command=0;
        uint32_t timeout;
        uint32_t remote_ID;
 
@@ -3263,17 +3226,20 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
        timeout = (uint32_t)(phba->fc_ratov << 1);
 
        pring = &phba->sli.ring[LPFC_ELS_RING];
-       dlp = &pring->txcmplq;
 
        list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
                cmd = &piocb->iocb;
 
-               if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
+               if ((piocb->iocb_flag & LPFC_IO_LIBDFC) ||
+                       (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN) ||
+                       (piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)) {
                        continue;
                }
                pcmd = (struct lpfc_dmabuf *) piocb->context2;
-               elscmd = (uint32_t *) (pcmd->virt);
-               els_command = *elscmd;
+               if (pcmd) {
+                       elscmd = (uint32_t *) (pcmd->virt);
+                       els_command = *elscmd;
+               }
 
                if ((els_command == ELS_CMD_FARP)
                    || (els_command == ELS_CMD_FARPR)) {
@@ -3289,19 +3255,10 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
                        continue;
                }
 
-               list_del(&piocb->list);
-               pring->txcmplq_cnt--;
-
                if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
                        struct lpfc_nodelist *ndlp;
-                       spin_unlock_irq(phba->host->host_lock);
-                       ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext);
-                       spin_lock_irq(phba->host->host_lock);
+                       ndlp = __lpfc_findnode_rpi(phba, cmd->ulpContext);
                        remote_ID = ndlp->nlp_DID;
-                       if (cmd->un.elsreq64.bdl.ulpIoTag32) {
-                               lpfc_sli_issue_abort_iotag32(phba,
-                                       pring, piocb);
-                       }
                } else {
                        remote_ID = cmd->un.elsreq64.remoteID;
                }
@@ -3313,17 +3270,7 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
                                phba->brd_no, els_command,
                                remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
 
-               /*
-                * The iocb has timed out; abort it.
-                */
-               if (piocb->iocb_cmpl) {
-                       cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-                       cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-                       spin_unlock_irq(phba->host->host_lock);
-                       (piocb->iocb_cmpl) (phba, piocb, piocb);
-                       spin_lock_irq(phba->host->host_lock);
-               } else
-                       lpfc_sli_release_iocbq(phba, piocb);
+               lpfc_sli_issue_abort_iotag(phba, pring, piocb);
        }
        if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
                mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
@@ -3332,16 +3279,13 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
 }
 
 void
-lpfc_els_flush_cmd(struct lpfc_hba * phba)
+lpfc_els_flush_cmd(struct lpfc_hba *phba)
 {
-       struct lpfc_sli_ring *pring;
+       LIST_HEAD(completions);
+       struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
        struct lpfc_iocbq *tmp_iocb, *piocb;
        IOCB_t *cmd = NULL;
-       struct lpfc_dmabuf *pcmd;
-       uint32_t *elscmd;
-       uint32_t els_command;
 
-       pring = &phba->sli.ring[LPFC_ELS_RING];
        spin_lock_irq(phba->host->host_lock);
        list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
                cmd = &piocb->iocb;
@@ -3351,29 +3295,15 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
                }
 
                /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
-               if ((cmd->ulpCommand == CMD_QUE_RING_BUF_CN) ||
-                   (cmd->ulpCommand == CMD_QUE_RING_BUF64_CN) ||
-                   (cmd->ulpCommand == CMD_CLOSE_XRI_CN) ||
-                   (cmd->ulpCommand == CMD_ABORT_XRI_CN)) {
+               if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
+                   cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
+                   cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
+                   cmd->ulpCommand == CMD_ABORT_XRI_CN)
                        continue;
-               }
 
-               pcmd = (struct lpfc_dmabuf *) piocb->context2;
-               elscmd = (uint32_t *) (pcmd->virt);
-               els_command = *elscmd;
+               list_move_tail(&piocb->list, &completions);
+               pring->txq_cnt--;
 
-               list_del(&piocb->list);
-               pring->txcmplq_cnt--;
-
-               cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-               cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-
-               if (piocb->iocb_cmpl) {
-                       spin_unlock_irq(phba->host->host_lock);
-                       (piocb->iocb_cmpl) (phba, piocb, piocb);
-                       spin_lock_irq(phba->host->host_lock);
-               } else
-                       lpfc_sli_release_iocbq(phba, piocb);
        }
 
        list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
@@ -3382,24 +3312,24 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
                if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
                        continue;
                }
-               pcmd = (struct lpfc_dmabuf *) piocb->context2;
-               elscmd = (uint32_t *) (pcmd->virt);
-               els_command = *elscmd;
 
-               list_del(&piocb->list);
-               pring->txcmplq_cnt--;
+               lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+       }
+       spin_unlock_irq(phba->host->host_lock);
 
-               cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-               cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+       while(!list_empty(&completions)) {
+               piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               cmd = &piocb->iocb;
+               list_del(&piocb->list);
 
                if (piocb->iocb_cmpl) {
-                       spin_unlock_irq(phba->host->host_lock);
+                       cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
                        (piocb->iocb_cmpl) (phba, piocb, piocb);
-                       spin_lock_irq(phba->host->host_lock);
                } else
                        lpfc_sli_release_iocbq(phba, piocb);
        }
-       spin_unlock_irq(phba->host->host_lock);
+
        return;
 }
 
@@ -3468,7 +3398,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        }
 
        did = icmd->un.rcvels.remoteID;
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+       ndlp = lpfc_findnode_did(phba, did);
        if (!ndlp) {
                /* Cannot find existing Fabric ndlp, so allocate a new one */
                ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
@@ -3484,12 +3414,13 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
                        ndlp->nlp_type |= NLP_FABRIC;
                }
-               ndlp->nlp_state = NLP_STE_UNUSED_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
        }
 
        phba->fc_stat.elsRcvFrame++;
-       elsiocb->context1 = ndlp;
+       if (elsiocb->context1)
+               lpfc_nlp_put(elsiocb->context1);
+       elsiocb->context1 = lpfc_nlp_get(ndlp);
        elsiocb->context2 = mp;
 
        if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
@@ -3513,9 +3444,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        case ELS_CMD_FLOGI:
                phba->fc_stat.elsRcvFLOGI++;
                lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        case ELS_CMD_LOGO:
                phba->fc_stat.elsRcvLOGO++;
@@ -3536,9 +3466,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        case ELS_CMD_RSCN:
                phba->fc_stat.elsRcvRSCN++;
                lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        case ELS_CMD_ADISC:
                phba->fc_stat.elsRcvADISC++;
@@ -3579,30 +3508,26 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        case ELS_CMD_LIRR:
                phba->fc_stat.elsRcvLIRR++;
                lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        case ELS_CMD_RPS:
                phba->fc_stat.elsRcvRPS++;
                lpfc_els_rcv_rps(phba, elsiocb, ndlp);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        case ELS_CMD_RPL:
                phba->fc_stat.elsRcvRPL++;
                lpfc_els_rcv_rpl(phba, elsiocb, ndlp);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        case ELS_CMD_RNID:
                phba->fc_stat.elsRcvRNID++;
                lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        default:
                /* Unsupported ELS command, reject */
@@ -3612,9 +3537,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
                                "%d:0115 Unknown ELS command x%x received from "
                                "NPORT x%x\n", phba->brd_no, cmd, did);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        }
 
@@ -3627,6 +3551,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                lpfc_els_rsp_reject(phba, stat.un.lsRjtError, elsiocb, ndlp);
        }
 
+       lpfc_nlp_put(elsiocb->context1);
+       elsiocb->context1 = NULL;
        if (elsiocb->context2) {
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
index c39564e85e944f62ebed5d8b3d41a6f75daf4ff7..61caa8d379e2dc7a120481da5f8ad54f671289f5 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -109,6 +109,9 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
                return;
        }
 
+       if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+               return;
+
        name = (uint8_t *)&ndlp->nlp_portname;
        phba = ndlp->nlp_phba;
 
@@ -147,11 +150,17 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
                                ndlp->nlp_state, ndlp->nlp_rpi);
        }
 
-       ndlp->rport = NULL;
-       rdata->pnode = NULL;
-
-       if (!(phba->fc_flag & FC_UNLOADING))
+       if (!(phba->fc_flag & FC_UNLOADING) &&
+           !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
+           !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
+           (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
                lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
+       else {
+               rdata->pnode = NULL;
+               ndlp->rport = NULL;
+               lpfc_nlp_put(ndlp);
+               put_device(&rport->dev);
+       }
 
        return;
 }
@@ -182,29 +191,35 @@ lpfc_work_list_done(struct lpfc_hba * phba)
                                *(int *)(evtp->evt_arg1)  = 0;
                        complete((struct completion *)(evtp->evt_arg2));
                        break;
-               case LPFC_EVT_OFFLINE:
+               case LPFC_EVT_OFFLINE_PREP:
                        if (phba->hba_state >= LPFC_LINK_DOWN)
-                               lpfc_offline(phba);
+                               lpfc_offline_prep(phba);
+                       *(int *)(evtp->evt_arg1) = 0;
+                       complete((struct completion *)(evtp->evt_arg2));
+                       break;
+               case LPFC_EVT_OFFLINE:
+                       lpfc_offline(phba);
                        lpfc_sli_brdrestart(phba);
                        *(int *)(evtp->evt_arg1) =
-                               lpfc_sli_brdready(phba,HS_FFRDY | HS_MBRDY);
+                               lpfc_sli_brdready(phba, HS_FFRDY | HS_MBRDY);
+                       lpfc_unblock_mgmt_io(phba);
                        complete((struct completion *)(evtp->evt_arg2));
                        break;
                case LPFC_EVT_WARM_START:
-                       if (phba->hba_state >= LPFC_LINK_DOWN)
-                               lpfc_offline(phba);
+                       lpfc_offline(phba);
                        lpfc_reset_barrier(phba);
                        lpfc_sli_brdreset(phba);
                        lpfc_hba_down_post(phba);
                        *(int *)(evtp->evt_arg1) =
                                lpfc_sli_brdready(phba, HS_MBRDY);
+                       lpfc_unblock_mgmt_io(phba);
                        complete((struct completion *)(evtp->evt_arg2));
                        break;
                case LPFC_EVT_KILL:
-                       if (phba->hba_state >= LPFC_LINK_DOWN)
-                               lpfc_offline(phba);
+                       lpfc_offline(phba);
                        *(int *)(evtp->evt_arg1)
                                = (phba->stopped) ? 0 : lpfc_sli_brdkill(phba);
+                       lpfc_unblock_mgmt_io(phba);
                        complete((struct completion *)(evtp->evt_arg2));
                        break;
                }
@@ -359,13 +374,12 @@ lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2,
 }
 
 int
-lpfc_linkdown(struct lpfc_hba * phba)
+lpfc_linkdown(struct lpfc_hba *phba)
 {
        struct lpfc_sli       *psli;
        struct lpfc_nodelist  *ndlp, *next_ndlp;
-       struct list_head *listp, *node_list[7];
-       LPFC_MBOXQ_t     *mb;
-       int               rc, i;
+       LPFC_MBOXQ_t          *mb;
+       int                   rc;
 
        psli = &phba->sli;
        /* sysfs or selective reset may call this routine to clean up */
@@ -397,31 +411,16 @@ lpfc_linkdown(struct lpfc_hba * phba)
        /* Cleanup any outstanding ELS commands */
        lpfc_els_flush_cmd(phba);
 
-       /* Issue a LINK DOWN event to all nodes */
-       node_list[0] = &phba->fc_npr_list;  /* MUST do this list first */
-       node_list[1] = &phba->fc_nlpmap_list;
-       node_list[2] = &phba->fc_nlpunmap_list;
-       node_list[3] = &phba->fc_prli_list;
-       node_list[4] = &phba->fc_reglogin_list;
-       node_list[5] = &phba->fc_adisc_list;
-       node_list[6] = &phba->fc_plogi_list;
-       for (i = 0; i < 7; i++) {
-               listp = node_list[i];
-               if (list_empty(listp))
-                       continue;
-
-               list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
-
+       /*
+        * Issue a LINK DOWN event to all nodes.
+        */
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+                               /* free any ndlp's on unused list */
+               if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+                       lpfc_drop_node(phba, ndlp);
+               else            /* otherwise, force node recovery. */
                        rc = lpfc_disc_state_machine(phba, ndlp, NULL,
-                                            NLP_EVT_DEVICE_RECOVERY);
-
-               }
-       }
-
-       /* free any ndlp's on unused list */
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
-                               nlp_listp) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                                                    NLP_EVT_DEVICE_RECOVERY);
        }
 
        /* Setup myDID for link up if we are in pt2pt mode */
@@ -452,11 +451,9 @@ lpfc_linkdown(struct lpfc_hba * phba)
 }
 
 static int
-lpfc_linkup(struct lpfc_hba * phba)
+lpfc_linkup(struct lpfc_hba *phba)
 {
        struct lpfc_nodelist *ndlp, *next_ndlp;
-       struct list_head *listp, *node_list[7];
-       int i;
 
        fc_host_post_event(phba->host, fc_get_event_number(),
                        FCH_EVT_LINKUP, 0);
@@ -470,29 +467,20 @@ lpfc_linkup(struct lpfc_hba * phba)
        spin_unlock_irq(phba->host->host_lock);
 
 
-       node_list[0] = &phba->fc_plogi_list;
-       node_list[1] = &phba->fc_adisc_list;
-       node_list[2] = &phba->fc_reglogin_list;
-       node_list[3] = &phba->fc_prli_list;
-       node_list[4] = &phba->fc_nlpunmap_list;
-       node_list[5] = &phba->fc_nlpmap_list;
-       node_list[6] = &phba->fc_npr_list;
-       for (i = 0; i < 7; i++) {
-               listp = node_list[i];
-               if (list_empty(listp))
-                       continue;
-
-               list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
-                       if (phba->fc_flag & FC_LBIT) {
+       if (phba->fc_flag & FC_LBIT) {
+               list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+                       if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) {
                                if (ndlp->nlp_type & NLP_FABRIC) {
-                                       /* On Linkup its safe to clean up the
+                                       /*
+                                        * On Linkup its safe to clean up the
                                         * ndlp from Fabric connections.
                                         */
-                                       lpfc_nlp_list(phba, ndlp,
-                                                       NLP_UNUSED_LIST);
+                                       lpfc_nlp_set_state(phba, ndlp,
+                                                          NLP_STE_UNUSED_NODE);
                                } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
-                                       /* Fail outstanding IO now since device
-                                        * is marked for PLOGI.
+                                       /*
+                                        * Fail outstanding IO now since
+                                        * device is marked for PLOGI.
                                         */
                                        lpfc_unreg_rpi(phba, ndlp);
                                }
@@ -501,9 +489,10 @@ lpfc_linkup(struct lpfc_hba * phba)
        }
 
        /* free any ndlp's on unused list */
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
-                               nlp_listp) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+                                nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+                       lpfc_drop_node(phba, ndlp);
        }
 
        return 0;
@@ -734,6 +723,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
                case LA_4GHZ_LINK:
                        phba->fc_linkspeed = LA_4GHZ_LINK;
                        break;
+               case LA_8GHZ_LINK:
+                       phba->fc_linkspeed = LA_8GHZ_LINK;
+                       break;
                default:
                        phba->fc_linkspeed = LA_UNKNW_LINK;
                        break;
@@ -889,12 +881,21 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        if (la->attType == AT_LINK_UP) {
                phba->fc_stat.LinkUp++;
-               lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
+               if (phba->fc_flag & FC_LOOPBACK_MODE) {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
+                               "%d:1306 Link Up Event in loop back mode "
+                               "x%x received Data: x%x x%x x%x x%x\n",
+                               phba->brd_no, la->eventTag, phba->fc_eventTag,
+                               la->granted_AL_PA, la->UlnkSpeed,
+                               phba->alpa_map[0]);
+               } else {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
                                "%d:1303 Link Up Event x%x received "
                                "Data: x%x x%x x%x x%x\n",
                                phba->brd_no, la->eventTag, phba->fc_eventTag,
                                la->granted_AL_PA, la->UlnkSpeed,
                                phba->alpa_map[0]);
+               }
                lpfc_mbx_process_link_up(phba, la);
        } else {
                phba->fc_stat.LinkDown++;
@@ -940,6 +941,7 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
        mempool_free( pmb, phba->mbox_mem_pool);
+       lpfc_nlp_put(ndlp);
 
        return;
 }
@@ -966,11 +968,14 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
        ndlp = (struct lpfc_nodelist *) pmb->context2;
        mp = (struct lpfc_dmabuf *) (pmb->context1);
 
+       pmb->context1 = NULL;
+       pmb->context2 = NULL;
+
        if (mb->mbxStatus) {
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
-               mempool_free( pmb, phba->mbox_mem_pool);
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               mempool_free(pmb, phba->mbox_mem_pool);
+               lpfc_nlp_put(ndlp);
 
                /* FLOGI failed, so just use loop map to make discovery list */
                lpfc_disc_list_loopmap(phba);
@@ -980,12 +985,11 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
                return;
        }
 
-       pmb->context1 = NULL;
-
        ndlp->nlp_rpi = mb->un.varWords[0];
        ndlp->nlp_type |= NLP_FABRIC;
-       ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+
+       lpfc_nlp_put(ndlp);     /* Drop the reference from the mbox */
 
        if (phba->hba_state == LPFC_FABRIC_CFG_LINK) {
                /* This NPort has been assigned an NPort_ID by the fabric as a
@@ -996,7 +1000,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
                 */
                lpfc_issue_els_scr(phba, SCR_DID, 0);
 
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+               ndlp = lpfc_findnode_did(phba, NameServer_DID);
                if (!ndlp) {
                        /* Allocate a new node instance. If the pool is empty,
                         * start the discovery process and skip the Nameserver
@@ -1008,15 +1012,14 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
                                lpfc_disc_start(phba);
                                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                                kfree(mp);
-                               mempool_free( pmb, phba->mbox_mem_pool);
+                               mempool_free(pmb, phba->mbox_mem_pool);
                                return;
                        } else {
                                lpfc_nlp_init(phba, ndlp, NameServer_DID);
                                ndlp->nlp_type |= NLP_FABRIC;
                        }
                }
-               ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-               lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
                lpfc_issue_els_plogi(phba, NameServer_DID, 0);
                if (phba->cfg_fdmi_on) {
                        ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
@@ -1032,7 +1035,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
-       mempool_free( pmb, phba->mbox_mem_pool);
+       mempool_free(pmb, phba->mbox_mem_pool);
        return;
 }
 
@@ -1057,10 +1060,11 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
        mp = (struct lpfc_dmabuf *) (pmb->context1);
 
        if (mb->mbxStatus) {
+               lpfc_nlp_put(ndlp);
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
-               mempool_free( pmb, phba->mbox_mem_pool);
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               mempool_free(pmb, phba->mbox_mem_pool);
+               lpfc_drop_node(phba, ndlp);
 
                /* RegLogin failed, so just use loop map to make discovery
                   list */
@@ -1075,8 +1079,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        ndlp->nlp_rpi = mb->un.varWords[0];
        ndlp->nlp_type |= NLP_FABRIC;
-       ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
 
        if (phba->hba_state < LPFC_HBA_READY) {
                /* Link up discovery requires Fabrib registration. */
@@ -1093,6 +1096,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
                lpfc_disc_start(phba);
        }
 
+       lpfc_nlp_put(ndlp);
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
        mempool_free( pmb, phba->mbox_mem_pool);
@@ -1101,8 +1105,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 }
 
 static void
-lpfc_register_remote_port(struct lpfc_hba * phba,
-                           struct lpfc_nodelist * ndlp)
+lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
        struct fc_rport *rport;
        struct lpfc_rport_data *rdata;
@@ -1114,8 +1117,19 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
        rport_ids.port_id = ndlp->nlp_DID;
        rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
 
+       /*
+        * We leave our node pointer in rport->dd_data when we unregister a
+        * FCP target port.  But fc_remote_port_add zeros the space to which
+        * rport->dd_data points.  So, if we're reusing a previously
+        * registered port, drop the reference that we took the last time we
+        * registered the port.
+        */
+       if (ndlp->rport && ndlp->rport->dd_data &&
+           *(struct lpfc_rport_data **) ndlp->rport->dd_data) {
+               lpfc_nlp_put(ndlp);
+       }
        ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids);
-       if (!rport) {
+       if (!rport || !get_device(&rport->dev)) {
                dev_printk(KERN_WARNING, &phba->pcidev->dev,
                           "Warning: fc_remote_port_add failed\n");
                return;
@@ -1125,7 +1139,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
        rport->maxframe_size = ndlp->nlp_maxframe;
        rport->supported_classes = ndlp->nlp_class_sup;
        rdata = rport->dd_data;
-       rdata->pnode = ndlp;
+       rdata->pnode = lpfc_nlp_get(ndlp);
 
        if (ndlp->nlp_type & NLP_FCP_TARGET)
                rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
@@ -1145,8 +1159,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
 }
 
 static void
-lpfc_unregister_remote_port(struct lpfc_hba * phba,
-                           struct lpfc_nodelist * ndlp)
+lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
        struct fc_rport *rport = ndlp->rport;
        struct lpfc_rport_data *rdata = rport->dd_data;
@@ -1154,6 +1167,8 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba,
        if (rport->scsi_target_id == -1) {
                ndlp->rport = NULL;
                rdata->pnode = NULL;
+               lpfc_nlp_put(ndlp);
+               put_device(&rport->dev);
        }
 
        fc_remote_port_delete(rport);
@@ -1161,178 +1176,70 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba,
        return;
 }
 
-int
-lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
+static void
+lpfc_nlp_counters(struct lpfc_hba *phba, int state, int count)
 {
-       enum { none, unmapped, mapped } rport_add = none, rport_del = none;
-       struct lpfc_sli      *psli;
-
-       psli = &phba->sli;
-       /* Sanity check to ensure we are not moving to / from the same list */
-       if ((nlp->nlp_flag & NLP_LIST_MASK) == list)
-               if (list != NLP_NO_LIST)
-                       return 0;
-
        spin_lock_irq(phba->host->host_lock);
-       switch (nlp->nlp_flag & NLP_LIST_MASK) {
-       case NLP_NO_LIST: /* Not on any list */
+       switch (state) {
+       case NLP_STE_UNUSED_NODE:
+               phba->fc_unused_cnt += count;
                break;
-       case NLP_UNUSED_LIST:
-               phba->fc_unused_cnt--;
-               list_del(&nlp->nlp_listp);
+       case NLP_STE_PLOGI_ISSUE:
+               phba->fc_plogi_cnt += count;
                break;
-       case NLP_PLOGI_LIST:
-               phba->fc_plogi_cnt--;
-               list_del(&nlp->nlp_listp);
+       case NLP_STE_ADISC_ISSUE:
+               phba->fc_adisc_cnt += count;
                break;
-       case NLP_ADISC_LIST:
-               phba->fc_adisc_cnt--;
-               list_del(&nlp->nlp_listp);
+       case NLP_STE_REG_LOGIN_ISSUE:
+               phba->fc_reglogin_cnt += count;
                break;
-       case NLP_REGLOGIN_LIST:
-               phba->fc_reglogin_cnt--;
-               list_del(&nlp->nlp_listp);
+       case NLP_STE_PRLI_ISSUE:
+               phba->fc_prli_cnt += count;
                break;
-       case NLP_PRLI_LIST:
-               phba->fc_prli_cnt--;
-               list_del(&nlp->nlp_listp);
+       case NLP_STE_UNMAPPED_NODE:
+               phba->fc_unmap_cnt += count;
                break;
-       case NLP_UNMAPPED_LIST:
-               phba->fc_unmap_cnt--;
-               list_del(&nlp->nlp_listp);
-               nlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
-               nlp->nlp_type &= ~NLP_FC_NODE;
-               phba->nport_event_cnt++;
-               if (nlp->rport)
-                       rport_del = unmapped;
+       case NLP_STE_MAPPED_NODE:
+               phba->fc_map_cnt += count;
                break;
-       case NLP_MAPPED_LIST:
-               phba->fc_map_cnt--;
-               list_del(&nlp->nlp_listp);
-               phba->nport_event_cnt++;
-               if (nlp->rport)
-                       rport_del = mapped;
-               break;
-       case NLP_NPR_LIST:
-               phba->fc_npr_cnt--;
-               list_del(&nlp->nlp_listp);
-               /* Stop delay tmo if taking node off NPR list */
-               if ((nlp->nlp_flag & NLP_DELAY_TMO) &&
-                  (list != NLP_NPR_LIST)) {
-                       spin_unlock_irq(phba->host->host_lock);
-                       lpfc_cancel_retry_delay_tmo(phba, nlp);
-                       spin_lock_irq(phba->host->host_lock);
-               }
+       case NLP_STE_NPR_NODE:
+               phba->fc_npr_cnt += count;
                break;
        }
+       spin_unlock_irq(phba->host->host_lock);
+}
 
-       nlp->nlp_flag &= ~NLP_LIST_MASK;
-
-       /* Add NPort <did> to <num> list */
-       lpfc_printf_log(phba,
-                       KERN_INFO,
-                       LOG_NODE,
-                       "%d:0904 Add NPort x%x to %d list Data: x%x\n",
-                       phba->brd_no,
-                       nlp->nlp_DID, list, nlp->nlp_flag);
-
-       switch (list) {
-       case NLP_NO_LIST: /* No list, just remove it */
-               spin_unlock_irq(phba->host->host_lock);
-               lpfc_nlp_remove(phba, nlp);
-               spin_lock_irq(phba->host->host_lock);
-               /* as node removed - stop further transport calls */
-               rport_del = none;
-               break;
-       case NLP_UNUSED_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the unused list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_unused_list);
-               phba->fc_unused_cnt++;
-               break;
-       case NLP_PLOGI_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the plogi list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_plogi_list);
-               phba->fc_plogi_cnt++;
-               break;
-       case NLP_ADISC_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the adisc list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_adisc_list);
-               phba->fc_adisc_cnt++;
-               break;
-       case NLP_REGLOGIN_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the reglogin list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_reglogin_list);
-               phba->fc_reglogin_cnt++;
-               break;
-       case NLP_PRLI_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the prli list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_prli_list);
-               phba->fc_prli_cnt++;
-               break;
-       case NLP_UNMAPPED_LIST:
-               rport_add = unmapped;
-               /* ensure all vestiges of "mapped" significance are gone */
-               nlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the unmap list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_nlpunmap_list);
-               phba->fc_unmap_cnt++;
-               phba->nport_event_cnt++;
-               nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
-               nlp->nlp_type |= NLP_FC_NODE;
-               break;
-       case NLP_MAPPED_LIST:
-               rport_add = mapped;
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the map list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_nlpmap_list);
-               phba->fc_map_cnt++;
+static void
+lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+                      int old_state, int new_state)
+{
+       if (new_state == NLP_STE_UNMAPPED_NODE) {
+               ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
+               ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
+               ndlp->nlp_type |= NLP_FC_NODE;
+       }
+       if (new_state == NLP_STE_MAPPED_NODE)
+               ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
+       if (new_state == NLP_STE_NPR_NODE)
+               ndlp->nlp_flag &= ~NLP_RCV_PLOGI;
+
+       /* Transport interface */
+       if (ndlp->rport && (old_state == NLP_STE_MAPPED_NODE ||
+                           old_state == NLP_STE_UNMAPPED_NODE)) {
                phba->nport_event_cnt++;
-               nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
-               break;
-       case NLP_NPR_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the npr list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_npr_list);
-               phba->fc_npr_cnt++;
-
-               nlp->nlp_flag &= ~NLP_RCV_PLOGI;
-               break;
-       case NLP_JUST_DQ:
-               break;
+               lpfc_unregister_remote_port(phba, ndlp);
        }
 
-       spin_unlock_irq(phba->host->host_lock);
-
-       /*
-        * We make all the calls into the transport after we have
-        * moved the node between lists. This so that we don't
-        * release the lock while in-between lists.
-        */
-
-       /* Don't upcall midlayer if we're unloading */
-       if (!(phba->fc_flag & FC_UNLOADING)) {
-               /*
-                * We revalidate the rport pointer as the "add" function
-                * may have removed the remote port.
-                */
-               if ((rport_del != none) && nlp->rport)
-                       lpfc_unregister_remote_port(phba, nlp);
-
-               if (rport_add != none) {
+       if (new_state ==  NLP_STE_MAPPED_NODE ||
+           new_state == NLP_STE_UNMAPPED_NODE) {
+               phba->nport_event_cnt++;
                        /*
                         * Tell the fc transport about the port, if we haven't
                         * already. If we have, and it's a scsi entity, be
                         * sure to unblock any attached scsi devices
                         */
-                       if ((!nlp->rport) || (nlp->rport->port_state ==
-                                       FC_PORTSTATE_BLOCKED))
-                               lpfc_register_remote_port(phba, nlp);
+                       lpfc_register_remote_port(phba, ndlp);
+       }
 
                        /*
                         * if we added to Mapped list, but the remote port
@@ -1340,19 +1247,95 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
                         * our presentable range - move the node to the
                         * Unmapped List
                         */
-                       if ((rport_add == mapped) &&
-                           ((!nlp->rport) ||
-                            (nlp->rport->scsi_target_id == -1) ||
-                            (nlp->rport->scsi_target_id >= LPFC_MAX_TARGET))) {
-                               nlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-                               spin_lock_irq(phba->host->host_lock);
-                               nlp->nlp_flag |= NLP_TGT_NO_SCSIID;
-                               spin_unlock_irq(phba->host->host_lock);
-                               lpfc_nlp_list(phba, nlp, NLP_UNMAPPED_LIST);
-                       }
-               }
+       if (new_state == NLP_STE_MAPPED_NODE &&
+           (!ndlp->rport ||
+            ndlp->rport->scsi_target_id == -1 ||
+            ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) {
+               spin_lock_irq(phba->host->host_lock);
+               ndlp->nlp_flag |= NLP_TGT_NO_SCSIID;
+               spin_unlock_irq(phba->host->host_lock);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
        }
-       return 0;
+}
+
+static char *
+lpfc_nlp_state_name(char *buffer, size_t size, int state)
+{
+       static char *states[] = {
+               [NLP_STE_UNUSED_NODE] = "UNUSED",
+               [NLP_STE_PLOGI_ISSUE] = "PLOGI",
+               [NLP_STE_ADISC_ISSUE] = "ADISC",
+               [NLP_STE_REG_LOGIN_ISSUE] = "REGLOGIN",
+               [NLP_STE_PRLI_ISSUE] = "PRLI",
+               [NLP_STE_UNMAPPED_NODE] = "UNMAPPED",
+               [NLP_STE_MAPPED_NODE] = "MAPPED",
+               [NLP_STE_NPR_NODE] = "NPR",
+       };
+
+       if (state < ARRAY_SIZE(states) && states[state])
+               strlcpy(buffer, states[state], size);
+       else
+               snprintf(buffer, size, "unknown (%d)", state);
+       return buffer;
+}
+
+void
+lpfc_nlp_set_state(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int state)
+{
+       int  old_state = ndlp->nlp_state;
+       char name1[16], name2[16];
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+                       "%d:0904 NPort state transition x%06x, %s -> %s\n",
+                       phba->brd_no,
+                       ndlp->nlp_DID,
+                       lpfc_nlp_state_name(name1, sizeof(name1), old_state),
+                       lpfc_nlp_state_name(name2, sizeof(name2), state));
+       if (old_state == NLP_STE_NPR_NODE &&
+           (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 &&
+           state != NLP_STE_NPR_NODE)
+               lpfc_cancel_retry_delay_tmo(phba, ndlp);
+       if (old_state == NLP_STE_UNMAPPED_NODE) {
+               ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
+               ndlp->nlp_type &= ~NLP_FC_NODE;
+       }
+
+       if (list_empty(&ndlp->nlp_listp)) {
+               spin_lock_irq(phba->host->host_lock);
+               list_add_tail(&ndlp->nlp_listp, &phba->fc_nodes);
+               spin_unlock_irq(phba->host->host_lock);
+       } else if (old_state)
+               lpfc_nlp_counters(phba, old_state, -1);
+
+       ndlp->nlp_state = state;
+       lpfc_nlp_counters(phba, state, 1);
+       lpfc_nlp_state_cleanup(phba, ndlp, old_state, state);
+}
+
+void
+lpfc_dequeue_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+       if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
+               lpfc_cancel_retry_delay_tmo(phba, ndlp);
+       if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
+               lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
+       spin_lock_irq(phba->host->host_lock);
+       list_del_init(&ndlp->nlp_listp);
+       spin_unlock_irq(phba->host->host_lock);
+       lpfc_nlp_state_cleanup(phba, ndlp, ndlp->nlp_state, 0);
+}
+
+void
+lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+       if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
+               lpfc_cancel_retry_delay_tmo(phba, ndlp);
+       if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
+               lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
+       spin_lock_irq(phba->host->host_lock);
+       list_del_init(&ndlp->nlp_listp);
+       spin_unlock_irq(phba->host->host_lock);
+       lpfc_nlp_put(ndlp);
 }
 
 /*
@@ -1464,6 +1447,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba,
 static int
 lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
 {
+       LIST_HEAD(completions);
        struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
        struct lpfc_iocbq *iocb, *next_iocb;
@@ -1492,29 +1476,29 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
                                     (phba, pring, iocb, ndlp))) {
                                        /* It matches, so deque and call compl
                                           with an error */
-                                       list_del(&iocb->list);
+                                       list_move_tail(&iocb->list,
+                                                      &completions);
                                        pring->txq_cnt--;
-                                       if (iocb->iocb_cmpl) {
-                                               icmd = &iocb->iocb;
-                                               icmd->ulpStatus =
-                                                   IOSTAT_LOCAL_REJECT;
-                                               icmd->un.ulpWord[4] =
-                                                   IOERR_SLI_ABORTED;
-                                               spin_unlock_irq(phba->host->
-                                                               host_lock);
-                                               (iocb->iocb_cmpl) (phba,
-                                                                  iocb, iocb);
-                                               spin_lock_irq(phba->host->
-                                                             host_lock);
-                                       } else
-                                               lpfc_sli_release_iocbq(phba,
-                                                                      iocb);
                                }
                        }
                        spin_unlock_irq(phba->host->host_lock);
 
                }
        }
+
+       while (!list_empty(&completions)) {
+               iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               list_del(&iocb->list);
+
+               if (iocb->iocb_cmpl) {
+                       icmd = &iocb->iocb;
+                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+                       (iocb->iocb_cmpl) (phba, iocb, iocb);
+               } else
+                       lpfc_sli_release_iocbq(phba, iocb);
+       }
+
        return 0;
 }
 
@@ -1554,7 +1538,7 @@ lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
  * so it can be freed.
  */
 static int
-lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
 {
        LPFC_MBOXQ_t       *mb;
        LPFC_MBOXQ_t       *nextmb;
@@ -1567,17 +1551,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
                        phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
                        ndlp->nlp_state, ndlp->nlp_rpi);
 
-       lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ);
-
-       /*
-        * if unloading the driver - just leave the remote port in place.
-        * The driver unload will force the attached devices to detach
-        * and flush cache's w/o generating flush errors.
-        */
-       if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) {
-               lpfc_unregister_remote_port(phba, ndlp);
-               ndlp->nlp_sid = NLP_NO_SID;
-       }
+       lpfc_dequeue_node(phba, ndlp);
 
        /* cleanup any ndlp on mbox q waiting for reglogin cmpl */
        if ((mb = phba->sli.mbox_active)) {
@@ -1599,11 +1573,12 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
                        }
                        list_del(&mb->list);
                        mempool_free(mb, phba->mbox_mem_pool);
+                       lpfc_nlp_put(ndlp);
                }
        }
        spin_unlock_irq(phba->host->host_lock);
 
-       lpfc_els_abort(phba,ndlp,0);
+       lpfc_els_abort(phba,ndlp);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~NLP_DELAY_TMO;
        spin_unlock_irq(phba->host->host_lock);
@@ -1624,27 +1599,27 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
  * If we are in the middle of using the nlp in the discovery state
  * machine, defer the free till we reach the end of the state machine.
  */
-int
-lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+static void
+lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
+       struct lpfc_rport_data *rdata;
 
        if (ndlp->nlp_flag & NLP_DELAY_TMO) {
                lpfc_cancel_retry_delay_tmo(phba, ndlp);
        }
 
-       if (ndlp->nlp_disc_refcnt) {
-               spin_lock_irq(phba->host->host_lock);
-               ndlp->nlp_flag |= NLP_DELAY_REMOVE;
-               spin_unlock_irq(phba->host->host_lock);
-       } else {
-               lpfc_freenode(phba, ndlp);
-               mempool_free( ndlp, phba->nlp_mem_pool);
+       lpfc_cleanup_node(phba, ndlp);
+
+       if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) {
+               put_device(&ndlp->rport->dev);
+               rdata = ndlp->rport->dd_data;
+               rdata->pnode = NULL;
+               ndlp->rport = NULL;
        }
-       return 0;
 }
 
 static int
-lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did)
+lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
 {
        D_ID mydid;
        D_ID ndlpdid;
@@ -1693,57 +1668,36 @@ lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did)
        return 0;
 }
 
-/* Search for a nodelist entry on a specific list */
+/* Search for a nodelist entry */
 struct lpfc_nodelist *
-lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
+lpfc_findnode_did(struct lpfc_hba *phba, uint32_t did)
 {
        struct lpfc_nodelist *ndlp;
-       struct list_head *lists[]={&phba->fc_nlpunmap_list,
-                                  &phba->fc_nlpmap_list,
-                                  &phba->fc_plogi_list,
-                                  &phba->fc_adisc_list,
-                                  &phba->fc_reglogin_list,
-                                  &phba->fc_prli_list,
-                                  &phba->fc_npr_list,
-                                  &phba->fc_unused_list};
-       uint32_t search[]={NLP_SEARCH_UNMAPPED,
-                          NLP_SEARCH_MAPPED,
-                          NLP_SEARCH_PLOGI,
-                          NLP_SEARCH_ADISC,
-                          NLP_SEARCH_REGLOGIN,
-                          NLP_SEARCH_PRLI,
-                          NLP_SEARCH_NPR,
-                          NLP_SEARCH_UNUSED};
-       int i;
        uint32_t data1;
 
        spin_lock_irq(phba->host->host_lock);
-       for (i = 0; i < ARRAY_SIZE(lists); i++ ) {
-               if (!(order & search[i]))
-                       continue;
-               list_for_each_entry(ndlp, lists[i], nlp_listp) {
-                       if (lpfc_matchdid(phba, ndlp, did)) {
-                               data1 = (((uint32_t) ndlp->nlp_state << 24) |
-                                        ((uint32_t) ndlp->nlp_xri << 16) |
-                                        ((uint32_t) ndlp->nlp_type << 8) |
-                                        ((uint32_t) ndlp->nlp_rpi & 0xff));
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                                               "%d:0929 FIND node DID "
-                                               " Data: x%p x%x x%x x%x\n",
-                                               phba->brd_no,
-                                               ndlp, ndlp->nlp_DID,
-                                               ndlp->nlp_flag, data1);
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
+       list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+               if (lpfc_matchdid(phba, ndlp, did)) {
+                       data1 = (((uint32_t) ndlp->nlp_state << 24) |
+                                ((uint32_t) ndlp->nlp_xri << 16) |
+                                ((uint32_t) ndlp->nlp_type << 8) |
+                                ((uint32_t) ndlp->nlp_rpi & 0xff));
+                       lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+                                       "%d:0929 FIND node DID "
+                                       " Data: x%p x%x x%x x%x\n",
+                                       phba->brd_no,
+                                       ndlp, ndlp->nlp_DID,
+                                       ndlp->nlp_flag, data1);
+                       spin_unlock_irq(phba->host->host_lock);
+                       return ndlp;
                }
        }
        spin_unlock_irq(phba->host->host_lock);
 
        /* FIND node did <did> NOT FOUND */
        lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                       "%d:0932 FIND node did x%x NOT FOUND Data: x%x\n",
-                       phba->brd_no, did, order);
+                       "%d:0932 FIND node did x%x NOT FOUND.\n",
+                       phba->brd_no, did);
        return NULL;
 }
 
@@ -1751,9 +1705,8 @@ struct lpfc_nodelist *
 lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
 {
        struct lpfc_nodelist *ndlp;
-       uint32_t flg;
 
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+       ndlp = lpfc_findnode_did(phba, did);
        if (!ndlp) {
                if ((phba->fc_flag & FC_RSCN_MODE) &&
                   ((lpfc_rscn_payload_check(phba, did) == 0)))
@@ -1763,8 +1716,7 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
                if (!ndlp)
                        return NULL;
                lpfc_nlp_init(phba, ndlp, did);
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
                return ndlp;
        }
@@ -1780,11 +1732,10 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
                } else
                        ndlp = NULL;
        } else {
-               flg = ndlp->nlp_flag & NLP_LIST_MASK;
-               if ((flg == NLP_ADISC_LIST) || (flg == NLP_PLOGI_LIST))
+               if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
+                   ndlp->nlp_state == NLP_STE_PLOGI_ISSUE)
                        return NULL;
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
        }
        return ndlp;
@@ -1842,8 +1793,9 @@ lpfc_disc_start(struct lpfc_hba * phba)
        struct lpfc_sli *psli;
        LPFC_MBOXQ_t *mbox;
        struct lpfc_nodelist *ndlp, *next_ndlp;
-       uint32_t did_changed, num_sent;
+       uint32_t num_sent;
        uint32_t clear_la_pending;
+       int did_changed;
        int rc;
 
        psli = &phba->sli;
@@ -1877,14 +1829,13 @@ lpfc_disc_start(struct lpfc_hba * phba)
                        phba->fc_plogi_cnt, phba->fc_adisc_cnt);
 
        /* If our did changed, we MUST do PLOGI */
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                               nlp_listp) {
-               if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
-                       if (did_changed) {
-                               spin_lock_irq(phba->host->host_lock);
-                               ndlp->nlp_flag &= ~NLP_NPR_ADISC;
-                               spin_unlock_irq(phba->host->host_lock);
-                       }
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+                   (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+                   did_changed) {
+                       spin_lock_irq(phba->host->host_lock);
+                       ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+                       spin_unlock_irq(phba->host->host_lock);
                }
        }
 
@@ -1944,11 +1895,11 @@ lpfc_disc_start(struct lpfc_hba * phba)
 static void
 lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
 {
+       LIST_HEAD(completions);
        struct lpfc_sli *psli;
        IOCB_t     *icmd;
        struct lpfc_iocbq    *iocb, *next_iocb;
        struct lpfc_sli_ring *pring;
-       struct lpfc_dmabuf   *mp;
 
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];
@@ -1956,6 +1907,7 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
        /* Error matching iocb on txq or txcmplq
         * First check the txq.
         */
+       spin_lock_irq(phba->host->host_lock);
        list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
                if (iocb->context1 != ndlp) {
                        continue;
@@ -1964,9 +1916,8 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
                if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
                    (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
 
-                       list_del(&iocb->list);
+                       list_move_tail(&iocb->list, &completions);
                        pring->txq_cnt--;
-                       lpfc_els_free_iocb(phba, iocb);
                }
        }
 
@@ -1978,43 +1929,22 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
                icmd = &iocb->iocb;
                if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
                    (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
+                       lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+               }
+       }
+       spin_unlock_irq(phba->host->host_lock);
 
-                       iocb->iocb_cmpl = NULL;
-                       /* context2 = cmd, context2->next = rsp, context3 =
-                          bpl */
-                       if (iocb->context2) {
-                               /* Free the response IOCB before handling the
-                                  command. */
-
-                               mp = (struct lpfc_dmabuf *) (iocb->context2);
-                               mp = list_get_first(&mp->list,
-                                                   struct lpfc_dmabuf,
-                                                   list);
-                               if (mp) {
-                                       /* Delay before releasing rsp buffer to
-                                        * give UNREG mbox a chance to take
-                                        * effect.
-                                        */
-                                       list_add(&mp->list,
-                                               &phba->freebufList);
-                               }
-                               lpfc_mbuf_free(phba,
-                                              ((struct lpfc_dmabuf *)
-                                               iocb->context2)->virt,
-                                              ((struct lpfc_dmabuf *)
-                                               iocb->context2)->phys);
-                               kfree(iocb->context2);
-                       }
+       while (!list_empty(&completions)) {
+               iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               list_del(&iocb->list);
 
-                       if (iocb->context3) {
-                               lpfc_mbuf_free(phba,
-                                              ((struct lpfc_dmabuf *)
-                                               iocb->context3)->virt,
-                                              ((struct lpfc_dmabuf *)
-                                               iocb->context3)->phys);
-                               kfree(iocb->context3);
-                       }
-               }
+               if (iocb->iocb_cmpl) {
+                       icmd = &iocb->iocb;
+                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+                       (iocb->iocb_cmpl) (phba, iocb, iocb);
+               } else
+                       lpfc_sli_release_iocbq(phba, iocb);
        }
 
        return;
@@ -2025,21 +1955,16 @@ lpfc_disc_flush_list(struct lpfc_hba * phba)
 {
        struct lpfc_nodelist *ndlp, *next_ndlp;
 
-       if (phba->fc_plogi_cnt) {
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
-                                       nlp_listp) {
-                       lpfc_free_tx(phba, ndlp);
-                       lpfc_nlp_remove(phba, ndlp);
-               }
-       }
-       if (phba->fc_adisc_cnt) {
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
-                                       nlp_listp) {
-                       lpfc_free_tx(phba, ndlp);
-                       lpfc_nlp_remove(phba, ndlp);
+       if (phba->fc_plogi_cnt || phba->fc_adisc_cnt) {
+               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+                                        nlp_listp) {
+                       if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
+                           ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
+                               lpfc_free_tx(phba, ndlp);
+                               lpfc_nlp_put(ndlp);
+                       }
                }
        }
-       return;
 }
 
 /*****************************************************************************/
@@ -2108,11 +2033,13 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
                                 phba->brd_no);
 
                /* Start discovery by sending FLOGI, clean up old rpis */
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                                       nlp_listp) {
+               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+                                        nlp_listp) {
+                       if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+                               continue;
                        if (ndlp->nlp_type & NLP_FABRIC) {
                                /* Clean up the ndlp on Fabric connections */
-                               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                               lpfc_drop_node(phba, ndlp);
                        } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
                                /* Fail outstanding IO now since device
                                 * is marked for PLOGI.
@@ -2153,9 +2080,9 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
                                "login\n", phba->brd_no);
 
                /* Next look for NameServer ndlp */
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+               ndlp = lpfc_findnode_did(phba, NameServer_DID);
                if (ndlp)
-                       lpfc_nlp_remove(phba, ndlp);
+                       lpfc_nlp_put(ndlp);
                /* Start discovery */
                lpfc_disc_start(phba);
                break;
@@ -2168,9 +2095,8 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
                                phba->brd_no,
                                phba->fc_ns_retry, LPFC_MAX_NS_RETRY);
 
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
-                                                               NameServer_DID);
-               if (ndlp) {
+               ndlp = lpfc_findnode_did(phba, NameServer_DID);
+               if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
                        if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
                                /* Try it one more time */
                                rc = lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT);
@@ -2220,6 +2146,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
                initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
                rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
                                         (MBX_NOWAIT | MBX_STOP_IOCB));
+               lpfc_set_loopback_flag(phba);
                if (rc == MBX_NOT_FINISHED)
                        mempool_free(initlinkmbox, phba->mbox_mem_pool);
 
@@ -2317,8 +2244,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        ndlp->nlp_rpi = mb->un.varWords[0];
        ndlp->nlp_type |= NLP_FABRIC;
-       ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
 
        /* Start issuing Fabric-Device Management Interface (FDMI)
         * command to 0xfffffa (FDMI well known port)
@@ -2333,87 +2259,100 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
                mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
        }
 
+                               /* Mailbox took a reference to the node */
+       lpfc_nlp_put(ndlp);
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
-       mempool_free( pmb, phba->mbox_mem_pool);
+       mempool_free(pmb, phba->mbox_mem_pool);
 
        return;
 }
 
+static int
+lpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param)
+{
+       uint16_t *rpi = param;
+
+       return ndlp->nlp_rpi == *rpi;
+}
+
+static int
+lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param)
+{
+       return memcmp(&ndlp->nlp_portname, param,
+                     sizeof(ndlp->nlp_portname)) == 0;
+}
+
+/*
+ * Search node lists for a remote port matching filter criteria
+ * Caller needs to hold host_lock before calling this routine.
+ */
+struct lpfc_nodelist *
+__lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
+{
+       struct lpfc_nodelist *ndlp;
+
+       list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state != NLP_STE_UNUSED_NODE &&
+                   filter(ndlp, param))
+                       return ndlp;
+       }
+       return NULL;
+}
+
 /*
- * This routine looks up the ndlp  lists
- * for the given RPI. If rpi found
- * it return the node list pointer
- * else return NULL.
+ * Search node lists for a remote port matching filter criteria
+ * This routine is used when the caller does NOT have host_lock.
  */
+struct lpfc_nodelist *
+lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
+{
+       struct lpfc_nodelist *ndlp;
+
+       spin_lock_irq(phba->host->host_lock);
+       ndlp = __lpfc_find_node(phba, filter, param);
+       spin_unlock_irq(phba->host->host_lock);
+       return ndlp;
+}
+
+/*
+ * This routine looks up the ndlp lists for the given RPI. If rpi found it
+ * returns the node list pointer else return NULL.
+ */
+struct lpfc_nodelist *
+__lpfc_findnode_rpi(struct lpfc_hba *phba, uint16_t rpi)
+{
+       return __lpfc_find_node(phba, lpfc_filter_by_rpi, &rpi);
+}
+
 struct lpfc_nodelist *
 lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
 {
        struct lpfc_nodelist *ndlp;
-       struct list_head * lists[]={&phba->fc_nlpunmap_list,
-                                   &phba->fc_nlpmap_list,
-                                   &phba->fc_plogi_list,
-                                   &phba->fc_adisc_list,
-                                   &phba->fc_reglogin_list};
-       int i;
 
        spin_lock_irq(phba->host->host_lock);
-       for (i = 0; i < ARRAY_SIZE(lists); i++ )
-               list_for_each_entry(ndlp, lists[i], nlp_listp)
-                       if (ndlp->nlp_rpi == rpi) {
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
+       ndlp = __lpfc_findnode_rpi(phba, rpi);
        spin_unlock_irq(phba->host->host_lock);
-       return NULL;
+       return ndlp;
 }
 
 /*
- * This routine looks up the ndlp  lists
- * for the given WWPN. If WWPN found
- * it return the node list pointer
- * else return NULL.
+ * This routine looks up the ndlp lists for the given WWPN. If WWPN found it
+ * returns the node list pointer else return NULL.
  */
 struct lpfc_nodelist *
-lpfc_findnode_wwpn(struct lpfc_hba * phba, uint32_t order,
-                  struct lpfc_name * wwpn)
+lpfc_findnode_wwpn(struct lpfc_hba *phba, struct lpfc_name *wwpn)
 {
        struct lpfc_nodelist *ndlp;
-       struct list_head * lists[]={&phba->fc_nlpunmap_list,
-                                   &phba->fc_nlpmap_list,
-                                   &phba->fc_npr_list,
-                                   &phba->fc_plogi_list,
-                                   &phba->fc_adisc_list,
-                                   &phba->fc_reglogin_list,
-                                   &phba->fc_prli_list};
-       uint32_t search[]={NLP_SEARCH_UNMAPPED,
-                          NLP_SEARCH_MAPPED,
-                          NLP_SEARCH_NPR,
-                          NLP_SEARCH_PLOGI,
-                          NLP_SEARCH_ADISC,
-                          NLP_SEARCH_REGLOGIN,
-                          NLP_SEARCH_PRLI};
-       int i;
 
        spin_lock_irq(phba->host->host_lock);
-       for (i = 0; i < ARRAY_SIZE(lists); i++ ) {
-               if (!(order & search[i]))
-                       continue;
-               list_for_each_entry(ndlp, lists[i], nlp_listp) {
-                       if (memcmp(&ndlp->nlp_portname, wwpn,
-                                  sizeof(struct lpfc_name)) == 0) {
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
-               }
-       }
+       ndlp = __lpfc_find_node(phba, lpfc_filter_by_wwpn, wwpn);
        spin_unlock_irq(phba->host->host_lock);
        return NULL;
 }
 
 void
-lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
-                uint32_t did)
+lpfc_nlp_init(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
 {
        memset(ndlp, 0, sizeof (struct lpfc_nodelist));
        INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
@@ -2423,5 +2362,30 @@ lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        ndlp->nlp_DID = did;
        ndlp->nlp_phba = phba;
        ndlp->nlp_sid = NLP_NO_SID;
+       INIT_LIST_HEAD(&ndlp->nlp_listp);
+       kref_init(&ndlp->kref);
        return;
 }
+
+void
+lpfc_nlp_release(struct kref *kref)
+{
+       struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist,
+                                                 kref);
+       lpfc_nlp_remove(ndlp->nlp_phba, ndlp);
+       mempool_free(ndlp, ndlp->nlp_phba->nlp_mem_pool);
+}
+
+struct lpfc_nodelist *
+lpfc_nlp_get(struct lpfc_nodelist *ndlp)
+{
+       if (ndlp)
+               kref_get(&ndlp->kref);
+       return ndlp;
+}
+
+int
+lpfc_nlp_put(struct lpfc_nodelist *ndlp)
+{
+       return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0;
+}
index f79cb61369065007a88ca4dccb6e50c2bb1ec174..2623a9bc7775f0f4fe8bd5026f8964303ad42ee2 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -1078,6 +1078,8 @@ typedef struct {
 /* Start FireFly Register definitions */
 #define PCI_VENDOR_ID_EMULEX        0x10df
 #define PCI_DEVICE_ID_FIREFLY       0x1ae5
+#define PCI_DEVICE_ID_SAT_SMB       0xf011
+#define PCI_DEVICE_ID_SAT_MID       0xf015
 #define PCI_DEVICE_ID_RFLY          0xf095
 #define PCI_DEVICE_ID_PFLY          0xf098
 #define PCI_DEVICE_ID_LP101         0xf0a1
@@ -1089,6 +1091,9 @@ typedef struct {
 #define PCI_DEVICE_ID_NEPTUNE       0xf0f5
 #define PCI_DEVICE_ID_NEPTUNE_SCSP  0xf0f6
 #define PCI_DEVICE_ID_NEPTUNE_DCSP  0xf0f7
+#define PCI_DEVICE_ID_SAT           0xf100
+#define PCI_DEVICE_ID_SAT_SCSP      0xf111
+#define PCI_DEVICE_ID_SAT_DCSP      0xf112
 #define PCI_DEVICE_ID_SUPERFLY      0xf700
 #define PCI_DEVICE_ID_DRAGONFLY     0xf800
 #define PCI_DEVICE_ID_CENTAUR       0xf900
@@ -1098,6 +1103,7 @@ typedef struct {
 #define PCI_DEVICE_ID_LP10000S      0xfc00
 #define PCI_DEVICE_ID_LP11000S      0xfc10
 #define PCI_DEVICE_ID_LPE11000S     0xfc20
+#define PCI_DEVICE_ID_SAT_S         0xfc40
 #define PCI_DEVICE_ID_HELIOS        0xfd00
 #define PCI_DEVICE_ID_HELIOS_SCSP   0xfd11
 #define PCI_DEVICE_ID_HELIOS_DCSP   0xfd12
@@ -1118,6 +1124,7 @@ typedef struct {
 #define HELIOS_JEDEC_ID             0x0364
 #define ZEPHYR_JEDEC_ID             0x0577
 #define VIPER_JEDEC_ID              0x4838
+#define SATURN_JEDEC_ID             0x1004
 
 #define JEDEC_ID_MASK               0x0FFFF000
 #define JEDEC_ID_SHIFT              12
@@ -1565,7 +1572,7 @@ typedef struct {
 #define LINK_SPEED_1G   1       /* 1 Gigabaud */
 #define LINK_SPEED_2G   2       /* 2 Gigabaud */
 #define LINK_SPEED_4G   4       /* 4 Gigabaud */
-#define LINK_SPEED_8G   8       /* 4 Gigabaud */
+#define LINK_SPEED_8G   8       /* 8 Gigabaud */
 #define LINK_SPEED_10G   16      /* 10 Gigabaud */
 
 } INIT_LINK_VAR;
index dcf6106f557a0dac93efb20710dcbf9d1bec7bc7..dcb4ba0ecee1825067b2344562ab0e21d4df0601 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -386,12 +386,12 @@ lpfc_config_port_post(struct lpfc_hba * phba)
         * Setup the ring 0 (els)  timeout handler
         */
        timeout = phba->fc_ratov << 1;
-       phba->els_tmofunc.expires = jiffies + HZ * timeout;
-       add_timer(&phba->els_tmofunc);
+       mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
 
        lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
        pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
        rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+       lpfc_set_loopback_flag(phba);
        if (rc != MBX_SUCCESS) {
                lpfc_printf_log(phba,
                                KERN_ERR,
@@ -418,33 +418,6 @@ lpfc_config_port_post(struct lpfc_hba * phba)
        return (0);
 }
 
-static int
-lpfc_discovery_wait(struct lpfc_hba *phba)
-{
-       int i = 0;
-
-       while ((phba->hba_state != LPFC_HBA_READY) ||
-              (phba->num_disc_nodes) || (phba->fc_prli_sent) ||
-              ((phba->fc_map_cnt == 0) && (i<2)) ||
-              (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
-               /* Check every second for 30 retries. */
-               i++;
-               if (i > 30) {
-                       return -ETIMEDOUT;
-               }
-               if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) {
-                       /* The link is down.  Set linkdown timeout */
-                       return -ETIMEDOUT;
-               }
-
-               /* Delay for 1 second to give discovery time to complete. */
-               msleep(1000);
-
-       }
-
-       return 0;
-}
-
 /************************************************************************/
 /*                                                                      */
 /*    lpfc_hba_down_prep                                                */
@@ -550,12 +523,15 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
                 * There was a firmware error.  Take the hba offline and then
                 * attempt to restart it.
                 */
+               lpfc_offline_prep(phba);
                lpfc_offline(phba);
                lpfc_sli_brdrestart(phba);
                if (lpfc_online(phba) == 0) {   /* Initialize the HBA */
                        mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
+                       lpfc_unblock_mgmt_io(phba);
                        return;
                }
+               lpfc_unblock_mgmt_io(phba);
        } else {
                /* The if clause above forces this code path when the status
                 * failure is a value other than FFER6.  Do not call the offline
@@ -573,7 +549,9 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
                                SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
 
                psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+               lpfc_offline_prep(phba);
                lpfc_offline(phba);
+               lpfc_unblock_mgmt_io(phba);
                phba->hba_state = LPFC_HBA_ERROR;
                lpfc_hba_down_post(phba);
        }
@@ -633,7 +611,7 @@ lpfc_handle_latt_free_mbuf:
 lpfc_handle_latt_free_mp:
        kfree(mp);
 lpfc_handle_latt_free_pmb:
-       kfree(pmb);
+       mempool_free(pmb, phba->mbox_mem_pool);
 lpfc_handle_latt_err_exit:
        /* Enable Link attention interrupts */
        spin_lock_irq(phba->host->host_lock);
@@ -925,6 +903,24 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
                m = (typeof(m)){"LPe11000-S", max_speed,
                        "PCIe"};
                break;
+       case PCI_DEVICE_ID_SAT:
+               m = (typeof(m)){"LPe12000", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_MID:
+               m = (typeof(m)){"LPe1250", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_SMB:
+               m = (typeof(m)){"LPe121", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_DCSP:
+               m = (typeof(m)){"LPe12002-SP", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_SCSP:
+               m = (typeof(m)){"LPe12000-SP", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_S:
+               m = (typeof(m)){"LPe12000-S", max_speed, "PCIe"};
+               break;
        default:
                m = (typeof(m)){ NULL };
                break;
@@ -1174,69 +1170,17 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
 }
 
 static void
-lpfc_cleanup(struct lpfc_hba * phba, uint32_t save_bind)
+lpfc_cleanup(struct lpfc_hba * phba)
 {
        struct lpfc_nodelist *ndlp, *next_ndlp;
 
        /* clean up phba - lpfc specific */
        lpfc_can_disctmo(phba);
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpunmap_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+               lpfc_nlp_put(ndlp);
 
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list,
-                                nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
-                               nlp_listp) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_reglogin_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
+       INIT_LIST_HEAD(&phba->fc_nodes);
 
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       INIT_LIST_HEAD(&phba->fc_nlpmap_list);
-       INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
-       INIT_LIST_HEAD(&phba->fc_unused_list);
-       INIT_LIST_HEAD(&phba->fc_plogi_list);
-       INIT_LIST_HEAD(&phba->fc_adisc_list);
-       INIT_LIST_HEAD(&phba->fc_reglogin_list);
-       INIT_LIST_HEAD(&phba->fc_prli_list);
-       INIT_LIST_HEAD(&phba->fc_npr_list);
-
-       phba->fc_map_cnt   = 0;
-       phba->fc_unmap_cnt = 0;
-       phba->fc_plogi_cnt = 0;
-       phba->fc_adisc_cnt = 0;
-       phba->fc_reglogin_cnt = 0;
-       phba->fc_prli_cnt  = 0;
-       phba->fc_npr_cnt   = 0;
-       phba->fc_unused_cnt= 0;
        return;
 }
 
@@ -1262,21 +1206,6 @@ lpfc_stop_timer(struct lpfc_hba * phba)
 {
        struct lpfc_sli *psli = &phba->sli;
 
-       /* Instead of a timer, this has been converted to a
-        * deferred procedding list.
-        */
-       while (!list_empty(&phba->freebufList)) {
-
-               struct lpfc_dmabuf *mp = NULL;
-
-               list_remove_head((&phba->freebufList), mp,
-                                struct lpfc_dmabuf, list);
-               if (mp) {
-                       lpfc_mbuf_free(phba, mp->virt, mp->phys);
-                       kfree(mp);
-               }
-       }
-
        del_timer_sync(&phba->fcp_poll_timer);
        del_timer_sync(&phba->fc_estabtmo);
        del_timer_sync(&phba->fc_disctmo);
@@ -1302,60 +1231,76 @@ lpfc_online(struct lpfc_hba * phba)
                       "%d:0458 Bring Adapter online\n",
                       phba->brd_no);
 
-       if (!lpfc_sli_queue_setup(phba))
+       lpfc_block_mgmt_io(phba);
+
+       if (!lpfc_sli_queue_setup(phba)) {
+               lpfc_unblock_mgmt_io(phba);
                return 1;
+       }
 
-       if (lpfc_sli_hba_setup(phba))   /* Initialize the HBA */
+       if (lpfc_sli_hba_setup(phba)) { /* Initialize the HBA */
+               lpfc_unblock_mgmt_io(phba);
                return 1;
+       }
 
        spin_lock_irq(phba->host->host_lock);
        phba->fc_flag &= ~FC_OFFLINE_MODE;
        spin_unlock_irq(phba->host->host_lock);
 
+       lpfc_unblock_mgmt_io(phba);
        return 0;
 }
 
-int
-lpfc_offline(struct lpfc_hba * phba)
+void
+lpfc_block_mgmt_io(struct lpfc_hba * phba)
 {
-       struct lpfc_sli_ring *pring;
-       struct lpfc_sli *psli;
        unsigned long iflag;
-       int i;
-       int cnt = 0;
 
-       if (!phba)
-               return 0;
+       spin_lock_irqsave(phba->host->host_lock, iflag);
+       phba->fc_flag |= FC_BLOCK_MGMT_IO;
+       spin_unlock_irqrestore(phba->host->host_lock, iflag);
+}
+
+void
+lpfc_unblock_mgmt_io(struct lpfc_hba * phba)
+{
+       unsigned long iflag;
+
+       spin_lock_irqsave(phba->host->host_lock, iflag);
+       phba->fc_flag &= ~FC_BLOCK_MGMT_IO;
+       spin_unlock_irqrestore(phba->host->host_lock, iflag);
+}
+
+void
+lpfc_offline_prep(struct lpfc_hba * phba)
+{
+       struct lpfc_nodelist  *ndlp, *next_ndlp;
 
        if (phba->fc_flag & FC_OFFLINE_MODE)
-               return 0;
+               return;
 
-       psli = &phba->sli;
+       lpfc_block_mgmt_io(phba);
 
        lpfc_linkdown(phba);
+
+       /* Issue an unreg_login to all nodes */
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+               if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
+                       lpfc_unreg_rpi(phba, ndlp);
+
        lpfc_sli_flush_mbox_queue(phba);
+}
 
-       for (i = 0; i < psli->num_rings; i++) {
-               pring = &psli->ring[i];
-               /* The linkdown event takes 30 seconds to timeout. */
-               while (pring->txcmplq_cnt) {
-                       mdelay(10);
-                       if (cnt++ > 3000) {
-                               lpfc_printf_log(phba,
-                                       KERN_WARNING, LOG_INIT,
-                                       "%d:0466 Outstanding IO when "
-                                       "bringing Adapter offline\n",
-                                       phba->brd_no);
-                               break;
-                       }
-               }
-       }
+void
+lpfc_offline(struct lpfc_hba * phba)
+{
+       unsigned long iflag;
 
+       if (phba->fc_flag & FC_OFFLINE_MODE)
+               return;
 
        /* stop all timers associated with this hba */
        lpfc_stop_timer(phba);
-       phba->work_hba_events = 0;
-       phba->work_ha = 0;
 
        lpfc_printf_log(phba,
                       KERN_WARNING,
@@ -1366,11 +1311,12 @@ lpfc_offline(struct lpfc_hba * phba)
        /* Bring down the SLI Layer and cleanup.  The HBA is offline
           now.  */
        lpfc_sli_hba_down(phba);
-       lpfc_cleanup(phba, 1);
+       lpfc_cleanup(phba);
        spin_lock_irqsave(phba->host->host_lock, iflag);
+       phba->work_hba_events = 0;
+       phba->work_ha = 0;
        phba->fc_flag |= FC_OFFLINE_MODE;
        spin_unlock_irqrestore(phba->host->host_lock, iflag);
-       return 0;
 }
 
 /******************************************************************************
@@ -1407,6 +1353,156 @@ lpfc_scsi_free(struct lpfc_hba * phba)
        return 0;
 }
 
+void lpfc_remove_device(struct lpfc_hba *phba)
+{
+       unsigned long iflag;
+
+       lpfc_free_sysfs_attr(phba);
+
+       spin_lock_irqsave(phba->host->host_lock, iflag);
+       phba->fc_flag |= FC_UNLOADING;
+
+       spin_unlock_irqrestore(phba->host->host_lock, iflag);
+
+       fc_remove_host(phba->host);
+       scsi_remove_host(phba->host);
+
+       kthread_stop(phba->worker_thread);
+
+       /*
+        * Bring down the SLI Layer. This step disable all interrupts,
+        * clears the rings, discards all mailbox commands, and resets
+        * the HBA.
+        */
+       lpfc_sli_hba_down(phba);
+       lpfc_sli_brdrestart(phba);
+
+       /* Release the irq reservation */
+       free_irq(phba->pcidev->irq, phba);
+       pci_disable_msi(phba->pcidev);
+
+       lpfc_cleanup(phba);
+       lpfc_stop_timer(phba);
+       phba->work_hba_events = 0;
+
+       /*
+        * Call scsi_free before mem_free since scsi bufs are released to their
+        * corresponding pools here.
+        */
+       lpfc_scsi_free(phba);
+       lpfc_mem_free(phba);
+
+       /* Free resources associated with SLI2 interface */
+       dma_free_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE,
+                         phba->slim2p, phba->slim2p_mapping);
+
+       /* unmap adapter SLIM and Control Registers */
+       iounmap(phba->ctrl_regs_memmap_p);
+       iounmap(phba->slim_memmap_p);
+
+       pci_release_regions(phba->pcidev);
+       pci_disable_device(phba->pcidev);
+
+       idr_remove(&lpfc_hba_index, phba->brd_no);
+       scsi_host_put(phba->host);
+}
+
+void lpfc_scan_start(struct Scsi_Host *host)
+{
+       struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+
+       if (lpfc_alloc_sysfs_attr(phba))
+               goto error;
+
+       phba->MBslimaddr = phba->slim_memmap_p;
+       phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
+       phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
+       phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
+       phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+
+       if (lpfc_sli_hba_setup(phba))
+               goto error;
+
+       /*
+        * hba setup may have changed the hba_queue_depth so we need to adjust
+        * the value of can_queue.
+        */
+       host->can_queue = phba->cfg_hba_queue_depth - 10;
+       return;
+
+error:
+       lpfc_remove_device(phba);
+}
+
+int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+       struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+
+       if (!phba->host)
+               return 1;
+       if (time >= 30 * HZ)
+               goto finished;
+
+       if (phba->hba_state != LPFC_HBA_READY)
+               return 0;
+       if (phba->num_disc_nodes || phba->fc_prli_sent)
+               return 0;
+       if ((phba->fc_map_cnt == 0) && (time < 2 * HZ))
+               return 0;
+       if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)
+               return 0;
+       if ((phba->hba_state > LPFC_LINK_DOWN) || (time < 15 * HZ))
+               return 0;
+
+finished:
+       if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
+               spin_lock_irq(shost->host_lock);
+               lpfc_poll_start_timer(phba);
+               spin_unlock_irq(shost->host_lock);
+       }
+
+       /*
+        * set fixed host attributes
+        * Must done after lpfc_sli_hba_setup()
+        */
+
+       fc_host_node_name(shost) = wwn_to_u64(phba->fc_nodename.u.wwn);
+       fc_host_port_name(shost) = wwn_to_u64(phba->fc_portname.u.wwn);
+       fc_host_supported_classes(shost) = FC_COS_CLASS3;
+
+       memset(fc_host_supported_fc4s(shost), 0,
+               sizeof(fc_host_supported_fc4s(shost)));
+       fc_host_supported_fc4s(shost)[2] = 1;
+       fc_host_supported_fc4s(shost)[7] = 1;
+
+       lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
+
+       fc_host_supported_speeds(shost) = 0;
+       if (phba->lmt & LMT_10Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
+       if (phba->lmt & LMT_4Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT;
+       if (phba->lmt & LMT_2Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_2GBIT;
+       if (phba->lmt & LMT_1Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_1GBIT;
+
+       fc_host_maxframe_size(shost) =
+               ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
+                (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
+
+       /* This value is also unchanging */
+       memset(fc_host_active_fc4s(shost), 0,
+               sizeof(fc_host_active_fc4s(shost)));
+       fc_host_active_fc4s(shost)[2] = 1;
+       fc_host_active_fc4s(shost)[7] = 1;
+
+       spin_lock_irq(shost->host_lock);
+       phba->fc_flag &= ~FC_LOADING;
+       spin_unlock_irq(shost->host_lock);
+
+       return 1;
+}
 
 static int __devinit
 lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
@@ -1445,9 +1541,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
                goto out_put_host;
 
        host->unique_id = phba->brd_no;
-       INIT_LIST_HEAD(&phba->ctrspbuflist);
-       INIT_LIST_HEAD(&phba->rnidrspbuflist);
-       INIT_LIST_HEAD(&phba->freebufList);
 
        /* Initialize timers used by driver */
        init_timer(&phba->fc_estabtmo);
@@ -1482,16 +1575,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        host->max_lun = phba->cfg_max_luns;
        host->this_id = -1;
 
-       /* Initialize all internally managed lists. */
-       INIT_LIST_HEAD(&phba->fc_nlpmap_list);
-       INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
-       INIT_LIST_HEAD(&phba->fc_unused_list);
-       INIT_LIST_HEAD(&phba->fc_plogi_list);
-       INIT_LIST_HEAD(&phba->fc_adisc_list);
-       INIT_LIST_HEAD(&phba->fc_reglogin_list);
-       INIT_LIST_HEAD(&phba->fc_prli_list);
-       INIT_LIST_HEAD(&phba->fc_npr_list);
-
+       INIT_LIST_HEAD(&phba->fc_nodes);
 
        pci_set_master(pdev);
        retval = pci_set_mwi(pdev);
@@ -1609,13 +1693,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 
        host->transportt = lpfc_transport_template;
        pci_set_drvdata(pdev, host);
-       error = scsi_add_host(host, &pdev->dev);
-       if (error)
-               goto out_kthread_stop;
-
-       error = lpfc_alloc_sysfs_attr(phba);
-       if (error)
-               goto out_remove_host;
 
        if (phba->cfg_use_msi) {
                error = pci_enable_msi(phba->pcidev);
@@ -1631,73 +1708,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                        "%d:0451 Enable interrupt handler failed\n",
                        phba->brd_no);
-               goto out_free_sysfs_attr;
+               goto out_kthread_stop;
        }
-       phba->MBslimaddr = phba->slim_memmap_p;
-       phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
-       phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
-       phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
-       phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
 
-       error = lpfc_sli_hba_setup(phba);
-       if (error) {
-               error = -ENODEV;
+       error = scsi_add_host(host, &pdev->dev);
+       if (error)
                goto out_free_irq;
-       }
-
-       /*
-        * hba setup may have changed the hba_queue_depth so we need to adjust
-        * the value of can_queue.
-        */
-       host->can_queue = phba->cfg_hba_queue_depth - 10;
-
-       lpfc_discovery_wait(phba);
 
-       if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
-               spin_lock_irq(phba->host->host_lock);
-               lpfc_poll_start_timer(phba);
-               spin_unlock_irq(phba->host->host_lock);
-       }
+       scsi_scan_host(host);
 
-       /*
-        * set fixed host attributes
-        * Must done after lpfc_sli_hba_setup()
-        */
-
-       fc_host_node_name(host) = wwn_to_u64(phba->fc_nodename.u.wwn);
-       fc_host_port_name(host) = wwn_to_u64(phba->fc_portname.u.wwn);
-       fc_host_supported_classes(host) = FC_COS_CLASS3;
-
-       memset(fc_host_supported_fc4s(host), 0,
-               sizeof(fc_host_supported_fc4s(host)));
-       fc_host_supported_fc4s(host)[2] = 1;
-       fc_host_supported_fc4s(host)[7] = 1;
-
-       lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(host));
-
-       fc_host_supported_speeds(host) = 0;
-       if (phba->lmt & LMT_10Gb)
-               fc_host_supported_speeds(host) |= FC_PORTSPEED_10GBIT;
-       if (phba->lmt & LMT_4Gb)
-               fc_host_supported_speeds(host) |= FC_PORTSPEED_4GBIT;
-       if (phba->lmt & LMT_2Gb)
-               fc_host_supported_speeds(host) |= FC_PORTSPEED_2GBIT;
-       if (phba->lmt & LMT_1Gb)
-               fc_host_supported_speeds(host) |= FC_PORTSPEED_1GBIT;
-
-       fc_host_maxframe_size(host) =
-               ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
-                (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
-
-       /* This value is also unchanging */
-       memset(fc_host_active_fc4s(host), 0,
-               sizeof(fc_host_active_fc4s(host)));
-       fc_host_active_fc4s(host)[2] = 1;
-       fc_host_active_fc4s(host)[7] = 1;
-
-       spin_lock_irq(phba->host->host_lock);
-       phba->fc_flag &= ~FC_LOADING;
-       spin_unlock_irq(phba->host->host_lock);
        return 0;
 
 out_free_irq:
@@ -1705,11 +1724,6 @@ out_free_irq:
        phba->work_hba_events = 0;
        free_irq(phba->pcidev->irq, phba);
        pci_disable_msi(phba->pcidev);
-out_free_sysfs_attr:
-       lpfc_free_sysfs_attr(phba);
-out_remove_host:
-