]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 23 Oct 2010 00:34:15 +0000 (17:34 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 23 Oct 2010 00:34:15 +0000 (17:34 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (84 commits)
  [SCSI] be2iscsi: SGE Len == 64K
  [SCSI] be2iscsi: Remove premature free of cid
  [SCSI] be2iscsi: More time for FW
  [SCSI] libsas: fix bug for vacant phy
  [SCSI] sd: Fix overflow with big physical blocks
  [SCSI] st: add MTWEOFI to write filemarks without flushing drive buffer
  [SCSI] libsas: Don't issue commands to devices that have been hot-removed
  [SCSI] megaraid_sas: Add Online Controller Reset to MegaRAID SAS drive
  [SCSI] lpfc 8.3.17: Update lpfc driver version to 8.3.17
  [SCSI] lpfc 8.3.17: Replace function reset methodology
  [SCSI] lpfc 8.3.17: SCSI fixes
  [SCSI] lpfc 8.3.17: BSG fixes
  [SCSI] lpfc 8.3.17: SLI Additions and Fixes
  [SCSI] lpfc 8.3.17: Code Cleanup and Locking fixes
  [SCSI] zfcp: Remove scsi_cmnd->serial_number from debug traces
  [SCSI] ipr: fix array error logging
  [SCSI] aha152x: enable PCMCIA on 64bit
  [SCSI] scsi_dh_alua: Handle all states correctly
  [SCSI] cxgb4i: connection and ddp setting update
  [SCSI] cxgb3i: fixed connection over vlan
  ...

14 files changed:
1  2 
drivers/s390/scsi/zfcp_cfdc.c
drivers/s390/scsi/zfcp_scsi.c
drivers/scsi/be2iscsi/be_iscsi.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/megaraid/megaraid_sas.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_nx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/sd.c
drivers/scsi/st.c

index 1838cda68ba8ac3258129646081a6f1cdb62b724,a56d14166c99394bf79ab88135f6564f85211f01..d692e229ecba59c03549fc19447e81d8184503da
@@@ -2,9 -2,10 +2,10 @@@
   * zfcp device driver
   *
   * Userspace interface for accessing the
-  * Access Control Lists / Control File Data Channel
+  * Access Control Lists / Control File Data Channel;
+  * handling of response code and states for ports and LUNs.
   *
-  * Copyright IBM Corporation 2008, 2009
+  * Copyright IBM Corporation 2008, 2010
   */
  
  #define KMSG_COMPONENT "zfcp"
@@@ -251,9 -252,8 +252,9 @@@ static const struct file_operations zfc
        .open = nonseekable_open,
        .unlocked_ioctl = zfcp_cfdc_dev_ioctl,
  #ifdef CONFIG_COMPAT
 -      .compat_ioctl = zfcp_cfdc_dev_ioctl
 +      .compat_ioctl = zfcp_cfdc_dev_ioctl,
  #endif
 +      .llseek = no_llseek,
  };
  
  struct miscdevice zfcp_cfdc_misc = {
        .name = "zfcp_cfdc",
        .fops = &zfcp_cfdc_fops,
  };
+ /**
+  * zfcp_cfdc_adapter_access_changed - Process change in adapter ACT
+  * @adapter: Adapter where the Access Control Table (ACT) changed
+  *
+  * After a change in the adapter ACT, check if access to any
+  * previously denied resources is now possible.
+  */
+ void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *adapter)
+ {
+       unsigned long flags;
+       struct zfcp_port *port;
+       struct scsi_device *sdev;
+       struct zfcp_scsi_dev *zfcp_sdev;
+       int status;
+       if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
+               return;
+       read_lock_irqsave(&adapter->port_list_lock, flags);
+       list_for_each_entry(port, &adapter->port_list, list) {
+               status = atomic_read(&port->status);
+               if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) ||
+                   (status & ZFCP_STATUS_COMMON_ACCESS_BOXED))
+                       zfcp_erp_port_reopen(port,
+                                            ZFCP_STATUS_COMMON_ERP_FAILED,
+                                            "cfaac_1", NULL);
+       }
+       read_unlock_irqrestore(&adapter->port_list_lock, flags);
+       shost_for_each_device(sdev, port->adapter->scsi_host) {
+               zfcp_sdev = sdev_to_zfcp(sdev);
+               status = atomic_read(&zfcp_sdev->status);
+               if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) ||
+                   (status & ZFCP_STATUS_COMMON_ACCESS_BOXED))
+                       zfcp_erp_lun_reopen(sdev,
+                                           ZFCP_STATUS_COMMON_ERP_FAILED,
+                                           "cfaac_2", NULL);
+       }
+ }
+ static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table)
+ {
+       u16 subtable = table >> 16;
+       u16 rule = table & 0xffff;
+       const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" };
+       if (subtable && subtable < ARRAY_SIZE(act_type))
+               dev_warn(&adapter->ccw_device->dev,
+                        "Access denied according to ACT rule type %s, "
+                        "rule %d\n", act_type[subtable], rule);
+ }
+ /**
+  * zfcp_cfdc_port_denied - Process "access denied" for port
+  * @port: The port where the acces has been denied
+  * @qual: The FSF status qualifier for the access denied FSF status
+  */
+ void zfcp_cfdc_port_denied(struct zfcp_port *port,
+                          union fsf_status_qual *qual)
+ {
+       dev_warn(&port->adapter->ccw_device->dev,
+                "Access denied to port 0x%016Lx\n",
+                (unsigned long long)port->wwpn);
+       zfcp_act_eval_err(port->adapter, qual->halfword[0]);
+       zfcp_act_eval_err(port->adapter, qual->halfword[1]);
+       zfcp_erp_set_port_status(port,
+                                ZFCP_STATUS_COMMON_ERP_FAILED |
+                                ZFCP_STATUS_COMMON_ACCESS_DENIED);
+ }
+ /**
+  * zfcp_cfdc_lun_denied - Process "access denied" for LUN
+  * @sdev: The SCSI device / LUN where the access has been denied
+  * @qual: The FSF status qualifier for the access denied FSF status
+  */
+ void zfcp_cfdc_lun_denied(struct scsi_device *sdev,
+                         union fsf_status_qual *qual)
+ {
+       struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+       dev_warn(&zfcp_sdev->port->adapter->ccw_device->dev,
+                "Access denied to LUN 0x%016Lx on port 0x%016Lx\n",
+                zfcp_scsi_dev_lun(sdev),
+                (unsigned long long)zfcp_sdev->port->wwpn);
+       zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->halfword[0]);
+       zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->halfword[1]);
+       zfcp_erp_set_lun_status(sdev,
+                               ZFCP_STATUS_COMMON_ERP_FAILED |
+                               ZFCP_STATUS_COMMON_ACCESS_DENIED);
+       atomic_clear_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status);
+       atomic_clear_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status);
+ }
+ /**
+  * zfcp_cfdc_lun_shrng_vltn - Evaluate LUN sharing violation status
+  * @sdev: The LUN / SCSI device where sharing violation occurred
+  * @qual: The FSF status qualifier from the LUN sharing violation
+  */
+ void zfcp_cfdc_lun_shrng_vltn(struct scsi_device *sdev,
+                             union fsf_status_qual *qual)
+ {
+       struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+       if (qual->word[0])
+               dev_warn(&zfcp_sdev->port->adapter->ccw_device->dev,
+                        "LUN 0x%Lx on port 0x%Lx is already in "
+                        "use by CSS%d, MIF Image ID %x\n",
+                        zfcp_scsi_dev_lun(sdev),
+                        (unsigned long long)zfcp_sdev->port->wwpn,
+                        qual->fsf_queue_designator.cssid,
+                        qual->fsf_queue_designator.hla);
+       else
+               zfcp_act_eval_err(zfcp_sdev->port->adapter, qual->word[2]);
+       zfcp_erp_set_lun_status(sdev,
+                               ZFCP_STATUS_COMMON_ERP_FAILED |
+                               ZFCP_STATUS_COMMON_ACCESS_DENIED);
+       atomic_clear_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status);
+       atomic_clear_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status);
+ }
+ /**
+  * zfcp_cfdc_open_lun_eval - Eval access ctrl. status for successful "open lun"
+  * @sdev: The SCSI device / LUN where to evaluate the status
+  * @bottom: The qtcb bottom with the status from the "open lun"
+  *
+  * Returns: 0 if LUN is usable, -EACCES if the access control table
+  *          reports an unsupported configuration.
+  */
+ int zfcp_cfdc_open_lun_eval(struct scsi_device *sdev,
+                           struct fsf_qtcb_bottom_support *bottom)
+ {
+       int shared, rw;
+       struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+       struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
+       if ((adapter->connection_features & FSF_FEATURE_NPIV_MODE) ||
+           !(adapter->adapter_features & FSF_FEATURE_LUN_SHARING) ||
+           zfcp_ccw_priv_sch(adapter))
+               return 0;
+       shared = !(bottom->lun_access_info & FSF_UNIT_ACCESS_EXCLUSIVE);
+       rw = (bottom->lun_access_info & FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
+       if (shared)
+               atomic_set_mask(ZFCP_STATUS_LUN_SHARED, &zfcp_sdev->status);
+       if (!rw) {
+               atomic_set_mask(ZFCP_STATUS_LUN_READONLY, &zfcp_sdev->status);
+               dev_info(&adapter->ccw_device->dev, "SCSI device at LUN "
+                        "0x%016Lx on port 0x%016Lx opened read-only\n",
+                        zfcp_scsi_dev_lun(sdev),
+                        (unsigned long long)zfcp_sdev->port->wwpn);
+       }
+       if (!shared && !rw) {
+               dev_err(&adapter->ccw_device->dev, "Exclusive read-only access "
+                       "not supported (LUN 0x%016Lx, port 0x%016Lx)\n",
+                       zfcp_scsi_dev_lun(sdev),
+                       (unsigned long long)zfcp_sdev->port->wwpn);
+               zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED);
+               zfcp_erp_lun_shutdown(sdev, 0, "fsouh_6", NULL);
+               return -EACCES;
+       }
+       if (shared && rw) {
+               dev_err(&adapter->ccw_device->dev,
+                       "Shared read-write access not supported "
+                       "(LUN 0x%016Lx, port 0x%016Lx)\n",
+                       zfcp_scsi_dev_lun(sdev),
+                       (unsigned long long)zfcp_sdev->port->wwpn);
+               zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED);
+               zfcp_erp_lun_shutdown(sdev, 0, "fsosh_8", NULL);
+               return -EACCES;
+       }
+       return 0;
+ }
index 208256e39def9e1d6dd7ce19724724d6e99bada4,ae10883a5b2879a67623b717a19a13a9014c8dbe..50286d8707f305b981c1e56ffa02df7b3ce3b0d9
@@@ -49,11 -49,12 +49,12 @@@ static int zfcp_scsi_change_queue_depth
        return sdev->queue_depth;
  }
  
- static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
+ static void zfcp_scsi_slave_destroy(struct scsi_device *sdev)
  {
-       struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
-       unit->device = NULL;
-       put_device(&unit->dev);
+       struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
+       zfcp_erp_lun_shutdown_wait(sdev, "scssd_1");
+       put_device(&zfcp_sdev->port->dev);
  }
  
  static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
@@@ -78,23 -79,16 +79,16 @@@ static void zfcp_scsi_command_fail(stru
  static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
                                  void (*done) (struct scsi_cmnd *))
  {
-       struct zfcp_unit *unit;
-       struct zfcp_adapter *adapter;
-       int    status, scsi_result, ret;
+       struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
+       struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
        struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device));
+       int    status, scsi_result, ret;
  
        /* reset the status for this request */
        scpnt->result = 0;
        scpnt->host_scribble = NULL;
        scpnt->scsi_done = done;
  
-       /*
-        * figure out adapter and target device
-        * (stored there by zfcp_scsi_slave_alloc)
-        */
-       adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
-       unit = scpnt->device->hostdata;
        scsi_result = fc_remote_port_chkready(rport);
        if (unlikely(scsi_result)) {
                scpnt->result = scsi_result;
                return 0;
        }
  
-       status = atomic_read(&unit->status);
+       status = atomic_read(&zfcp_sdev->status);
        if (unlikely(status & ZFCP_STATUS_COMMON_ERP_FAILED) &&
-                    !(atomic_read(&unit->port->status) &
+                    !(atomic_read(&zfcp_sdev->port->status) &
                       ZFCP_STATUS_COMMON_ERP_FAILED)) {
-               /* only unit access denied, but port is good
+               /* only LUN access denied, but port is good
                 * not covered by FC transport, have to fail here */
                zfcp_scsi_command_fail(scpnt, DID_ERROR);
                return 0;
  
        if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) {
                /* This could be either
-                * open unit pending: this is temporary, will result in
-                *      open unit or ERP_FAILED, so retry command
+                * open LUN pending: this is temporary, will result in
+                *      open LUN or ERP_FAILED, so retry command
                 * call to rport_delete pending: mimic retry from
                 *      fc_remote_port_chkready until rport is BLOCKED
                 */
                return 0;
        }
  
-       ret = zfcp_fsf_send_fcp_command_task(unit, scpnt);
+       ret = zfcp_fsf_fcp_cmnd(scpnt);
        if (unlikely(ret == -EBUSY))
                return SCSI_MLQUEUE_DEVICE_BUSY;
        else if (unlikely(ret < 0))
        return ret;
  }
  
- static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter,
-                                         unsigned int id, u64 lun)
+ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)
  {
-       unsigned long flags;
+       struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
+       struct zfcp_adapter *adapter =
+               (struct zfcp_adapter *) sdev->host->hostdata[0];
+       struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
        struct zfcp_port *port;
-       struct zfcp_unit *unit = NULL;
+       struct zfcp_unit *unit;
  
-       read_lock_irqsave(&adapter->port_list_lock, flags);
-       list_for_each_entry(port, &adapter->port_list, list) {
-               if (!port->rport || (id != port->rport->scsi_target_id))
-                       continue;
-               unit = zfcp_get_unit_by_lun(port, lun);
-               if (unit)
-                       break;
-       }
-       read_unlock_irqrestore(&adapter->port_list_lock, flags);
+       port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
+       if (!port)
+               return -ENXIO;
  
-       return unit;
- }
+       unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev));
+       if (unit)
+               put_device(&unit->dev);
  
- static int zfcp_scsi_slave_alloc(struct scsi_device *sdp)
- {
-       struct zfcp_adapter *adapter;
-       struct zfcp_unit *unit;
-       u64 lun;
+       if (!unit && !(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) {
+               put_device(&port->dev);
+               return -ENXIO;
+       }
  
-       adapter = (struct zfcp_adapter *) sdp->host->hostdata[0];
-       if (!adapter)
-               goto out;
+       zfcp_sdev->port = port;
+       zfcp_sdev->latencies.write.channel.min = 0xFFFFFFFF;
+       zfcp_sdev->latencies.write.fabric.min = 0xFFFFFFFF;
+       zfcp_sdev->latencies.read.channel.min = 0xFFFFFFFF;
+       zfcp_sdev->latencies.read.fabric.min = 0xFFFFFFFF;
+       zfcp_sdev->latencies.cmd.channel.min = 0xFFFFFFFF;
+       zfcp_sdev->latencies.cmd.fabric.min = 0xFFFFFFFF;
+       spin_lock_init(&zfcp_sdev->latencies.lock);
  
-       int_to_scsilun(sdp->lun, (struct scsi_lun *)&lun);
-       unit = zfcp_unit_lookup(adapter, sdp->id, lun);
-       if (unit) {
-               sdp->hostdata = unit;
-               unit->device = sdp;
-               return 0;
-       }
- out:
-       return -ENXIO;
+       zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING);
+       zfcp_erp_lun_reopen(sdev, 0, "scsla_1", NULL);
+       zfcp_erp_wait(port->adapter);
+       return 0;
  }
  
  static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
        struct Scsi_Host *scsi_host = scpnt->device->host;
        struct zfcp_adapter *adapter =
                (struct zfcp_adapter *) scsi_host->hostdata[0];
-       struct zfcp_unit *unit = scpnt->device->hostdata;
        struct zfcp_fsf_req *old_req, *abrt_req;
        unsigned long flags;
        unsigned long old_reqid = (unsigned long) scpnt->host_scribble;
        write_unlock_irqrestore(&adapter->abort_lock, flags);
  
        while (retry--) {
-               abrt_req = zfcp_fsf_abort_fcp_command(old_reqid, unit);
+               abrt_req = zfcp_fsf_abort_fcp_cmnd(scpnt);
                if (abrt_req)
                        break;
  
  
  static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
  {
-       struct zfcp_unit *unit = scpnt->device->hostdata;
-       struct zfcp_adapter *adapter = unit->port->adapter;
+       struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
+       struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
        struct zfcp_fsf_req *fsf_req = NULL;
        int retval = SUCCESS, ret;
        int retry = 3;
  
        while (retry--) {
-               fsf_req = zfcp_fsf_send_fcp_ctm(unit, tm_flags);
+               fsf_req = zfcp_fsf_fcp_task_mgmt(scpnt, tm_flags);
                if (fsf_req)
                        break;
  
  
                if (!(atomic_read(&adapter->status) &
                      ZFCP_STATUS_COMMON_RUNNING)) {
-                       zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt);
+                       zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags);
                        return SUCCESS;
                }
        }
        wait_for_completion(&fsf_req->completion);
  
        if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
-               zfcp_dbf_scsi_devreset("fail", tm_flags, unit, scpnt);
+               zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags);
                retval = FAILED;
        } else
-               zfcp_dbf_scsi_devreset("okay", tm_flags, unit, scpnt);
+               zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags);
  
        zfcp_fsf_req_free(fsf_req);
        return retval;
@@@ -287,8 -277,8 +277,8 @@@ static int zfcp_scsi_eh_target_reset_ha
  
  static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
  {
-       struct zfcp_unit *unit = scpnt->device->hostdata;
-       struct zfcp_adapter *adapter = unit->port->adapter;
+       struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
+       struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
        int ret;
  
        zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt);
@@@ -319,8 -309,8 +309,8 @@@ int zfcp_adapter_scsi_register(struct z
        }
  
        /* tell the SCSI stack some characteristics of this adapter */
-       adapter->scsi_host->max_id = 1;
-       adapter->scsi_host->max_lun = 1;
+       adapter->scsi_host->max_id = 511;
+       adapter->scsi_host->max_lun = 0xFFFFFFFF;
        adapter->scsi_host->max_channel = 0;
        adapter->scsi_host->unique_id = dev_id.devno;
        adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */
@@@ -534,20 -524,6 +524,6 @@@ static void zfcp_scsi_terminate_rport_i
        }
  }
  
- static void zfcp_scsi_queue_unit_register(struct zfcp_port *port)
- {
-       struct zfcp_unit *unit;
-       read_lock_irq(&port->unit_list_lock);
-       list_for_each_entry(unit, &port->unit_list, list) {
-               get_device(&unit->dev);
-               if (scsi_queue_work(port->adapter->scsi_host,
-                                   &unit->scsi_work) <= 0)
-                       put_device(&unit->dev);
-       }
-       read_unlock_irq(&port->unit_list_lock);
- }
  static void zfcp_scsi_rport_register(struct zfcp_port *port)
  {
        struct fc_rport_identifiers ids;
        port->rport = rport;
        port->starget_id = rport->scsi_target_id;
  
-       zfcp_scsi_queue_unit_register(port);
+       zfcp_unit_queue_scsi_scan(port);
  }
  
  static void zfcp_scsi_rport_block(struct zfcp_port *port)
@@@ -637,29 -613,6 +613,6 @@@ void zfcp_scsi_rport_work(struct work_s
        put_device(&port->dev);
  }
  
- /**
-  * zfcp_scsi_scan - Register LUN with SCSI midlayer
-  * @unit: The LUN/unit to register
-  */
- void zfcp_scsi_scan(struct zfcp_unit *unit)
- {
-       struct fc_rport *rport = unit->port->rport;
-       if (rport && rport->port_state == FC_PORTSTATE_ONLINE)
-               scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
-                                scsilun_to_int((struct scsi_lun *)
-                                               &unit->fcp_lun), 0);
- }
- void zfcp_scsi_scan_work(struct work_struct *work)
- {
-       struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
-                                             scsi_work);
-       zfcp_scsi_scan(unit);
-       put_device(&unit->dev);
- }
  /**
   * zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host
   * @adapter: The adapter where to configure DIF/DIX for the SCSI host
@@@ -681,7 -634,6 +634,7 @@@ void zfcp_scsi_set_prot(struct zfcp_ada
            adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) {
                mask |= SHOST_DIX_TYPE1_PROTECTION;
                scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP);
 +              shost->sg_prot_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2;
                shost->sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2;
                shost->max_sectors = ZFCP_QDIO_MAX_SBALES_PER_REQ * 8 / 2;
        }
@@@ -735,7 -687,6 +688,6 @@@ struct fc_function_template zfcp_transp
        .show_host_port_type = 1,
        .show_host_speed = 1,
        .show_host_port_id = 1,
-       .disable_target_scan = 1,
        .dd_bsg_size = sizeof(struct zfcp_fsf_ct_els),
  };
  
index 7f11f3e48e120ec82f1d7e26a0f1055fca771f97,8b897c80ec7a800058f2ac7f472ece2ce1c1be3e..eaaa8813067d06ff8c11777f8dbe462344b96379
@@@ -300,7 -300,8 +300,7 @@@ int beiscsi_get_host_param(struct Scsi_
                           enum iscsi_host_param param, char *buf)
  {
        struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost);
 -      int len = 0;
 -      int status;
 +      int status = 0;
  
        SE_DEBUG(DBG_LVL_8, "In beiscsi_get_host_param, param= %d\n", param);
        switch (param) {
        default:
                return iscsi_host_get_param(shost, param, buf);
        }
 -      return len;
 +      return status;
  }
  
  int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba)
@@@ -522,7 -523,6 +522,6 @@@ static int beiscsi_open_conn(struct isc
        if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start +
                                  phba->params.cxns_per_ctrl * 2)) {
                SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
-               beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
                goto free_ep;
        }
  
                SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed"
                                    " status = %d extd_status = %d\n",
                                    status, extd_status);
-               beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
                free_mcc_tag(&phba->ctrl, tag);
                pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
                            nonemb_cmd.va, nonemb_cmd.dma);
                beiscsi_ep->cid_vld = 1;
                SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
        }
-       beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
        pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
                            nonemb_cmd.va, nonemb_cmd.dma);
        return 0;
index 535085cd27ecf885ff9e917e233e6c593ec591da,1787bd2eb4a6a7b95645e1bae06b7fc73be18c26..55f09e92ab5918fd5019cacaded186d2cd1b1c55
@@@ -130,6 -130,17 +130,6 @@@ static void sas_scsi_task_done(struct s
        sc->scsi_done(sc);
  }
  
 -static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd)
 -{
 -      enum task_attribute ta = TASK_ATTR_SIMPLE;
 -      if (cmd->request && blk_rq_tagged(cmd->request)) {
 -              if (cmd->device->ordered_tags &&
 -                  (cmd->request->cmd_flags & REQ_HARDBARRIER))
 -                      ta = TASK_ATTR_ORDERED;
 -      }
 -      return ta;
 -}
 -
  static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
                                               struct domain_device *dev,
                                               gfp_t gfp_flags)
        task->ssp_task.retry_count = 1;
        int_to_scsilun(cmd->device->lun, &lun);
        memcpy(task->ssp_task.LUN, &lun.scsi_lun, 8);
 -      task->ssp_task.task_attr = sas_scsi_get_task_attr(cmd);
 +      task->ssp_task.task_attr = TASK_ATTR_SIMPLE;
        memcpy(task->ssp_task.cdb, cmd->cmnd, 16);
  
        task->scatter = scsi_sglist(cmd);
@@@ -217,6 -228,13 +217,13 @@@ int sas_queuecommand(struct scsi_cmnd *
                        goto out;
                }
  
+               /* If the device fell off, no sense in issuing commands */
+               if (dev->gone) {
+                       cmd->result = DID_BAD_TARGET << 16;
+                       scsi_done(cmd);
+                       goto out;
+               }
                res = -ENOMEM;
                task = sas_create_task(cmd, dev, GFP_ATOMIC);
                if (!task)
index 51e2579a743a8c0f249577e64e520a014061e1f5,55951f4d32600924e9eb038ba63b2d4f1368b6ff..d3c9cdee292b11cdcf44cd9b163bec3e7749814d
@@@ -33,6 -33,7 +33,6 @@@
  #include <linux/spinlock.h>
  #include <linux/interrupt.h>
  #include <linux/delay.h>
 -#include <linux/smp_lock.h>
  #include <linux/uio.h>
  #include <linux/slab.h>
  #include <asm/uaccess.h>
@@@ -61,6 -62,11 +61,11 @@@ MODULE_VERSION(MEGASAS_VERSION)
  MODULE_AUTHOR("megaraidlinux@lsi.com");
  MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
  
+ static int megasas_transition_to_ready(struct megasas_instance *instance);
+ static int megasas_get_pd_list(struct megasas_instance *instance);
+ static int megasas_issue_init_mfi(struct megasas_instance *instance);
+ static int megasas_register_aen(struct megasas_instance *instance,
+                               u32 seq_num, u32 class_locale_word);
  /*
   * PCI ID table for all supported controllers
   */
@@@ -163,7 -169,7 +168,7 @@@ megasas_return_cmd(struct megasas_insta
  static inline void
  megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
  {
-       writel(1, &(regs)->outbound_intr_mask);
+       writel(0, &(regs)->outbound_intr_mask);
  
        /* Dummy readl to force pci flush */
        readl(&regs->outbound_intr_mask);
@@@ -199,24 -205,27 +204,27 @@@ static in
  megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
  {
        u32 status;
+       u32 mfiStatus = 0;
        /*
         * Check if it is our interrupt
         */
        status = readl(&regs->outbound_intr_status);
  
-       if (!(status & MFI_OB_INTR_STATUS_MASK)) {
-               return 1;
-       }
+       if (status & MFI_OB_INTR_STATUS_MASK)
+               mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
+       if (status & MFI_XSCALE_OMR0_CHANGE_INTERRUPT)
+               mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
  
        /*
         * Clear the interrupt by writing back the same value
         */
-       writel(status, &regs->outbound_intr_status);
+       if (mfiStatus)
+               writel(status, &regs->outbound_intr_status);
  
        /* Dummy readl to force pci flush */
        readl(&regs->outbound_intr_status);
  
-       return 0;
+       return mfiStatus;
  }
  
  /**
@@@ -231,8 -240,69 +239,69 @@@ megasas_fire_cmd_xscale(struct megasas_
                u32 frame_count,
                struct megasas_register_set __iomem *regs)
  {
+       unsigned long flags;
+       spin_lock_irqsave(&instance->hba_lock, flags);
        writel((frame_phys_addr >> 3)|(frame_count),
               &(regs)->inbound_queue_port);
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
+ }
+ /**
+  * megasas_adp_reset_xscale -  For controller reset
+  * @regs:                              MFI register set
+  */
+ static int
+ megasas_adp_reset_xscale(struct megasas_instance *instance,
+       struct megasas_register_set __iomem *regs)
+ {
+       u32 i;
+       u32 pcidata;
+       writel(MFI_ADP_RESET, &regs->inbound_doorbell);
+       for (i = 0; i < 3; i++)
+               msleep(1000); /* sleep for 3 secs */
+       pcidata  = 0;
+       pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata);
+       printk(KERN_NOTICE "pcidata = %x\n", pcidata);
+       if (pcidata & 0x2) {
+               printk(KERN_NOTICE "mfi 1068 offset read=%x\n", pcidata);
+               pcidata &= ~0x2;
+               pci_write_config_dword(instance->pdev,
+                               MFI_1068_PCSR_OFFSET, pcidata);
+               for (i = 0; i < 2; i++)
+                       msleep(1000); /* need to wait 2 secs again */
+               pcidata  = 0;
+               pci_read_config_dword(instance->pdev,
+                               MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata);
+               printk(KERN_NOTICE "1068 offset handshake read=%x\n", pcidata);
+               if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) {
+                       printk(KERN_NOTICE "1068 offset pcidt=%x\n", pcidata);
+                       pcidata = 0;
+                       pci_write_config_dword(instance->pdev,
+                               MFI_1068_FW_HANDSHAKE_OFFSET, pcidata);
+               }
+       }
+       return 0;
+ }
+ /**
+  * megasas_check_reset_xscale -       For controller reset check
+  * @regs:                             MFI register set
+  */
+ static int
+ megasas_check_reset_xscale(struct megasas_instance *instance,
+               struct megasas_register_set __iomem *regs)
+ {
+       u32 consumer;
+       consumer = *instance->consumer;
+       if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
+               (*instance->consumer == MEGASAS_ADPRESET_INPROG_SIGN)) {
+               return 1;
+       }
+       return 0;
  }
  
  static struct megasas_instance_template megasas_instance_template_xscale = {
        .disable_intr = megasas_disable_intr_xscale,
        .clear_intr = megasas_clear_intr_xscale,
        .read_fw_status_reg = megasas_read_fw_status_reg_xscale,
+       .adp_reset = megasas_adp_reset_xscale,
+       .check_reset = megasas_check_reset_xscale,
  };
  
  /**
@@@ -263,7 -335,7 +334,7 @@@ megasas_enable_intr_ppc(struct megasas_
  {
        writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
      
-       writel(~0x80000004, &(regs)->outbound_intr_mask);
+       writel(~0x80000000, &(regs)->outbound_intr_mask);
  
        /* Dummy readl to force pci flush */
        readl(&regs->outbound_intr_mask);
@@@ -306,7 -378,7 +377,7 @@@ megasas_clear_intr_ppc(struct megasas_r
        status = readl(&regs->outbound_intr_status);
  
        if (!(status & MFI_REPLY_1078_MESSAGE_INTERRUPT)) {
-               return 1;
+               return 0;
        }
  
        /*
        /* Dummy readl to force pci flush */
        readl(&regs->outbound_doorbell_clear);
  
-       return 0;
+       return 1;
  }
  /**
   * megasas_fire_cmd_ppc -     Sends command to the FW
@@@ -331,10 -403,34 +402,34 @@@ megasas_fire_cmd_ppc(struct megasas_ins
                u32 frame_count,
                struct megasas_register_set __iomem *regs)
  {
+       unsigned long flags;
+       spin_lock_irqsave(&instance->hba_lock, flags);
        writel((frame_phys_addr | (frame_count<<1))|1, 
                        &(regs)->inbound_queue_port);
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
  }
  
+ /**
+  * megasas_adp_reset_ppc -    For controller reset
+  * @regs:                             MFI register set
+  */
+ static int
+ megasas_adp_reset_ppc(struct megasas_instance *instance,
+                       struct megasas_register_set __iomem *regs)
+ {
+       return 0;
+ }
+ /**
+  * megasas_check_reset_ppc -  For controller reset check
+  * @regs:                             MFI register set
+  */
+ static int
+ megasas_check_reset_ppc(struct megasas_instance *instance,
+                       struct megasas_register_set __iomem *regs)
+ {
+       return 0;
+ }
  static struct megasas_instance_template megasas_instance_template_ppc = {
        
        .fire_cmd = megasas_fire_cmd_ppc,
        .disable_intr = megasas_disable_intr_ppc,
        .clear_intr = megasas_clear_intr_ppc,
        .read_fw_status_reg = megasas_read_fw_status_reg_ppc,
+       .adp_reset = megasas_adp_reset_ppc,
+       .check_reset = megasas_check_reset_ppc,
  };
  
  /**
@@@ -396,7 -494,7 +493,7 @@@ megasas_clear_intr_skinny(struct megasa
        status = readl(&regs->outbound_intr_status);
  
        if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) {
-               return 1;
+               return 0;
        }
  
        /*
        */
        readl(&regs->outbound_intr_status);
  
-       return 0;
+       return 1;
  }
  
  /**
@@@ -425,11 -523,33 +522,33 @@@ megasas_fire_cmd_skinny(struct megasas_
                        struct megasas_register_set __iomem *regs)
  {
        unsigned long flags;
-       spin_lock_irqsave(&instance->fire_lock, flags);
+       spin_lock_irqsave(&instance->hba_lock, flags);
        writel(0, &(regs)->inbound_high_queue_port);
        writel((frame_phys_addr | (frame_count<<1))|1,
                &(regs)->inbound_low_queue_port);
-       spin_unlock_irqrestore(&instance->fire_lock, flags);
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
+ }
+ /**
+  * megasas_adp_reset_skinny - For controller reset
+  * @regs:                             MFI register set
+  */
+ static int
+ megasas_adp_reset_skinny(struct megasas_instance *instance,
+                       struct megasas_register_set __iomem *regs)
+ {
+       return 0;
+ }
+ /**
+  * megasas_check_reset_skinny -       For controller reset check
+  * @regs:                             MFI register set
+  */
+ static int
+ megasas_check_reset_skinny(struct megasas_instance *instance,
+                               struct megasas_register_set __iomem *regs)
+ {
+       return 0;
  }
  
  static struct megasas_instance_template megasas_instance_template_skinny = {
        .disable_intr = megasas_disable_intr_skinny,
        .clear_intr = megasas_clear_intr_skinny,
        .read_fw_status_reg = megasas_read_fw_status_reg_skinny,
+       .adp_reset = megasas_adp_reset_skinny,
+       .check_reset = megasas_check_reset_skinny,
  };
  
  
@@@ -494,23 -616,29 +615,29 @@@ static in
  megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
  {
        u32 status;
+       u32 mfiStatus = 0;
        /*
         * Check if it is our interrupt
         */
        status = readl(&regs->outbound_intr_status);
  
-       if (!(status & MFI_GEN2_ENABLE_INTERRUPT_MASK))
-               return 1;
+       if (status & MFI_GEN2_ENABLE_INTERRUPT_MASK) {
+               mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
+       }
+       if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) {
+               mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
+       }
  
        /*
         * Clear the interrupt by writing back the same value
         */
-       writel(status, &regs->outbound_doorbell_clear);
+       if (mfiStatus)
+               writel(status, &regs->outbound_doorbell_clear);
  
        /* Dummy readl to force pci flush */
        readl(&regs->outbound_intr_status);
  
-       return 0;
+       return mfiStatus;
  }
  /**
   * megasas_fire_cmd_gen2 -     Sends command to the FW
@@@ -524,8 -652,74 +651,74 @@@ megasas_fire_cmd_gen2(struct megasas_in
                        u32 frame_count,
                        struct megasas_register_set __iomem *regs)
  {
+       unsigned long flags;
+       spin_lock_irqsave(&instance->hba_lock, flags);
        writel((frame_phys_addr | (frame_count<<1))|1,
                        &(regs)->inbound_queue_port);
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
+ }
+ /**
+  * megasas_adp_reset_gen2 -   For controller reset
+  * @regs:                             MFI register set
+  */
+ static int
+ megasas_adp_reset_gen2(struct megasas_instance *instance,
+                       struct megasas_register_set __iomem *reg_set)
+ {
+       u32                     retry = 0 ;
+       u32                     HostDiag;
+       writel(0, &reg_set->seq_offset);
+       writel(4, &reg_set->seq_offset);
+       writel(0xb, &reg_set->seq_offset);
+       writel(2, &reg_set->seq_offset);
+       writel(7, &reg_set->seq_offset);
+       writel(0xd, &reg_set->seq_offset);
+       msleep(1000);
+       HostDiag = (u32)readl(&reg_set->host_diag);
+       while ( !( HostDiag & DIAG_WRITE_ENABLE) ) {
+               msleep(100);
+               HostDiag = (u32)readl(&reg_set->host_diag);
+               printk(KERN_NOTICE "RESETGEN2: retry=%x, hostdiag=%x\n",
+                                       retry, HostDiag);
+               if (retry++ >= 100)
+                       return 1;
+       }
+       printk(KERN_NOTICE "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag);
+       writel((HostDiag | DIAG_RESET_ADAPTER), &reg_set->host_diag);
+       ssleep(10);
+       HostDiag = (u32)readl(&reg_set->host_diag);
+       while ( ( HostDiag & DIAG_RESET_ADAPTER) ) {
+               msleep(100);
+               HostDiag = (u32)readl(&reg_set->host_diag);
+               printk(KERN_NOTICE "RESET_GEN2: retry=%x, hostdiag=%x\n",
+                               retry, HostDiag);
+               if (retry++ >= 1000)
+                       return 1;
+       }
+       return 0;
+ }
+ /**
+  * megasas_check_reset_gen2 - For controller reset check
+  * @regs:                             MFI register set
+  */
+ static int
+ megasas_check_reset_gen2(struct megasas_instance *instance,
+               struct megasas_register_set __iomem *regs)
+ {
+       return 0;
  }
  
  static struct megasas_instance_template megasas_instance_template_gen2 = {
        .disable_intr = megasas_disable_intr_gen2,
        .clear_intr = megasas_clear_intr_gen2,
        .read_fw_status_reg = megasas_read_fw_status_reg_gen2,
+       .adp_reset = megasas_adp_reset_gen2,
+       .check_reset = megasas_check_reset_gen2,
  };
  
  /**
  *     This is the end of set of functions & definitions
- *     specific to ppc (deviceid : 0x60) controllers
+ *       specific to gen2 (deviceid : 0x78, 0x79) controllers
  */
  
  /**
@@@ -598,8 -794,7 +793,7 @@@ megasas_issue_blocked_cmd(struct megasa
        instance->instancet->fire_cmd(instance,
                        cmd->frame_phys_addr, 0, instance->reg_set);
  
-       wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
-               MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
+       wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA);
  
        return 0;
  }
@@@ -647,8 -842,8 +841,8 @@@ megasas_issue_blocked_abort_cmd(struct 
        /*
         * Wait for this cmd to complete
         */
-       wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF),
-               MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
+       wait_event(instance->abort_cmd_wait_q, cmd->cmd_status != 0xFF);
+       cmd->sync_cmd = 0;
  
        megasas_return_cmd(instance, cmd);
        return 0;
@@@ -1130,14 -1325,22 +1324,22 @@@ megasas_queue_command(struct scsi_cmnd 
        u32 frame_count;
        struct megasas_cmd *cmd;
        struct megasas_instance *instance;
+       unsigned long flags;
  
        instance = (struct megasas_instance *)
            scmd->device->host->hostdata;
  
-       /* Don't process if we have already declared adapter dead */
-       if (instance->hw_crit_error)
+       if (instance->issuepend_done == 0)
                return SCSI_MLQUEUE_HOST_BUSY;
  
+       spin_lock_irqsave(&instance->hba_lock, flags);
+       if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+               spin_unlock_irqrestore(&instance->hba_lock, flags);
+               return SCSI_MLQUEUE_HOST_BUSY;
+       }
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
        scmd->scsi_done = done;
        scmd->result = 0;
  
@@@ -1273,6 -1476,18 +1475,18 @@@ static int megasas_slave_alloc(struct s
        return 0;
  }
  
+ static void megaraid_sas_kill_hba(struct megasas_instance *instance)
+ {
+       if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+               (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+               writel(MFI_STOP_ADP,
+                       &instance->reg_set->reserved_0[0]);
+       } else {
+               writel(MFI_STOP_ADP,
+                       &instance->reg_set->inbound_doorbell);
+       }
+ }
  /**
   * megasas_complete_cmd_dpc    -      Returns FW's controller structure
   * @instance_addr:                    Address of adapter soft state
@@@ -1290,7 -1505,7 +1504,7 @@@ static void megasas_complete_cmd_dpc(un
        unsigned long flags;
  
        /* If we have already declared adapter dead, donot complete cmds */
-       if (instance->hw_crit_error)
+       if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR )
                return;
  
        spin_lock_irqsave(&instance->completion_lock, flags);
  
        while (consumer != producer) {
                context = instance->reply_queue[consumer];
+               if (context >= instance->max_fw_cmds) {
+                       printk(KERN_ERR "Unexpected context value %x\n",
+                               context);
+                       BUG();
+               }
  
                cmd = instance->cmd_list[context];
  
  static int megasas_wait_for_outstanding(struct megasas_instance *instance)
  {
        int i;
+       u32 reset_index;
        u32 wait_time = MEGASAS_RESET_WAIT_TIME;
+       u8 adprecovery;
+       unsigned long flags;
+       struct list_head clist_local;
+       struct megasas_cmd *reset_cmd;
+       spin_lock_irqsave(&instance->hba_lock, flags);
+       adprecovery = instance->adprecovery;
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
+       if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+               INIT_LIST_HEAD(&clist_local);
+               spin_lock_irqsave(&instance->hba_lock, flags);
+               list_splice_init(&instance->internal_reset_pending_q,
+                               &clist_local);
+               spin_unlock_irqrestore(&instance->hba_lock, flags);
+               printk(KERN_NOTICE "megasas: HBA reset wait ...\n");
+               for (i = 0; i < wait_time; i++) {
+                       msleep(1000);
+                       spin_lock_irqsave(&instance->hba_lock, flags);
+                       adprecovery = instance->adprecovery;
+                       spin_unlock_irqrestore(&instance->hba_lock, flags);
+                       if (adprecovery == MEGASAS_HBA_OPERATIONAL)
+                               break;
+               }
+               if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+                       printk(KERN_NOTICE "megasas: reset: Stopping HBA.\n");
+                       spin_lock_irqsave(&instance->hba_lock, flags);
+                       instance->adprecovery   = MEGASAS_HW_CRITICAL_ERROR;
+                       spin_unlock_irqrestore(&instance->hba_lock, flags);
+                       return FAILED;
+               }
+               reset_index     = 0;
+               while (!list_empty(&clist_local)) {
+                       reset_cmd       = list_entry((&clist_local)->next,
+                                               struct megasas_cmd, list);
+                       list_del_init(&reset_cmd->list);
+                       if (reset_cmd->scmd) {
+                               reset_cmd->scmd->result = DID_RESET << 16;
+                               printk(KERN_NOTICE "%d:%p reset [%02x], %#lx\n",
+                                       reset_index, reset_cmd,
+                                       reset_cmd->scmd->cmnd[0],
+                                       reset_cmd->scmd->serial_number);
+                               reset_cmd->scmd->scsi_done(reset_cmd->scmd);
+                               megasas_return_cmd(instance, reset_cmd);
+                       } else if (reset_cmd->sync_cmd) {
+                               printk(KERN_NOTICE "megasas:%p synch cmds"
+                                               "reset queue\n",
+                                               reset_cmd);
+                               reset_cmd->cmd_status = ENODATA;
+                               instance->instancet->fire_cmd(instance,
+                                               reset_cmd->frame_phys_addr,
+                                               0, instance->reg_set);
+                       } else {
+                               printk(KERN_NOTICE "megasas: %p unexpected"
+                                       "cmds lst\n",
+                                       reset_cmd);
+                       }
+                       reset_index++;
+               }
+               return SUCCESS;
+       }
  
        for (i = 0; i < wait_time; i++) {
  
        }
  
        if (atomic_read(&instance->fw_outstanding)) {
+               printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n");
                /*
                * Send signal to FW to stop processing any pending cmds.
                * The controller will be taken offline by the OS now.
                                &instance->reg_set->inbound_doorbell);
                }
                megasas_dump_pending_frames(instance);
-               instance->hw_crit_error = 1;
+               spin_lock_irqsave(&instance->hba_lock, flags);
+               instance->adprecovery   = MEGASAS_HW_CRITICAL_ERROR;
+               spin_unlock_irqrestore(&instance->hba_lock, flags);
                return FAILED;
        }
  
+       printk(KERN_NOTICE "megaraid_sas: no pending cmds after reset\n");
        return SUCCESS;
  }
  
@@@ -1412,7 -1706,7 +1705,7 @@@ static int megasas_generic_reset(struc
        scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n",
                 scmd->serial_number, scmd->cmnd[0], scmd->retries);
  
-       if (instance->hw_crit_error) {
+       if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
                printk(KERN_ERR "megasas: cannot recover from previous reset "
                       "failures\n");
                return FAILED;
@@@ -1567,7 -1861,8 +1860,8 @@@ megasas_service_aen(struct megasas_inst
        instance->aen_cmd = NULL;
        megasas_return_cmd(instance, cmd);
  
-       if (instance->unload == 0) {
+       if ((instance->unload == 0) &&
+               ((instance->issuepend_done == 1))) {
                struct megasas_aen_event *ev;
                ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
                if (!ev) {
@@@ -1662,6 -1957,9 +1956,9 @@@ megasas_complete_cmd(struct megasas_ins
        struct megasas_header *hdr = &cmd->frame->hdr;
        unsigned long flags;
  
+       /* flag for the retry reset */
+       cmd->retry_for_fw_reset = 0;
        if (cmd->scmd)
                cmd->scmd->SCp.ptr = NULL;
  
        }
  }
  
+ /**
+  * megasas_issue_pending_cmds_again - issue all pending cmds
+  *                                    in FW again because of the fw reset
+  * @instance:                         Adapter soft state
+  */
+ static inline void
+ megasas_issue_pending_cmds_again(struct megasas_instance *instance)
+ {
+       struct megasas_cmd *cmd;
+       struct list_head clist_local;
+       union megasas_evt_class_locale class_locale;
+       unsigned long flags;
+       u32 seq_num;
+       INIT_LIST_HEAD(&clist_local);
+       spin_lock_irqsave(&instance->hba_lock, flags);
+       list_splice_init(&instance->internal_reset_pending_q, &clist_local);
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
+       while (!list_empty(&clist_local)) {
+               cmd     = list_entry((&clist_local)->next,
+                                       struct megasas_cmd, list);
+               list_del_init(&cmd->list);
+               if (cmd->sync_cmd || cmd->scmd) {
+                       printk(KERN_NOTICE "megaraid_sas: command %p, %p:%d"
+                               "detected to be pending while HBA reset.\n",
+                                       cmd, cmd->scmd, cmd->sync_cmd);
+                       cmd->retry_for_fw_reset++;
+                       if (cmd->retry_for_fw_reset == 3) {
+                               printk(KERN_NOTICE "megaraid_sas: cmd %p, %p:%d"
+                                       "was tried multiple times during reset."
+                                       "Shutting down the HBA\n",
+                                       cmd, cmd->scmd, cmd->sync_cmd);
+                               megaraid_sas_kill_hba(instance);
+                               instance->adprecovery =
+                                               MEGASAS_HW_CRITICAL_ERROR;
+                               return;
+                       }
+               }
+               if (cmd->sync_cmd == 1) {
+                       if (cmd->scmd) {
+                               printk(KERN_NOTICE "megaraid_sas: unexpected"
+                                       "cmd attached to internal command!\n");
+                       }
+                       printk(KERN_NOTICE "megasas: %p synchronous cmd"
+                                               "on the internal reset queue,"
+                                               "issue it again.\n", cmd);
+                       cmd->cmd_status = ENODATA;
+                       instance->instancet->fire_cmd(instance,
+                                                       cmd->frame_phys_addr ,
+                                                       0, instance->reg_set);
+               } else if (cmd->scmd) {
+                       printk(KERN_NOTICE "megasas: %p scsi cmd [%02x],%#lx"
+                       "detected on the internal queue, issue again.\n",
+                       cmd, cmd->scmd->cmnd[0], cmd->scmd->serial_number);
+                       atomic_inc(&instance->fw_outstanding);
+                       instance->instancet->fire_cmd(instance,
+                                       cmd->frame_phys_addr,
+                                       cmd->frame_count-1, instance->reg_set);
+               } else {
+                       printk(KERN_NOTICE "megasas: %p unexpected cmd on the"
+                               "internal reset defer list while re-issue!!\n",
+                               cmd);
+               }
+       }
+       if (instance->aen_cmd) {
+               printk(KERN_NOTICE "megaraid_sas: aen_cmd in def process\n");
+               megasas_return_cmd(instance, instance->aen_cmd);
+               instance->aen_cmd       = NULL;
+       }
+       /*
+       * Initiate AEN (Asynchronous Event Notification)
+       */
+       seq_num = instance->last_seq_num;
+       class_locale.members.reserved = 0;
+       class_locale.members.locale = MR_EVT_LOCALE_ALL;
+       class_locale.members.class = MR_EVT_CLASS_DEBUG;
+       megasas_register_aen(instance, seq_num, class_locale.word);
+ }
+ /**
+  * Move the internal reset pending commands to a deferred queue.
+  *
+  * We move the commands pending at internal reset time to a
+  * pending queue. This queue would be flushed after successful
+  * completion of the internal reset sequence. if the internal reset
+  * did not complete in time, the kernel reset handler would flush
+  * these commands.
+  **/
+ static void
+ megasas_internal_reset_defer_cmds(struct megasas_instance *instance)
+ {
+       struct megasas_cmd *cmd;
+       int i;
+       u32 max_cmd = instance->max_fw_cmds;
+       u32 defer_index;
+       unsigned long flags;
+       defer_index     = 0;
+       spin_lock_irqsave(&instance->cmd_pool_lock, flags);
+       for (i = 0; i < max_cmd; i++) {
+               cmd = instance->cmd_list[i];
+               if (cmd->sync_cmd == 1 || cmd->scmd) {
+                       printk(KERN_NOTICE "megasas: moving cmd[%d]:%p:%d:%p"
+                                       "on the defer queue as internal\n",
+                               defer_index, cmd, cmd->sync_cmd, cmd->scmd);
+                       if (!list_empty(&cmd->list)) {
+                               printk(KERN_NOTICE "megaraid_sas: ERROR while"
+                                       " moving this cmd:%p, %d %p, it was"
+                                       "discovered on some list?\n",
+                                       cmd, cmd->sync_cmd, cmd->scmd);
+                               list_del_init(&cmd->list);
+                       }
+                       defer_index++;
+                       list_add_tail(&cmd->list,
+                               &instance->internal_reset_pending_q);
+               }
+       }
+       spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
+ }
+ static void
+ process_fw_state_change_wq(struct work_struct *work)
+ {
+       struct megasas_instance *instance =
+               container_of(work, struct megasas_instance, work_init);
+       u32 wait;
+       unsigned long flags;
+       if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) {
+               printk(KERN_NOTICE "megaraid_sas: error, recovery st %x \n",
+                               instance->adprecovery);
+               return ;
+       }
+       if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+               printk(KERN_NOTICE "megaraid_sas: FW detected to be in fault"
+                                       "state, restarting it...\n");
+               instance->instancet->disable_intr(instance->reg_set);
+               atomic_set(&instance->fw_outstanding, 0);
+               atomic_set(&instance->fw_reset_no_pci_access, 1);
+               instance->instancet->adp_reset(instance, instance->reg_set);
+               atomic_set(&instance->fw_reset_no_pci_access, 0 );
+               printk(KERN_NOTICE "megaraid_sas: FW restarted successfully,"
+                                       "initiating next stage...\n");
+               printk(KERN_NOTICE "megaraid_sas: HBA recovery state machine,"
+                                       "state 2 starting...\n");
+               /*waitting for about 20 second before start the second init*/
+               for (wait = 0; wait < 30; wait++) {
+                       msleep(1000);
+               }
+               if (megasas_transition_to_ready(instance)) {
+                       printk(KERN_NOTICE "megaraid_sas:adapter not ready\n");
+                       megaraid_sas_kill_hba(instance);
+                       instance->adprecovery   = MEGASAS_HW_CRITICAL_ERROR;
+                       return ;
+               }
+               if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
+                       (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
+                       (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)
+                       ) {
+                       *instance->consumer = *instance->producer;
+               } else {
+                       *instance->consumer = 0;
+                       *instance->producer = 0;
+               }
+               megasas_issue_init_mfi(instance);
+               spin_lock_irqsave(&instance->hba_lock, flags);
+               instance->adprecovery   = MEGASAS_HBA_OPERATIONAL;
+               spin_unlock_irqrestore(&instance->hba_lock, flags);
+               instance->instancet->enable_intr(instance->reg_set);
+               megasas_issue_pending_cmds_again(instance);
+               instance->issuepend_done = 1;
+       }
+       return ;
+ }
  /**
   * megasas_deplete_reply_queue -      Processes all completed commands
   * @instance:                         Adapter soft state
   * @alt_status:                               Alternate status to be returned to
   *                                    SCSI mid-layer instead of the status
   *                                    returned by the FW
+  * Note: this must be called with hba lock held
   */
  static int
- megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
+ megasas_deplete_reply_queue(struct megasas_instance *instance,
+                                       u8 alt_status)
  {
-       /*
-        * Check if it is our interrupt
-        * Clear the interrupt 
-        */
-       if(instance->instancet->clear_intr(instance->reg_set))
+       u32 mfiStatus;
+       u32 fw_state;
+       if ((mfiStatus = instance->instancet->check_reset(instance,
+                                       instance->reg_set)) == 1) {
+               return IRQ_HANDLED;
+       }
+       if ((mfiStatus = instance->instancet->clear_intr(
+                                               instance->reg_set)
+                                               ) == 0) {
                return IRQ_NONE;
+       }
+       instance->mfiStatus = mfiStatus;
+       if ((mfiStatus & MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE)) {
+               fw_state = instance->instancet->read_fw_status_reg(
+                               instance->reg_set) & MFI_STATE_MASK;
+               if (fw_state != MFI_STATE_FAULT) {
+                       printk(KERN_NOTICE "megaraid_sas: fw state:%x\n",
+                                               fw_state);
+               }
+               if ((fw_state == MFI_STATE_FAULT) &&
+                               (instance->disableOnlineCtrlReset == 0)) {
+                       printk(KERN_NOTICE "megaraid_sas: wait adp restart\n");
+                       if ((instance->pdev->device ==
+                                       PCI_DEVICE_ID_LSI_SAS1064R) ||
+                               (instance->pdev->device ==
+                                       PCI_DEVICE_ID_DELL_PERC5) ||
+                               (instance->pdev->device ==
+                                       PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
+                               *instance->consumer =
+                                       MEGASAS_ADPRESET_INPROG_SIGN;
+                       }
+                       instance->instancet->disable_intr(instance->reg_set);
+                       instance->adprecovery   = MEGASAS_ADPRESET_SM_INFAULT;
+                       instance->issuepend_done = 0;
+                       atomic_set(&instance->fw_outstanding, 0);
+                       megasas_internal_reset_defer_cmds(instance);
+                       printk(KERN_NOTICE "megasas: fwState=%x, stage:%d\n",
+                                       fw_state, instance->adprecovery);
+                       schedule_work(&instance->work_init);
+                       return IRQ_HANDLED;
+               } else {
+                       printk(KERN_NOTICE "megasas: fwstate:%x, dis_OCR=%x\n",
+                               fw_state, instance->disableOnlineCtrlReset);
+               }
+       }
  
-       if (instance->hw_crit_error)
-               goto out_done;
-         /*
-        * Schedule the tasklet for cmd completion
-        */
        tasklet_schedule(&instance->isr_tasklet);
- out_done:
        return IRQ_HANDLED;
  }
  /**
   * megasas_isr - isr entry point
   */
  static irqreturn_t megasas_isr(int irq, void *devp)
  {
-       return megasas_deplete_reply_queue((struct megasas_instance *)devp,
-                                          DID_OK);
+       struct megasas_instance *instance;
+       unsigned long flags;
+       irqreturn_t     rc;
+       if (atomic_read(
+               &(((struct megasas_instance *)devp)->fw_reset_no_pci_access)))
+               return IRQ_HANDLED;
+       instance = (struct megasas_instance *)devp;
+       spin_lock_irqsave(&instance->hba_lock, flags);
+       rc =  megasas_deplete_reply_queue(instance, DID_OK);
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
+       return rc;
  }
  
  /**
@@@ -1971,7 -2531,7 +2530,7 @@@ megasas_transition_to_ready(struct mega
                               "in %d secs\n", fw_state, max_wait);
                        return -ENODEV;
                }
-       };
+       }
        printk(KERN_INFO "megasas: FW now in Ready state\n");
  
        return 0;
@@@ -2053,6 -2613,7 +2612,7 @@@ static int megasas_create_frame_pool(st
         */
        sgl_sz = sge_sz * instance->max_num_sge;
        frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE;
+       frame_count = 15;
  
        /*
         * We need one extra frame for the MFI command
@@@ -2200,6 -2761,7 +2760,7 @@@ static int megasas_alloc_cmds(struct me
                cmd = instance->cmd_list[i];
                memset(cmd, 0, sizeof(struct megasas_cmd));
                cmd->index = i;
+               cmd->scmd = NULL;
                cmd->instance = instance;
  
                list_add_tail(&cmd->list, &instance->cmd_pool);
@@@ -2367,7 -2929,7 +2928,7 @@@ megasas_get_ld_list(struct megasas_inst
  
        /* the following function will get the instance PD LIST */
  
-       if ((ret == 0) && (ci->ldCount < MAX_LOGICAL_DRIVES)) {
+       if ((ret == 0) && (ci->ldCount <= MAX_LOGICAL_DRIVES)) {
                memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
  
                for (ld_index = 0; ld_index < ci->ldCount; ld_index++) {
@@@ -2681,6 -3243,21 +3242,21 @@@ static int megasas_init_mfi(struct mega
        if (megasas_issue_init_mfi(instance))
                goto fail_fw_init;
  
+       instance->fw_support_ieee = 0;
+       instance->fw_support_ieee =
+               (instance->instancet->read_fw_status_reg(reg_set) &
+               0x04000000);
+       printk(KERN_NOTICE "megasas_init_mfi: fw_support_ieee=%d",
+                       instance->fw_support_ieee);
+       if (instance->fw_support_ieee)
+               instance->flag_ieee = 1;
+       /** for passthrough
+       * the following function will get the PD LIST.
+       */
        memset(instance->pd_list, 0 ,
                (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
        megasas_get_pd_list(instance);
                max_sectors_2 = ctrl_info->max_request_size;
  
                tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2);
+               instance->disableOnlineCtrlReset =
+               ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
        }
  
        instance->max_sectors_per_req = instance->max_num_sge *
@@@ -2928,6 -3507,7 +3506,7 @@@ megasas_register_aen(struct megasas_ins
        dcmd->flags = MFI_FRAME_DIR_READ;
        dcmd->timeout = 0;
        dcmd->pad_0 = 0;
+       instance->last_seq_num = seq_num;
        dcmd->data_xfer_len = sizeof(struct megasas_evt_detail);
        dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
        dcmd->mbox.w[0] = seq_num;
@@@ -3096,6 -3676,7 +3675,7 @@@ megasas_probe_one(struct pci_dev *pdev
  
        instance = (struct megasas_instance *)host->hostdata;
        memset(instance, 0, sizeof(*instance));
+       atomic_set( &instance->fw_reset_no_pci_access, 0 );
  
        instance->producer = pci_alloc_consistent(pdev, sizeof(u32),
                                                  &instance->producer_h);
        megasas_poll_wait_aen = 0;
        instance->flag_ieee = 0;
        instance->ev = NULL;
+       instance->issuepend_done = 1;
+       instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+       megasas_poll_wait_aen = 0;
  
        instance->evt_detail = pci_alloc_consistent(pdev,
                                                    sizeof(struct
         * Initialize locks and queues
         */
        INIT_LIST_HEAD(&instance->cmd_pool);
+       INIT_LIST_HEAD(&instance->internal_reset_pending_q);
  
        atomic_set(&instance->fw_outstanding,0);
  
        init_waitqueue_head(&instance->abort_cmd_wait_q);
  
        spin_lock_init(&instance->cmd_pool_lock);
-       spin_lock_init(&instance->fire_lock);
+       spin_lock_init(&instance->hba_lock);
        spin_lock_init(&instance->completion_lock);
        spin_lock_init(&poll_aen_lock);
  
        instance->flag = 0;
        instance->unload = 1;
        instance->last_time = 0;
+       instance->disableOnlineCtrlReset = 1;
+       INIT_WORK(&instance->work_init, process_fw_state_change_wq);
  
        /*
         * Initialize MFI Firmware
@@@ -3252,6 -3840,9 +3839,9 @@@ static void megasas_flush_cache(struct 
        struct megasas_cmd *cmd;
        struct megasas_dcmd_frame *dcmd;
  
+       if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+               return;
        cmd = megasas_get_cmd(instance);
  
        if (!cmd)
@@@ -3289,6 -3880,9 +3879,9 @@@ static void megasas_shutdown_controller
        struct megasas_cmd *cmd;
        struct megasas_dcmd_frame *dcmd;
  
+       if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+               return;
        cmd = megasas_get_cmd(instance);
  
        if (!cmd)
@@@ -3556,6 -4150,7 +4149,6 @@@ static void megasas_shutdown(struct pci
   */
  static int megasas_mgmt_open(struct inode *inode, struct file *filep)
  {
 -      cycle_kernel_lock();
        /*
         * Allow only those users with admin rights
         */
@@@ -3779,6 -4374,9 +4372,9 @@@ static int megasas_mgmt_ioctl_fw(struc
        struct megasas_iocpacket *ioc;
        struct megasas_instance *instance;
        int error;
+       int i;
+       unsigned long flags;
+       u32 wait_time = MEGASAS_RESET_WAIT_TIME;
  
        ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);
        if (!ioc)
                goto out_kfree_ioc;
        }
  
-       if (instance->hw_crit_error == 1) {
-               printk(KERN_DEBUG "Controller in Crit ERROR\n");
+       if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+               printk(KERN_ERR "Controller in crit error\n");
                error = -ENODEV;
                goto out_kfree_ioc;
        }
                error = -ERESTARTSYS;
                goto out_kfree_ioc;
        }
+       for (i = 0; i < wait_time; i++) {
+               spin_lock_irqsave(&instance->hba_lock, flags);
+               if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+                       spin_unlock_irqrestore(&instance->hba_lock, flags);
+                       break;
+               }
+               spin_unlock_irqrestore(&instance->hba_lock, flags);
+               if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+                       printk(KERN_NOTICE "megasas: waiting"
+                               "for controller reset to finish\n");
+               }
+               msleep(1000);
+       }
+       spin_lock_irqsave(&instance->hba_lock, flags);
+       if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+               spin_unlock_irqrestore(&instance->hba_lock, flags);
+               printk(KERN_ERR "megaraid_sas: timed out while"
+                       "waiting for HBA to recover\n");
+               error = -ENODEV;
+               goto out_kfree_ioc;
+       }
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
        error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc);
        up(&instance->ioctl_sem);
  
@@@ -3826,6 -4453,9 +4451,9 @@@ static int megasas_mgmt_ioctl_aen(struc
        struct megasas_instance *instance;
        struct megasas_aen aen;
        int error;
+       int i;
+       unsigned long flags;
+       u32 wait_time = MEGASAS_RESET_WAIT_TIME;
  
        if (file->private_data != file) {
                printk(KERN_DEBUG "megasas: fasync_helper was not "
        if (!instance)
                return -ENODEV;
  
-       if (instance->hw_crit_error == 1) {
-               error = -ENODEV;
+       if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+               return -ENODEV;
        }
  
        if (instance->unload == 1) {
                return -ENODEV;
        }
  
+       for (i = 0; i < wait_time; i++) {
+               spin_lock_irqsave(&instance->hba_lock, flags);
+               if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+                       spin_unlock_irqrestore(&instance->hba_lock,
+                                               flags);
+                       break;
+               }
+               spin_unlock_irqrestore(&instance->hba_lock, flags);
+               if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+                       printk(KERN_NOTICE "megasas: waiting for"
+                               "controller reset to finish\n");
+               }
+               msleep(1000);
+       }
+       spin_lock_irqsave(&instance->hba_lock, flags);
+       if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+               spin_unlock_irqrestore(&instance->hba_lock, flags);
+               printk(KERN_ERR "megaraid_sas: timed out while waiting"
+                               "for HBA to recover.\n");
+               return -ENODEV;
+       }
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
        mutex_lock(&instance->aen_mutex);
        error = megasas_register_aen(instance, aen.seq_num,
                                     aen.class_locale_word);
@@@ -3955,7 -4613,6 +4611,7 @@@ static const struct file_operations meg
  #ifdef CONFIG_COMPAT
        .compat_ioctl = megasas_mgmt_compat_ioctl,
  #endif
 +      .llseek = noop_llseek,
  };
  
  /*
index 114bc5a81171993ac91c27ba600cee72adb9aed9,029fe6b9d4636d4d017f60573c03f3a0c3261e69..2ff4342ae362ecfae79b03f86ec460a08dc40888
@@@ -1538,22 -1538,22 +1538,22 @@@ qla2x00_dev_loss_tmo_callbk(struct fc_r
        if (!fcport)
                return;
  
-       if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags))
-               return;
-       if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) {
-               qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16);
-               return;
-       }
        /*
         * Transport has effectively 'deleted' the rport, clear
         * all local references.
         */
        spin_lock_irq(host->host_lock);
-       fcport->rport = NULL;
+       fcport->rport = fcport->drport = NULL;
        *((fc_port_t **)rport->dd_data) = NULL;
        spin_unlock_irq(host->host_lock);
+       if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags))
+               return;
+       if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) {
+               qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16);
+               return;
+       }
  }
  
  static void
@@@ -1676,14 -1676,14 +1676,14 @@@ static voi
  qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
  {
        scsi_qla_host_t *vha = shost_priv(shost);
-       u64 node_name;
+       uint8_t node_name[WWN_SIZE] = { 0xFF, 0xFF, 0xFF, 0xFF, \
+               0xFF, 0xFF, 0xFF, 0xFF};
+       u64 fabric_name = wwn_to_u64(node_name);
  
        if (vha->device_flags & SWITCH_FOUND)
-               node_name = wwn_to_u64(vha->fabric_node_name);
-       else
-               node_name = wwn_to_u64(vha->node_name);
+               fabric_name = wwn_to_u64(vha->fabric_node_name);
  
-       fc_host_fabric_name(shost) = node_name;
+       fc_host_fabric_name(shost) = fabric_name;
  }
  
  static void
@@@ -1776,6 -1776,7 +1776,7 @@@ qla24xx_vport_create(struct fc_vport *f
        }
  
        /* initialize attributes */
+       fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count;
        fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name);
        fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name);
        fc_host_supported_classes(vha->host) =
@@@ -1838,33 -1839,26 +1839,33 @@@ qla24xx_vport_delete(struct fc_vport *f
  
        qla24xx_disable_vp(vha);
  
 +      vha->flags.delete_progress = 1;
 +
        fc_remove_host(vha->host);
  
        scsi_remove_host(vha->host);
  
 -      qla2x00_free_fcports(vha);
 +      if (vha->timer_active) {
 +              qla2x00_vp_stop_timer(vha);
 +              DEBUG15(printk(KERN_INFO "scsi(%ld): timer for the vport[%d]"
 +              " = %p has stopped\n", vha->host_no, vha->vp_idx, vha));
 +      }
  
        qla24xx_deallocate_vp_id(vha);
  
 +      /* No pending activities shall be there on the vha now */
 +      DEBUG(msleep(random32()%10));  /* Just to see if something falls on
 +                                      * the net we have placed below */
 +
 +      BUG_ON(atomic_read(&vha->vref_count));
 +
 +      qla2x00_free_fcports(vha);
 +
        mutex_lock(&ha->vport_lock);
        ha->cur_vport_count--;
        clear_bit(vha->vp_idx, ha->vp_idx_map);
        mutex_unlock(&ha->vport_lock);
  
 -      if (vha->timer_active) {
 -              qla2x00_vp_stop_timer(vha);
 -              DEBUG15(printk ("scsi(%ld): timer for the vport[%d] = %p "
 -                  "has stopped\n",
 -                  vha->host_no, vha->vp_idx, vha));
 -        }
 -
        if (vha->req->id && !ha->flags.cpu_affinity_enabled) {
                if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS)
                        qla_printk(KERN_WARNING, ha,
@@@ -1984,6 -1978,7 +1985,7 @@@ qla2x00_init_host_attr(scsi_qla_host_t 
        struct qla_hw_data *ha = vha->hw;
        u32 speed = FC_PORTSPEED_UNKNOWN;
  
+       fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count;
        fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name);
        fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name);
        fc_host_supported_classes(vha->host) = FC_COS_CLASS3;
index d2a4e1530708add3659525948aec20ce13629f91,df7d74f93e5097225d90dd43acfadf2e6ea51823..e1d3ad40a946cc4c206a0755053bfcc67fa60ac2
@@@ -706,6 -706,11 +706,11 @@@ typedef struct 
  #define MBC_SET_PORT_CONFIG           0x122   /* Set port configuration */
  #define MBC_GET_PORT_CONFIG           0x123   /* Get port configuration */
  
+ /*
+  * ISP81xx mailbox commands
+  */
+ #define MBC_WRITE_MPI_REGISTER                0x01    /* Write MPI Register. */
  /* Firmware return data sizes */
  #define FCAL_MAP_SIZE 128
  
@@@ -2641,7 -2646,6 +2646,7 @@@ struct qla_hw_data 
  #define MBX_UPDATE_FLASH_ACTIVE       3
  
        struct mutex vport_lock;        /* Virtual port synchronization */
 +      spinlock_t vport_slock; /* order is hardware_lock, then vport_slock */
        struct completion mbx_cmd_comp; /* Serialize mbx access */
        struct completion mbx_intr_comp;  /* Used for completion notification */
        struct completion dcbx_comp;    /* For set port config notification */
@@@ -2829,7 -2833,6 +2834,7 @@@ typedef struct scsi_qla_host 
                uint32_t        management_server_logged_in :1;
                uint32_t        process_response_queue  :1;
                uint32_t        difdix_supported:1;
 +              uint32_t        delete_progress:1;
        } flags;
  
        atomic_t        loop_state;
  #define NPIV_CONFIG_NEEDED    16
  #define ISP_UNRECOVERABLE     17
  #define FCOE_CTX_RESET_NEEDED 18      /* Initiate FCoE context reset */
+ #define MPI_RESET_NEEDED      19      /* Initiate MPI FW reset */
  
        uint32_t        device_flags;
  #define SWITCH_FOUND          BIT_0
        struct req_que *req;
        int             fw_heartbeat_counter;
        int             seconds_since_last_heartbeat;
 +
 +      atomic_t        vref_count;
  } scsi_qla_host_t;
  
  /*
         test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \
         atomic_read(&ha->loop_state) == LOOP_DOWN)
  
 +#define QLA_VHA_MARK_BUSY(__vha, __bail) do {              \
 +      atomic_inc(&__vha->vref_count);                      \
 +      mb();                                                \
 +      if (__vha->flags.delete_progress) {                  \
 +              atomic_dec(&__vha->vref_count);              \
 +              __bail = 1;                                  \
 +      } else {                                             \
 +              __bail = 0;                                  \
 +      }                                                    \
 +} while (0)
 +
 +#define QLA_VHA_MARK_NOT_BUSY(__vha) do {                  \
 +      atomic_dec(&__vha->vref_count);                      \
 +} while (0)
 +
 +
  #define qla_printk(level, ha, format, arg...) \
        dev_printk(level , &((ha)->pdev->dev) , format , ## arg)
  
  
  #define CMD_SP(Cmnd)          ((Cmnd)->SCp.ptr)
  
+ #define QLA_SG_ALL    1024
  enum nexus_wait_type {
        WAIT_HOST = 0,
        WAIT_TARGET,
index 9c383baebe279d0c27bb3027dc1bd337ab52603e,c2d7bb8cd53fa8da93b804ed550445f71376c800..3cafbef40737e55f99d815060f9d22566efe080c
@@@ -69,29 -69,21 +69,29 @@@ qla2x00_ctx_sp_free(srb_t *sp
  {
        struct srb_ctx *ctx = sp->ctx;
        struct srb_iocb *iocb = ctx->u.iocb_cmd;
 +      struct scsi_qla_host *vha = sp->fcport->vha;
  
        del_timer_sync(&iocb->timer);
        kfree(iocb);
        kfree(ctx);
        mempool_free(sp, sp->fcport->vha->hw->srb_mempool);
 +
 +      QLA_VHA_MARK_NOT_BUSY(vha);
  }
  
  inline srb_t *
  qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size,
      unsigned long tmo)
  {
 -      srb_t *sp;
 +      srb_t *sp = NULL;
        struct qla_hw_data *ha = vha->hw;
        struct srb_ctx *ctx;
        struct srb_iocb *iocb;
 +      uint8_t bail;
 +
 +      QLA_VHA_MARK_BUSY(vha, bail);
 +      if (bail)
 +              return NULL;
  
        sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
        if (!sp)
        iocb->timer.function = qla2x00_ctx_sp_timeout;
        add_timer(&iocb->timer);
  done:
 +      if (!sp)
 +              QLA_VHA_MARK_NOT_BUSY(vha);
        return sp;
  }
  
@@@ -953,6 -943,19 +953,19 @@@ qla2x00_reset_chip(scsi_qla_host_t *vha
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
  }
  
+ /**
+  * qla81xx_reset_mpi() - Reset's MPI FW via Write MPI Register MBC.
+  *
+  * Returns 0 on success.
+  */
+ int
+ qla81xx_reset_mpi(scsi_qla_host_t *vha)
+ {
+       uint16_t mb[4] = {0x1010, 0, 1, 0};
+       return qla81xx_write_mpi_register(vha, mb);
+ }
  /**
   * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC.
   * @ha: HA context
@@@ -967,6 -970,7 +980,7 @@@ qla24xx_reset_risc(scsi_qla_host_t *vha
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
        uint32_t cnt, d2;
        uint16_t wd;
+       static int abts_cnt; /* ISP abort retry counts */
  
        spin_lock_irqsave(&ha->hardware_lock, flags);
  
                barrier();
        }
  
+       /* If required, do an MPI FW reset now */
+       if (test_and_clear_bit(MPI_RESET_NEEDED, &vha->dpc_flags)) {
+               if (qla81xx_reset_mpi(vha) != QLA_SUCCESS) {
+                       if (++abts_cnt < 5) {
+                               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+                               set_bit(MPI_RESET_NEEDED, &vha->dpc_flags);
+                       } else {
+                               /*
+                                * We exhausted the ISP abort retries. We have to
+                                * set the board offline.
+                                */
+                               abts_cnt = 0;
+                               vha->flags.online = 0;
+                       }
+               }
+       }
        WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
        RD_REG_DWORD(&reg->hccr);
  
@@@ -1787,15 -1808,11 +1818,15 @@@ qla2x00_init_rings(scsi_qla_host_t *vha
                qla2x00_init_response_q_entries(rsp);
        }
  
 +      spin_lock_irqsave(&ha->vport_slock, flags);
        /* Clear RSCN queue. */
        list_for_each_entry(vp, &ha->vp_list, list) {
                vp->rscn_in_ptr = 0;
                vp->rscn_out_ptr = 0;
        }
 +
 +      spin_unlock_irqrestore(&ha->vport_slock, flags);
 +
        ha->isp_ops->config_rings(vha);
  
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@@ -2799,6 -2816,9 +2830,9 @@@ qla2x00_iidma_fcport(scsi_qla_host_t *v
        if (!IS_IIDMA_CAPABLE(ha))
                return;
  
+       if (atomic_read(&fcport->state) != FCS_ONLINE)
+               return;
        if (fcport->fp_speed == PORT_SPEED_UNKNOWN ||
            fcport->fp_speed > ha->link_data_rate)
                return;
@@@ -3232,17 -3252,12 +3266,17 @@@ qla2x00_find_all_fabric_devs(scsi_qla_h
                /* Bypass virtual ports of the same host. */
                found = 0;
                if (ha->num_vhosts) {
 +                      unsigned long flags;
 +
 +                      spin_lock_irqsave(&ha->vport_slock, flags);
                        list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
                                if (new_fcport->d_id.b24 == vp->d_id.b24) {
                                        found = 1;
                                        break;
                                }
                        }
 +                      spin_unlock_irqrestore(&ha->vport_slock, flags);
 +
                        if (found)
                                continue;
                }
@@@ -3362,7 -3377,6 +3396,7 @@@ qla2x00_find_new_loop_id(scsi_qla_host_
        struct qla_hw_data *ha = vha->hw;
        struct scsi_qla_host *vp;
        struct scsi_qla_host *tvp;
 +      unsigned long flags = 0;
  
        rval = QLA_SUCCESS;
  
                /* Check for loop ID being already in use. */
                found = 0;
                fcport = NULL;
 +
 +              spin_lock_irqsave(&ha->vport_slock, flags);
                list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
                        list_for_each_entry(fcport, &vp->vp_fcports, list) {
                                if (fcport->loop_id == dev->loop_id &&
                        if (found)
                                break;
                }
 +              spin_unlock_irqrestore(&ha->vport_slock, flags);
  
                /* If not in use then it is free to use. */
                if (!found) {
  qla2x00_update_fcports(scsi_qla_host_t *base_vha)
  {
        fc_port_t *fcport;
 -      struct scsi_qla_host *tvp, *vha;
 +      struct scsi_qla_host *vha;
 +      struct qla_hw_data *ha = base_vha->hw;
 +      unsigned long flags;
  
 +      spin_lock_irqsave(&ha->vport_slock, flags);
        /* Go with deferred removal of rport references. */
 -      list_for_each_entry_safe(vha, tvp, &base_vha->hw->vp_list, list)
 -              list_for_each_entry(fcport, &vha->vp_fcports, list)
 +      list_for_each_entry(vha, &base_vha->hw->vp_list, list) {
 +              atomic_inc(&vha->vref_count);
 +              list_for_each_entry(fcport, &vha->vp_fcports, list) {
                        if (fcport && fcport->drport &&
 -                          atomic_read(&fcport->state) != FCS_UNCONFIGURED)
 +                          atomic_read(&fcport->state) != FCS_UNCONFIGURED) {
 +                              spin_unlock_irqrestore(&ha->vport_slock, flags);
 +
                                qla2x00_rport_del(fcport);
 +
 +                              spin_lock_irqsave(&ha->vport_slock, flags);
 +                      }
 +              }
 +              atomic_dec(&vha->vref_count);
 +      }
 +      spin_unlock_irqrestore(&ha->vport_slock, flags);
  }
  
  void
@@@ -3842,7 -3840,7 +3876,7 @@@ qla2x00_abort_isp_cleanup(scsi_qla_host
  {
        struct qla_hw_data *ha = vha->hw;
        struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev);
 -      struct scsi_qla_host *tvp;
 +      unsigned long flags;
  
        vha->flags.online = 0;
        ha->flags.chip_reset_done = 0;
        if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
                atomic_set(&vha->loop_state, LOOP_DOWN);
                qla2x00_mark_all_devices_lost(vha, 0);
 -              list_for_each_entry_safe(vp, tvp, &base_vha->hw->vp_list, list)
 +
 +              spin_lock_irqsave(&ha->vport_slock, flags);
 +              list_for_each_entry(vp, &base_vha->hw->vp_list, list) {
 +                      atomic_inc(&vp->vref_count);
 +                      spin_unlock_irqrestore(&ha->vport_slock, flags);
 +
                        qla2x00_mark_all_devices_lost(vp, 0);
 +
 +                      spin_lock_irqsave(&ha->vport_slock, flags);
 +                      atomic_dec(&vp->vref_count);
 +              }
 +              spin_unlock_irqrestore(&ha->vport_slock, flags);
        } else {
                if (!atomic_read(&vha->loop_down_timer))
                        atomic_set(&vha->loop_down_timer,
                            LOOP_DOWN_TIME);
        }
  
-       /* Make sure for ISP 82XX IO DMA is complete */
-       if (IS_QLA82XX(ha)) {
-               if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
-                       WAIT_HOST) == QLA_SUCCESS) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                       "Done wait for pending commands\n"));
+       if (!ha->flags.eeh_busy) {
+               /* Make sure for ISP 82XX IO DMA is complete */
+               if (IS_QLA82XX(ha)) {
+                       if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
+                               WAIT_HOST) == QLA_SUCCESS) {
+                               DEBUG2(qla_printk(KERN_INFO, ha,
+                               "Done wait for pending commands\n"));
+                       }
                }
-       }
  
-       /* Requeue all commands in outstanding command list. */
-       qla2x00_abort_all_cmds(vha, DID_RESET << 16);
+               /* Requeue all commands in outstanding command list. */
+               qla2x00_abort_all_cmds(vha, DID_RESET << 16);
+       }
  }
  
  /*
@@@ -3908,8 -3898,8 +3944,8 @@@ qla2x00_abort_isp(scsi_qla_host_t *vha
        uint8_t        status = 0;
        struct qla_hw_data *ha = vha->hw;
        struct scsi_qla_host *vp;
 -      struct scsi_qla_host *tvp;
        struct req_que *req = ha->req_q_map[0];
 +      unsigned long flags;
  
        if (vha->flags.online) {
                qla2x00_abort_isp_cleanup(vha);
                DEBUG(printk(KERN_INFO
                                "qla2x00_abort_isp(%ld): succeeded.\n",
                                vha->host_no));
 -              list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
 -                      if (vp->vp_idx)
 +
 +              spin_lock_irqsave(&ha->vport_slock, flags);
 +              list_for_each_entry(vp, &ha->vp_list, list) {
 +                      if (vp->vp_idx) {
 +                              atomic_inc(&vp->vref_count);
 +                              spin_unlock_irqrestore(&ha->vport_slock, flags);
 +
                                qla2x00_vp_abort_isp(vp);
 +
 +                              spin_lock_irqsave(&ha->vport_slock, flags);
 +                              atomic_dec(&vp->vref_count);
 +                      }
                }
 +              spin_unlock_irqrestore(&ha->vport_slock, flags);
 +
        } else {
                qla_printk(KERN_INFO, ha,
                        "qla2x00_abort_isp: **** FAILED ****\n");
@@@ -5242,7 -5221,7 +5278,7 @@@ qla82xx_restart_isp(scsi_qla_host_t *vh
        struct req_que *req = ha->req_q_map[0];
        struct rsp_que *rsp = ha->rsp_q_map[0];
        struct scsi_qla_host *vp;
 -      struct scsi_qla_host *tvp;
 +      unsigned long flags;
  
        status = qla2x00_init_rings(vha);
        if (!status) {
                DEBUG(printk(KERN_INFO
                        "qla82xx_restart_isp(%ld): succeeded.\n",
                        vha->host_no));
 -              list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
 -                      if (vp->vp_idx)
 +
 +              spin_lock_irqsave(&ha->vport_slock, flags);
 +              list_for_each_entry(vp, &ha->vp_list, list) {
 +                      if (vp->vp_idx) {
 +                              atomic_inc(&vp->vref_count);
 +                              spin_unlock_irqrestore(&ha->vport_slock, flags);
 +
                                qla2x00_vp_abort_isp(vp);
 +
 +                              spin_lock_irqsave(&ha->vport_slock, flags);
 +                              atomic_dec(&vp->vref_count);
 +                      }
                }
 +              spin_unlock_irqrestore(&ha->vport_slock, flags);
 +
        } else {
                qla_printk(KERN_INFO, ha,
                        "qla82xx_restart_isp: **** FAILED ****\n");
index 28f65be19dad9878f19981a18ebc60ef13bed356,bb4d63a792aa8fb5fc5bc3088256cf54115f93f7..e0e43d9e7ed130346d27f86c7f60b933c2fea6cf
@@@ -412,8 -412,14 +412,14 @@@ skip_rio
                                    "Unrecoverable Hardware Error: adapter "
                                    "marked OFFLINE!\n");
                                vha->flags.online = 0;
-                       } else
+                       } else {
+                               /* Check to see if MPI timeout occured */
+                               if ((mbx & MBX_3) && (ha->flags.port0))
+                                       set_bit(MPI_RESET_NEEDED,
+                                           &vha->dpc_flags);
                                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+                       }
                } else if (mb[1] == 0) {
                        qla_printk(KERN_INFO, ha,
                            "Unrecoverable Hardware Error: adapter marked "
@@@ -1706,20 -1712,19 +1712,20 @@@ qla2x00_status_entry(scsi_qla_host_t *v
                                cp->result = DID_ERROR << 16;
                                break;
                        }
 -              } else if (!lscsi_status) {
 +              } else {
                        DEBUG2(qla_printk(KERN_INFO, ha,
                            "scsi(%ld:%d:%d) Dropped frame(s) detected (0x%x "
                            "of 0x%x bytes).\n", vha->host_no, cp->device->id,
                            cp->device->lun, resid, scsi_bufflen(cp)));
  
 -                      cp->result = DID_ERROR << 16;
 -                      break;
 +                      cp->result = DID_ERROR << 16 | lscsi_status;
 +                      goto check_scsi_status;
                }
  
                cp->result = DID_OK << 16 | lscsi_status;
                logit = 0;
  
 +check_scsi_status:
                /*
                 * Check to see if SCSI Status is non zero. If so report SCSI
                 * Status.
index a595ec8264f8d7f73823a11d0616591a7957bd63,52024080c3939b4f8c16092f305c571a0c5a3d10..effd8a1403d9dceddaf4260d8c4822bafdf5ddd4
@@@ -2913,7 -2913,7 +2913,7 @@@ qla24xx_report_id_acquisition(scsi_qla_
        uint16_t stat = le16_to_cpu(rptid_entry->vp_idx);
        struct qla_hw_data *ha = vha->hw;
        scsi_qla_host_t *vp;
 -      scsi_qla_host_t *tvp;
 +      unsigned long   flags;
  
        if (rptid_entry->entry_status != 0)
                return;
                        return;
                }
  
 -              list_for_each_entry_safe(vp, tvp, &ha->vp_list, list)
 +              spin_lock_irqsave(&ha->vport_slock, flags);
 +              list_for_each_entry(vp, &ha->vp_list, list)
                        if (vp_idx == vp->vp_idx)
                                break;
 +              spin_unlock_irqrestore(&ha->vport_slock, flags);
 +
                if (!vp)
                        return;
  
@@@ -3828,8 -3825,6 +3828,6 @@@ qla2x00_loopback_test(scsi_qla_host_t *
  
        /* Copy mailbox information */
        memcpy( mresp, mcp->mb, 64);
-       mresp[3] = mcp->mb[18];
-       mresp[4] = mcp->mb[19];
        return rval;
  }
  
@@@ -3890,9 -3885,10 +3888,10 @@@ qla2x00_echo_test(scsi_qla_host_t *vha
        }
  
        /* Copy mailbox information */
-       memcpy( mresp, mcp->mb, 32);
+       memcpy(mresp, mcp->mb, 64);
        return rval;
  }
  int
  qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic)
  {
@@@ -3952,6 -3948,67 +3951,67 @@@ qla2x00_write_ram_word(scsi_qla_host_t 
        return rval;
  }
  
+ int
+ qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb)
+ {
+       int rval;
+       uint32_t stat, timer;
+       uint16_t mb0 = 0;
+       struct qla_hw_data *ha = vha->hw;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+       rval = QLA_SUCCESS;
+       DEBUG11(qla_printk(KERN_INFO, ha,
+           "%s(%ld): entered.\n", __func__, vha->host_no));
+       clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+       /* Write the MBC data to the registers */
+       WRT_REG_WORD(&reg->mailbox0, MBC_WRITE_MPI_REGISTER);
+       WRT_REG_WORD(&reg->mailbox1, mb[0]);
+       WRT_REG_WORD(&reg->mailbox2, mb[1]);
+       WRT_REG_WORD(&reg->mailbox3, mb[2]);
+       WRT_REG_WORD(&reg->mailbox4, mb[3]);
+       WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
+       /* Poll for MBC interrupt */
+       for (timer = 6000000; timer; timer--) {
+               /* Check for pending interrupts. */
+               stat = RD_REG_DWORD(&reg->host_status);
+               if (stat & HSRX_RISC_INT) {
+                       stat &= 0xff;
+                       if (stat == 0x1 || stat == 0x2 ||
+                           stat == 0x10 || stat == 0x11) {
+                               set_bit(MBX_INTERRUPT,
+                                   &ha->mbx_cmd_flags);
+                               mb0 = RD_REG_WORD(&reg->mailbox0);
+                               WRT_REG_DWORD(&reg->hccr,
+                                   HCCRX_CLR_RISC_INT);
+                               RD_REG_DWORD(&reg->hccr);
+                               break;
+                       }
+               }
+               udelay(5);
+       }
+       if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags))
+               rval = mb0 & MBS_MASK;
+       else
+               rval = QLA_FUNCTION_FAILED;
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(printk(KERN_INFO "%s(%ld): failed=%x mb[0]=%x.\n",
+                   __func__, vha->host_no, rval, mb[0]));
+       } else {
+               DEBUG11(printk(KERN_INFO
+                   "%s(%ld): done.\n", __func__, vha->host_no));
+       }
+       return rval;
+ }
  int
  qla2x00_get_data_rate(scsi_qla_host_t *vha)
  {
index 0a71cc71eab23922e9c6aee451962f60a1e3cfb3,8d8e40b829e4df89db23047c8508a938d1cd8274..8d9edfb39803ff26809743ef8cf5e0b22abd305b
@@@ -403,6 -403,54 +403,54 @@@ qla82xx_pci_set_crbwindow(struct qla_hw
        return off;
  }
  
+ static int
+ qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong *off)
+ {
+       struct crb_128M_2M_sub_block_map *m;
+       if (*off >= QLA82XX_CRB_MAX)
+               return -1;
+       if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) {
+               *off = (*off - QLA82XX_PCI_CAMQM) +
+                   QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase;
+               return 0;
+       }
+       if (*off < QLA82XX_PCI_CRBSPACE)
+               return -1;
+       *off -= QLA82XX_PCI_CRBSPACE;
+       /* Try direct map */
+       m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)];
+       if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) {
+               *off = *off + m->start_2M - m->start_128M + ha->nx_pcibase;
+               return 0;
+       }
+       /* Not in direct map, use crb window */
+       return 1;
+ }
+ #define CRB_WIN_LOCK_TIMEOUT 100000000
+ static int qla82xx_crb_win_lock(struct qla_hw_data *ha)
+ {
+       int done = 0, timeout = 0;
+       while (!done) {
+               /* acquire semaphore3 from PCI HW block */
+               done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK));
+               if (done == 1)
+                       break;
+               if (timeout >= CRB_WIN_LOCK_TIMEOUT)
+                       return -1;
+               timeout++;
+       }
+       qla82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->portnum);
+       return 0;
+ }
  int
  qla82xx_wr_32(struct qla_hw_data *ha, ulong off, u32 data)
  {
@@@ -453,24 -501,6 +501,6 @@@ qla82xx_rd_32(struct qla_hw_data *ha, u
        return data;
  }
  
- #define CRB_WIN_LOCK_TIMEOUT 100000000
- int qla82xx_crb_win_lock(struct qla_hw_data *ha)
- {
-       int done = 0, timeout = 0;
-       while (!done) {
-               /* acquire semaphore3 from PCI HW block */
-               done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK));
-               if (done == 1)
-                       break;
-               if (timeout >= CRB_WIN_LOCK_TIMEOUT)
-                       return -1;
-               timeout++;
-       }
-       qla82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->portnum);
-       return 0;
- }
  #define IDC_LOCK_TIMEOUT 100000000
  int qla82xx_idc_lock(struct qla_hw_data *ha)
  {
@@@ -504,36 -534,6 +534,6 @@@ void qla82xx_idc_unlock(struct qla_hw_d
        qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK));
  }
  
- int
- qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong *off)
- {
-       struct crb_128M_2M_sub_block_map *m;
-       if (*off >= QLA82XX_CRB_MAX)
-               return -1;
-       if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) {
-               *off = (*off - QLA82XX_PCI_CAMQM) +
-                   QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase;
-               return 0;
-       }
-       if (*off < QLA82XX_PCI_CRBSPACE)
-               return -1;
-       *off -= QLA82XX_PCI_CRBSPACE;
-       /* Try direct map */
-       m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)];
-       if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) {
-               *off = *off + m->start_2M - m->start_128M + ha->nx_pcibase;
-               return 0;
-       }
-       /* Not in direct map, use crb window */
-       return 1;
- }
  /*  PCI Windowing for DDR regions.  */
  #define QLA82XX_ADDR_IN_RANGE(addr, low, high) \
        (((addr) <= (high)) && ((addr) >= (low)))
@@@ -557,7 -557,7 +557,7 @@@ qla82xx_pci_mem_bound_check(struct qla_
  
  int qla82xx_pci_set_window_warning_count;
  
- unsigned long
static unsigned long
  qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
  {
        int window;
@@@ -798,7 -798,8 +798,8 @@@ qla82xx_pci_mem_write_direct(struct qla
  }
  
  #define MTU_FUDGE_FACTOR 100
- unsigned long qla82xx_decode_crb_addr(unsigned long addr)
+ static unsigned long
+ qla82xx_decode_crb_addr(unsigned long addr)
  {
        int i;
        unsigned long base_addr, offset, pci_base;
  static long rom_max_timeout = 100;
  static long qla82xx_rom_lock_timeout = 100;
  
- int
static int
  qla82xx_rom_lock(struct qla_hw_data *ha)
  {
        int done = 0, timeout = 0;
        return 0;
  }
  
- int
static int
  qla82xx_wait_rom_busy(struct qla_hw_data *ha)
  {
        long timeout = 0;
        return 0;
  }
  
- int
static int
  qla82xx_wait_rom_done(struct qla_hw_data *ha)
  {
        long timeout = 0;
        return 0;
  }
  
- int
static int
  qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
  {
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr);
        return 0;
  }
  
- int
static int
  qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
  {
        int ret, loops = 0;
        return ret;
  }
  
- int
static int
  qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val)
  {
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR);
        return 0;
  }
  
- int
static int
  qla82xx_flash_wait_write_finish(struct qla_hw_data *ha)
  {
        long timeout = 0;
        return ret;
  }
  
- int
static int
  qla82xx_flash_set_write_enable(struct qla_hw_data *ha)
  {
        uint32_t val;
        return 0;
  }
  
- int
static int
  qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val)
  {
        if (qla82xx_flash_set_write_enable(ha))
        return qla82xx_flash_wait_write_finish(ha);
  }
  
- int
static int
  qla82xx_write_disable_flash(struct qla_hw_data *ha)
  {
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI);
        return 0;
  }
  
- int
static int
  ql82xx_rom_lock_d(struct qla_hw_data *ha)
  {
        int loops = 0;
        return 0;;
  }
  
- int
static int
  qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr,
        uint32_t data)
  {
@@@ -1061,7 -1062,8 +1062,8 @@@ done_write
  /* This routine does CRB initialize sequence
   *  to put the ISP into operational state
   */
- int qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
+ static int
+ qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
  {
        int addr, val;
        int i ;
        return 0;
  }
  
- int qla82xx_check_for_bad_spd(struct qla_hw_data *ha)
+ static int
+ qla82xx_check_for_bad_spd(struct qla_hw_data *ha)
  {
        u32 val = 0;
        val = qla82xx_rd_32(ha, BOOT_LOADER_DIMM_STATUS);
        return 0;
  }
  
- int
+ static int
+ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
+               u64 off, void *data, int size)
+ {
+       int i, j, ret = 0, loop, sz[2], off0;
+       int scale, shift_amount, startword;
+       uint32_t temp;
+       uint64_t off8, mem_crb, tmpw, word[2] = {0, 0};
+       /*
+        * If not MN, go check for MS or invalid.
+        */
+       if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
+               mem_crb = QLA82XX_CRB_QDR_NET;
+       else {
+               mem_crb = QLA82XX_CRB_DDR_NET;
+               if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
+                       return qla82xx_pci_mem_write_direct(ha,
+                           off, data, size);
+       }
+       off0 = off & 0x7;
+       sz[0] = (size < (8 - off0)) ? size : (8 - off0);
+       sz[1] = size - sz[0];
+       off8 = off & 0xfffffff0;
+       loop = (((off & 0xf) + size - 1) >> 4) + 1;
+       shift_amount = 4;
+       scale = 2;
+       startword = (off & 0xf)/8;
+       for (i = 0; i < loop; i++) {
+               if (qla82xx_pci_mem_read_2M(ha, off8 +
+                   (i << shift_amount), &word[i * scale], 8))
+                       return -1;
+       }
+       switch (size) {
+       case 1:
+               tmpw = *((uint8_t *)data);
+               break;
+       case 2:
+               tmpw = *((uint16_t *)data);
+               break;
+       case 4:
+               tmpw = *((uint32_t *)data);
+               break;
+       case 8:
+       default:
+               tmpw = *((uint64_t *)data);
+               break;
+       }
+       if (sz[0] == 8) {
+               word[startword] = tmpw;
+       } else {
+               word[startword] &=
+                       ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
+               word[startword] |= tmpw << (off0 * 8);
+       }
+       if (sz[1] != 0) {
+               word[startword+1] &= ~(~0ULL << (sz[1] * 8));
+               word[startword+1] |= tmpw >> (sz[0] * 8);
+       }
+       /*
+        * don't lock here - write_wx gets the lock if each time
+        * write_lock_irqsave(&adapter->adapter_lock, flags);
+        * netxen_nic_pci_change_crbwindow_128M(adapter, 0);
+        */
+       for (i = 0; i < loop; i++) {
+               temp = off8 + (i << shift_amount);
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
+               temp = 0;
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp);
+               temp = word[i * scale] & 0xffffffff;
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
+               temp = (word[i * scale] >> 32) & 0xffffffff;
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
+               temp = word[i*scale + 1] & 0xffffffff;
+               qla82xx_wr_32(ha, mem_crb +
+                   MIU_TEST_AGT_WRDATA_UPPER_LO, temp);
+               temp = (word[i*scale + 1] >> 32) & 0xffffffff;
+               qla82xx_wr_32(ha, mem_crb +
+                   MIU_TEST_AGT_WRDATA_UPPER_HI, temp);
+               temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+               temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+               for (j = 0; j < MAX_CTL_CHECK; j++) {
+                       temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
+                       if ((temp & MIU_TA_CTL_BUSY) == 0)
+                               break;
+               }
+               if (j >= MAX_CTL_CHECK) {
+                       if (printk_ratelimit())
+                               dev_err(&ha->pdev->dev,
+                                   "failed to write through agent\n");
+                       ret = -1;
+                       break;
+               }
+       }
+       return ret;
+ }
+ static int
  qla82xx_fw_load_from_flash(struct qla_hw_data *ha)
  {
        int  i;
@@@ -1357,114 -1469,6 +1469,6 @@@ qla82xx_pci_mem_read_2M(struct qla_hw_d
        return 0;
  }
  
- int
- qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
-               u64 off, void *data, int size)
- {
-       int i, j, ret = 0, loop, sz[2], off0;
-       int scale, shift_amount, startword;
-       uint32_t temp;
-       uint64_t off8, mem_crb, tmpw, word[2] = {0, 0};
-       /*
-        * If not MN, go check for MS or invalid.
-        */
-       if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
-               mem_crb = QLA82XX_CRB_QDR_NET;
-       else {
-               mem_crb = QLA82XX_CRB_DDR_NET;
-               if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
-                       return qla82xx_pci_mem_write_direct(ha,
-                           off, data, size);
-       }
-       off0 = off & 0x7;
-       sz[0] = (size < (8 - off0)) ? size : (8 - off0);
-       sz[1] = size - sz[0];
-       off8 = off & 0xfffffff0;
-       loop = (((off & 0xf) + size - 1) >> 4) + 1;
-       shift_amount = 4;
-       scale = 2;
-       startword = (off & 0xf)/8;
-       for (i = 0; i < loop; i++) {
-               if (qla82xx_pci_mem_read_2M(ha, off8 +
-                   (i << shift_amount), &word[i * scale], 8))
-                       return -1;
-       }
-       switch (size) {
-       case 1:
-               tmpw = *((uint8_t *)data);
-               break;
-       case 2:
-               tmpw = *((uint16_t *)data);
-               break;
-       case 4:
-               tmpw = *((uint32_t *)data);
-               break;
-       case 8:
-       default:
-               tmpw = *((uint64_t *)data);
-               break;
-       }
-       if (sz[0] == 8) {
-               word[startword] = tmpw;
-       } else {
-               word[startword] &=
-                       ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
-               word[startword] |= tmpw << (off0 * 8);
-       }
-       if (sz[1] != 0) {
-               word[startword+1] &= ~(~0ULL << (sz[1] * 8));
-               word[startword+1] |= tmpw >> (sz[0] * 8);
-       }
-       /*
-        * don't lock here - write_wx gets the lock if each time
-        * write_lock_irqsave(&adapter->adapter_lock, flags);
-        * netxen_nic_pci_change_crbwindow_128M(adapter, 0);
-        */
-       for (i = 0; i < loop; i++) {
-               temp = off8 + (i << shift_amount);
-               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
-               temp = 0;
-               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp);
-               temp = word[i * scale] & 0xffffffff;
-               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
-               temp = (word[i * scale] >> 32) & 0xffffffff;
-               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
-               temp = word[i*scale + 1] & 0xffffffff;
-               qla82xx_wr_32(ha, mem_crb +
-                   MIU_TEST_AGT_WRDATA_UPPER_LO, temp);
-               temp = (word[i*scale + 1] >> 32) & 0xffffffff;
-               qla82xx_wr_32(ha, mem_crb +
-                   MIU_TEST_AGT_WRDATA_UPPER_HI, temp);
-               temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
-               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
-               temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
-               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
-               for (j = 0; j < MAX_CTL_CHECK; j++) {
-                       temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
-                       if ((temp & MIU_TA_CTL_BUSY) == 0)
-                               break;
-               }
-               if (j >= MAX_CTL_CHECK) {
-                       if (printk_ratelimit())
-                               dev_err(&ha->pdev->dev,
-                                   "failed to write through agent\n");
-                       ret = -1;
-                       break;
-               }
-       }
-       return ret;
- }
  
  static struct qla82xx_uri_table_desc *
  qla82xx_get_table_desc(const u8 *unirom, int section)
@@@ -1725,7 -1729,8 +1729,8 @@@ void qla82xx_reset_adapter(struct scsi_
        ha->isp_ops->disable_intrs(ha);
  }
  
- int qla82xx_fw_load_from_blob(struct qla_hw_data *ha)
+ static int
+ qla82xx_fw_load_from_blob(struct qla_hw_data *ha)
  {
        u64 *ptr64;
        u32 i, flashaddr, size;
@@@ -1836,7 -1841,8 +1841,8 @@@ qla82xx_validate_firmware_blob(scsi_qla
        return 0;
  }
  
- int qla82xx_check_cmdpeg_state(struct qla_hw_data *ha)
+ static int
+ qla82xx_check_cmdpeg_state(struct qla_hw_data *ha)
  {
        u32 val = 0;
        int retries = 60;
        return QLA_FUNCTION_FAILED;
  }
  
- int qla82xx_check_rcvpeg_state(struct qla_hw_data *ha)
+ static int
+ qla82xx_check_rcvpeg_state(struct qla_hw_data *ha)
  {
        u32 val = 0;
        int retries = 60;
@@@ -1933,7 -1940,7 +1940,7 @@@ static struct qla82xx_legacy_intr_set l
   * @ha: SCSI driver HA context
   * @mb0: Mailbox0 register
   */
- void
static void
  qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
  {
        uint16_t        cnt;
@@@ -2257,7 -2264,7 +2264,7 @@@ void qla82xx_init_flags(struct qla_hw_d
        ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
  }
  
static inline void
+ inline void
  qla82xx_set_drv_active(scsi_qla_host_t *vha)
  {
        uint32_t drv_active;
  
        /* If reset value is all FF's, initialize DRV_ACTIVE */
        if (drv_active == 0xffffffff) {
-               qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, 0);
+               qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE,
+                       QLA82XX_DRV_NOT_ACTIVE);
                drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
        }
-       drv_active |= (1 << (ha->portnum * 4));
+       drv_active |= (QLA82XX_DRV_ACTIVE << (ha->portnum * 4));
        qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
  }
  
@@@ -2280,7 -2288,7 +2288,7 @@@ qla82xx_clear_drv_active(struct qla_hw_
        uint32_t drv_active;
  
        drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
-       drv_active &= ~(1 << (ha->portnum * 4));
+       drv_active &= ~(QLA82XX_DRV_ACTIVE << (ha->portnum * 4));
        qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
  }
  
@@@ -2291,7 -2299,7 +2299,7 @@@ qla82xx_need_reset(struct qla_hw_data *
        int rval;
  
        drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
-       rval = drv_state & (1 << (ha->portnum * 4));
+       rval = drv_state & (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
        return rval;
  }
  
@@@ -2305,7 -2313,7 +2313,7 @@@ qla82xx_set_rst_ready(struct qla_hw_dat
  
        /* If reset value is all FF's, initialize DRV_STATE */
        if (drv_state == 0xffffffff) {
-               qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0);
+               qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, QLA82XX_DRVST_NOT_RDY);
                drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
        }
        drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
@@@ -2335,7 -2343,8 +2343,8 @@@ qla82xx_set_qsnt_ready(struct qla_hw_da
        qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
  }
  
- int qla82xx_load_fw(scsi_qla_host_t *vha)
+ static int
+ qla82xx_load_fw(scsi_qla_host_t *vha)
  {
        int rst;
        struct fw_blob *blob;
@@@ -2411,7 -2420,7 +2420,7 @@@ fw_load_failed
        return QLA_FUNCTION_FAILED;
  }
  
static int
+ int
  qla82xx_start_firmware(scsi_qla_host_t *vha)
  {
        int           pcie_cap;
        struct qla_hw_data *ha = vha->hw;
  
        /* scrub dma mask expansion register */
-       qla82xx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555);
+       qla82xx_wr_32(ha, CRB_DMA_SHIFT, QLA82XX_DMA_SHIFT_VALUE);
  
        /* Put both the PEG CMD and RCV PEG to default state
         * of 0 before resetting the hardware
@@@ -2672,19 -2681,6 +2681,19 @@@ qla82xx_start_scsi(srb_t *sp
  sufficient_dsds:
                req_cnt = 1;
  
 +              if (req->cnt < (req_cnt + 2)) {
 +                      cnt = (uint16_t)RD_REG_DWORD_RELAXED(
 +                              &reg->req_q_out[0]);
 +                      if (req->ring_index < cnt)
 +                              req->cnt = cnt - req->ring_index;
 +                      else
 +                              req->cnt = req->length -
 +                                      (req->ring_index - cnt);
 +              }
 +
 +              if (req->cnt < (req_cnt + 2))
 +                      goto queuing_error;
 +
                ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC);
                if (!sp->ctx) {
                        DEBUG(printk(KERN_INFO
@@@ -2882,7 -2878,7 +2891,7 @@@ queuing_error
        return QLA_FUNCTION_FAILED;
  }
  
- uint32_t *
static uint32_t *
  qla82xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
        uint32_t length)
  {
@@@ -2903,7 -2899,7 +2912,7 @@@ done_read
        return dwptr;
  }
  
- int
static int
  qla82xx_unprotect_flash(struct qla_hw_data *ha)
  {
        int ret;
@@@ -2934,7 -2930,7 +2943,7 @@@ done_unprotect
        return ret;
  }
  
- int
static int
  qla82xx_protect_flash(struct qla_hw_data *ha)
  {
        int ret;
@@@ -2963,7 -2959,7 +2972,7 @@@ done_protect
        return ret;
  }
  
- int
static int
  qla82xx_erase_sector(struct qla_hw_data *ha, int addr)
  {
        int ret = 0;
@@@ -3156,6 -3152,20 +3165,20 @@@ qla82xx_start_iocbs(srb_t *sp
        }
  }
  
+ void qla82xx_rom_lock_recovery(struct qla_hw_data *ha)
+ {
+       if (qla82xx_rom_lock(ha))
+               /* Someone else is holding the lock. */
+               qla_printk(KERN_INFO, ha, "Resetting rom_lock\n");
+       /*
+        * Either we got the lock, or someone
+        * else died while holding it.
+        * In either case, unlock.
+        */
+       qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
+ }
  /*
   * qla82xx_device_bootstrap
   *    Initialize device, set DEV_READY, start fw
  static int
  qla82xx_device_bootstrap(scsi_qla_host_t *vha)
  {
-       int rval, i, timeout;
+       int rval = QLA_SUCCESS;
+       int i, timeout;
        uint32_t old_count, count;
        struct qla_hw_data *ha = vha->hw;
+       int need_reset = 0, peg_stuck = 1;
  
-       if (qla82xx_need_reset(ha))
-               goto dev_initialize;
+       need_reset = qla82xx_need_reset(ha);
  
        old_count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
  
  
                count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
                if (count != old_count)
+                       peg_stuck = 0;
+       }
+       if (need_reset) {
+               /* We are trying to perform a recovery here. */
+               if (peg_stuck)
+                       qla82xx_rom_lock_recovery(ha);
+               goto dev_initialize;
+       } else  {
+               /* Start of day for this ha context. */
+               if (peg_stuck) {
+                       /* Either we are the first or recovery in progress. */
+                       qla82xx_rom_lock_recovery(ha);
+                       goto dev_initialize;
+               } else
+                       /* Firmware already running. */
                        goto dev_ready;
        }
  
+       return rval;
  dev_initialize:
        /* set to DEV_INITIALIZING */
        qla_printk(KERN_INFO, ha, "HW State: INITIALIZING\n");
@@@ -3304,6 -3333,9 +3346,9 @@@ qla82xx_check_fw_alive(scsi_qla_host_t 
        struct qla_hw_data *ha = vha->hw;
  
        fw_heartbeat_counter = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+       /* all 0xff, assume AER/EEH in progress, ignore */
+       if (fw_heartbeat_counter == 0xffffffff)
+               return;
        if (vha->fw_heartbeat_counter == fw_heartbeat_counter) {
                vha->seconds_since_last_heartbeat++;
                /* FW not alive after 2 seconds */
                                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                        }
                        qla2xxx_wake_dpc(vha);
 +                      ha->flags.fw_hung = 1;
                        if (ha->flags.mbox_busy) {
 -                              ha->flags.fw_hung = 1;
                                ha->flags.mbox_int = 1;
                                DEBUG2(qla_printk(KERN_ERR, ha,
 -                                  "Due to fw hung, doing premature "
 -                                  "completion of mbx command\n"));
 -                              complete(&ha->mbx_intr_comp);
 +                                      "Due to fw hung, doing premature "
 +                                      "completion of mbx command\n"));
 +                              if (test_bit(MBX_INTR_WAIT,
 +                                      &ha->mbx_cmd_flags))
 +                                      complete(&ha->mbx_intr_comp);
                        }
                }
 -      }
 +      } else
 +              vha->seconds_since_last_heartbeat = 0;
        vha->fw_heartbeat_counter = fw_heartbeat_counter;
  }
  
@@@ -3434,15 -3463,13 +3479,15 @@@ void qla82xx_watchdog(scsi_qla_host_t *
                                "%s(): Adapter reset needed!\n", __func__);
                        set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                        qla2xxx_wake_dpc(vha);
 +                      ha->flags.fw_hung = 1;
                        if (ha->flags.mbox_busy) {
 -                              ha->flags.fw_hung = 1;
                                ha->flags.mbox_int = 1;
                                DEBUG2(qla_printk(KERN_ERR, ha,
 -                                  "Need reset, doing premature "
 -                                  "completion of mbx command\n"));
 -                              complete(&ha->mbx_intr_comp);
 +                                      "Need reset, doing premature "
 +                                      "completion of mbx command\n"));
 +                              if (test_bit(MBX_INTR_WAIT,
 +                                      &ha->mbx_cmd_flags))
 +                                      complete(&ha->mbx_intr_comp);
                        }
                } else {
                        qla82xx_check_fw_alive(vha);
index 9946fac542556567bea18e0c8f3ae252267fc81b,bdd53f0ebef05d04fd8ce0b0a9c8ddd1d62a1a16..800ea926975236214c2846e4aa8b18ad12ebd56c
@@@ -1295,17 -1295,12 +1295,12 @@@ static in
  qla2xxx_slave_configure(struct scsi_device *sdev)
  {
        scsi_qla_host_t *vha = shost_priv(sdev->host);
-       struct qla_hw_data *ha = vha->hw;
-       struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
        struct req_que *req = vha->req;
  
        if (sdev->tagged_supported)
                scsi_activate_tcq(sdev, req->max_q_depth);
        else
                scsi_deactivate_tcq(sdev, req->max_q_depth);
-       rport->dev_loss_tmo = ha->port_down_retry_count;
        return 0;
  }
  
@@@ -2141,8 -2136,16 +2136,16 @@@ qla2x00_probe_one(struct pci_dev *pdev
        else
                base_vha->mgmt_svr_loop_id = MANAGEMENT_SERVER +
                                                base_vha->vp_idx;
-       if (IS_QLA2100(ha))
-               host->sg_tablesize = 32;
+       /* Set the SG table size based on ISP type */
+       if (!IS_FWI2_CAPABLE(ha)) {
+               if (IS_QLA2100(ha))
+                       host->sg_tablesize = 32;
+       } else {
+               if (!IS_QLA82XX(ha))
+                       host->sg_tablesize = QLA_SG_ALL;
+       }
        host->max_id = max_id;
        host->this_id = 255;
        host->cmd_per_lun = 3;
@@@ -2341,28 -2344,16 +2344,28 @@@ probe_out
  static void
  qla2x00_remove_one(struct pci_dev *pdev)
  {
 -      scsi_qla_host_t *base_vha, *vha, *temp;
 +      scsi_qla_host_t *base_vha, *vha;
        struct qla_hw_data  *ha;
 +      unsigned long flags;
  
        base_vha = pci_get_drvdata(pdev);
        ha = base_vha->hw;
  
 -      list_for_each_entry_safe(vha, temp, &ha->vp_list, list) {
 -              if (vha && vha->fc_vport)
 +      spin_lock_irqsave(&ha->vport_slock, flags);
 +      list_for_each_entry(vha, &ha->vp_list, list) {
 +              atomic_inc(&vha->vref_count);
 +
 +              if (vha && vha->fc_vport) {
 +                      spin_unlock_irqrestore(&ha->vport_slock, flags);
 +
                        fc_vport_terminate(vha->fc_vport);
 +
 +                      spin_lock_irqsave(&ha->vport_slock, flags);
 +              }
 +
 +              atomic_dec(&vha->vref_count);
        }
 +      spin_unlock_irqrestore(&ha->vport_slock, flags);
  
        set_bit(UNLOADING, &base_vha->dpc_flags);
  
@@@ -2987,17 -2978,10 +2990,17 @@@ static struct qla_work_evt 
  qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type)
  {
        struct qla_work_evt *e;
 +      uint8_t bail;
 +
 +      QLA_VHA_MARK_BUSY(vha, bail);
 +      if (bail)
 +              return NULL;
  
        e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC);
 -      if (!e)
 +      if (!e) {
 +              QLA_VHA_MARK_NOT_BUSY(vha);
                return NULL;
 +      }
  
        INIT_LIST_HEAD(&e->list);
        e->type = type;
@@@ -3154,9 -3138,6 +3157,9 @@@ qla2x00_do_work(struct scsi_qla_host *v
                }
                if (e->flags & QLA_EVT_FLAG_FREE)
                        kfree(e);
 +
 +              /* For each work completed decrement vha ref count */
 +              QLA_VHA_MARK_NOT_BUSY(vha);
        }
  }
  
@@@ -3553,6 -3534,11 +3556,11 @@@ qla2x00_timer(scsi_qla_host_t *vha
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req;
  
+       if (ha->flags.eeh_busy) {
+               qla2x00_restart_timer(vha, WATCH_INTERVAL);
+               return;
+       }
        if (IS_QLA82XX(ha))
                qla82xx_watchdog(vha);
  
@@@ -3782,8 -3768,21 +3790,21 @@@ qla2xxx_pci_error_detected(struct pci_d
                return PCI_ERS_RESULT_CAN_RECOVER;
        case pci_channel_io_frozen:
                ha->flags.eeh_busy = 1;
+               /* For ISP82XX complete any pending mailbox cmd */
+               if (IS_QLA82XX(ha)) {
+                       ha->flags.fw_hung = 1;
+                       if (ha->flags.mbox_busy) {
+                               ha->flags.mbox_int = 1;
+                               DEBUG2(qla_printk(KERN_ERR, ha,
+                                       "Due to pci channel io frozen, doing premature "
+                                       "completion of mbx command\n"));
+                               complete(&ha->mbx_intr_comp);
+                       }
+               }
                qla2x00_free_irqs(vha);
                pci_disable_device(pdev);
+               /* Return back all IOs */
+               qla2x00_abort_all_cmds(vha, DID_RESET << 16);
                return PCI_ERS_RESULT_NEED_RESET;
        case pci_channel_io_perm_failure:
                ha->flags.pci_channel_io_perm_failure = 1;
@@@ -3804,6 -3803,9 +3825,9 @@@ qla2xxx_pci_mmio_enabled(struct pci_de
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
        struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
  
+       if (IS_QLA82XX(ha))
+               return PCI_ERS_RESULT_RECOVERED;
        spin_lock_irqsave(&ha->hardware_lock, flags);
        if (IS_QLA2100(ha) || IS_QLA2200(ha)){
                stat = RD_REG_DWORD(&reg->hccr);
                return PCI_ERS_RESULT_RECOVERED;
  }
  
+ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
+ {
+       uint32_t rval = QLA_FUNCTION_FAILED;
+       uint32_t drv_active = 0;
+       struct qla_hw_data *ha = base_vha->hw;
+       int fn;
+       struct pci_dev *other_pdev = NULL;
+       DEBUG17(qla_printk(KERN_INFO, ha,
+           "scsi(%ld): In qla82xx_error_recovery\n", base_vha->host_no));
+       set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
+       if (base_vha->flags.online) {
+               /* Abort all outstanding commands,
+                * so as to be requeued later */
+               qla2x00_abort_isp_cleanup(base_vha);
+       }
+       fn = PCI_FUNC(ha->pdev->devfn);
+       while (fn > 0) {
+               fn--;
+               DEBUG17(qla_printk(KERN_INFO, ha,
+                   "Finding pci device at function = 0x%x\n", fn));
+               other_pdev =
+                   pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
+                   ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
+                   fn));
+               if (!other_pdev)
+                       continue;
+               if (atomic_read(&other_pdev->enable_cnt)) {
+                       DEBUG17(qla_printk(KERN_INFO, ha,
+                           "Found PCI func availabe and enabled at 0x%x\n",
+                           fn));
+                       pci_dev_put(other_pdev);
+                       break;
+               }
+               pci_dev_put(other_pdev);
+       }
+       if (!fn) {
+               /* Reset owner */
+               DEBUG17(qla_printk(KERN_INFO, ha,
+                   "This devfn is reset owner = 0x%x\n", ha->pdev->devfn));
+               qla82xx_idc_lock(ha);
+               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+                   QLA82XX_DEV_INITIALIZING);
+               qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION,
+                   QLA82XX_IDC_VERSION);
+               drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+               DEBUG17(qla_printk(KERN_INFO, ha,
+                   "drv_active = 0x%x\n", drv_active));
+               qla82xx_idc_unlock(ha);
+               /* Reset if device is not already reset
+                * drv_active would be 0 if a reset has already been done
+                */
+               if (drv_active)
+                       rval = qla82xx_start_firmware(base_vha);
+               else
+                       rval = QLA_SUCCESS;
+               qla82xx_idc_lock(ha);
+               if (rval != QLA_SUCCESS) {
+                       qla_printk(KERN_INFO, ha, "HW State: FAILED\n");
+                       qla82xx_clear_drv_active(ha);
+                       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+                           QLA82XX_DEV_FAILED);
+               } else {
+                       qla_printk(KERN_INFO, ha, "HW State: READY\n");
+                       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+                           QLA82XX_DEV_READY);
+                       qla82xx_idc_unlock(ha);
+                       ha->flags.fw_hung = 0;
+                       rval = qla82xx_restart_isp(base_vha);
+                       qla82xx_idc_lock(ha);
+                       /* Clear driver state register */
+                       qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0);
+                       qla82xx_set_drv_active(base_vha);
+               }
+               qla82xx_idc_unlock(ha);
+       } else {
+               DEBUG17(qla_printk(KERN_INFO, ha,
+                   "This devfn is not reset owner = 0x%x\n", ha->pdev->devfn));
+               if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) ==
+                   QLA82XX_DEV_READY)) {
+                       ha->flags.fw_hung = 0;
+                       rval = qla82xx_restart_isp(base_vha);
+                       qla82xx_idc_lock(ha);
+                       qla82xx_set_drv_active(base_vha);
+                       qla82xx_idc_unlock(ha);
+               }
+       }
+       clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
+       return rval;
+ }
  static pci_ers_result_t
  qla2xxx_pci_slot_reset(struct pci_dev *pdev)
  {
        if (rc) {
                qla_printk(KERN_WARNING, ha,
                    "Can't re-enable PCI device after reset.\n");
-               return ret;
+               goto exit_slot_reset;
        }
  
        rsp = ha->rsp_q_map[0];
        if (qla2x00_request_irqs(ha, rsp))
-               return ret;
+               goto exit_slot_reset;
  
        if (ha->isp_ops->pci_config(base_vha))
-               return ret;
+               goto exit_slot_reset;
+       if (IS_QLA82XX(ha)) {
+               if (qla82xx_error_recovery(base_vha) == QLA_SUCCESS) {
+                       ret = PCI_ERS_RESULT_RECOVERED;
+                       goto exit_slot_reset;
+               } else
+                       goto exit_slot_reset;
+       }
  
        while (ha->flags.mbox_busy && retries--)
                msleep(1000);
        clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
  
  
+ exit_slot_reset:
        DEBUG17(qla_printk(KERN_WARNING, ha,
            "slot_reset-return:ret=%x\n", ret));
  
@@@ -3948,7 -4062,6 +4084,7 @@@ static struct pci_driver qla2xxx_pci_dr
  
  static struct file_operations apidev_fops = {
        .owner = THIS_MODULE,
 +      .llseek = noop_llseek,
  };
  
  /**
diff --combined drivers/scsi/sd.c
index 20514c47a5aaabfc04e5b09ba81de516403574e7,08b60dda8bcf53142a8527e3123d0e611fd02474..20295774bf70c8c800ff0cd0eb1fe7b1488ec989
@@@ -477,7 -477,7 +477,7 @@@ static int scsi_setup_discard_cmnd(stru
  
  static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq)
  {
-       rq->timeout = SD_TIMEOUT;
+       rq->timeout = SD_FLUSH_TIMEOUT;
        rq->retries = SD_MAX_RETRIES;
        rq->cmd[0] = SYNCHRONIZE_CACHE;
        rq->cmd_len = 10;
@@@ -870,7 -870,7 +870,7 @@@ static int sd_release(struct gendisk *d
  
        SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_release\n"));
  
 -      if (atomic_dec_return(&sdkp->openers) && sdev->removable) {
 +      if (atomic_dec_return(&sdkp->openers) == 0 && sdev->removable) {
                if (scsi_block_when_processing_errors(sdev))
                        scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
        }
@@@ -1072,7 -1072,7 +1072,7 @@@ static int sd_sync_cache(struct scsi_di
                 * flush everything.
                 */
                res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
-                                      SD_TIMEOUT, SD_MAX_RETRIES, NULL);
+                                      SD_FLUSH_TIMEOUT, SD_MAX_RETRIES, NULL);
                if (res == 0)
                        break;
        }
@@@ -1554,7 -1554,7 +1554,7 @@@ static int read_capacity_16(struct scsi
        }
  
        /* Logical blocks per physical block exponent */
-       sdkp->hw_sector_size = (1 << (buffer[13] & 0xf)) * sector_size;
+       sdkp->physical_block_size = (1 << (buffer[13] & 0xf)) * sector_size;
  
        /* Lowest aligned logical block */
        alignment = ((buffer[14] & 0x3f) << 8 | buffer[15]) * sector_size;
                struct request_queue *q = sdp->request_queue;
  
                sdkp->thin_provisioning = 1;
-               q->limits.discard_granularity = sdkp->hw_sector_size;
+               q->limits.discard_granularity = sdkp->physical_block_size;
                q->limits.max_discard_sectors = 0xffffffff;
  
                if (buffer[14] & 0x40) /* TPRZ */
@@@ -1635,7 -1635,7 +1635,7 @@@ static int read_capacity_10(struct scsi
        }
  
        sdkp->capacity = lba + 1;
-       sdkp->hw_sector_size = sector_size;
+       sdkp->physical_block_size = sector_size;
        return sector_size;
  }
  
@@@ -1756,10 -1756,10 +1756,10 @@@ got_data
                                  (unsigned long long)sdkp->capacity,
                                  sector_size, cap_str_10, cap_str_2);
  
-                       if (sdkp->hw_sector_size != sector_size)
+                       if (sdkp->physical_block_size != sector_size)
                                sd_printk(KERN_NOTICE, sdkp,
                                          "%u-byte physical blocks\n",
-                                         sdkp->hw_sector_size);
+                                         sdkp->physical_block_size);
                }
        }
  
        else if (sector_size == 256)
                sdkp->capacity >>= 1;
  
-       blk_queue_physical_block_size(sdp->request_queue, sdkp->hw_sector_size);
+       blk_queue_physical_block_size(sdp->request_queue,
+                                     sdkp->physical_block_size);
        sdkp->device->sector_size = sector_size;
  }
  
@@@ -2039,14 -2040,24 +2040,24 @@@ static void sd_read_block_limits(struc
                lba_count = get_unaligned_be32(&buffer[20]);
                desc_count = get_unaligned_be32(&buffer[24]);
  
-               if (lba_count) {
-                       q->limits.max_discard_sectors =
-                               lba_count * sector_sz >> 9;
-                       if (desc_count)
+               if (lba_count && desc_count) {
+                       if (sdkp->tpvpd && !sdkp->tpu)
+                               sdkp->unmap = 0;
+                       else
                                sdkp->unmap = 1;
                }
  
+               if (sdkp->tpvpd && !sdkp->tpu && !sdkp->tpws) {
+                       sd_printk(KERN_ERR, sdkp, "Thin provisioning is " \
+                                 "enabled but neither TPU, nor TPWS are " \
+                                 "set. Disabling discard!\n");
+                       goto out;
+               }
+               if (lba_count)
+                       q->limits.max_discard_sectors =
+                               lba_count * sector_sz >> 9;
                granularity = get_unaligned_be32(&buffer[28]);
  
                if (granularity)
@@@ -2087,6 -2098,31 +2098,31 @@@ static void sd_read_block_characteristi
        kfree(buffer);
  }
  
+ /**
+  * sd_read_thin_provisioning - Query thin provisioning VPD page
+  * @disk: disk to query
+  */
+ static void sd_read_thin_provisioning(struct scsi_disk *sdkp)
+ {
+       unsigned char *buffer;
+       const int vpd_len = 8;
+       if (sdkp->thin_provisioning == 0)
+               return;
+       buffer = kmalloc(vpd_len, GFP_KERNEL);
+       if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb2, buffer, vpd_len))
+               goto out;
+       sdkp->tpvpd = 1;
+       sdkp->tpu   = (buffer[5] >> 7) & 1;     /* UNMAP */
+       sdkp->tpws  = (buffer[5] >> 6) & 1;     /* WRITE SAME(16) with UNMAP */
+  out:
+       kfree(buffer);
+ }
  static int sd_try_extended_inquiry(struct scsi_device *sdp)
  {
        /*
@@@ -2109,7 -2145,7 +2145,7 @@@ static int sd_revalidate_disk(struct ge
        struct scsi_disk *sdkp = scsi_disk(disk);
        struct scsi_device *sdp = sdkp->device;
        unsigned char *buffer;
 -      unsigned ordered;
 +      unsigned flush = 0;
  
        SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp,
                                      "sd_revalidate_disk\n"));
                sd_read_capacity(sdkp, buffer);
  
                if (sd_try_extended_inquiry(sdp)) {
+                       sd_read_thin_provisioning(sdkp);
                        sd_read_block_limits(sdkp);
                        sd_read_block_characteristics(sdkp);
                }
  
        /*
         * We now have all cache related info, determine how we deal
 -       * with ordered requests.  Note that as the current SCSI
 -       * dispatch function can alter request order, we cannot use
 -       * QUEUE_ORDERED_TAG_* even when ordered tag is supported.
 +       * with flush requests.
         */
 -      if (sdkp->WCE)
 -              ordered = sdkp->DPOFUA
 -                      ? QUEUE_ORDERED_DRAIN_FUA : QUEUE_ORDERED_DRAIN_FLUSH;
 -      else
 -              ordered = QUEUE_ORDERED_DRAIN;
 +      if (sdkp->WCE) {
 +              flush |= REQ_FLUSH;
 +              if (sdkp->DPOFUA)
 +                      flush |= REQ_FUA;
 +      }
  
 -      blk_queue_ordered(sdkp->disk->queue, ordered);
 +      blk_queue_flush(sdkp->disk->queue, flush);
  
        set_capacity(disk, sdkp->capacity);
        kfree(buffer);
@@@ -2250,11 -2289,10 +2287,10 @@@ static void sd_probe_async(void *data, 
        index = sdkp->index;
        dev = &sdp->sdev_gendev;
  
-       if (index < SD_MAX_DISKS) {
-               gd->major = sd_major((index & 0xf0) >> 4);
-               gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
-               gd->minors = SD_MINORS;
-       }
+       gd->major = sd_major((index & 0xf0) >> 4);
+       gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
+       gd->minors = SD_MINORS;
        gd->fops = &sd_fops;
        gd->private_data = &sdkp->driver;
        gd->queue = sdkp->device->request_queue;
@@@ -2344,6 -2382,12 +2380,12 @@@ static int sd_probe(struct device *dev
        if (error)
                goto out_put;
  
+       if (index >= SD_MAX_DISKS) {
+               error = -ENODEV;
+               sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name space exhausted.\n");
+               goto out_free_index;
+       }
        error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN);
        if (error)
                goto out_free_index;
@@@ -2623,15 -2667,15 +2665,15 @@@ module_exit(exit_sd)
  static void sd_print_sense_hdr(struct scsi_disk *sdkp,
                               struct scsi_sense_hdr *sshdr)
  {
 -      sd_printk(KERN_INFO, sdkp, "");
 +      sd_printk(KERN_INFO, sdkp, " ");
        scsi_show_sense_hdr(sshdr);
 -      sd_printk(KERN_INFO, sdkp, "");
 +      sd_printk(KERN_INFO, sdkp, " ");
        scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
  }
  
  static void sd_print_result(struct scsi_disk *sdkp, int result)
  {
 -      sd_printk(KERN_INFO, sdkp, "");
 +      sd_printk(KERN_INFO, sdkp, " ");
        scsi_show_result(result);
  }
  
diff --combined drivers/scsi/st.c
index afdc3f5d915cf7fc278d980147e632a68e727d32,9e2c3a72ff4de799e6ce20cfaa83f8dfc6e1a6c5..5b7388f1c83545975b4ebcad9a73f62cb7669f36
@@@ -9,7 -9,7 +9,7 @@@
     Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
     Michael Schaefer, J"org Weule, and Eric Youngdale.
  
-    Copyright 1992 - 2008 Kai Makisara
+    Copyright 1992 - 2010 Kai Makisara
     email Kai.Makisara@kolumbus.fi
  
     Some small formal changes - aeb, 950809
@@@ -17,7 -17,7 +17,7 @@@
     Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
   */
  
- static const char *verstr = "20081215";
+ static const char *verstr = "20100829";
  
  #include <linux/module.h>
  
@@@ -39,6 -39,7 +39,6 @@@
  #include <linux/cdev.h>
  #include <linux/delay.h>
  #include <linux/mutex.h>
 -#include <linux/smp_lock.h>
  
  #include <asm/uaccess.h>
  #include <asm/dma.h>
@@@ -75,7 -76,6 +75,7 @@@
  #include "st_options.h"
  #include "st.h"
  
 +static DEFINE_MUTEX(st_mutex);
  static int buffer_kbs;
  static int max_sg_segs;
  static int try_direct_io = TRY_DIRECT_IO;
@@@ -1180,7 -1180,7 +1180,7 @@@ static int st_open(struct inode *inode
        int dev = TAPE_NR(inode);
        char *name;
  
 -      lock_kernel();
 +      mutex_lock(&st_mutex);
        /*
         * We really want to do nonseekable_open(inode, filp); here, but some
         * versions of tar incorrectly call lseek on tapes and bail out if that
        filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
  
        if (!(STp = scsi_tape_get(dev))) {
 -              unlock_kernel();
 +              mutex_unlock(&st_mutex);
                return -ENXIO;
        }
  
        if (STp->in_use) {
                write_unlock(&st_dev_arr_lock);
                scsi_tape_put(STp);
 -              unlock_kernel();
 +              mutex_unlock(&st_mutex);
                DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); )
                return (-EBUSY);
        }
                        retval = (-EIO);
                goto err_out;
        }
 -      unlock_kernel();
 +      mutex_unlock(&st_mutex);
        return 0;
  
   err_out:
        normalize_buffer(STp->buffer);
        STp->in_use = 0;
        scsi_tape_put(STp);
 -      unlock_kernel();
 +      mutex_unlock(&st_mutex);
        return retval;
  
  }
@@@ -2696,18 -2696,21 +2696,21 @@@ static int st_int_ioctl(struct scsi_tap
                }
                break;
        case MTWEOF:
+       case MTWEOFI:
        case MTWSM:
                if (STp->write_prot)
                        return (-EACCES);
                cmd[0] = WRITE_FILEMARKS;
                if (cmd_in == MTWSM)
                        cmd[1] = 2;
+               if (cmd_in == MTWEOFI)
+                       cmd[1] |= 1;
                cmd[2] = (arg >> 16);
                cmd[3] = (arg >> 8);
                cmd[4] = arg;
                timeout = STp->device->request_queue->rq_timeout;
                  DEBC(
-                      if (cmd_in == MTWEOF)
+                    if (cmd_in != MTWSM)
                                 printk(ST_DEB_MSG "%s: Writing %d filemarks.\n", name,
                                 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
                       else
                else if (chg_eof)
                        STps->eof = ST_NOEOF;
  
-               if (cmd_in == MTWEOF)
-                       STps->rw = ST_IDLE;
+               if (cmd_in == MTWEOF || cmd_in == MTWEOFI)
+                       STps->rw = ST_IDLE;  /* prevent automatic WEOF at close */
        } else { /* SCSI command was not completely successful. Don't return
                      from this block without releasing the SCSI command block! */
                struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
                else
                        undone = 0;
  
-               if (cmd_in == MTWEOF &&
+               if ((cmd_in == MTWEOF || cmd_in == MTWEOFI) &&
                    cmdstatp->have_sense &&
                    (cmdstatp->flags & SENSE_EOM)) {
                        if (cmdstatp->sense_hdr.sense_key == NO_SENSE ||