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:
-       fc_remove_host(phba->host);
-       scsi_remove_host(phba->host);
 out_kthread_stop:
        kthread_stop(phba->worker_thread);
 out_free_iocbq:
@@ -1747,56 +1761,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host   *host = pci_get_drvdata(pdev);
        struct lpfc_hba    *phba = (struct lpfc_hba *)host->hostdata;
-       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, 0);
-       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(&pdev->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);
+       lpfc_remove_device(phba);
 
        pci_set_drvdata(pdev, NULL);
 }
@@ -1941,6 +1907,18 @@ static struct pci_device_id lpfc_id_table[] = {
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S,
                PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SMB,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_DCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S,
+               PCI_ANY_ID, PCI_ANY_ID, },
        { 0 }
 };
 
index 4d016c2a1b26ebd14a8eb577d73c2c809bdd1337..8041c3f06f7b466483c4ec61d256adc49c2b6d6c 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              *
@@ -212,6 +212,7 @@ lpfc_init_link(struct lpfc_hba * phba,
                        case LINK_SPEED_1G:
                        case LINK_SPEED_2G:
                        case LINK_SPEED_4G:
+                       case LINK_SPEED_8G:
                                mb->un.varInitLnk.link_flags |=
                                                        FLAGS_LINK_SPEED;
                                mb->un.varInitLnk.link_speed = linkspeed;
index 0c7e731dc45a6cdba715693d4c72ae0526920a7b..b309841e3846a571aaadd44fe60c950587315203 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              *
@@ -168,14 +168,13 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba * phba,
  * routine effectively results in a "software abort".
  */
 int
-lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
-       int send_abts)
+lpfc_els_abort(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;
-       IOCB_t *icmd;
-       int    found = 0;
+       IOCB_t *cmd;
 
        /* Abort outstanding I/O on NPort <nlp_DID> */
        lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
@@ -188,75 +187,39 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        pring = &psli->ring[LPFC_ELS_RING];
 
        /* First check the txq */
-       do {
-               found = 0;
-               spin_lock_irq(phba->host->host_lock);
-               list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
-                       /* Check to see if iocb matches the nport we are looking
-                          for */
-                       if ((lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))) {
-                               found = 1;
-                               /* It matches, so deque and call compl with an
-                                  error */
-                               list_del(&iocb->list);
-                               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);
-                               break;
-                       }
+       spin_lock_irq(phba->host->host_lock);
+       list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+               /* Check to see if iocb matches the nport we are looking
+                  for */
+               if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
+                       /* It matches, so deque and call compl with an
+                          error */
+                       list_move_tail(&iocb->list, &completions);
+                       pring->txq_cnt--;
                }
-               spin_unlock_irq(phba->host->host_lock);
-       } while (found);
+       }
 
-       /* Everything on txcmplq will be returned by firmware
-        * with a no rpi / linkdown / abort error.  For ring 0,
-        * ELS discovery, we want to get rid of it right here.
-        */
        /* Next check the txcmplq */
-       do {
-               found = 0;
-               spin_lock_irq(phba->host->host_lock);
-               list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq,
-                                        list) {
-                       /* Check to see if iocb matches the nport we are looking
-                          for */
-                       if ((lpfc_check_sli_ndlp (phba, pring, iocb, ndlp))) {
-                               found = 1;
-                               /* It matches, so deque and call compl with an
-                                  error */
-                               list_del(&iocb->list);
-                               pring->txcmplq_cnt--;
-
-                               icmd = &iocb->iocb;
-                               /* If the driver is completing an ELS
-                                * command early, flush it out of the firmware.
-                                */
-                               if (send_abts &&
-                                  (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) &&
-                                  (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);
-                               break;
-                       }
-               }
-               spin_unlock_irq(phba->host->host_lock);
-       } while(found);
+       list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+               /* Check to see if iocb matches the nport we are looking
+                  for */
+               if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
+                       lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+       }
+       spin_unlock_irq(phba->host->host_lock);
+
+       while (!list_empty(&completions)) {
+               iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               cmd = &iocb->iocb;
+               list_del(&iocb->list);
+
+               if (iocb->iocb_cmpl) {
+                       cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+                       (iocb->iocb_cmpl) (phba, iocb, iocb);
+               } else
+                       lpfc_sli_release_iocbq(phba, iocb);
+       }
 
        /* If we are delaying issuing an ELS command, cancel it */
        if (ndlp->nlp_flag & NLP_DELAY_TMO)
@@ -390,7 +353,10 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
         * queue this mbox command to be processed later.
         */
        mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
-       mbox->context2  = ndlp;
+       /*
+        * mbox->context2 = lpfc_nlp_get(ndlp) deferred until mailbox
+        * command issued in lpfc_cmpl_els_acc().
+        */
        ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
 
        /*
@@ -404,7 +370,7 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
         */
        if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
                /* software abort outstanding PLOGI */
-               lpfc_els_abort(phba, ndlp, 1);
+               lpfc_els_abort(phba, ndlp);
        }
 
        lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
@@ -471,8 +437,7 @@ lpfc_rcv_padisc(struct lpfc_hba * phba,
        spin_unlock_irq(phba->host->host_lock);
        ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
        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);
        return 0;
 }
 
@@ -502,12 +467,10 @@ lpfc_rcv_logo(struct lpfc_hba * phba,
 
                ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
                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);
        } else {
                ndlp->nlp_prev_state = ndlp->nlp_state;
-               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);
        }
 
        spin_lock_irq(phba->host->host_lock);
@@ -601,11 +564,10 @@ lpfc_rcv_plogi_unused_node(struct lpfc_hba * phba,
 
        if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
                ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
-               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);
                return ndlp->nlp_state;
        }
-       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       lpfc_drop_node(phba, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -614,7 +576,7 @@ lpfc_rcv_els_unused_node(struct lpfc_hba * phba,
                         struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
        lpfc_issue_els_logo(phba, ndlp, 0);
-       lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
        return ndlp->nlp_state;
 }
 
@@ -630,7 +592,7 @@ lpfc_rcv_logo_unused_node(struct lpfc_hba * phba,
        ndlp->nlp_flag |= NLP_LOGO_ACC;
        spin_unlock_irq(phba->host->host_lock);
        lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
-       lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
 
        return ndlp->nlp_state;
 }
@@ -639,7 +601,7 @@ static uint32_t
 lpfc_cmpl_logo_unused_node(struct lpfc_hba * phba,
                          struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
-       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       lpfc_drop_node(phba, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -647,7 +609,7 @@ static uint32_t
 lpfc_device_rm_unused_node(struct lpfc_hba * phba,
                           struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
-       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       lpfc_drop_node(phba, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -697,7 +659,7 @@ lpfc_rcv_logo_plogi_issue(struct lpfc_hba * phba,
        cmdiocb = (struct lpfc_iocbq *) arg;
 
        /* software abort outstanding PLOGI */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
        return ndlp->nlp_state;
@@ -712,7 +674,7 @@ lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba,
        cmdiocb = (struct lpfc_iocbq *) arg;
 
        /* software abort outstanding PLOGI */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        if (evt == NLP_EVT_RCV_LOGO) {
                lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
@@ -727,8 +689,7 @@ lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba,
        spin_unlock_irq(phba->host->host_lock);
        ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
        ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
-       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 ndlp->nlp_state;
 }
@@ -803,32 +764,26 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
                goto out;
 
        lpfc_unreg_rpi(phba, ndlp);
-       if (lpfc_reg_login
-           (phba, irsp->un.elsreq64.remoteID,
-            (uint8_t *) sp, mbox, 0) == 0) {
+       if (lpfc_reg_login(phba, irsp->un.elsreq64.remoteID, (uint8_t *) sp,
+                          mbox, 0) == 0) {
                switch (ndlp->nlp_DID) {
                case NameServer_DID:
-                       mbox->mbox_cmpl =
-                               lpfc_mbx_cmpl_ns_reg_login;
+                       mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
                        break;
                case FDMI_DID:
-                       mbox->mbox_cmpl =
-                               lpfc_mbx_cmpl_fdmi_reg_login;
+                       mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
                        break;
                default:
-                       mbox->mbox_cmpl =
-                               lpfc_mbx_cmpl_reg_login;
+                       mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
                }
-               mbox->context2 = ndlp;
+               mbox->context2 = lpfc_nlp_get(ndlp);
                if (lpfc_sli_issue_mbox(phba, mbox,
                                        (MBX_NOWAIT | MBX_STOP_IOCB))
                    != MBX_NOT_FINISHED) {
-                       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);
                        return ndlp->nlp_state;
                }
+               lpfc_nlp_put(ndlp);
                mp = (struct lpfc_dmabuf *)mbox->context1;
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
@@ -841,7 +796,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
  out:
        /* Free this node since the driver cannot login or has the wrong
           sparm */
-       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       lpfc_drop_node(phba, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -855,9 +810,9 @@ lpfc_device_rm_plogi_issue(struct lpfc_hba * phba,
        }
        else {
                /* software abort outstanding PLOGI */
-               lpfc_els_abort(phba, ndlp, 1);
+               lpfc_els_abort(phba, ndlp);
 
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
 }
@@ -868,11 +823,10 @@ lpfc_device_recov_plogi_issue(struct lpfc_hba * phba,
                            uint32_t evt)
 {
        /* software abort outstanding PLOGI */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
-       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);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
        spin_unlock_irq(phba->host->host_lock);
@@ -888,7 +842,7 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba,
        struct lpfc_iocbq *cmdiocb;
 
        /* software abort outstanding ADISC */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        cmdiocb = (struct lpfc_iocbq *) arg;
 
@@ -896,8 +850,7 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba,
                return ndlp->nlp_state;
        }
        ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-       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);
 
        return ndlp->nlp_state;
@@ -926,7 +879,7 @@ lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba,
        cmdiocb = (struct lpfc_iocbq *) arg;
 
        /* software abort outstanding ADISC */
-       lpfc_els_abort(phba, ndlp, 0);
+       lpfc_els_abort(phba, ndlp);
 
        lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
        return ndlp->nlp_state;
@@ -987,20 +940,17 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_hba * phba,
                memset(&ndlp->nlp_portname, 0, sizeof (struct lpfc_name));
 
                ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-               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_unreg_rpi(phba, ndlp);
                return ndlp->nlp_state;
        }
 
        if (ndlp->nlp_type & NLP_FCP_TARGET) {
                ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-               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);
        } else {
                ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-               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);
        }
        return ndlp->nlp_state;
 }
@@ -1016,9 +966,9 @@ lpfc_device_rm_adisc_issue(struct lpfc_hba * phba,
        }
        else {
                /* software abort outstanding ADISC */
-               lpfc_els_abort(phba, ndlp, 1);
+               lpfc_els_abort(phba, ndlp);
 
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
 }
@@ -1029,11 +979,10 @@ lpfc_device_recov_adisc_issue(struct lpfc_hba * phba,
                            uint32_t evt)
 {
        /* software abort outstanding ADISC */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-       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);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
        ndlp->nlp_flag |= NLP_NPR_ADISC;
@@ -1074,9 +1023,36 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba,
                             uint32_t evt)
 {
        struct lpfc_iocbq *cmdiocb;
+       LPFC_MBOXQ_t      *mb;
+       LPFC_MBOXQ_t      *nextmb;
+       struct lpfc_dmabuf *mp;
 
        cmdiocb = (struct lpfc_iocbq *) arg;
 
+       /* cleanup any ndlp on mbox q waiting for reglogin cmpl */
+       if ((mb = phba->sli.mbox_active)) {
+               if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+                  (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+                       mb->context2 = NULL;
+                       mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+               }
+       }
+
+       spin_lock_irq(phba->host->host_lock);
+       list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
+               if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+                  (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+                       mp = (struct lpfc_dmabuf *) (mb->context1);
+                       if (mp) {
+                               lpfc_mbuf_free(phba, mp->virt, mp->phys);
+                               kfree(mp);
+                       }
+                       list_del(&mb->list);
+                       mempool_free(mb, phba->mbox_mem_pool);
+               }
+       }
+       spin_unlock_irq(phba->host->host_lock);
+
        lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
        return ndlp->nlp_state;
 }
@@ -1133,8 +1109,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
                 */
                if (mb->mbxStatus == MBXERR_RPI_FULL) {
                        ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
-                       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);
                        return ndlp->nlp_state;
                }
 
@@ -1147,8 +1122,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
 
                lpfc_issue_els_logo(phba, ndlp, 0);
                ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-               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 ndlp->nlp_state;
        }
 
@@ -1157,13 +1131,11 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
        /* Only if we are not a fabric nport do we issue PRLI */
        if (!(ndlp->nlp_type & NLP_FABRIC)) {
                ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-               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, 0);
        } else {
                ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-               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);
        }
        return ndlp->nlp_state;
 }
@@ -1178,7 +1150,7 @@ lpfc_device_rm_reglogin_issue(struct lpfc_hba * phba,
                return ndlp->nlp_state;
        }
        else {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
 }
@@ -1189,8 +1161,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_hba * phba,
                               uint32_t evt)
 {
        ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-       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);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
        spin_unlock_irq(phba->host->host_lock);
@@ -1230,7 +1201,7 @@ lpfc_rcv_logo_prli_issue(struct lpfc_hba * phba,
        cmdiocb = (struct lpfc_iocbq *) arg;
 
        /* Software abort outstanding PRLI before sending acc */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
        return ndlp->nlp_state;
@@ -1279,8 +1250,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba,
        irsp = &rspiocb->iocb;
        if (irsp->ulpStatus) {
                ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-               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);
                return ndlp->nlp_state;
        }
 
@@ -1298,8 +1268,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba,
        }
 
        ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-       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);
        return ndlp->nlp_state;
 }
 
@@ -1330,9 +1299,9 @@ lpfc_device_rm_prli_issue(struct lpfc_hba * phba,
        }
        else {
                /* software abort outstanding PLOGI */
-               lpfc_els_abort(phba, ndlp, 1);
+               lpfc_els_abort(phba, ndlp);
 
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
 }
@@ -1359,11 +1328,10 @@ lpfc_device_recov_prli_issue(struct lpfc_hba * phba,
                           struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
        /* software abort outstanding PRLI */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-       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);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
        spin_unlock_irq(phba->host->host_lock);
@@ -1436,8 +1404,7 @@ lpfc_device_recov_unmap_node(struct lpfc_hba * phba,
                           struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
        ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE;
-       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_NODEV_REMOVE | NLP_NPR_2B_DISC);
        lpfc_disc_set_adisc(phba, ndlp);
 
@@ -1518,8 +1485,7 @@ lpfc_device_recov_mapped_node(struct lpfc_hba * phba,
                            uint32_t evt)
 {
        ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE;
-       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);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
        spin_unlock_irq(phba->host->host_lock);
@@ -1551,8 +1517,7 @@ lpfc_rcv_plogi_npr_node(struct lpfc_hba * phba,
        /* send PLOGI immediately, move to PLOGI issue state */
        if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
                ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-               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);
        }
 
@@ -1580,16 +1545,13 @@ lpfc_rcv_prli_npr_node(struct lpfc_hba * phba,
                        ndlp->nlp_flag &= ~NLP_NPR_ADISC;
                        spin_unlock_irq(phba->host->host_lock);
                        ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                       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, 0);
                } else {
                        ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                       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);
                }
-
        }
        return ndlp->nlp_state;
 }
@@ -1627,13 +1589,11 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba,
                !(ndlp->nlp_flag & NLP_NPR_2B_DISC)){
                if (ndlp->nlp_flag & NLP_NPR_ADISC) {
                        ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                       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, 0);
                } else {
                        ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                       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);
                }
        }
@@ -1682,7 +1642,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_hba * phba,
 
        irsp = &rspiocb->iocb;
        if (irsp->ulpStatus) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
        return ndlp->nlp_state;
@@ -1700,7 +1660,7 @@ lpfc_cmpl_prli_npr_node(struct lpfc_hba * phba,
 
        irsp = &rspiocb->iocb;
        if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
        return ndlp->nlp_state;
@@ -1728,7 +1688,7 @@ lpfc_cmpl_adisc_npr_node(struct lpfc_hba * phba,
 
        irsp = &rspiocb->iocb;
        if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
        return ndlp->nlp_state;
@@ -1749,7 +1709,7 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba,
                ndlp->nlp_rpi = mb->un.varWords[0];
        else {
                if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                       lpfc_drop_node(phba, ndlp);
                        return NLP_STE_FREED_NODE;
                }
        }
@@ -1765,7 +1725,7 @@ lpfc_device_rm_npr_node(struct lpfc_hba * phba,
                ndlp->nlp_flag |= NLP_NODEV_REMOVE;
                return ndlp->nlp_state;
        }
-       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       lpfc_drop_node(phba, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -1964,7 +1924,7 @@ lpfc_disc_state_machine(struct lpfc_hba * phba,
        uint32_t(*func) (struct lpfc_hba *, struct lpfc_nodelist *, void *,
                         uint32_t);
 
-       ndlp->nlp_disc_refcnt++;
+       lpfc_nlp_get(ndlp);
        cur_state = ndlp->nlp_state;
 
        /* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
@@ -1987,18 +1947,7 @@ lpfc_disc_state_machine(struct lpfc_hba * phba,
                       phba->brd_no,
                       rc, ndlp->nlp_DID, ndlp->nlp_flag);
 
-       ndlp->nlp_disc_refcnt--;
+       lpfc_nlp_put(ndlp);
 
-       /* Check to see if ndlp removal is deferred */
-       if ((ndlp->nlp_disc_refcnt == 0)
-           && (ndlp->nlp_flag & NLP_DELAY_REMOVE)) {
-               spin_lock_irq(phba->host->host_lock);
-               ndlp->nlp_flag &= ~NLP_DELAY_REMOVE;
-               spin_unlock_irq(phba->host->host_lock);
-               lpfc_nlp_remove(phba, ndlp);
-               return NLP_STE_FREED_NODE;
-       }
-       if (rc == NLP_STE_FREED_NODE)
-               return NLP_STE_FREED_NODE;
        return rc;
 }
index c3e68e0d8f7445e426fa0ee28cc35ab5903c37cc..9a12d05e99e4d938460948186e8d0df9f7f9df5d 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              *
@@ -146,6 +146,10 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)
 
        spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
        list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+       if (lpfc_cmd) {
+               lpfc_cmd->seg_cnt = 0;
+               lpfc_cmd->nonsg_phys = 0;
+       }
        spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
        return  lpfc_cmd;
 }
@@ -288,13 +292,13 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
 }
 
 static void
-lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
+lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
 {
        struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
        struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
        struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
        struct lpfc_hba *phba = lpfc_cmd->scsi_hba;
-       uint32_t fcpi_parm = lpfc_cmd->cur_iocbq.iocb.un.fcpi.fcpi_parm;
+       uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm;
        uint32_t resp_info = fcprsp->rspStatus2;
        uint32_t scsi_status = fcprsp->rspStatus3;
        uint32_t *lp;
@@ -355,6 +359,24 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
                                be32_to_cpu(fcpcmd->fcpDl), cmnd->resid,
                                fcpi_parm, cmnd->cmnd[0], cmnd->underflow);
 
+               /*
+                * If there is an under run check if under run reported by
+                * storage array is same as the under run reported by HBA.
+                * If this is not same, there is a dropped frame.
+                */
+               if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
+                       fcpi_parm &&
+                       (cmnd->resid != fcpi_parm)) {
+                       lpfc_printf_log(phba, KERN_WARNING,
+                               LOG_FCP | LOG_FCP_ERROR,
+                               "%d:0735 FCP Read Check Error and Underrun "
+                               "Data: x%x x%x x%x x%x\n", phba->brd_no,
+                               be32_to_cpu(fcpcmd->fcpDl),
+                               cmnd->resid,
+                               fcpi_parm, cmnd->cmnd[0]);
+                       cmnd->resid = cmnd->request_bufflen;
+                       host_status = DID_ERROR;
+               }
                /*
                 * The cmnd->underflow is the minimum number of bytes that must
                 * be transfered for this command.  Provided a sense condition
@@ -435,7 +457,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                switch (lpfc_cmd->status) {
                case IOSTAT_FCP_RSP_ERROR:
                        /* Call FCP RSP handler to determine result */
-                       lpfc_handle_fcp_err(lpfc_cmd);
+                       lpfc_handle_fcp_err(lpfc_cmd,pIocbOut);
                        break;
                case IOSTAT_NPORT_BSY:
                case IOSTAT_FABRIC_BSY:
@@ -466,10 +488,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 
        result = cmd->result;
        sdev = cmd->device;
+       lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
        cmd->scsi_done(cmd);
 
        if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
-               lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
                lpfc_release_scsi_buf(phba, lpfc_cmd);
                return;
        }
@@ -527,7 +549,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                }
        }
 
-       lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
        lpfc_release_scsi_buf(phba, lpfc_cmd);
 }
 
@@ -670,6 +691,18 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
        return (1);
 }
 
+static void
+lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba,
+                       struct lpfc_iocbq *cmdiocbq,
+                       struct lpfc_iocbq *rspiocbq)
+{
+       struct lpfc_scsi_buf *lpfc_cmd =
+               (struct lpfc_scsi_buf *) cmdiocbq->context1;
+       if (lpfc_cmd)
+               lpfc_release_scsi_buf(phba, lpfc_cmd);
+       return;
+}
+
 static int
 lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
                    unsigned  tgt_id, unsigned int lun,
@@ -706,8 +739,9 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
                                       &phba->sli.ring[phba->sli.fcp_ring],
                                       iocbq, iocbqrsp, lpfc_cmd->timeout);
        if (ret != IOCB_SUCCESS) {
+               if (ret == IOCB_TIMEDOUT)
+                       iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
                lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
-               ret = FAILED;
        } else {
                ret = SUCCESS;
                lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4];
@@ -974,7 +1008,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 }
 
 static int
-lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
+lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 {
        struct Scsi_Host *shost = cmnd->device->host;
        struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
@@ -984,6 +1018,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
        struct lpfc_nodelist *pnode = rdata->pnode;
        uint32_t cmd_result = 0, cmd_status = 0;
        int ret = FAILED;
+       int iocb_status = IOCB_SUCCESS;
        int cnt, loopcnt;
 
        lpfc_block_error_handler(cmnd);
@@ -995,7 +1030,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
         */
        while ( 1 ) {
                if (!pnode)
-                       return FAILED;
+                       goto out;
 
                if (pnode->nlp_state != NLP_STE_MAPPED_NODE) {
                        spin_unlock_irq(phba->host->host_lock);
@@ -1013,7 +1048,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
                        }
                        pnode = rdata->pnode;
                        if (!pnode)
-                               return FAILED;
+                               goto out;
                }
                if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
                        break;
@@ -1028,7 +1063,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
        lpfc_cmd->rdata = rdata;
 
        ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun,
-                                          FCP_LUN_RESET);
+                                          FCP_TARGET_RESET);
        if (!ret)
                goto out_free_scsi_buf;
 
@@ -1040,16 +1075,21 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
                goto out_free_scsi_buf;
 
        lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-                       "%d:0703 Issue LUN Reset to TGT %d LUN %d "
-                       "Data: x%x x%x\n", phba->brd_no, cmnd->device->id,
+                       "%d:0703 Issue target reset to TGT %d LUN %d rpi x%x "
+                       "nlp_flag x%x\n", phba->brd_no, cmnd->device->id,
                        cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
 
-       ret = lpfc_sli_issue_iocb_wait(phba,
+       iocb_status = lpfc_sli_issue_iocb_wait(phba,
                                       &phba->sli.ring[phba->sli.fcp_ring],
                                       iocbq, iocbqrsp, lpfc_cmd->timeout);
-       if (ret == IOCB_SUCCESS)
-               ret = SUCCESS;
 
+       if (iocb_status == IOCB_TIMEDOUT)
+               iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
+
+       if (iocb_status == IOCB_SUCCESS)
+               ret = SUCCESS;
+       else
+               ret = iocb_status;
 
        cmd_result = iocbqrsp->iocb.un.ulpWord[4];
        cmd_status = iocbqrsp->iocb.ulpStatus;
@@ -1087,18 +1127,19 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
 
        if (cnt) {
                lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-                       "%d:0719 LUN Reset I/O flush failure: cnt x%x\n",
+                       "%d:0719 device reset I/O flush failure: cnt x%x\n",
                        phba->brd_no, cnt);
                ret = FAILED;
        }
 
 out_free_scsi_buf:
-       lpfc_release_scsi_buf(phba, lpfc_cmd);
-
+       if (iocb_status != IOCB_TIMEDOUT) {
+               lpfc_release_scsi_buf(phba, lpfc_cmd);
+       }
        lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-                       "%d:0713 SCSI layer issued LUN reset (%d, %d) "
-                       "Data: x%x x%x x%x\n",
-                       phba->brd_no, cmnd->device->id,cmnd->device->lun,
+                       "%d:0713 SCSI layer issued device reset (%d, %d) "
+                       "return x%x status x%x result x%x\n",
+                       phba->brd_no, cmnd->device->id, cmnd->device->lun,
                        ret, cmd_status, cmd_result);
 
 out:
@@ -1107,7 +1148,7 @@ out:
 }
 
 static int
-lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
+lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
 {
        struct Scsi_Host *shost = cmnd->device->host;
        struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
@@ -1134,10 +1175,12 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
         * fail, this routine returns failure to the midlayer.
         */
        for (i = 0; i < LPFC_MAX_TARGET; i++) {
-               /* Search the mapped list for this target ID */
+               /* Search for mapped node by target ID */
                match = 0;
-               list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-                       if ((i == ndlp->nlp_sid) && ndlp->rport) {
+               list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+                       if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
+                           i == ndlp->nlp_sid &&
+                           ndlp->rport) {
                                match = 1;
                                break;
                        }
@@ -1152,13 +1195,17 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
                                "%d:0700 Bus Reset on target %d failed\n",
                                phba->brd_no, i);
                        err_count++;
+                       break;
                }
        }
 
+       if (ret != IOCB_TIMEDOUT)
+               lpfc_release_scsi_buf(phba, lpfc_cmd);
+
        if (err_count == 0)
                ret = SUCCESS;
-
-       lpfc_release_scsi_buf(phba, lpfc_cmd);
+       else
+               ret = FAILED;
 
        /*
         * All outstanding txcmplq I/Os should have been aborted by
@@ -1299,11 +1346,13 @@ struct scsi_host_template lpfc_template = {
        .info                   = lpfc_info,
        .queuecommand           = lpfc_queuecommand,
        .eh_abort_handler       = lpfc_abort_handler,
-       .eh_device_reset_handler= lpfc_reset_lun_handler,
-       .eh_bus_reset_handler   = lpfc_reset_bus_handler,
+       .eh_device_reset_handler= lpfc_device_reset_handler,
+       .eh_bus_reset_handler   = lpfc_bus_reset_handler,
        .slave_alloc            = lpfc_slave_alloc,
        .slave_configure        = lpfc_slave_configure,
        .slave_destroy          = lpfc_slave_destroy,
+       .scan_finished          = lpfc_scan_finished,
+       .scan_start             = lpfc_scan_start,
        .this_id                = -1,
        .sg_tablesize           = LPFC_SG_SEG_CNT,
        .cmd_per_lun            = LPFC_CMD_PER_LUN,
index 9fb6960a8adaca023b7faad67187f5c378c50e00..a1e721459e2b21a1734bff082c33e4f3c7df2bc7 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              *
@@ -528,6 +528,7 @@ lpfc_sli_wake_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
         * If pdone_q is empty, the driver thread gave up waiting and
         * continued running.
         */
+       pmboxq->mbox_flag |= LPFC_MBX_WAKE;
        pdone_q = (wait_queue_head_t *) pmboxq->context1;
        if (pdone_q)
                wake_up_interruptible(pdone_q);
@@ -538,11 +539,32 @@ void
 lpfc_sli_def_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
        struct lpfc_dmabuf *mp;
+       uint16_t rpi;
+       int rc;
+
        mp = (struct lpfc_dmabuf *) (pmb->context1);
+
        if (mp) {
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
        }
+
+       /*
+        * If a REG_LOGIN succeeded  after node is destroyed or node
+        * is in re-discovery driver need to cleanup the RPI.
+        */
+       if (!(phba->fc_flag & FC_UNLOADING) &&
+               (pmb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+               (!pmb->mb.mbxStatus)) {
+
+               rpi = pmb->mb.un.varWords[0];
+               lpfc_unreg_login(phba, rpi, pmb);
+               pmb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
+               rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+               if (rc != MBX_NOT_FINISHED)
+                       return;
+       }
+
        mempool_free( pmb, phba->mbox_mem_pool);
        return;
 }
@@ -693,25 +715,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
                } else {
                        spin_unlock_irq(phba->host->host_lock);
                        /* Turn on IOCB processing */
-                       for (i = 0; i < phba->sli.num_rings; i++) {
+                       for (i = 0; i < phba->sli.num_rings; i++)
                                lpfc_sli_turn_on_ring(phba, i);
-                       }
-
-                       /* Free any lpfc_dmabuf's waiting for mbox cmd cmpls */
-                       while (!list_empty(&phba->freebufList)) {
-                               struct lpfc_dmabuf *mp;
-
-                               mp = NULL;
-                               list_remove_head((&phba->freebufList),
-                                                mp,
-                                                struct lpfc_dmabuf,
-                                                list);
-                               if (mp) {
-                                       lpfc_mbuf_free(phba, mp->virt,
-                                                      mp->phys);
-                                       kfree(mp);
-                               }
-                       }
                }
 
        } while (process_next);
@@ -833,6 +838,14 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
                         * All other are passed to the completion callback.
                         */
                        if (pring->ringno == LPFC_ELS_RING) {
+                               if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) {
+                                       cmdiocbp->iocb_flag &=
+                                               ~LPFC_DRIVER_ABORTED;
+                                       saveq->iocb.ulpStatus =
+                                               IOSTAT_LOCAL_REJECT;
+                                       saveq->iocb.un.ulpWord[4] =
+                                               IOERR_SLI_ABORTED;
+                               }
                                spin_unlock_irqrestore(phba->host->host_lock,
                                                       iflag);
                                (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
@@ -1464,8 +1477,9 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
 int
 lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
+       LIST_HEAD(completions);
        struct lpfc_iocbq *iocb, *next_iocb;
-       IOCB_t *icmd = NULL, *cmd = NULL;
+       IOCB_t *cmd = NULL;
        int errcnt;
 
        errcnt = 0;
@@ -1474,46 +1488,28 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
         * First do the txq.
         */
        spin_lock_irq(phba->host->host_lock);
-       list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
-               list_del_init(&iocb->list);
-               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);
-       }
+       list_splice_init(&pring->txq, &completions);
        pring->txq_cnt = 0;
-       INIT_LIST_HEAD(&(pring->txq));
 
        /* Next issue ABTS for everything on the txcmplq */
-       list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
-               cmd = &iocb->iocb;
+       list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
+               lpfc_sli_issue_abort_iotag(phba, pring, iocb);
 
-               /*
-                * Imediate abort of IOCB, deque and call compl
-                */
+       spin_unlock_irq(phba->host->host_lock);
 
-               list_del_init(&iocb->list);
-               pring->txcmplq_cnt--;
+       while (!list_empty(&completions)) {
+               iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               cmd = &iocb->iocb;
+               list_del(&iocb->list);
 
                if (iocb->iocb_cmpl) {
                        cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
                        cmd->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);
        }
 
-       INIT_LIST_HEAD(&pring->txcmplq);
-       pring->txcmplq_cnt = 0;
-       spin_unlock_irq(phba->host->host_lock);
-
        return errcnt;
 }
 
@@ -1588,6 +1584,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
        hc_copy = readl(phba->HCregaddr);
        writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
+       phba->fc_flag |= FC_IGNORE_ERATT;
 
        if (readl(phba->HAregaddr) & HA_ERATT) {
                /* Clear Chip error bit */
@@ -1630,6 +1627,7 @@ clear_errat:
        }
 
 restore_hc:
+       phba->fc_flag &= ~FC_IGNORE_ERATT;
        writel(hc_copy, phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
 }
@@ -1665,6 +1663,7 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
        status &= ~HC_ERINT_ENA;
        writel(status, phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
+       phba->fc_flag |= FC_IGNORE_ERATT;
        spin_unlock_irq(phba->host->host_lock);
 
        lpfc_kill_board(phba, pmb);
@@ -1674,6 +1673,9 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
        if (retval != MBX_SUCCESS) {
                if (retval != MBX_BUSY)
                        mempool_free(pmb, phba->mbox_mem_pool);
+               spin_lock_irq(phba->host->host_lock);
+               phba->fc_flag &= ~FC_IGNORE_ERATT;
+               spin_unlock_irq(phba->host->host_lock);
                return 1;
        }
 
@@ -1700,6 +1702,7 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
        }
        spin_lock_irq(phba->host->host_lock);
        psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+       phba->fc_flag &= ~FC_IGNORE_ERATT;
        spin_unlock_irq(phba->host->host_lock);
 
        psli->mbox_active = NULL;
@@ -1985,42 +1988,6 @@ lpfc_sli_hba_setup_exit:
        return rc;
 }
 
-static void
-lpfc_mbox_abort(struct lpfc_hba * phba)
-{
-       LPFC_MBOXQ_t *pmbox;
-       MAILBOX_t *mb;
-
-       if (phba->sli.mbox_active) {
-               del_timer_sync(&phba->sli.mbox_tmo);
-               phba->work_hba_events &= ~WORKER_MBOX_TMO;
-               pmbox = phba->sli.mbox_active;
-               mb = &pmbox->mb;
-               phba->sli.mbox_active = NULL;
-               if (pmbox->mbox_cmpl) {
-                       mb->mbxStatus = MBX_NOT_FINISHED;
-                       (pmbox->mbox_cmpl) (phba, pmbox);
-               }
-               phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-       }
-
-       /* Abort all the non active mailbox commands. */
-       spin_lock_irq(phba->host->host_lock);
-       pmbox = lpfc_mbox_get(phba);
-       while (pmbox) {
-               mb = &pmbox->mb;
-               if (pmbox->mbox_cmpl) {
-                       mb->mbxStatus = MBX_NOT_FINISHED;
-                       spin_unlock_irq(phba->host->host_lock);
-                       (pmbox->mbox_cmpl) (phba, pmbox);
-                       spin_lock_irq(phba->host->host_lock);
-               }
-               pmbox = lpfc_mbox_get(phba);
-       }
-       spin_unlock_irq(phba->host->host_lock);
-       return;
-}
-
 /*! lpfc_mbox_timeout
  *
  * \pre
@@ -2055,6 +2022,8 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
 {
        LPFC_MBOXQ_t *pmbox;
        MAILBOX_t *mb;
+       struct lpfc_sli *psli = &phba->sli;
+       struct lpfc_sli_ring *pring;
 
        spin_lock_irq(phba->host->host_lock);
        if (!(phba->work_hba_events & WORKER_MBOX_TMO)) {
@@ -2062,8 +2031,6 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
                return;
        }
 
-       phba->work_hba_events &= ~WORKER_MBOX_TMO;
-
        pmbox = phba->sli.mbox_active;
        mb = &pmbox->mb;
 
@@ -2078,17 +2045,32 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
                phba->sli.sli_flag,
                phba->sli.mbox_active);
 
-       phba->sli.mbox_active = NULL;
-       if (pmbox->mbox_cmpl) {
-               mb->mbxStatus = MBX_NOT_FINISHED;
-               spin_unlock_irq(phba->host->host_lock);
-               (pmbox->mbox_cmpl) (phba, pmbox);
-               spin_lock_irq(phba->host->host_lock);
-       }
-       phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-
+       /* Setting state unknown so lpfc_sli_abort_iocb_ring
+        * would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing
+        * it to fail all oustanding SCSI IO.
+        */
+       phba->hba_state = LPFC_STATE_UNKNOWN;
+       phba->work_hba_events &= ~WORKER_MBOX_TMO;
+       phba->fc_flag |= FC_ESTABLISH_LINK;
+       psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
        spin_unlock_irq(phba->host->host_lock);
-       lpfc_mbox_abort(phba);
+
+       pring = &psli->ring[psli->fcp_ring];
+       lpfc_sli_abort_iocb_ring(phba, pring);
+
+       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                       "%d:0316 Resetting board due to mailbox timeout\n",
+                       phba->brd_no);
+       /*
+        * lpfc_offline calls lpfc_sli_hba_down which will clean up
+        * on oustanding mailbox commands.
+        */
+       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;
 }
 
@@ -2320,9 +2302,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
                        spin_unlock_irqrestore(phba->host->host_lock,
                                               drvr_flag);
 
-                       /* Can be in interrupt context, do not sleep */
-                       /* (or might be called with interrupts disabled) */
-                       mdelay(1);
+                       msleep(1);
 
                        spin_lock_irqsave(phba->host->host_lock, drvr_flag);
 
@@ -2430,7 +2410,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        if (unlikely(phba->hba_state == LPFC_LINK_DOWN)) {
                /*
-                * Only CREATE_XRI, CLOSE_XRI, ABORT_XRI, and QUE_RING_BUF
+                * Only CREATE_XRI, CLOSE_XRI, and QUE_RING_BUF
                 * can be issued if the link is not up.
                 */
                switch (piocb->iocb.ulpCommand) {
@@ -2444,6 +2424,8 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                piocb->iocb_cmpl = NULL;
                        /*FALLTHROUGH*/
                case CMD_CREATE_XRI_CR:
+               case CMD_CLOSE_XRI_CN:
+               case CMD_CLOSE_XRI_CX:
                        break;
                default:
                        goto iocb_busy;
@@ -2637,11 +2619,12 @@ lpfc_sli_queue_setup(struct lpfc_hba * phba)
 int
 lpfc_sli_hba_down(struct lpfc_hba * phba)
 {
+       LIST_HEAD(completions);
        struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
        LPFC_MBOXQ_t *pmb;
-       struct lpfc_iocbq *iocb, *next_iocb;
-       IOCB_t *icmd = NULL;
+       struct lpfc_iocbq *iocb;
+       IOCB_t *cmd = NULL;
        int i;
        unsigned long flags = 0;
 
@@ -2649,7 +2632,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
        lpfc_hba_down_prep(phba);
 
        spin_lock_irqsave(phba->host->host_lock, flags);
-
        for (i = 0; i < psli->num_rings; i++) {
                pring = &psli->ring[i];
                pring->flag |= LPFC_DEFERRED_RING_EVENT;
@@ -2658,28 +2640,25 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
                 * Error everything on the txq since these iocbs have not been
                 * given to the FW yet.
                 */
+               list_splice_init(&pring->txq, &completions);
                pring->txq_cnt = 0;
 
-               list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
-                       list_del_init(&iocb->list);
-                       if (iocb->iocb_cmpl) {
-                               icmd = &iocb->iocb;
-                               icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-                               icmd->un.ulpWord[4] = IOERR_SLI_DOWN;
-                               spin_unlock_irqrestore(phba->host->host_lock,
-                                                      flags);
-                               (iocb->iocb_cmpl) (phba, iocb, iocb);
-                               spin_lock_irqsave(phba->host->host_lock, flags);
-                       } else
-                               lpfc_sli_release_iocbq(phba, iocb);
-               }
+       }
+       spin_unlock_irqrestore(phba->host->host_lock, flags);
 
-               INIT_LIST_HEAD(&(pring->txq));
+       while (!list_empty(&completions)) {
+               iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               cmd = &iocb->iocb;
+               list_del(&iocb->list);
 
+               if (iocb->iocb_cmpl) {
+                       cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       cmd->un.ulpWord[4] = IOERR_SLI_DOWN;
+                       (iocb->iocb_cmpl) (phba, iocb, iocb);
+               } else
+                       lpfc_sli_release_iocbq(phba, iocb);
        }
 
-       spin_unlock_irqrestore(phba->host->host_lock, flags);
-
        /* Return any active mbox cmds */
        del_timer_sync(&psli->mbox_tmo);
        spin_lock_irqsave(phba->host->host_lock, flags);
@@ -2768,85 +2747,138 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 }
 
 static void
-lpfc_sli_abort_elsreq_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
-                          struct lpfc_iocbq * rspiocb)
+lpfc_sli_abort_els_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+                       struct lpfc_iocbq * rspiocb)
 {
-       struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
-       /* Free the resources associated with the ELS_REQUEST64 IOCB the driver
-        * just aborted.
-        * In this case, context2  = cmd,  context2->next = rsp, context3 = bpl
-        */
-       if (cmdiocb->context2) {
-               buf_ptr1 = (struct lpfc_dmabuf *) cmdiocb->context2;
-
-               /* Free the response IOCB before completing the abort
-                  command.  */
-               buf_ptr = NULL;
-               list_remove_head((&buf_ptr1->list), buf_ptr,
-                                struct lpfc_dmabuf, list);
-               if (buf_ptr) {
-                       lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-                       kfree(buf_ptr);
-               }
-               lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
-               kfree(buf_ptr1);
-       }
+       IOCB_t *irsp;
+       uint16_t abort_iotag, abort_context;
+       struct lpfc_iocbq *abort_iocb, *rsp_ab_iocb;
+       struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+
+       abort_iocb = NULL;
+       irsp = &rspiocb->iocb;
+
+       spin_lock_irq(phba->host->host_lock);
 
-       if (cmdiocb->context3) {
-               buf_ptr = (struct lpfc_dmabuf *) cmdiocb->context3;
-               lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-               kfree(buf_ptr);
+       if (irsp->ulpStatus) {
+               abort_context = cmdiocb->iocb.un.acxri.abortContextTag;
+               abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag;
+
+               if (abort_iotag != 0 && abort_iotag <= phba->sli.last_iotag)
+                       abort_iocb = phba->sli.iocbq_lookup[abort_iotag];
+
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "%d:0327 Cannot abort els iocb %p"
+                               " with tag %x context %x\n",
+                               phba->brd_no, abort_iocb,
+                               abort_iotag, abort_context);
+
+               /*
+                * make sure we have the right iocbq before taking it
+                * off the txcmplq and try to call completion routine.
+                */
+               if (abort_iocb &&
+                   abort_iocb->iocb.ulpContext == abort_context &&
+                   abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) {
+                       list_del(&abort_iocb->list);
+                       pring->txcmplq_cnt--;
+
+                       rsp_ab_iocb = lpfc_sli_get_iocbq(phba);
+                       if (rsp_ab_iocb == NULL)
+                               lpfc_sli_release_iocbq(phba, abort_iocb);
+                       else {
+                               abort_iocb->iocb_flag &=
+                                       ~LPFC_DRIVER_ABORTED;
+                               rsp_ab_iocb->iocb.ulpStatus =
+                                       IOSTAT_LOCAL_REJECT;
+                               rsp_ab_iocb->iocb.un.ulpWord[4] =
+                                       IOERR_SLI_ABORTED;
+                               spin_unlock_irq(phba->host->host_lock);
+                               (abort_iocb->iocb_cmpl)
+                                       (phba, abort_iocb, rsp_ab_iocb);
+                               spin_lock_irq(phba->host->host_lock);
+                               lpfc_sli_release_iocbq(phba, rsp_ab_iocb);
+                       }
+               }
        }
 
        lpfc_sli_release_iocbq(phba, cmdiocb);
+       spin_unlock_irq(phba->host->host_lock);
        return;
 }
 
 int
-lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba,
-                            struct lpfc_sli_ring * pring,
-                            struct lpfc_iocbq * cmdiocb)
+lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba,
+                          struct lpfc_sli_ring * pring,
+                          struct lpfc_iocbq * cmdiocb)
 {
        struct lpfc_iocbq *abtsiocbp;
        IOCB_t *icmd = NULL;
        IOCB_t *iabt = NULL;
+       int retval = IOCB_ERROR;
+
+       /* There are certain command types we don't want
+        * to abort.
+        */
+       icmd = &cmdiocb->iocb;
+       if ((icmd->ulpCommand == CMD_ABORT_XRI_CN) ||
+           (icmd->ulpCommand == CMD_CLOSE_XRI_CN))
+               return 0;
+
+       /* If we're unloading, interrupts are disabled so we
+        * need to cleanup the iocb here.
+        */
+       if (phba->fc_flag & FC_UNLOADING)
+               goto abort_iotag_exit;
 
        /* issue ABTS for this IOCB based on iotag */
        abtsiocbp = lpfc_sli_get_iocbq(phba);
        if (abtsiocbp == NULL)
                return 0;
 
+       /* This signals the response to set the correct status
+        * before calling the completion handler.
+        */
+       cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED;
+
        iabt = &abtsiocbp->iocb;
-       icmd = &cmdiocb->iocb;
-       switch (icmd->ulpCommand) {
-       case CMD_ELS_REQUEST64_CR:
-               /* Even though we abort the ELS command, the firmware may access
-                * the BPL or other resources before it processes our
-                * ABORT_MXRI64. Thus we must delay reusing the cmdiocb
-                * resources till the actual abort request completes.
-                */
-               abtsiocbp->context1 = (void *)((unsigned long)icmd->ulpCommand);
-               abtsiocbp->context2 = cmdiocb->context2;
-               abtsiocbp->context3 = cmdiocb->context3;
-               cmdiocb->context2 = NULL;
-               cmdiocb->context3 = NULL;
-               abtsiocbp->iocb_cmpl = lpfc_sli_abort_elsreq_cmpl;
-               break;
-       default:
-               lpfc_sli_release_iocbq(phba, abtsiocbp);
-               return 0;
-       }
+       iabt->un.acxri.abortType = ABORT_TYPE_ABTS;
+       iabt->un.acxri.abortContextTag = icmd->ulpContext;
+       iabt->un.acxri.abortIoTag = icmd->ulpIoTag;
+       iabt->ulpLe = 1;
+       iabt->ulpClass = icmd->ulpClass;
 
-       iabt->un.amxri.abortType = ABORT_TYPE_ABTS;
-       iabt->un.amxri.iotag32 = icmd->un.elsreq64.bdl.ulpIoTag32;
+       if (phba->hba_state >= LPFC_LINK_UP)
+               iabt->ulpCommand = CMD_ABORT_XRI_CN;
+       else
+               iabt->ulpCommand = CMD_CLOSE_XRI_CN;
 
-       iabt->ulpLe = 1;
-       iabt->ulpClass = CLASS3;
-       iabt->ulpCommand = CMD_ABORT_MXRI64_CN;
+       abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl;
 
-       if (lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0) == IOCB_ERROR) {
-               lpfc_sli_release_iocbq(phba, abtsiocbp);
-               return 0;
+       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                       "%d:0339 Abort xri x%x, original iotag x%x, abort "
+                       "cmd iotag x%x\n",
+                       phba->brd_no, iabt->un.acxri.abortContextTag,
+                       iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
+       retval = lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
+
+abort_iotag_exit:
+
+       /* If we could not issue an abort dequeue the iocb and handle
+        * the completion here.
+        */
+       if (retval == IOCB_ERROR) {
+               list_del(&cmdiocb->list);
+               pring->txcmplq_cnt--;
+
+               if (cmdiocb->iocb_cmpl) {
+                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+                       spin_unlock_irq(phba->host->host_lock);
+                       (cmdiocb->iocb_cmpl) (phba, cmdiocb, cmdiocb);
+                       spin_lock_irq(phba->host->host_lock);
+               } else
+                       lpfc_sli_release_iocbq(phba, cmdiocb);
        }
 
        return 1;
@@ -2918,9 +2950,11 @@ void
 lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                           struct lpfc_iocbq * rspiocb)
 {
-       spin_lock_irq(phba->host->host_lock);
+       unsigned long iflags;
+
+       spin_lock_irqsave(phba->host->host_lock, iflags);
        lpfc_sli_release_iocbq(phba, cmdiocb);
-       spin_unlock_irq(phba->host->host_lock);
+       spin_unlock_irqrestore(phba->host->host_lock, iflags);
        return;
 }
 
@@ -3043,22 +3077,22 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
                                timeout_req);
                spin_lock_irq(phba->host->host_lock);
 
-               if (timeleft == 0) {
+               if (piocb->iocb_flag & LPFC_IO_WAKE) {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                                       "%d:0331 IOCB wake signaled\n",
+                                       phba->brd_no);
+               } else if (timeleft == 0) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                        "%d:0338 IOCB wait timeout error - no "
                                        "wake response Data x%x\n",
                                        phba->brd_no, timeout);
                        retval = IOCB_TIMEDOUT;
-               } else if (!(piocb->iocb_flag & LPFC_IO_WAKE)) {
+               } else {
                        lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                        "%d:0330 IOCB wake NOT set, "
                                        "Data x%x x%lx\n", phba->brd_no,
                                        timeout, (timeleft / jiffies));
                        retval = IOCB_TIMEDOUT;
-               } else {
-                       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-                                       "%d:0331 IOCB wake signaled\n",
-                                       phba->brd_no);
                }
        } else {
                lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -3087,8 +3121,6 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
                         uint32_t timeout)
 {
        DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
-       DECLARE_WAITQUEUE(wq_entry, current);
-       uint32_t timeleft = 0;
        int retval;
 
        /* The caller must leave context1 empty. */
@@ -3101,27 +3133,25 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
        /* setup context field to pass wait_queue pointer to wake function  */
        pmboxq->context1 = &done_q;
 
-       /* start to sleep before we wait, to avoid races */
-       set_current_state(TASK_INTERRUPTIBLE);
-       add_wait_queue(&done_q, &wq_entry);
-
        /* now issue the command */
        retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
 
        if (retval == MBX_BUSY || retval == MBX_SUCCESS) {
-               timeleft = schedule_timeout(timeout * HZ);
+               wait_event_interruptible_timeout(done_q,
+                               pmboxq->mbox_flag & LPFC_MBX_WAKE,
+                               timeout * HZ);
+
                pmboxq->context1 = NULL;
-               /* if schedule_timeout returns 0, we timed out and were not
-                  woken up */
-               if ((timeleft == 0) || signal_pending(current))
-                       retval = MBX_TIMEOUT;
-               else
+               /*
+                * if LPFC_MBX_WAKE flag is set the mailbox is completed
+                * else do not free the resources.
+                */
+               if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
                        retval = MBX_SUCCESS;
+               else
+                       retval = MBX_TIMEOUT;
        }
 
-
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&done_q, &wq_entry);
        return retval;
 }
 
@@ -3184,6 +3214,11 @@ lpfc_intr_handler(int irq, void *dev_id)
         */
        spin_lock(phba->host->host_lock);
        ha_copy = readl(phba->HAregaddr);
+       /* If somebody is waiting to handle an eratt don't process it
+        * here.  The brdkill function will do this.
+        */
+       if (phba->fc_flag & FC_IGNORE_ERATT)
+               ha_copy &= ~HA_ERATT;
        writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
        readl(phba->HAregaddr); /* flush */
        spin_unlock(phba->host->host_lock);
index a43549959dc7bb45bd9ebabcd8121afdcf201a00..41c38d324ab005ce43efd90f27d7be2fd93c5db2 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                                                  *
  *                                                                 *
@@ -39,9 +39,10 @@ struct lpfc_iocbq {
        IOCB_t iocb;            /* IOCB cmd */
        uint8_t retry;          /* retry counter for IOCB cmd - if needed */
        uint8_t iocb_flag;
-#define LPFC_IO_LIBDFC 1       /* libdfc iocb */
-#define LPFC_IO_WAKE   2       /* High Priority Queue signal flag */
-#define LPFC_IO_FCP    4       /* FCP command -- iocbq in scsi_buf */
+#define LPFC_IO_LIBDFC         1       /* libdfc iocb */
+#define LPFC_IO_WAKE           2       /* High Priority Queue signal flag */
+#define LPFC_IO_FCP            4       /* FCP command -- iocbq in scsi_buf */
+#define LPFC_DRIVER_ABORTED    8       /* driver aborted this request */
 
        uint8_t abort_count;
        uint8_t rsvd2;
@@ -67,6 +68,8 @@ struct lpfc_iocbq {
 #define IOCB_ERROR          2
 #define IOCB_TIMEDOUT       3
 
+#define LPFC_MBX_WAKE  1
+
 typedef struct lpfcMboxq {
        /* MBOXQs are used in single linked lists */
        struct list_head list;  /* ptr to next mailbox command */
@@ -75,6 +78,7 @@ typedef struct lpfcMboxq {
        void *context2;         /* caller context information */
 
        void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
+       uint8_t mbox_flag;
 
 } LPFC_MBOXQ_t;
 
index a61ef3d1e7f1b08090403de95e4547246c65420f..92a9107019d2c6de3b87a5ec7c899df256d6c063 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                                                  *
  *                                                                 *
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.1.11"
+#define LPFC_DRIVER_VERSION "8.1.12"
 
 #define LPFC_DRIVER_NAME "lpfc"
 
 #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
                LPFC_DRIVER_VERSION
-#define LPFC_COPYRIGHT "Copyright(c) 2004-2006 Emulex.  All rights reserved."
+#define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex.  All rights reserved."
 
 #define DFC_API_VERSION "0.0.0"
index 7fc6e06ea7e19e2780f8c1fd9b608115ab71f0a9..3cce75d70263a4fd5b315e53241548f3b23a8012 100644 (file)
@@ -1754,7 +1754,8 @@ __mega_busywait_mbox (adapter_t *adapter)
        for (counter = 0; counter < 10000; counter++) {
                if (!mbox->m_in.busy)
                        return 0;
-               udelay(100); yield();
+               udelay(100);
+               cond_resched();
        }
        return -1;              /* give up after 1 second */
 }
@@ -3177,7 +3178,10 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end )
 
        return len;
 }
-
+#else
+static inline void mega_create_proc_entry(int index, struct proc_dir_entry *parent)
+{
+}
 #endif
 
 
@@ -4342,7 +4346,7 @@ mega_support_cluster(adapter_t *adapter)
        return 0;
 }
 
-
+#ifdef CONFIG_PROC_FS
 /**
  * mega_adapinq()
  * @adapter - pointer to our soft state
@@ -4447,7 +4451,7 @@ mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt,
 
        return rval;
 }
-
+#endif
 
 /**
  * mega_internal_command()
@@ -4965,7 +4969,6 @@ megaraid_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host *host = pci_get_drvdata(pdev);
        adapter_t *adapter = (adapter_t *)host->hostdata;
-       char    buf[12] = { 0 };
 
        scsi_remove_host(host);
 
@@ -5011,8 +5014,11 @@ megaraid_remove_one(struct pci_dev *pdev)
                remove_proc_entry("raiddrives-30-39",
                                adapter->controller_proc_dir_entry);
 #endif
-               sprintf(buf, "hba%d", adapter->host->host_no);
-               remove_proc_entry(buf, mega_proc_dir_entry);
+               {
+                       char    buf[12] = { 0 };
+                       sprintf(buf, "hba%d", adapter->host->host_no);
+                       remove_proc_entry(buf, mega_proc_dir_entry);
+               }
        }
 #endif
 
index c6e74643abe29be7f7d52ad29b7fd8634c548c4d..ee70bd4ae4badc0f2f7a82eb0a523d5702c796f4 100644 (file)
@@ -1002,7 +1002,6 @@ static int megaraid_reset(Scsi_Cmnd *);
 static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int);
 static int megaraid_biosparam(struct scsi_device *, struct block_device *,
                sector_t, int []);
-static int mega_print_inquiry(char *, char *);
 
 static int mega_build_sglist (adapter_t *adapter, scb_t *scb,
                              u32 *buffer, u32 *length);
@@ -1024,6 +1023,7 @@ static int mega_init_scb (adapter_t *);
 static int mega_is_bios_enabled (adapter_t *);
 
 #ifdef CONFIG_PROC_FS
+static int mega_print_inquiry(char *, char *);
 static void mega_create_proc_entry(int, struct proc_dir_entry *);
 static int proc_read_config(char *, char **, off_t, int, int *, void *);
 static int proc_read_stat(char *, char **, off_t, int, int *, void *);
@@ -1040,10 +1040,10 @@ static int proc_rdrv_20(char *, char **, off_t, int, int *, void *);
 static int proc_rdrv_30(char *, char **, off_t, int, int *, void *);
 static int proc_rdrv_40(char *, char **, off_t, int, int *, void *);
 static int proc_rdrv(adapter_t *, char *, int, int);
-#endif
 
 static int mega_adapinq(adapter_t *, dma_addr_t);
 static int mega_internal_dev_inquiry(adapter_t *, u8, u8, dma_addr_t);
+#endif
 
 static int mega_support_ext_cdb(adapter_t *);
 static mega_passthru* mega_prepare_passthru(adapter_t *, scb_t *,
index f33a678f0897d749788ec7e2ed35e742019f1c18..e075a52ac104e06fcf94bf1ca35a816d4bfdf079 100644 (file)
@@ -60,7 +60,7 @@ EXPORT_SYMBOL(mraid_mm_unregister_adp);
 EXPORT_SYMBOL(mraid_mm_adapter_app_handle);
 
 static int majorno;
-static uint32_t drvr_ver       = 0x02200206;
+static uint32_t drvr_ver       = 0x02200207;
 
 static int adapters_count_g;
 static struct list_head adapters_list_g;
index cf3666d7d97aa8750eb12aee5715fd839379670e..e64d1a19d8d7e0f771fb235cc11bb7dbcdb42359 100644 (file)
@@ -185,7 +185,7 @@ struct mesh_state {
  * Driver is too messy, we need a few prototypes...
  */
 static void mesh_done(struct mesh_state *ms, int start_next);
-static void mesh_interrupt(int irq, void *dev_id);
+static void mesh_interrupt(struct mesh_state *ms);
 static void cmd_complete(struct mesh_state *ms);
 static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd);
 static void halt_dma(struct mesh_state *ms);
@@ -466,7 +466,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
                                dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",
                                     MKWORD(mr->interrupt, mr->exception,
                                            mr->error, mr->fifo_count));
-                               mesh_interrupt(0, (void *)ms);
+                               mesh_interrupt(ms);
                                if (ms->phase != arbitrating)
                                        return;
                        }
@@ -504,7 +504,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
                dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x",
                     MKWORD(mr->interrupt, mr->exception,
                            mr->error, mr->fifo_count));
-               mesh_interrupt(0, (void *)ms);
+               mesh_interrupt(ms);
                if (ms->phase != arbitrating)
                        return;
                dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",
@@ -1018,10 +1018,11 @@ static void handle_reset(struct mesh_state *ms)
 static irqreturn_t do_mesh_interrupt(int irq, void *dev_id)
 {
        unsigned long flags;
-       struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host;
+       struct mesh_state *ms = dev_id;
+       struct Scsi_Host *dev = ms->host;
        
        spin_lock_irqsave(dev->host_lock, flags);
-       mesh_interrupt(irq, dev_id);
+       mesh_interrupt(ms);
        spin_unlock_irqrestore(dev->host_lock, flags);
        return IRQ_HANDLED;
 }
@@ -1661,9 +1662,8 @@ static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
  * handler (do_mesh_interrupt) or by other functions in
  * exceptional circumstances
  */
-static void mesh_interrupt(int irq, void *dev_id)
+static void mesh_interrupt(struct mesh_state *ms)
 {
-       struct mesh_state *ms = (struct mesh_state *) dev_id;
        volatile struct mesh_regs __iomem *mr = ms->mesh;
        int intr;
 
index 6777e8a69153a9a7c6eabc671ac4ea8a7ae2d642..54d8bdf86852b7541542298b05ce1f20b0c55c9e 100644 (file)
@@ -4293,7 +4293,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->devnum = devnum;    /* specifies microcode load address */
 
 #ifdef QLA_64BIT_PTR
-       if (pci_set_dma_mask(ha->pdev, (dma_addr_t) ~ 0ULL)) {
+       if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
                if (pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK)) {
                        printk(KERN_WARNING "scsi(%li): Unable to set a "
                               "suitable DMA mask - aborting\n", ha->host_no);
index 3e296ab845b653a454efc4f05a70f444eed4a67d..db998d84cd402e379a1c611ecbacf01e10a64361 100644 (file)
@@ -130,18 +130,17 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
 int
 qla2100_pci_config(scsi_qla_host_t *ha)
 {
-       uint16_t w, mwi;
+       int ret;
+       uint16_t w;
        uint32_t d;
        unsigned long flags;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
        pci_set_master(ha->pdev);
-       mwi = 0;
-       if (pci_set_mwi(ha->pdev))
-               mwi = PCI_COMMAND_INVALIDATE;
+       ret = pci_set_mwi(ha->pdev);
 
        pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
-       w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+       w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
        pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
        /* Reset expansion ROM address decode enable */
@@ -166,22 +165,22 @@ qla2100_pci_config(scsi_qla_host_t *ha)
 int
 qla2300_pci_config(scsi_qla_host_t *ha)
 {
-       uint16_t        w, mwi;
+       int             ret;
+       uint16_t        w;
        uint32_t        d;
        unsigned long   flags = 0;
        uint32_t        cnt;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
        pci_set_master(ha->pdev);
-       mwi = 0;
-       if (pci_set_mwi(ha->pdev))
-               mwi = PCI_COMMAND_INVALIDATE;
+       ret = pci_set_mwi(ha->pdev);
 
        pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
-       w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+       w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
 
        if (IS_QLA2322(ha) || IS_QLA6322(ha))
                w &= ~PCI_COMMAND_INTX_DISABLE;
+       pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
        /*
         * If this is a 2300 card and not 2312, reset the
@@ -210,7 +209,7 @@ qla2300_pci_config(scsi_qla_host_t *ha)
                ha->fb_rev = RD_FB_CMD_REG(ha, reg);
 
                if (ha->fb_rev == FPM_2300)
-                       w &= ~PCI_COMMAND_INVALIDATE;
+                       pci_clear_mwi(ha->pdev);
 
                /* Deselect FPM registers. */
                WRT_REG_WORD(&reg->ctrl_status, 0x0);
@@ -227,7 +226,6 @@ qla2300_pci_config(scsi_qla_host_t *ha)
 
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
        }
-       pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
        pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
 
@@ -253,19 +251,18 @@ qla2300_pci_config(scsi_qla_host_t *ha)
 int
 qla24xx_pci_config(scsi_qla_host_t *ha)
 {
-       uint16_t w, mwi;
+       int ret;
+       uint16_t w;
        uint32_t d;
        unsigned long flags = 0;
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
        int pcix_cmd_reg, pcie_dctl_reg;
 
        pci_set_master(ha->pdev);
-       mwi = 0;
-       if (pci_set_mwi(ha->pdev))
-               mwi = PCI_COMMAND_INVALIDATE;
+       ret = pci_set_mwi(ha->pdev);
 
        pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
-       w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+       w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
        w &= ~PCI_COMMAND_INTX_DISABLE;
        pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
@@ -3931,6 +3928,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
 
        if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
                return;
+       if (!ha->fw_major_version)
+               return;
 
        ret = qla2x00_stop_firmware(ha);
        for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) {
index d4885616cd39c19077e72b2f083f563ec5cb2ad9..ca463469063d56358e2a1c91235f824175e2e738 100644 (file)
@@ -1726,6 +1726,17 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
        qla_printk(KERN_WARNING, ha,
            "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
 skip_msix:
+
+       if (!IS_QLA24XX(ha))
+               goto skip_msi;
+
+       ret = pci_enable_msi(ha->pdev);
+       if (!ret) {
+               DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
+               ha->flags.msi_enabled = 1;
+       }
+skip_msi:
+
        ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler,
            IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
        if (!ret) {
@@ -1746,6 +1757,8 @@ qla2x00_free_irqs(scsi_qla_host_t *ha)
 
        if (ha->flags.msix_enabled)
                qla24xx_disable_msix(ha);
-       else if (ha->flags.inta_enabled)
+       else if (ha->flags.inta_enabled) {
                free_irq(ha->host->irq, ha);
+               pci_disable_msi(ha->pdev);
+       }
 }
index b78919a318e2b2ee87dc9170c676e2f64de2b6a1..dd076da86a465d668d6b251512492176a65e81be 100644 (file)
@@ -36,7 +36,7 @@ module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xlogintimeout,
                "Login timeout value in seconds.");
 
-int qlport_down_retry = 30;
+int qlport_down_retry;
 module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(qlport_down_retry,
                "Maximum number of command retries to a port that returns "
@@ -1577,9 +1577,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                goto probe_failed;
        }
 
-       if (qla2x00_initialize_adapter(ha) &&
-           !(ha->device_flags & DFLG_NO_CABLE)) {
-
+       if (qla2x00_initialize_adapter(ha)) {
                qla_printk(KERN_WARNING, ha,
                    "Failed to initialize adapter\n");
 
index dc85495c337f856ecb220abd63166717308df227..c375a4efbc71b5cbe9372787db0bd9a14498e4b1 100644 (file)
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.01.07-k6"
+#define QLA2XXX_VERSION      "8.01.07-k7"
 
 #define QLA_DRIVER_MAJOR_VER   8
 #define QLA_DRIVER_MINOR_VER   1
index 7b4e077a39c18c770bbd42a80c7696ea83066e8e..6437d024b0dd725b84a58d097be601a154df6917 100644 (file)
@@ -8,6 +8,8 @@
 #include "ql4_def.h"
 #include <scsi/scsi_dbg.h>
 
+#if 0
+
 static void qla4xxx_print_srb_info(struct srb * srb)
 {
        printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags);
@@ -195,3 +197,5 @@ void qla4xxx_dump_buffer(void *b, uint32_t size)
        if (cnt % 16)
                printk(KERN_DEBUG "\n");
 }
+
+#endif  /*  0  */
index e021eb5db2b2c6c7eb858c2092ce7c56903a47fb..5b00cb04e7c07d82b946e7426d0e968348b735a0 100644 (file)
@@ -43,8 +43,6 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
                            uint16_t *tcp_source_port_num,
                            uint16_t *connection_id);
 
-struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host * ha,
-                                    uint32_t fw_ddb_index);
 int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
                          dma_addr_t fw_ddb_entry_dma);
 
@@ -55,18 +53,11 @@ void qla4xxx_get_crash_record(struct scsi_qla_host * ha);
 struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
 int qla4xxx_add_sess(struct ddb_entry *);
 void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry);
-int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
-                                  uint16_t fw_ddb_index,
-                                  uint16_t connection_id,
-                                  uint16_t option);
-int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
-                                uint16_t fw_ddb_index);
 int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha);
 int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
 void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
                                       uint32_t intr_status);
 int qla4xxx_init_rings(struct scsi_qla_host * ha);
-void qla4xxx_dump_buffer(void *b, uint32_t size);
 struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index);
 void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
 int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
index b907b06d72ab4b30bd8541fa6fc1a4955b251284..6365df26861271a711d31d957b1bd9b1f52b7489 100644 (file)
@@ -7,9 +7,8 @@
 
 #include "ql4_def.h"
 
-/*
- * QLogic ISP4xxx Hardware Support Function Prototypes.
- */
+static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+                                           uint32_t fw_ddb_index);
 
 static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
 {
@@ -48,7 +47,8 @@ static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
  * This routine deallocates and unlinks the specified ddb_entry from the
  * adapter's
  **/
-void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry)
+static void qla4xxx_free_ddb(struct scsi_qla_host *ha,
+                            struct ddb_entry *ddb_entry)
 {
        /* Remove device entry from list */
        list_del_init(&ddb_entry->list);
@@ -370,9 +370,9 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
  * must be initialized prior to        calling this routine
  *
  **/
-int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
-                            struct ddb_entry *ddb_entry,
-                            uint32_t fw_ddb_index)
+static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
+                                   struct ddb_entry *ddb_entry,
+                                   uint32_t fw_ddb_index)
 {
        struct dev_db_entry *fw_ddb_entry = NULL;
        dma_addr_t fw_ddb_entry_dma;
@@ -450,8 +450,8 @@ int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
  * This routine allocates a ddb_entry, ititializes some values, and
  * inserts it into the ddb list.
  **/
-struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
-                                    uint32_t fw_ddb_index)
+static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+                                           uint32_t fw_ddb_index)
 {
        struct ddb_entry *ddb_entry;
 
index d41ce380eedcbd298185a15db290cb15c946b00a..a216a1781afbbc92a179595ad45893ae9f376903 100644 (file)
@@ -19,8 +19,8 @@
  *     - advances the request_in pointer
  *     - checks for queue full
  **/
-int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
-                       struct queue_entry **queue_entry)
+static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
+                              struct queue_entry **queue_entry)
 {
        uint16_t request_in;
        uint8_t status = QLA_SUCCESS;
@@ -62,8 +62,8 @@ int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
  *
  * This routine issues a marker IOCB.
  **/
-int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
-                            struct ddb_entry *ddb_entry, int lun)
+static int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
+                                   struct ddb_entry *ddb_entry, int lun)
 {
        struct marker_entry *marker_entry;
        unsigned long flags = 0;
@@ -96,7 +96,7 @@ exit_send_marker:
        return status;
 }
 
-struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
+static struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
        struct scsi_qla_host *ha)
 {
        struct continuation_t1_entry *cont_entry;
@@ -120,7 +120,7 @@ struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
        return cont_entry;
 }
 
-uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
+static uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
 {
        uint16_t iocbs;
 
@@ -133,9 +133,9 @@ uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
        return iocbs;
 }
 
-void qla4xxx_build_scsi_iocbs(struct srb *srb,
-                             struct command_t3_entry *cmd_entry,
-                             uint16_t tot_dsds)
+static void qla4xxx_build_scsi_iocbs(struct srb *srb,
+                                    struct command_t3_entry *cmd_entry,
+                                    uint16_t tot_dsds)
 {
        struct scsi_qla_host *ha;
        uint16_t avail_dsds;
index 7f28657eef3f1d60e74827d7084408299042eea3..f116ff9172374bc3a07a6f10e58cf18bf84d02d7 100644 (file)
@@ -20,9 +20,9 @@
  * If outCount is 0, this routine completes successfully WITHOUT waiting
  * for the mailbox command to complete.
  **/
-int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
-                           uint8_t outCount, uint32_t *mbx_cmd,
-                           uint32_t *mbx_sts)
+static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+                                  uint8_t outCount, uint32_t *mbx_cmd,
+                                  uint32_t *mbx_sts)
 {
        int status = QLA_ERROR;
        uint8_t i;
@@ -170,6 +170,8 @@ mbox_exit:
 }
 
 
+#if 0
+
 /**
  * qla4xxx_issue_iocb - issue mailbox iocb command
  * @ha: adapter state pointer.
@@ -243,6 +245,8 @@ int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
        return QLA_SUCCESS;
 }
 
+#endif  /*  0  */
+
 /**
  * qla4xxx_initialize_fw_cb - initializes firmware control block.
  * @ha: Pointer to host adapter structure.
@@ -570,6 +574,7 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
        return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
 }
 
+#if 0
 int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
                                    uint16_t fw_ddb_index)
 {
@@ -594,6 +599,7 @@ int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
 
                return status;
 }
+#endif  /*  0  */
 
 /**
  * qla4xxx_get_crash_record - retrieves crash record.
@@ -649,6 +655,7 @@ exit_get_crash_record:
                                  crash_record, crash_record_dma);
 }
 
+#if 0
 /**
  * qla4xxx_get_conn_event_log - retrieves connection event log
  * @ha: Pointer to host adapter structure.
@@ -738,6 +745,7 @@ exit_get_event_log:
                dma_free_coherent(&ha->pdev->dev, event_log_size, event_log,
                                  event_log_dma);
 }
+#endif  /*  0  */
 
 /**
  * qla4xxx_reset_lun - issues LUN Reset
@@ -834,7 +842,8 @@ int qla4xxx_get_fw_version(struct scsi_qla_host * ha)
        return QLA_SUCCESS;
 }
 
-int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr)
+static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha,
+                                  dma_addr_t dma_addr)
 {
        uint32_t mbox_cmd[MBOX_REG_COUNT];
        uint32_t mbox_sts[MBOX_REG_COUNT];
@@ -855,7 +864,7 @@ int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr)
        return QLA_SUCCESS;
 }
 
-int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
+static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
 {
        uint32_t mbox_cmd[MBOX_REG_COUNT];
        uint32_t mbox_sts[MBOX_REG_COUNT];
index 0bfddf893ed0eba06e1362e0a4f06016eafcf86c..da21f5fbbf87cbb6f6c2c8502fbdd41a97551d59 100644 (file)
@@ -14,7 +14,7 @@
 /*
  * Driver version
  */
-char qla4xxx_version_str[40];
+static char qla4xxx_version_str[40];
 
 /*
  * SRB allocation cache
@@ -45,8 +45,7 @@ int ql4_mod_unload = 0;
 /*
  * SCSI host template entry points
  */
-
-void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
+static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
 
 /*
  * iSCSI template entry points
@@ -1352,7 +1351,7 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
  * At exit, the @ha's flags.enable_64bit_addressing set to indicated
  * supported addressing method.
  */
-void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
+static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
 {
        int retval;
 
@@ -1627,7 +1626,7 @@ static struct pci_device_id qla4xxx_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
 
-struct pci_driver qla4xxx_pci_driver = {
+static struct pci_driver qla4xxx_pci_driver = {
        .name           = DRIVER_NAME,
        .id_table       = qla4xxx_pci_tbl,
        .probe          = qla4xxx_probe_adapter,
index 3963e7013bd90eca80df51c268427a4f3107af32..e8350c562d24c0a4598d7a4c0e4066c1b4911d35 100644 (file)
@@ -38,7 +38,6 @@
 #include "scsi_logging.h"
 
 #define SENSE_TIMEOUT          (10*HZ)
-#define START_UNIT_TIMEOUT     (30*HZ)
 
 /*
  * These should *probably* be handled by the host itself.
@@ -936,7 +935,7 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
 
                for (i = 0; rtn == NEEDS_RETRY && i < 2; i++)
                        rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
-                                               START_UNIT_TIMEOUT, 0);
+                                               scmd->device->timeout, 0);
 
                if (rtn == SUCCESS)
                        return 0;
index 14c4f065b2b8091c88c853bd7cbc732e027f160d..b4d1ece46f789d92e6cc94acdb38410625852233 100644 (file)
@@ -1718,31 +1718,12 @@ fc_starget_delete(struct work_struct *work)
        struct fc_rport *rport =
                container_of(work, struct fc_rport, stgt_delete_work);
        struct Scsi_Host *shost = rport_to_shost(rport);
-       unsigned long flags;
        struct fc_internal *i = to_fc_internal(shost->transportt);
 
-       /*
-        * Involve the LLDD if possible. All io on the rport is to
-        * be terminated, either as part of the dev_loss_tmo callback
-        * processing, or via the terminate_rport_io function.
-        */
-       if (i->f->dev_loss_tmo_callbk)
-               i->f->dev_loss_tmo_callbk(rport);
-       else if (i->f->terminate_rport_io)
+       /* Involve the LLDD if possible to terminate all io on the rport. */
+       if (i->f->terminate_rport_io)
                i->f->terminate_rport_io(rport);
 
-       spin_lock_irqsave(shost->host_lock, flags);
-       if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
-               spin_unlock_irqrestore(shost->host_lock, flags);
-               if (!cancel_delayed_work(&rport->fail_io_work))
-                       fc_flush_devloss(shost);
-               if (!cancel_delayed_work(&rport->dev_loss_work))
-                       fc_flush_devloss(shost);
-               spin_lock_irqsave(shost->host_lock, flags);
-               rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
-       }
-       spin_unlock_irqrestore(shost->host_lock, flags);
-
        scsi_remove_target(&rport->dev);
 }
 
@@ -1760,6 +1741,7 @@ fc_rport_final_delete(struct work_struct *work)
        struct device *dev = &rport->dev;
        struct Scsi_Host *shost = rport_to_shost(rport);
        struct fc_internal *i = to_fc_internal(shost->transportt);
+       unsigned long flags;
 
        /*
         * if a scan is pending, flush the SCSI Host work_q so that 
@@ -1768,13 +1750,37 @@ fc_rport_final_delete(struct work_struct *work)
        if (rport->flags & FC_RPORT_SCAN_PENDING)
                scsi_flush_work(shost);
 
+       /* involve the LLDD to terminate all pending i/o */
+       if (i->f->terminate_rport_io)
+               i->f->terminate_rport_io(rport);
+
+       /*
+        * Cancel any outstanding timers. These should really exist
+        * only when rmmod'ing the LLDD and we're asking for
+        * immediate termination of the rports
+        */
+       spin_lock_irqsave(shost->host_lock, flags);
+       if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
+               spin_unlock_irqrestore(shost->host_lock, flags);
+               if (!cancel_delayed_work(&rport->fail_io_work))
+                       fc_flush_devloss(shost);
+               if (!cancel_delayed_work(&rport->dev_loss_work))
+                       fc_flush_devloss(shost);
+               spin_lock_irqsave(shost->host_lock, flags);
+               rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
+       }
+       spin_unlock_irqrestore(shost->host_lock, flags);
+
        /* Delete SCSI target and sdevs */
        if (rport->scsi_target_id != -1)
                fc_starget_delete(&rport->stgt_delete_work);
-       else if (i->f->dev_loss_tmo_callbk)
+
+       /*
+        * Notify the driver that the rport is now dead. The LLDD will
+        * also guarantee that any communication to the rport is terminated
+        */
+       if (i->f->dev_loss_tmo_callbk)
                i->f->dev_loss_tmo_callbk(rport);
-       else if (i->f->terminate_rport_io)
-               i->f->terminate_rport_io(rport);
 
        transport_remove_device(dev);
        device_del(dev);
@@ -1963,8 +1969,6 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
                        }
 
                        if (match) {
-                               struct delayed_work *work =
-                                                       &rport->dev_loss_work;
 
                                memcpy(&rport->node_name, &ids->node_name,
                                        sizeof(rport->node_name));
@@ -1982,46 +1986,61 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
                                                fci->f->dd_fcrport_size);
 
                                /*
-                                * If we were blocked, we were a target.
-                                * If no longer a target, we leave the timer
-                                * running in case the port changes roles
-                                * prior to the timer expiring. If the timer
-                                * fires, the target will be torn down.
+                                * If we were not a target, cancel the
+                                * io terminate and rport timers, and
+                                * we're done.
+                                *
+                                * If we were a target, but our new role
+                                * doesn't indicate a target, leave the
+                                * timers running expecting the role to
+                                * change as the target fully logs in. If
+                                * it doesn't, the target will be torn down.
+                                *
+                                * If we were a target, and our role shows
+                                * we're still a target, cancel the timers
+                                * and kick off a scan.
                                 */
-                               if (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET))
-                                       return rport;
 
-                               /* restart the target */
+                               /* was a target, not in roles */
+                               if ((rport->scsi_target_id != -1) &&
+                                   (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET)))
+                                       return rport;
 
                                /*
-                                * Stop the target timers first. Take no action
-                                * on the del_timer failure as the state
-                                * machine state change will validate the
-                                * transaction.
+                                * Stop the fail io and dev_loss timers.
+                                * If they flush, the port_state will
+                                * be checked and will NOOP the function.
                                 */
                                if (!cancel_delayed_work(&rport->fail_io_work))
                                        fc_flush_devloss(shost);
-                               if (!cancel_delayed_work(work))
+                               if (!cancel_delayed_work(&rport->dev_loss_work))
                                        fc_flush_devloss(shost);
 
                                spin_lock_irqsave(shost->host_lock, flags);
 
                                rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
 
-                               /* initiate a scan of the target */
-                               rport->flags |= FC_RPORT_SCAN_PENDING;
-                               scsi_queue_work(shost, &rport->scan_work);
-
-                               spin_unlock_irqrestore(shost->host_lock, flags);
-
-                               scsi_target_unblock(&rport->dev);
+                               /* if target, initiate a scan */
+                               if (rport->scsi_target_id != -1) {
+                                       rport->flags |= FC_RPORT_SCAN_PENDING;
+                                       scsi_queue_work(shost,
+                                                       &rport->scan_work);
+                                       spin_unlock_irqrestore(shost->host_lock,
+                                                       flags);
+                                       scsi_target_unblock(&rport->dev);
+                               } else
+                                       spin_unlock_irqrestore(shost->host_lock,
+                                                       flags);
 
                                return rport;
                        }
                }
        }
 
-       /* Search the bindings array */
+       /*
+        * Search the bindings array
+        * Note: if never a FCP target, you won't be on this list
+        */
        if (fc_host->tgtid_bind_type != FC_TGTID_BIND_NONE) {
 
                /* search for a matching consistent binding */
@@ -2158,15 +2177,24 @@ fc_remote_port_delete(struct fc_rport  *rport)
 
        spin_lock_irqsave(shost->host_lock, flags);
 
-       /* If no scsi target id mapping, delete it */
-       if (rport->scsi_target_id == -1) {
-               list_del(&rport->peers);
-               rport->port_state = FC_PORTSTATE_DELETED;
-               fc_queue_work(shost, &rport->rport_delete_work);
+       if (rport->port_state != FC_PORTSTATE_ONLINE) {
                spin_unlock_irqrestore(shost->host_lock, flags);
                return;
        }
 
+       /*
+        * In the past, we if this was not an FCP-Target, we would
+        * unconditionally just jump to deleting the rport.
+        * However, rports can be used as node containers by the LLDD,
+        * and its not appropriate to just terminate the rport at the
+        * first sign of a loss in connectivity. The LLDD may want to
+        * send ELS traffic to re-validate the login. If the rport is
+        * immediately deleted, it makes it inappropriate for a node
+        * container.
+        * So... we now unconditionally wait dev_loss_tmo before
+        * destroying an rport.
+        */
+
        rport->port_state = FC_PORTSTATE_BLOCKED;
 
        rport->flags |= FC_RPORT_DEVLOSS_PENDING;
@@ -2263,11 +2291,11 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
 EXPORT_SYMBOL(fc_remote_port_rolechg);
 
 /**
- * fc_timeout_deleted_rport - Timeout handler for a deleted remote port that
- *                       was a SCSI target (thus was blocked), and failed
- *                       to return in the alloted time.
+ * fc_timeout_deleted_rport - Timeout handler for a deleted remote port,
+ *                     which we blocked, and has now failed to return
+ *                     in the allotted time.
  * 
- * @work:      rport target that failed to reappear in the alloted time.
+ * @work:      rport target that failed to reappear in the allotted time.
  **/
 static void
 fc_timeout_deleted_rport(struct work_struct *work)
@@ -2283,10 +2311,12 @@ fc_timeout_deleted_rport(struct work_struct *work)
        rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
 
        /*
-        * If the port is ONLINE, then it came back. Validate it's still an
-        * FCP target. If not, tear down the scsi_target on it.
+        * If the port is ONLINE, then it came back. If it was a SCSI
+        * target, validate it still is. If not, tear down the
+        * scsi_target on it.
         */
        if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
+           (rport->scsi_target_id != -1) &&
            !(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
                dev_printk(KERN_ERR, &rport->dev,
                        "blocked FC remote port time out: no longer"
@@ -2297,18 +2327,24 @@ fc_timeout_deleted_rport(struct work_struct *work)
                return;
        }
 
+       /* NOOP state - we're flushing workq's */
        if (rport->port_state != FC_PORTSTATE_BLOCKED) {
                spin_unlock_irqrestore(shost->host_lock, flags);
                dev_printk(KERN_ERR, &rport->dev,
-                       "blocked FC remote port time out: leaving target alone\n");
+                       "blocked FC remote port time out: leaving"
+                       " rport%s alone\n",
+                       (rport->scsi_target_id != -1) ?  " and starget" : "");
                return;
        }
 
-       if (fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) {
+       if ((fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) ||
+           (rport->scsi_target_id == -1)) {
                list_del(&rport->peers);
                rport->port_state = FC_PORTSTATE_DELETED;
                dev_printk(KERN_ERR, &rport->dev,
-                       "blocked FC remote port time out: removing target\n");
+                       "blocked FC remote port time out: removing"
+                       " rport%s\n",
+                       (rport->scsi_target_id != -1) ?  " and starget" : "");
                fc_queue_work(shost, &rport->rport_delete_work);
                spin_unlock_irqrestore(shost->host_lock, flags);
                return;
index 3158949ffa62206f98c0437462b83a3142f3f215..e7b85e832eb5990d76f45b4b30d255525dae030d 100644 (file)
@@ -351,6 +351,27 @@ static u8  dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20};
  * (DCBs, SRBs, Queueing)
  *
  **********************************************************************/
+static void inline dc390_start_segment(struct dc390_srb* pSRB)
+{
+       struct scatterlist *psgl = pSRB->pSegmentList;
+
+       /* start new sg segment */
+       pSRB->SGBusAddr = sg_dma_address(psgl);
+       pSRB->SGToBeXferLen = sg_dma_len(psgl);
+}
+
+static unsigned long inline dc390_advance_segment(struct dc390_srb* pSRB, u32 residue)
+{
+       unsigned long xfer = pSRB->SGToBeXferLen - residue;
+
+       /* xfer more bytes transferred */
+       pSRB->SGBusAddr += xfer;
+       pSRB->TotalXferredLen += xfer;
+       pSRB->SGToBeXferLen = residue;
+
+       return xfer;
+}
+
 static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun)
 {
    struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL;
@@ -625,70 +646,6 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
     return 0;
 }
 
-//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/
-#define DMA_INT 0
-
-#if DMA_INT
-/* This is similar to AM53C974.c ... */
-static u8 
-dc390_dma_intr (struct dc390_acb* pACB)
-{
-  struct dc390_srb* pSRB;
-  u8 dstate;
-  DEBUG0(u16 pstate; struct pci_dev *pdev = pACB->pdev);
-  
-  DEBUG0(pci_read_config_word(pdev, PCI_STATUS, &pstate));
-  DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\
-       { printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \
-         pci_write_config_word(pdev, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));});
-
-  dstate = DC390_read8 (DMA_Status); 
-
-  if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate;
-  else pSRB  = pACB->pActiveDCB->pActiveSRB;
-  
-  if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT))
-    {
-       printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate);
-       return dstate;
-    }
-  if (dstate & DMA_XFER_DONE)
-    {
-       u32 residual, xferCnt; int ctr = 6000000;
-       if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION))
-         {
-           do
-             {
-               DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n"));
-               dstate = DC390_read8 (DMA_Status);
-               residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 |
-                 DC390_read8 (CtcReg_High) << 16;
-               residual += DC390_read8 (Current_Fifo) & 0x1f;
-             } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr);
-           if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
-           /* residual =  ... */
-         }
-       else
-           residual = 0;
-       
-       /* ??? */
-       
-       xferCnt = pSRB->SGToBeXferLen - residual;
-       pSRB->SGBusAddr += xferCnt;
-       pSRB->TotalXferredLen += xferCnt;
-       pSRB->SGToBeXferLen = residual;
-# ifdef DC390_DEBUG0
-       printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", 
-               (unsigned int)residual, (unsigned int)xferCnt);
-# endif
-       
-       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-    }
-  dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
-  return dstate;
-}
-#endif
-
 
 static void __inline__
 dc390_InvalidCmd(struct dc390_acb* pACB)
@@ -708,9 +665,6 @@ DC390_Interrupt(void *dev_id)
     u8  phase;
     void   (*stateV)( struct dc390_acb*, struct dc390_srb*, u8 *);
     u8  istate, istatus;
-#if DMA_INT
-    u8  dstatus;
-#endif
 
     sstatus = DC390_read8 (Scsi_Status);
     if( !(sstatus & INTERRUPT) )
@@ -718,22 +672,9 @@ DC390_Interrupt(void *dev_id)
 
     DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus));
 
-#if DMA_INT
-    spin_lock_irq(pACB->pScsiHost->host_lock);
-    dstatus = dc390_dma_intr (pACB);
-    spin_unlock_irq(pACB->pScsiHost->host_lock);
-
-    DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus));
-    if (! (dstatus & SCSI_INTERRUPT))
-      {
-       DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n"));
-       return IRQ_NONE;
-      }
-#else
     //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
     //dstatus = DC390_read8 (DMA_Status);
     //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
-#endif
 
     spin_lock_irq(pACB->pScsiHost->host_lock);
 
@@ -821,11 +762,10 @@ static irqreturn_t do_DC390_Interrupt(int irq, void *dev_id)
 }
 
 static void
-dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+dc390_DataOut_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
 {
     u8   sstatus;
-    struct scatterlist *psgl;
-    u32    ResidCnt, xferCnt;
+    u32  ResidCnt;
     u8   dstate = 0;
 
     sstatus = *psstatus;
@@ -856,42 +796,35 @@ dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
            if( pSRB->SGIndex < pSRB->SGcount )
            {
                pSRB->pSegmentList++;
-               psgl = pSRB->pSegmentList;
 
-               pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-               pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+               dc390_start_segment(pSRB);
            }
            else
                pSRB->SGToBeXferLen = 0;
        }
        else
        {
-           ResidCnt  = (u32) DC390_read8 (Current_Fifo) & 0x1f;
-           ResidCnt |= (u32) DC390_read8 (CtcReg_High) << 16;
-           ResidCnt |= (u32) DC390_read8 (CtcReg_Mid) << 8; 
-           ResidCnt += (u32) DC390_read8 (CtcReg_Low);
-
-           xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-           pSRB->SGBusAddr += xferCnt;
-           pSRB->TotalXferredLen += xferCnt;
-           pSRB->SGToBeXferLen = ResidCnt;
+           ResidCnt = ((u32) DC390_read8 (Current_Fifo) & 0x1f) +
+                   (((u32) DC390_read8 (CtcReg_High) << 16) |
+                    ((u32) DC390_read8 (CtcReg_Mid) << 8) |
+                    (u32) DC390_read8 (CtcReg_Low));
+
+           dc390_advance_segment(pSRB, ResidCnt);
        }
     }
     if ((*psstatus & 7) != SCSI_DATA_OUT)
     {
-           DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+           DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD);
            DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     }      
 }
 
 static void
-dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+dc390_DataIn_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
 {
     u8   sstatus, residual, bval;
-    struct scatterlist *psgl;
-    u32    ResidCnt, i;
+    u32  ResidCnt, i;
     unsigned long   xferCnt;
-    u8      *ptr;
 
     sstatus = *psstatus;
 
@@ -922,19 +855,17 @@ dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
            DEBUG1(ResidCnt = ((unsigned long) DC390_read8 (CtcReg_High) << 16) \
                + ((unsigned long) DC390_read8 (CtcReg_Mid) << 8)               \
                + ((unsigned long) DC390_read8 (CtcReg_Low)));
-           DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen));
+           DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%u,ToBeXfer=%lu),", ResidCnt, pSRB->SGToBeXferLen));
 
-           DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+           DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
 
            pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
            pSRB->SGIndex++;
            if( pSRB->SGIndex < pSRB->SGcount )
            {
                pSRB->pSegmentList++;
-               psgl = pSRB->pSegmentList;
 
-               pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-               pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+               dc390_start_segment(pSRB);
            }
            else
                pSRB->SGToBeXferLen = 0;
@@ -973,47 +904,45 @@ din_1:
            }
            /* It seems a DMA Blast abort isn't that bad ... */
            if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n");
-           //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
-           dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24;
+           //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
+           dc390_laststatus &= ~0xff000000;
+           dc390_laststatus |= bval << 24;
 
            DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval));
-           ResidCnt = (u32) DC390_read8 (CtcReg_High);
-           ResidCnt <<= 8;
-           ResidCnt |= (u32) DC390_read8 (CtcReg_Mid);
-           ResidCnt <<= 8;
-           ResidCnt |= (u32) DC390_read8 (CtcReg_Low);
-
-           xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-           pSRB->SGBusAddr += xferCnt;
-           pSRB->TotalXferredLen += xferCnt;
-           pSRB->SGToBeXferLen = ResidCnt;
-
-           if( residual )
-           {
-               static int feedback_requested;
+           ResidCnt = (((u32) DC390_read8 (CtcReg_High) << 16) |
+                       ((u32) DC390_read8 (CtcReg_Mid) << 8)) |
+                   (u32) DC390_read8 (CtcReg_Low);
+
+           xferCnt = dc390_advance_segment(pSRB, ResidCnt);
+
+           if (residual) {
+               size_t count = 1;
+               size_t offset = pSRB->SGBusAddr - sg_dma_address(pSRB->pSegmentList);
+               unsigned long flags;
+               u8 *ptr;
+
                bval = DC390_read8 (ScsiFifo);      /* get one residual byte */
 
-               if (!feedback_requested) {
-                       feedback_requested = 1;
-                       printk(KERN_WARNING "%s: Please, contact <linux-scsi@vger.kernel.org> "
-                              "to help improve support for your system.\n", __FILE__);
+               local_irq_save(flags);
+               ptr = scsi_kmap_atomic_sg(pSRB->pSegmentList, pSRB->SGcount, &offset, &count);
+               if (likely(ptr)) {
+                       *(ptr + offset) = bval;
+                       scsi_kunmap_atomic_sg(ptr);
                }
+               local_irq_restore(flags);
+               WARN_ON(!ptr);
 
-               ptr = (u8 *) bus_to_virt( pSRB->SGBusAddr );
-               *ptr = bval;
-               pSRB->SGBusAddr++; xferCnt++;
-               pSRB->TotalXferredLen++;
-               pSRB->SGToBeXferLen--;
+               /* 1 more byte read */
+               xferCnt += dc390_advance_segment(pSRB, pSRB->SGToBeXferLen - 1);
            }
-           DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
+           DEBUG1(printk (KERN_DEBUG "Xfered: %lu, Total: %lu, Remaining: %lu\n", xferCnt,\
                           pSRB->TotalXferredLen, pSRB->SGToBeXferLen));
-
        }
     }
     if ((*psstatus & 7) != SCSI_DATA_IN)
     {
            DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
-           DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+           DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
     }
 }
 
@@ -1216,7 +1145,7 @@ dc390_MsgIn_set_sync (struct dc390_acb* pACB, struct dc390_srb* pSRB)
 
 
 /* handle RESTORE_PTR */
-/* I presume, this command is already mapped, so, have to remap. */
+/* This doesn't look very healthy... to-be-fixed */
 static void 
 dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
 {
@@ -1225,6 +1154,7 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
     pSRB->TotalXferredLen = 0;
     pSRB->SGIndex = 0;
     if (pcmd->use_sg) {
+       size_t saved;
        pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer;
        psgl = pSRB->pSegmentList;
        //dc390_pci_sync(pSRB);
@@ -1236,15 +1166,16 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
            if( pSRB->SGIndex < pSRB->SGcount )
            {
                pSRB->pSegmentList++;
-               psgl = pSRB->pSegmentList;
-               pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-               pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+
+               dc390_start_segment(pSRB);
            }
            else
                pSRB->SGToBeXferLen = 0;
        }
-       pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
-       pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
+
+       saved = pSRB->Saved_Ptr - pSRB->TotalXferredLen;
+       pSRB->SGToBeXferLen -= saved;
+       pSRB->SGBusAddr += saved;
        printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n",
                pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr);
 
@@ -1365,7 +1296,6 @@ dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
 static void
 dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
 {
-    struct scatterlist *psgl;
     unsigned long  lval;
     struct dc390_dcb*   pDCB = pACB->pActiveDCB;
 
@@ -1391,12 +1321,11 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
 
     if( pSRB->SGIndex < pSRB->SGcount )
     {
-       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */);
+       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
        if( !pSRB->SGToBeXferLen )
        {
-           psgl = pSRB->pSegmentList;
-           pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-           pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+           dc390_start_segment(pSRB);
+
            DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment."));
        }
        lval = pSRB->SGToBeXferLen;
@@ -1410,12 +1339,12 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
        DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen);
        DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr);
 
-       //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */
+       //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
        pSRB->SRBState = SRB_DATA_XFER;
 
        DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
 
-       DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+       DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir);
        //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT));
        //DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status)));
        //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT));
@@ -1436,8 +1365,8 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
        pSRB->SRBState |= SRB_XFERPAD;
        DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
 /*
-       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT;
-       DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
+       DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir);
 */
     }
 }
index 9b66fa8d38d948129df809016c0e81deb87cc900..c3d8c80cfb386182898fd966c4bd1b3d20685074 100644 (file)
 
 #define SEL_TIMEOUT            153     /* 250 ms selection timeout (@ 40 MHz) */
 
-#define pci_dma_lo32(a)                        (a & 0xffffffff)
-
-typedef u8             UCHAR;  /*  8 bits */
-typedef u16            USHORT; /* 16 bits */
-typedef u32            UINT;   /* 32 bits */
-typedef unsigned long  ULONG;  /* 32/64 bits */
-
-
 /*
 ;-----------------------------------------------------------------------
 ; SCSI Request Block
@@ -43,7 +35,9 @@ struct scatterlist    *pSegmentList;
 
 struct scatterlist Segmentx;   /* make a one entry of S/G list table */
 
-unsigned long  SGBusAddr;      /*;a segment starting address as seen by AM53C974A*/
+unsigned long  SGBusAddr;      /*;a segment starting address as seen by AM53C974A
+                                 in CPU endianness. We're only getting 32-bit bus
+                                 addresses by default */
 unsigned long  SGToBeXferLen;  /*; to be xfer length */
 unsigned long  TotalXferredLen;
 unsigned long  SavedTotXLen;
index ad0182ef7809bba62450e4788dfb658fd601ce8d..2e6bdc4e7a0ae1deb116b7d9e96e8e29bbf05b99 100644 (file)
@@ -314,8 +314,7 @@ struct scsi_core {
        struct list_head  task_queue;
        int               task_queue_size;
 
-       struct semaphore  queue_thread_sema;
-       int               queue_thread_kill;
+       struct task_struct *queue_thread;
 };
 
 struct sas_ha_event {