mpt3sas: Single driver module which supports both SAS 2.0 & SAS 3.0 HBAs
authorSreekanth Reddy <sreekanth.reddy@avagotech.com>
Wed, 11 Nov 2015 12:00:35 +0000 (17:30 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 12 Nov 2015 00:50:11 +0000 (19:50 -0500)
Modified the mpt3sas driver to have a single driver module which
supports both SAS 2.0 & SAS 3.0 HBA devices.

* Added SAS 2.0 HBA device IDs to the mpt3sas_pci_table pci table.

* Created two separate SCSI host templates for SAS2 and SAS3 HBAs so
  that, during the driver load time driver can use corresponding host
  template(based the pci device ID) while registering a scsi host
  adapter instance for that pci device.

* Registered two IOCTL devices, mpt2ctl is for SAS2 HBAs & mpt3ctl for
  SAS3 HBAs. Also updated the code to make sure that mpt2ctl device
  processes only those ioctl cmds issued for the SAS2 HBAs and mpt3ctl
  device processes only those ioctl cmds issued for the SAS3 HBAs.

* Added separate indexing for SAS2 and SAS3 HBAs.

* Replaced compile time check 'MPT2SAS_SCSI' to run time check
  'hba_mpi_version_belonged' whereever needed.

* Aliased this merged driver to mpt2sas using MODULE_ALIAS.

* Moved global varaible 'driver_name' to per adapter instance variable.

* Created two raid function template and used corresponding raid
  function templates based on the run time check
  'hba_mpi_version_belonged'.

* Moved mpt2sas_warpdrive.c file from mpt2sas to mpt3sas folder and
  renamed it as mpt3sas_warpdrive.c.

* Also renamed the functions in mpt3sas_warpdrive.c file to follow
  current driver function name convention.

* Updated the Makefile to build mpt3sas_warpdrive.o file for these
  WarpDrive-specific functions.

* Also in function mpt3sas_setup_direct_io(), used sector_div() API
  instead of division operator (which gives compilation errors on 32 bit
  machines).

* Removed mpt2sas files, mpt2sas directory & mpt3sas_module.c file.

* Added module parameter 'hbas_to_enumerate' which permits using this
  merged driver as a legacy mpt2sas driver or as a legacy mpt3sas
  driver.

  Here are the available options for this module parameter:

   0 - Merged driver which enumerates both SAS 2.0 & SAS 3.0 HBAs
   1 - Acts as legacy mpt2sas driver, which enumerates only SAS 2.0 HBAs
   2 - Acts as legacy mpt3sas driver, which enumerates only SAS 3.0 HBAs

* Removed mpt2sas entries from SCSI's Kconfig and Makefile files.

Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
15 files changed:
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/mpt2sas/Kconfig [deleted file]
drivers/scsi/mpt2sas/Makefile [deleted file]
drivers/scsi/mpt2sas/mpt2sas_module.c [deleted file]
drivers/scsi/mpt2sas/mpt2sas_warpdrive.c [deleted file]
drivers/scsi/mpt3sas/Kconfig
drivers/scsi/mpt3sas/Makefile
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_config.c
drivers/scsi/mpt3sas/mpt3sas_ctl.c
drivers/scsi/mpt3sas/mpt3sas_module.c [deleted file]
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/mpt3sas/mpt3sas_warpdrive.c [new file with mode: 0644]

index 95f7a76cfafcf8a296f43edec9d22ba7ce342c59..8aed855dd391de862eae8750f132ccbc8c893560 100644 (file)
@@ -541,7 +541,6 @@ config SCSI_ARCMSR
 
 source "drivers/scsi/esas2r/Kconfig"
 source "drivers/scsi/megaraid/Kconfig.megaraid"
-source "drivers/scsi/mpt2sas/Kconfig"
 source "drivers/scsi/mpt3sas/Kconfig"
 source "drivers/scsi/ufs/Kconfig"
 
index 1a8c9b53fafad5900ef775599a7f34abd34978eb..c14bca4a9675c1d1ce29d759354cd8a835bdf98d 100644 (file)
@@ -106,7 +106,6 @@ obj-$(CONFIG_CXLFLASH)              += cxlflash/
 obj-$(CONFIG_MEGARAID_LEGACY)  += megaraid.o
 obj-$(CONFIG_MEGARAID_NEWGEN)  += megaraid/
 obj-$(CONFIG_MEGARAID_SAS)     += megaraid/
-obj-$(CONFIG_SCSI_MPT2SAS)     += mpt2sas/
 obj-$(CONFIG_SCSI_MPT3SAS)     += mpt3sas/
 obj-$(CONFIG_SCSI_UFSHCD)      += ufs/
 obj-$(CONFIG_SCSI_ACARD)       += atp870u.o
diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig
deleted file mode 100644 (file)
index 1356a0a..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#
-# Kernel configuration file for the MPT2SAS
-#
-# This code is based on drivers/scsi/mpt2sas/Kconfig
-# Copyright (C) 2007-2014  LSI Corporation
-#  (mailto:DL-MPTFusionLinux@lsi.com)
-
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# NO WARRANTY
-# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
-# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
-# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
-# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
-# solely responsible for determining the appropriateness of using and
-# distributing the Program and assumes all risks associated with its
-# exercise of rights under this Agreement, including but not limited to
-# the risks and costs of program errors, damage to or loss of data,
-# programs or equipment, and unavailability or interruption of operations.
-
-# DISCLAIMER OF LIABILITY
-# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
-# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
-# USA.
-
-config SCSI_MPT2SAS
-       tristate "LSI MPT Fusion SAS 2.0 Device Driver"
-       depends on PCI && SCSI
-       select SCSI_SAS_ATTRS
-       select RAID_ATTRS
-       ---help---
-       This driver supports PCI-Express SAS 6Gb/s Host Adapters.
-
-config SCSI_MPT2SAS_MAX_SGE
-       int "LSI MPT Fusion Max number of SG Entries (16 - 128)"
-       depends on PCI && SCSI && SCSI_MPT2SAS
-       default "128"
-       range 16 128
-       ---help---
-       This option allows you to specify the maximum number of scatter-
-       gather entries per I/O. The driver default is 128, which matches
-       SAFE_PHYS_SEGMENTS.  However, it may decreased down to 16.
-       Decreasing this parameter will reduce memory requirements
-       on a per controller instance.
diff --git a/drivers/scsi/mpt2sas/Makefile b/drivers/scsi/mpt2sas/Makefile
deleted file mode 100644 (file)
index 3771616..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# mpt2sas makefile
-
-# share the official mpi headers from the mpt3sas driver
-ccflags-y += -I$(src)/../mpt3sas
-ccflags-y += -DSCSI_MPT2SAS
-
-# use the common object files from mpt3sas driver
-obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o
-mpt2sas-y +=  ../mpt3sas/mpt3sas_base.o        \
-               ../mpt3sas/mpt3sas_config.o    \
-               ../mpt3sas/mpt3sas_scsih.o     \
-               ../mpt3sas/mpt3sas_transport.o \
-               ../mpt3sas/mpt3sas_ctl.o       \
-               ../mpt3sas/mpt3sas_trigger_diag.o  \
-               mpt2sas_module.o
diff --git a/drivers/scsi/mpt2sas/mpt2sas_module.c b/drivers/scsi/mpt2sas/mpt2sas_module.c
deleted file mode 100644 (file)
index d407ed0..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Scsi Host Layer for MPT (Message Passing Technology) based controllers
- *
- * Copyright (C) 2012-2014  LSI Corporation
- * Copyright (C) 2013-2015 Avago Technologies
- *  (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program.
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/raid_class.h>
-
-#include "mpt3sas_base.h"
-#include "mpt3sas_ctl.h"
-
-MODULE_AUTHOR(MPT3SAS_AUTHOR);
-MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(MPT2SAS_DRIVER_VERSION);
-
-/* shost template */
-static struct scsi_host_template mpt2sas_driver_template = {
-       .module                         = THIS_MODULE,
-       .name                           = "Fusion MPT SAS Host",
-       .proc_name                      = MPT2SAS_DRIVER_NAME,
-       .queuecommand                   = scsih_qcmd,
-       .target_alloc                   = scsih_target_alloc,
-       .slave_alloc                    = scsih_slave_alloc,
-       .slave_configure                = scsih_slave_configure,
-       .target_destroy                 = scsih_target_destroy,
-       .slave_destroy                  = scsih_slave_destroy,
-       .scan_finished                  = scsih_scan_finished,
-       .scan_start                     = scsih_scan_start,
-       .change_queue_depth             = scsih_change_queue_depth,
-       .eh_abort_handler               = scsih_abort,
-       .eh_device_reset_handler        = scsih_dev_reset,
-       .eh_target_reset_handler        = scsih_target_reset,
-       .eh_host_reset_handler          = scsih_host_reset,
-       .bios_param                     = scsih_bios_param,
-       .can_queue                      = 1,
-       .this_id                        = -1,
-       .sg_tablesize                   = MPT2SAS_SG_DEPTH,
-       .max_sectors                    = 32767,
-       .cmd_per_lun                    = 7,
-       .use_clustering                 = ENABLE_CLUSTERING,
-       .shost_attrs                    = mpt3sas_host_attrs,
-       .sdev_attrs                     = mpt3sas_dev_attrs,
-       .track_queue_depth              = 1,
-};
-
-/* raid transport support */
-static struct raid_function_template mpt2sas_raid_functions = {
-       .cookie         = &mpt2sas_driver_template,
-       .is_raid        = scsih_is_raid,
-       .get_resync     = scsih_get_resync,
-       .get_state      = scsih_get_state,
-};
-
-/*
- * The pci device ids are defined in mpi/mpi2_cnfg.h.
- */
-static const struct pci_device_id mpt2sas_pci_table[] = {
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
-               PCI_ANY_ID, PCI_ANY_ID },
-       /* Falcon ~ 2008*/
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
-               PCI_ANY_ID, PCI_ANY_ID },
-       /* Liberator ~ 2108 */
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
-               PCI_ANY_ID, PCI_ANY_ID },
-       /* Meteor ~ 2116 */
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
-               PCI_ANY_ID, PCI_ANY_ID },
-       /* Thunderbolt ~ 2208 */
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
-               PCI_ANY_ID, PCI_ANY_ID },
-       /* Mustang ~ 2308 */
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
-               PCI_ANY_ID, PCI_ANY_ID },
-       /* SSS6200 */
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
-               PCI_ANY_ID, PCI_ANY_ID },
-       {0}     /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, mpt2sas_pci_table);
-
-static const struct file_operations mpt2sas_ctl_fops = {
-       .owner = THIS_MODULE,
-       .unlocked_ioctl = ctl_ioctl,
-       .poll = ctl_poll,
-       .fasync = ctl_fasync,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = ctl_ioctl_compat,
-#endif
-       .llseek = noop_llseek,
-};
-
-static struct miscdevice mpt2sas_ctl_dev = {
-       .minor  = MPT2SAS_MINOR,
-       .name   = MPT2SAS_DEV_NAME,
-       .fops   = &mpt2sas_ctl_fops,
-};
-
-/**
- * mpt2sas_ctl_init - main entry point for ctl.
- *
- */
-void
-mpt2sas_ctl_init(void)
-{
-       ctl_init();
-       if (misc_register(&mpt2sas_ctl_dev) < 0)
-               pr_err("%s can't register misc device [minor=%d]\n",
-                   MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR);
-}
-
-/**
- * mpt2sas_ctl_exit - exit point for ctl
- *
- */
-void
-mpt2sas_ctl_exit(void)
-{
-       ctl_exit();
-       misc_deregister(&mpt2sas_ctl_dev);
-}
-
-/**
- * _mpt2sas_probe - attach and add scsi host
- * @pdev: PCI device struct
- * @id: pci device id
- *
- * Returns 0 success, anything else error.
- */
-static int
-_mpt2sas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-       struct Scsi_Host *shost;
-       int rv;
-
-       shost = scsi_host_alloc(&mpt2sas_driver_template,
-                           sizeof(struct MPT3SAS_ADAPTER));
-       if (!shost)
-               return -ENODEV;
-
-       sprintf(driver_name, "%s", MPT2SAS_DRIVER_NAME);
-       rv = scsih_probe(pdev, shost);
-       return rv;
-}
-
-static struct pci_error_handlers _mpt2sas_err_handler = {
-       .error_detected = scsih_pci_error_detected,
-       .mmio_enabled = scsih_pci_mmio_enabled,
-       .slot_reset =   scsih_pci_slot_reset,
-       .resume =       scsih_pci_resume,
-};
-
-static struct pci_driver mpt2sas_driver = {
-       .name           = MPT2SAS_DRIVER_NAME,
-       .id_table       = mpt2sas_pci_table,
-       .probe          = _mpt2sas_probe,
-       .remove         = scsih_remove,
-       .shutdown       = scsih_shutdown,
-       .err_handler    = &_mpt2sas_err_handler,
-#ifdef CONFIG_PM
-       .suspend        = scsih_suspend,
-       .resume         = scsih_resume,
-#endif
-};
-
-/**
- * _mpt2sas_init - main entry point for this driver.
- *
- * Returns 0 success, anything else error.
- */
-static int __init
-_mpt2sas_init(void)
-{
-       int error;
-
-       pr_info("%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
-                                       MPT2SAS_DRIVER_VERSION);
-
-       mpt3sas_transport_template =
-           sas_attach_transport(&mpt3sas_transport_functions);
-       if (!mpt3sas_transport_template)
-               return -ENODEV;
-
-       mpt3sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
-       if (!mpt3sas_raid_template) {
-               sas_release_transport(mpt3sas_transport_template);
-               return -ENODEV;
-       }
-
-       error = scsih_init();
-       if (error) {
-               scsih_exit();
-               return error;
-       }
-
-       mpt2sas_ctl_init();
-
-       error = pci_register_driver(&mpt2sas_driver);
-       if (error)
-               scsih_exit();
-
-       return error;
-}
-
-/**
- * _mpt2sas_exit - exit point for this driver (when it is a module).
- *
- */
-static void __exit
-_mpt2sas_exit(void)
-{
-       pr_info("mpt2sas version %s unloading\n",
-                               MPT2SAS_DRIVER_VERSION);
-
-       pci_unregister_driver(&mpt2sas_driver);
-
-       mpt2sas_ctl_exit();
-
-       scsih_exit();
-}
-
-module_init(_mpt2sas_init);
-module_exit(_mpt2sas_exit);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_warpdrive.c b/drivers/scsi/mpt2sas/mpt2sas_warpdrive.c
deleted file mode 100644 (file)
index c4fcbc2..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Scsi Host Layer for MPT (Message Passing Technology) based controllers
- *
- * Copyright (C) 2012-2014  LSI Corporation
- * Copyright (C) 2013-2015 Avago Technologies
- *  (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program.
- */
-
-/**
- * _scsih_disable_ddio - Disable direct I/O for all the volumes
- * @ioc: per adapter object
- */
-static void
-_scsih_disable_ddio(struct MPT3SAS_ADAPTER *ioc)
-{
-       Mpi2RaidVolPage1_t vol_pg1;
-       Mpi2ConfigReply_t mpi_reply;
-       struct _raid_device *raid_device;
-       u16 handle;
-       u16 ioc_status;
-       unsigned long flags;
-
-       handle = 0xFFFF;
-       while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
-           &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
-               ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
-                   MPI2_IOCSTATUS_MASK;
-               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
-                       break;
-               handle = le16_to_cpu(vol_pg1.DevHandle);
-               spin_lock_irqsave(&ioc->raid_device_lock, flags);
-               raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
-               if (raid_device)
-                       raid_device->direct_io_enabled = 0;
-               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-       }
-       return;
-}
-
-
-/**
- * _scsih_get_num_volumes - Get number of volumes in the ioc
- * @ioc: per adapter object
- */
-static u8
-_scsih_get_num_volumes(struct MPT3SAS_ADAPTER *ioc)
-{
-       Mpi2RaidVolPage1_t vol_pg1;
-       Mpi2ConfigReply_t mpi_reply;
-       u16 handle;
-       u8 vol_cnt = 0;
-       u16 ioc_status;
-
-       handle = 0xFFFF;
-       while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
-           &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
-               ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
-                   MPI2_IOCSTATUS_MASK;
-               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
-                       break;
-               vol_cnt++;
-               handle = le16_to_cpu(vol_pg1.DevHandle);
-       }
-       return vol_cnt;
-}
-
-
-/**
- * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O.
- * @ioc: per adapter object
- * @raid_device: the raid_device object
- */
-static void
-_scsih_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
-       struct _raid_device *raid_device)
-{
-       Mpi2RaidVolPage0_t *vol_pg0;
-       Mpi2RaidPhysDiskPage0_t pd_pg0;
-       Mpi2ConfigReply_t mpi_reply;
-       u16 sz;
-       u8 num_pds, count;
-       unsigned long stripe_sz, block_sz;
-       u8 stripe_exp, block_exp;
-       u64 dev_max_lba;
-
-       if (!ioc->is_warpdrive)
-               return;
-
-       if (ioc->mfg_pg10_hide_flag ==  MFG_PAGE10_EXPOSE_ALL_DISKS) {
-               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
-                   "globally as drives are exposed\n", ioc->name);
-               return;
-       }
-       if (_scsih_get_num_volumes(ioc) > 1) {
-               _scsih_disable_ddio(ioc);
-               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
-                   "globally as number of drives > 1\n", ioc->name);
-               return;
-       }
-       if ((mpt3sas_config_get_number_pds(ioc, raid_device->handle,
-           &num_pds)) || !num_pds) {
-               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
-                   "Failure in computing number of drives\n", ioc->name);
-               return;
-       }
-
-       sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
-           sizeof(Mpi2RaidVol0PhysDisk_t));
-       vol_pg0 = kzalloc(sz, GFP_KERNEL);
-       if (!vol_pg0) {
-               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
-                   "Memory allocation failure for RVPG0\n", ioc->name);
-               return;
-       }
-
-       if ((mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
-            MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
-               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
-                   "Failure in retrieving RVPG0\n", ioc->name);
-               kfree(vol_pg0);
-               return;
-       }
-
-       /*
-        * WARPDRIVE:If number of physical disks in a volume exceeds the max pds
-        * assumed for WARPDRIVE, disable direct I/O
-        */
-       if (num_pds > MPT_MAX_WARPDRIVE_PDS) {
-               pr_warn(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
-                   "for the drive with handle(0x%04x): num_mem=%d, "
-                   "max_mem_allowed=%d\n", ioc->name, raid_device->handle,
-                   num_pds, MPT_MAX_WARPDRIVE_PDS);
-               kfree(vol_pg0);
-               return;
-       }
-       for (count = 0; count < num_pds; count++) {
-               if (mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
-                   &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
-                   vol_pg0->PhysDisk[count].PhysDiskNum) ||
-                   pd_pg0.DevHandle == MPT3SAS_INVALID_DEVICE_HANDLE) {
-                       pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
-                           "disabled for the drive with handle(0x%04x) member"
-                           "handle retrieval failed for member number=%d\n",
-                           ioc->name, raid_device->handle,
-                           vol_pg0->PhysDisk[count].PhysDiskNum);
-                       goto out_error;
-               }
-               /* Disable direct I/O if member drive lba exceeds 4 bytes */
-               dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA);
-               if (dev_max_lba >> 32) {
-                       pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
-                           "disabled for the drive with handle(0x%04x) member"
-                           " handle (0x%04x) unsupported max lba 0x%016llx\n",
-                           ioc->name, raid_device->handle,
-                           le16_to_cpu(pd_pg0.DevHandle),
-                           (unsigned long long)dev_max_lba);
-                       goto out_error;
-               }
-
-               raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle);
-       }
-
-       /*
-        * Assumption for WD: Direct I/O is not supported if the volume is
-        * not RAID0
-        */
-       if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) {
-               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
-                   "for the drive with handle(0x%04x): type=%d, "
-                   "s_sz=%uK, blk_size=%u\n", ioc->name,
-                   raid_device->handle, raid_device->volume_type,
-                   (le32_to_cpu(vol_pg0->StripeSize) *
-                   le16_to_cpu(vol_pg0->BlockSize)) / 1024,
-                   le16_to_cpu(vol_pg0->BlockSize));
-               goto out_error;
-       }
-
-       stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
-       stripe_exp = find_first_bit(&stripe_sz, 32);
-       if (stripe_exp == 32) {
-               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
-               "for the drive with handle(0x%04x) invalid stripe sz %uK\n",
-                   ioc->name, raid_device->handle,
-                   (le32_to_cpu(vol_pg0->StripeSize) *
-                   le16_to_cpu(vol_pg0->BlockSize)) / 1024);
-               goto out_error;
-       }
-       raid_device->stripe_exponent = stripe_exp;
-       block_sz = le16_to_cpu(vol_pg0->BlockSize);
-       block_exp = find_first_bit(&block_sz, 16);
-       if (block_exp == 16) {
-               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
-                   "for the drive with handle(0x%04x) invalid block sz %u\n",
-                   ioc->name, raid_device->handle,
-                   le16_to_cpu(vol_pg0->BlockSize));
-               goto out_error;
-       }
-       raid_device->block_exponent = block_exp;
-       raid_device->direct_io_enabled = 1;
-
-       pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is Enabled for the drive"
-           " with handle(0x%04x)\n", ioc->name, raid_device->handle);
-       /*
-        * WARPDRIVE: Though the following fields are not used for direct IO,
-        * stored for future purpose:
-        */
-       raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA);
-       raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
-       raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize);
-
-
-       kfree(vol_pg0);
-       return;
-
-out_error:
-       raid_device->direct_io_enabled = 0;
-       for (count = 0; count < num_pds; count++)
-               raid_device->pd_handle[count] = 0;
-       kfree(vol_pg0);
-       return;
-}
-
-/**
- * _scsih_scsi_direct_io_get - returns direct io flag
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns the smid stored scmd pointer.
- */
-static inline u8
-_scsih_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid)
-{
-       return ioc->scsi_lookup[smid - 1].direct_io;
-}
-
-/**
- * _scsih_scsi_direct_io_set - sets direct io flag
- * @ioc: per adapter object
- * @smid: system request message index
- * @direct_io: Zero or non-zero value to set in the direct_io flag
- *
- * Returns Nothing.
- */
-static inline void
-_scsih_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io)
-{
-       ioc->scsi_lookup[smid - 1].direct_io = direct_io;
-}
-
-/**
- * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O
- * @ioc: per adapter object
- * @scmd: pointer to scsi command object
- * @raid_device: pointer to raid device data structure
- * @mpi_request: pointer to the SCSI_IO reqest message frame
- * @smid: system request message index
- *
- * Returns nothing
- */
-static void
-_scsih_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
-       struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
-       u16 smid)
-{
-       sector_t v_lba, p_lba, stripe_off, stripe_unit, column, io_size;
-       u32 stripe_sz, stripe_exp;
-       u8 num_pds, cmd = scmd->cmnd[0];
-
-       if (cmd != READ_10 && cmd != WRITE_10 &&
-           cmd != READ_16 && cmd != WRITE_16)
-               return;
-
-       if (cmd == READ_10 || cmd == WRITE_10)
-               v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]);
-       else
-               v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]);
-
-       io_size = scsi_bufflen(scmd) >> raid_device->block_exponent;
-
-       if (v_lba + io_size - 1 > raid_device->max_lba)
-               return;
-
-       stripe_sz = raid_device->stripe_sz;
-       stripe_exp = raid_device->stripe_exponent;
-       stripe_off = v_lba & (stripe_sz - 1);
-
-       /* Return unless IO falls within a stripe */
-       if (stripe_off + io_size > stripe_sz)
-               return;
-
-       num_pds = raid_device->num_pds;
-       p_lba = v_lba >> stripe_exp;
-       stripe_unit = p_lba / num_pds;
-       column = p_lba % num_pds;
-       p_lba = (stripe_unit << stripe_exp) + stripe_off;
-       mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]);
-
-       if (cmd == READ_10 || cmd == WRITE_10)
-               put_unaligned_be32(lower_32_bits(p_lba),
-                                  &mpi_request->CDB.CDB32[2]);
-       else
-               put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]);
-
-       _scsih_scsi_direct_io_set(ioc, smid, 1);
-}
index 18b64bce10cb51808c712afacd8d2e5c08c9bf88..29061467cc174e118848dd44244ff28bb198deb3 100644 (file)
 # USA.
 
 config SCSI_MPT3SAS
-       tristate "LSI MPT Fusion SAS 3.0 Device Driver"
+       tristate "LSI MPT Fusion SAS 3.0 & SAS 2.0 Device Driver"
        depends on PCI && SCSI
        select SCSI_SAS_ATTRS
        select RAID_ATTRS
        ---help---
        This driver supports PCI-Express SAS 12Gb/s Host Adapters.
 
+config SCSI_MPT2SAS_MAX_SGE
+       int "LSI MPT Fusion SAS 2.0 Max number of SG Entries (16 - 256)"
+       depends on PCI && SCSI && SCSI_MPT3SAS
+       default "128"
+       range 16 256
+       ---help---
+       This option allows you to specify the maximum number of scatter-
+       gather entries per I/O. The driver default is 128, which matches
+       MAX_PHYS_SEGMENTS in most kernels.  However in SuSE kernels this
+       can be 256. However, it may decreased down to 16.  Decreasing this
+       parameter will reduce memory requirements on a per controller instance.
+
 config SCSI_MPT3SAS_MAX_SGE
-       int "LSI MPT Fusion Max number of SG Entries (16 - 256)"
+       int "LSI MPT Fusion SAS 3.0 Max number of SG Entries (16 - 256)"
        depends on PCI && SCSI && SCSI_MPT3SAS
        default "128"
        range 16 256
index 188057f69a9222c31975e70451adf09168d4872d..b7643f596c1e67ab67e0a954ab2250577de637d8 100644 (file)
@@ -6,4 +6,4 @@ mpt3sas-y +=  mpt3sas_base.o     \
                mpt3sas_transport.o     \
                mpt3sas_ctl.o   \
                mpt3sas_trigger_diag.o \
-               mpt3sas_module.o
+               mpt3sas_warpdrive.o
index f5d589e839b324ebd57f6f771a6f836643994c0b..11393ebf1a68ef8f14a38d58f1321d7783a84d72 100644 (file)
@@ -198,7 +198,7 @@ _base_fault_reset_work(struct work_struct *work)
                ioc->remove_host = 1;
                /*Remove the Dead Host */
                p = kthread_run(mpt3sas_remove_dead_ioc_func, ioc,
-                   "mpt3sas_dead_ioc_%d", ioc->id);
+                   "%s_dead_ioc_%d", ioc->driver_name, ioc->id);
                if (IS_ERR(p))
                        pr_err(MPT3SAS_FMT
                        "%s: Running mpt3sas_dead_ioc thread failed !!!!\n",
@@ -254,7 +254,8 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc)
 
        INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work);
        snprintf(ioc->fault_reset_work_q_name,
-           sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id);
+           sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status",
+           ioc->driver_name, ioc->id);
        ioc->fault_reset_work_q =
                create_singlethread_workqueue(ioc->fault_reset_work_q_name);
        if (!ioc->fault_reset_work_q) {
@@ -1835,10 +1836,10 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector)
        atomic_set(&reply_q->busy, 0);
        if (ioc->msix_enable)
                snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d",
-                   driver_name, ioc->id, index);
+                   ioc->driver_name, ioc->id, index);
        else
                snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d",
-                   driver_name, ioc->id);
+                   ioc->driver_name, ioc->id);
        r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name,
            reply_q);
        if (r) {
@@ -2064,7 +2065,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
 
 
        if (pci_request_selected_regions(pdev, ioc->bars,
-           driver_name)) {
+           ioc->driver_name)) {
                pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n",
                        ioc->name);
                ioc->bars = 0;
index 213d7f8fe3dc9a574721fecc891afe8021bef72e..25c141c9ec9d8773b2a7c3cb639f88259bf99609 100644 (file)
@@ -935,6 +935,7 @@ struct MPT3SAS_ADAPTER {
        u8              id;
        int             cpu_count;
        char            name[MPT_NAME_LENGTH];
+       char            driver_name[MPT_NAME_LENGTH];
        char            tmp_string[MPT_STRING_LENGTH];
        struct pci_dev  *pdev;
        Mpi2SystemInterfaceRegs_t __iomem *chip;
@@ -1246,7 +1247,6 @@ int mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc);
 
 
 /* scsih shared API */
-extern struct raid_template *mpt3sas_raid_template;
 u8 mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
        u32 reply);
 void mpt3sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase);
@@ -1270,39 +1270,8 @@ struct _sas_device *__mpt3sas_get_sdev_by_addr(
         struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
 
 void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc);
-
-void scsih_exit(void);
-int scsih_init(void);
-int scsih_probe(struct pci_dev *pdev, struct Scsi_Host *shost);
-void scsih_remove(struct pci_dev *pdev);
-void scsih_shutdown(struct pci_dev *pdev);
-pci_ers_result_t scsih_pci_error_detected(struct pci_dev *pdev,
-       pci_channel_state_t state);
-pci_ers_result_t scsih_pci_mmio_enabled(struct pci_dev *pdev);
-pci_ers_result_t scsih_pci_slot_reset(struct pci_dev *pdev);
-void scsih_pci_resume(struct pci_dev *pdev);
-int scsih_suspend(struct pci_dev *pdev, pm_message_t state);
-int scsih_resume(struct pci_dev *pdev);
-
-int scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd);
-int scsih_target_alloc(struct scsi_target *starget);
-int scsih_slave_alloc(struct scsi_device *sdev);
-int scsih_slave_configure(struct scsi_device *sdev);
-void scsih_target_destroy(struct scsi_target *starget);
-void scsih_slave_destroy(struct scsi_device *sdev);
-int scsih_scan_finished(struct Scsi_Host *shost, unsigned long time);
-void scsih_scan_start(struct Scsi_Host *shost);
-int scsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
-int scsih_abort(struct scsi_cmnd *scmd);
-int scsih_dev_reset(struct scsi_cmnd *scmd);
-int scsih_target_reset(struct scsi_cmnd *scmd);
-int scsih_host_reset(struct scsi_cmnd *scmd);
-int scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
-       sector_t capacity, int params[]);
-
-int scsih_is_raid(struct device *dev);
-void scsih_get_resync(struct device *dev);
-void scsih_get_state(struct device *dev);
+struct _raid_device *
+mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle);
 
 /* config shared API */
 u8 mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
@@ -1342,10 +1311,8 @@ int mpt3sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc,
        u16 sz);
 int mpt3sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
        *mpi_reply, Mpi2IOUnitPage1_t *config_page);
-#ifdef SCSI_MPT2SAS
 int mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc,
        Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz);
-#endif
 int mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
        *mpi_reply, Mpi2IOUnitPage1_t *config_page);
 int mpt3sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
@@ -1390,12 +1357,8 @@ int mpt3sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc,
 /* ctl shared API */
 extern struct device_attribute *mpt3sas_host_attrs[];
 extern struct device_attribute *mpt3sas_dev_attrs[];
-long ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-unsigned int ctl_poll(struct file *filep, poll_table *wait);
-int ctl_fasync(int fd, struct file *filep, int mode);
-long ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg);
-void ctl_init(void);
-void ctl_exit(void);
+void mpt3sas_ctl_init(ushort hbas_to_enumerate);
+void mpt3sas_ctl_exit(ushort hbas_to_enumerate);
 u8 mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
        u32 reply);
 void mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase);
@@ -1442,4 +1405,18 @@ void mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key,
        u8 asc, u8 ascq);
 void mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status,
        u32 loginfo);
+
+/* warpdrive APIs */
+u8 mpt3sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc);
+void mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
+       struct _raid_device *raid_device);
+inline u8
+mpt3sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid);
+inline void
+mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io);
+void
+mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
+       struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
+       u16 smid);
+
 #endif /* MPT3SAS_BASE_H_INCLUDED */
index 2bbb0346b46296745b9717d195656fa8861bdd2c..a6914ec99cc047ecb492e107988a1f5bb9551c1e 100644 (file)
@@ -865,7 +865,6 @@ mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
        return r;
 }
 
-#ifdef SCSI_MPT2SAS
 /**
  * mpt3sas_config_get_iounit_pg3 - obtain iounit page 3
  * @ioc: per adapter object
@@ -901,7 +900,6 @@ mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc,
  out:
        return r;
 }
-#endif
 
 /**
  * mpt3sas_config_get_iounit_pg8 - obtain iounit page 8
index f257c962c8993b6f98857d3ea6a4d4210a786dd3..d8366b056b70f48c046b1fcb06637f70174914ee 100644 (file)
@@ -409,11 +409,14 @@ mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
  * _ctl_verify_adapter - validates ioc_number passed from application
  * @ioc: per adapter object
  * @iocpp: The ioc pointer is returned in this.
+ * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
+ *             MPI25_VERSION for mpt3ctl ioctl device.
  *
  * Return (-1) means error, else ioc_number.
  */
 static int
-_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp)
+_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp,
+                                                       int mpi_version)
 {
        struct MPT3SAS_ADAPTER *ioc;
        /* global ioc lock to protect controller on list operations */
@@ -421,6 +424,11 @@ _ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp)
        list_for_each_entry(ioc, &mpt3sas_ioc_list, list) {
                if (ioc->id != ioc_number)
                        continue;
+               /* Check whether this ioctl command is from right
+                * ioctl device or not, if not continue the search.
+                */
+               if (ioc->hba_mpi_version_belonged != mpi_version)
+                       continue;
                spin_unlock(&gioc_lock);
                *iocpp = ioc;
                return ioc_number;
@@ -488,7 +496,7 @@ mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase)
 }
 
 /**
- * ctl_fasync -
+ * _ctl_fasync -
  * @fd -
  * @filep -
  * @mode -
@@ -496,19 +504,19 @@ mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase)
  * Called when application request fasyn callback handler.
  */
 int
-ctl_fasync(int fd, struct file *filep, int mode)
+_ctl_fasync(int fd, struct file *filep, int mode)
 {
        return fasync_helper(fd, filep, mode, &async_queue);
 }
 
 /**
- * ctl_poll -
+ * _ctl_poll -
  * @file -
  * @wait -
  *
  */
 unsigned int
-ctl_poll(struct file *filep, poll_table *wait)
+_ctl_poll(struct file *filep, poll_table *wait)
 {
        struct MPT3SAS_ADAPTER *ioc;
 
@@ -1034,7 +1042,7 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
        karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn);
        karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus);
        karg.firmware_version = ioc->facts.FWVersion.Word;
-       strcpy(karg.driver_version, driver_name);
+       strcpy(karg.driver_version, ioc->driver_name);
        strcat(karg.driver_version, "-");
        switch  (ioc->hba_mpi_version_belonged) {
        case MPI2_VERSION:
@@ -1049,10 +1057,6 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
                strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION);
                break;
        }
-       if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
-               strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION);
-       else
-               strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION);
        karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
 
        if (copy_to_user(arg, &karg, sizeof(karg))) {
@@ -2196,12 +2200,14 @@ _ctl_compat_mpt_command(struct MPT3SAS_ADAPTER *ioc, unsigned cmd,
  * _ctl_ioctl_main - main ioctl entry point
  * @file - (struct file)
  * @cmd - ioctl opcode
- * @arg -
- * compat - handles 32 bit applications in 64bit os
+ * @arg - user space data buffer
+ * @compat - handles 32 bit applications in 64bit os
+ * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
+ *             MPI25_VERSION for mpt3ctl ioctl device.
  */
 static long
 _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
-       u8 compat)
+       u8 compat, u16 mpi_version)
 {
        struct MPT3SAS_ADAPTER *ioc;
        struct mpt3_ioctl_header ioctl_header;
@@ -2216,7 +2222,8 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
                return -EFAULT;
        }
 
-       if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc)
+       if (_ctl_verify_adapter(ioctl_header.ioc_number,
+                               &ioc, mpi_version) == -1 || !ioc)
                return -ENODEV;
 
        /* pci_access_mutex lock acquired by ioctl path */
@@ -2324,23 +2331,43 @@ out_unlock_pciaccess:
 }
 
 /**
- * ctl_ioctl - main ioctl entry point (unlocked)
+ * _ctl_ioctl - mpt3ctl main ioctl entry point (unlocked)
  * @file - (struct file)
  * @cmd - ioctl opcode
  * @arg -
  */
 long
-ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        long ret;
 
-       ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0);
+       /* pass MPI25_VERSION value, to indicate that this ioctl cmd
+        * came from mpt3ctl ioctl device.
+        */
+       ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI25_VERSION);
        return ret;
 }
 
+/**
+ * _ctl_mpt2_ioctl - mpt2ctl main ioctl entry point (unlocked)
+ * @file - (struct file)
+ * @cmd - ioctl opcode
+ * @arg -
+ */
+long
+_ctl_mpt2_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       long ret;
+
+       /* pass MPI2_VERSION value, to indicate that this ioctl cmd
+        * came from mpt2ctl ioctl device.
+        */
+       ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI2_VERSION);
+       return ret;
+}
 #ifdef CONFIG_COMPAT
 /**
- * ctl_ioctl_compat - main ioctl entry point (compat)
+ *_ ctl_ioctl_compat - main ioctl entry point (compat)
  * @file -
  * @cmd -
  * @arg -
@@ -2348,11 +2375,28 @@ ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  * This routine handles 32 bit applications in 64bit os.
  */
 long
-ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
+_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
 {
        long ret;
 
-       ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1);
+       ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI25_VERSION);
+       return ret;
+}
+
+/**
+ *_ ctl_mpt2_ioctl_compat - main ioctl entry point (compat)
+ * @file -
+ * @cmd -
+ * @arg -
+ *
+ * This routine handles 32 bit applications in 64bit os.
+ */
+long
+_ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
+{
+       long ret;
+
+       ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI2_VERSION);
        return ret;
 }
 #endif
@@ -2739,7 +2783,6 @@ _ctl_ioc_reply_queue_count_show(struct device *cdev,
 static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show,
        NULL);
 
-#ifdef SCSI_MPT2SAS
 /**
  * _ctl_BRM_status_show - Backup Rail Monitor Status
  * @cdev - pointer to embedded class device
@@ -2815,7 +2858,6 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
        return rc;
 }
 static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL);
-#endif
 
 struct DIAG_BUFFER_START {
        __le32  Size;
@@ -3269,9 +3311,7 @@ struct device_attribute *mpt3sas_host_attrs[] = {
        &dev_attr_diag_trigger_event,
        &dev_attr_diag_trigger_scsi,
        &dev_attr_diag_trigger_mpi,
-#ifdef SCSI_MPT2SAS
        &dev_attr_BRM_status,
-#endif
        NULL,
 };
 
@@ -3325,23 +3365,74 @@ struct device_attribute *mpt3sas_dev_attrs[] = {
        NULL,
 };
 
+/* file operations table for mpt3ctl device */
+static const struct file_operations ctl_fops = {
+       .owner = THIS_MODULE,
+       .unlocked_ioctl = _ctl_ioctl,
+       .poll = _ctl_poll,
+       .fasync = _ctl_fasync,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = _ctl_ioctl_compat,
+#endif
+};
+
+/* file operations table for mpt2ctl device */
+static const struct file_operations ctl_gen2_fops = {
+       .owner = THIS_MODULE,
+       .unlocked_ioctl = _ctl_mpt2_ioctl,
+       .poll = _ctl_poll,
+       .fasync = _ctl_fasync,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = _ctl_mpt2_ioctl_compat,
+#endif
+};
+
+static struct miscdevice ctl_dev = {
+       .minor  = MPT3SAS_MINOR,
+       .name   = MPT3SAS_DEV_NAME,
+       .fops   = &ctl_fops,
+};
+
+static struct miscdevice gen2_ctl_dev = {
+       .minor  = MPT2SAS_MINOR,
+       .name   = MPT2SAS_DEV_NAME,
+       .fops   = &ctl_gen2_fops,
+};
+
 /**
- * ctl_init - main entry point for ctl.
+ * mpt3sas_ctl_init - main entry point for ctl.
  *
  */
 void
-ctl_init(void)
+mpt3sas_ctl_init(ushort hbas_to_enumerate)
 {
        async_queue = NULL;
+
+       /* Don't register mpt3ctl ioctl device if
+        * hbas_to_enumarate is one.
+        */
+       if (hbas_to_enumerate != 1)
+               if (misc_register(&ctl_dev) < 0)
+                       pr_err("%s can't register misc device [minor=%d]\n",
+                           MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR);
+
+       /* Don't register mpt3ctl ioctl device if
+        * hbas_to_enumarate is two.
+        */
+       if (hbas_to_enumerate != 2)
+               if (misc_register(&gen2_ctl_dev) < 0)
+                       pr_err("%s can't register misc device [minor=%d]\n",
+                           MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR);
+
        init_waitqueue_head(&ctl_poll_wait);
 }
 
 /**
- * ctl_exit - exit point for ctl
+ * mpt3sas_ctl_exit - exit point for ctl
  *
  */
 void
-ctl_exit(void)
+mpt3sas_ctl_exit(ushort hbas_to_enumerate)
 {
        struct MPT3SAS_ADAPTER *ioc;
        int i;
@@ -3366,4 +3457,8 @@ ctl_exit(void)
 
                kfree(ioc->event_log);
        }
+       if (hbas_to_enumerate != 1)
+               misc_deregister(&ctl_dev);
+       if (hbas_to_enumerate != 2)
+               misc_deregister(&gen2_ctl_dev);
 }
diff --git a/drivers/scsi/mpt3sas/mpt3sas_module.c b/drivers/scsi/mpt3sas/mpt3sas_module.c
deleted file mode 100644 (file)
index 322dc8d..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Scsi Host Layer for MPT (Message Passing Technology) based controllers
- *
- * Copyright (C) 2012-2014  LSI Corporation
- * Copyright (C) 2013-2015 Avago Technologies
- *  (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program.
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/raid_class.h>
-
-#include "mpt3sas_base.h"
-#include "mpt3sas_ctl.h"
-
-MODULE_AUTHOR(MPT3SAS_AUTHOR);
-MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(MPT3SAS_DRIVER_VERSION);
-
-/* shost template */
-static struct scsi_host_template mpt3sas_driver_template = {
-       .module                         = THIS_MODULE,
-       .name                           = "Fusion MPT SAS Host",
-       .proc_name                      = MPT3SAS_DRIVER_NAME,
-       .queuecommand                   = scsih_qcmd,
-       .target_alloc                   = scsih_target_alloc,
-       .slave_alloc                    = scsih_slave_alloc,
-       .slave_configure                = scsih_slave_configure,
-       .target_destroy                 = scsih_target_destroy,
-       .slave_destroy                  = scsih_slave_destroy,
-       .scan_finished                  = scsih_scan_finished,
-       .scan_start                     = scsih_scan_start,
-       .change_queue_depth             = scsih_change_queue_depth,
-       .eh_abort_handler               = scsih_abort,
-       .eh_device_reset_handler        = scsih_dev_reset,
-       .eh_target_reset_handler        = scsih_target_reset,
-       .eh_host_reset_handler          = scsih_host_reset,
-       .bios_param                     = scsih_bios_param,
-       .can_queue                      = 1,
-       .this_id                        = -1,
-       .sg_tablesize                   = MPT3SAS_SG_DEPTH,
-       .max_sectors                    = 32767,
-       .cmd_per_lun                    = 7,
-       .use_clustering                 = ENABLE_CLUSTERING,
-       .shost_attrs                    = mpt3sas_host_attrs,
-       .sdev_attrs                     = mpt3sas_dev_attrs,
-       .track_queue_depth              = 1,
-};
-
-/* raid transport support */
-static struct raid_function_template mpt3sas_raid_functions = {
-       .cookie         = &mpt3sas_driver_template,
-       .is_raid        = scsih_is_raid,
-       .get_resync     = scsih_get_resync,
-       .get_state      = scsih_get_state,
-};
-
-/*
- * The pci device ids are defined in mpi/mpi2_cnfg.h.
- */
-static const struct pci_device_id mpt3sas_pci_table[] = {
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008,
-               PCI_ANY_ID, PCI_ANY_ID },
-       /* Invader ~ 3108 */
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5,
-               PCI_ANY_ID, PCI_ANY_ID },
-       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6,
-               PCI_ANY_ID, PCI_ANY_ID },
-       {0}     /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table);
-
-static const struct file_operations mpt3sas_ctl_fops = {
-       .owner = THIS_MODULE,
-       .unlocked_ioctl = ctl_ioctl,
-       .poll = ctl_poll,
-       .fasync = ctl_fasync,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = ctl_ioctl_compat,
-#endif
-};
-
-static struct miscdevice mpt3sas_ctl_dev = {
-       .minor  = MPT3SAS_MINOR,
-       .name   = MPT3SAS_DEV_NAME,
-       .fops   = &mpt3sas_ctl_fops,
-};
-
-/**
- * mpt3sas_ctl_init - main entry point for ctl.
- *
- */
-void
-mpt3sas_ctl_init(void)
-{
-       ctl_init();
-       if (misc_register(&mpt3sas_ctl_dev) < 0)
-               pr_err("%s can't register misc device [minor=%d]\n",
-                   MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR);
-}
-
-/**
- * mpt3sas_ctl_exit - exit point for ctl
- *
- */
-void
-mpt3sas_ctl_exit(void)
-{
-       ctl_exit();
-       misc_deregister(&mpt3sas_ctl_dev);
-}
-
-/**
- * _mpt3sas_probe - attach and add scsi host
- * @pdev: PCI device struct
- * @id: pci device id
- *
- * Returns 0 success, anything else error.
- */
-static int
-_mpt3sas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-       struct Scsi_Host *shost;
-       int rv;
-
-       shost = scsi_host_alloc(&mpt3sas_driver_template,
-                               sizeof(struct MPT3SAS_ADAPTER));
-       if (!shost)
-               return -ENODEV;
-
-       sprintf(driver_name, "%s", MPT3SAS_DRIVER_NAME);
-       rv = scsih_probe(pdev, shost);
-       return rv;
-}
-
-static struct pci_error_handlers _mpt3sas_err_handler = {
-       .error_detected = scsih_pci_error_detected,
-       .mmio_enabled   = scsih_pci_mmio_enabled,
-       .slot_reset     = scsih_pci_slot_reset,
-       .resume         = scsih_pci_resume,
-};
-
-static struct pci_driver mpt3sas_driver = {
-       .name           = MPT3SAS_DRIVER_NAME,
-       .id_table       = mpt3sas_pci_table,
-       .probe          = _mpt3sas_probe,
-       .remove         = scsih_remove,
-       .shutdown       = scsih_shutdown,
-       .err_handler    = &_mpt3sas_err_handler,
-#ifdef CONFIG_PM
-       .suspend        = scsih_suspend,
-       .resume         = scsih_resume,
-#endif
-};
-
-/**
- * _mpt3sas_init - main entry point for this driver.
- *
- * Returns 0 success, anything else error.
- */
-static int __init
-_mpt3sas_init(void)
-{
-       int error;
-
-       pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME,
-                                       MPT3SAS_DRIVER_VERSION);
-
-       mpt3sas_transport_template =
-           sas_attach_transport(&mpt3sas_transport_functions);
-       if (!mpt3sas_transport_template)
-               return -ENODEV;
-
-       mpt3sas_raid_template = raid_class_attach(&mpt3sas_raid_functions);
-       if (!mpt3sas_raid_template) {
-               sas_release_transport(mpt3sas_transport_template);
-               return -ENODEV;
-       }
-
-       error = scsih_init();
-       if (error) {
-               scsih_exit();
-               return error;
-       }
-
-       mpt3sas_ctl_init();
-
-       error = pci_register_driver(&mpt3sas_driver);
-       if (error)
-               scsih_exit();
-
-       return error;
-}
-
-/**
- * _mpt3sas_exit - exit point for this driver (when it is a module).
- *
- */
-static void __exit
-_mpt3sas_exit(void)
-{
-       pr_info("mpt3sas version %s unloading\n",
-                               MPT3SAS_DRIVER_VERSION);
-
-       pci_unregister_driver(&mpt3sas_driver);
-
-       mpt3sas_ctl_exit();
-
-       scsih_exit();
-}
-
-module_init(_mpt3sas_init);
-module_exit(_mpt3sas_exit);
index d0ab0028c2eb2a4947a52f59c43d238650931e46..d95206b7e1167861531d2cd29c9ef27e7da82c25 100644 (file)
@@ -71,28 +71,17 @@ static int _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle,
 
 static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid);
 
-#ifdef SCSI_MPT2SAS
-static void _scsih_disable_ddio(struct MPT3SAS_ADAPTER *ioc);
-static u8 _scsih_get_num_volumes(struct MPT3SAS_ADAPTER *ioc);
-static void
-_scsih_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
-       struct _raid_device *raid_device);
-static inline u8
-_scsih_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid);
-static inline void
-_scsih_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io);
-static void
-_scsih_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
-       struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
-       u16 smid);
-#endif
-
 /* global parameters */
 LIST_HEAD(mpt3sas_ioc_list);
-char    driver_name[MPT_NAME_LENGTH];
 /* global ioc lock for list operations */
 DEFINE_SPINLOCK(gioc_lock);
 
+MODULE_AUTHOR(MPT3SAS_AUTHOR);
+MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MPT3SAS_DRIVER_VERSION);
+MODULE_ALIAS("mpt2sas");
+
 /* local parameters */
 static u8 scsi_io_cb_idx = -1;
 static u8 tm_cb_idx = -1;
@@ -102,7 +91,8 @@ static u8 port_enable_cb_idx = -1;
 static u8 transport_cb_idx = -1;
 static u8 scsih_cb_idx = -1;
 static u8 config_cb_idx = -1;
-static int mpt_ids;
+static int mpt2_ids;
+static int mpt3_ids;
 
 static u8 tm_tr_cb_idx = -1 ;
 static u8 tm_tr_volume_cb_idx = -1 ;
@@ -129,8 +119,12 @@ static u64 max_lun = MPT3SAS_MAX_LUN;
 module_param(max_lun, ullong, 0);
 MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
 
-
-
+static ushort hbas_to_enumerate;
+module_param(hbas_to_enumerate, ushort, 0);
+MODULE_PARM_DESC(hbas_to_enumerate,
+               " 0 - enumerates both SAS 2.0 & SAS 3.0 generation HBAs\n \
+                 1 - enumerates only SAS 2.0 generation HBAs\n \
+                 2 - enumerates only SAS 3.0 generation HBAs (default=0)");
 
 /* diag_buffer_enable is bitwise
  * bit 0 set = TRACE
@@ -156,6 +150,7 @@ MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 ");
 
 /* raid transport support */
 struct raid_template *mpt3sas_raid_template;
+struct raid_template *mpt2sas_raid_template;
 
 
 /**
@@ -879,7 +874,7 @@ _scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel)
 }
 
 /**
- * _scsih_raid_device_find_by_handle - raid device search
+ * mpt3sas_raid_device_find_by_handle - raid device search
  * @ioc: per adapter object
  * @handle: sas device handle (assigned by firmware)
  * Context: Calling function should acquire ioc->raid_device_lock
@@ -887,8 +882,8 @@ _scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel)
  * This searches for raid_device based on handle, then return raid_device
  * object.
  */
-static struct _raid_device *
-_scsih_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
+struct _raid_device *
+mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
 {
        struct _raid_device *raid_device, *r;
 
@@ -1304,10 +1299,8 @@ scsih_target_alloc(struct scsi_target *starget)
                if (test_bit(sas_device->handle, ioc->pd_handles))
                        sas_target_priv_data->flags |=
                            MPT_TARGET_FLAGS_RAID_COMPONENT;
-#ifndef SCSI_MPT2SAS
                if (sas_device->fast_path)
                        sas_target_priv_data->flags |= MPT_TARGET_FASTPATH_IO;
-#endif
        }
        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
@@ -1596,7 +1589,10 @@ scsih_get_resync(struct device *dev)
                percent_complete = 0;
 
  out:
-       raid_set_resync(mpt3sas_raid_template, dev, percent_complete);
+       if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+               raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
+       if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+               raid_set_resync(mpt3sas_raid_template, dev, percent_complete);
 }
 
 /**
@@ -1654,7 +1650,10 @@ scsih_get_state(struct device *dev)
                break;
        }
  out:
-       raid_set_state(mpt3sas_raid_template, dev, state);
+       if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+               raid_set_state(mpt2sas_raid_template, dev, state);
+       if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+               raid_set_state(mpt3sas_raid_template, dev, state);
 }
 
 /**
@@ -1663,7 +1662,8 @@ scsih_get_state(struct device *dev)
  * @volume_type: volume type
  */
 static void
-_scsih_set_level(struct scsi_device *sdev, u8 volume_type)
+_scsih_set_level(struct MPT3SAS_ADAPTER *ioc,
+       struct scsi_device *sdev, u8 volume_type)
 {
        enum raid_level level = RAID_LEVEL_UNKNOWN;
 
@@ -1682,7 +1682,12 @@ _scsih_set_level(struct scsi_device *sdev, u8 volume_type)
                break;
        }
 
-       raid_set_level(mpt3sas_raid_template, &sdev->sdev_gendev, level);
+       if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+               raid_set_level(mpt2sas_raid_template,
+                              &sdev->sdev_gendev, level);
+       if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+               raid_set_level(mpt3sas_raid_template,
+                              &sdev->sdev_gendev, level);
 }
 
 
@@ -1814,7 +1819,7 @@ scsih_slave_configure(struct scsi_device *sdev)
        if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
 
                spin_lock_irqsave(&ioc->raid_device_lock, flags);
-               raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+               raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
                spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
                if (!raid_device) {
                        dfailprintk(ioc, pr_warn(MPT3SAS_FMT
@@ -1830,12 +1835,10 @@ scsih_slave_configure(struct scsi_device *sdev)
                        return 1;
                }
 
-#ifdef SCSI_MPT2SAS
                /*
                 * WARPDRIVE: Initialize the required data for Direct IO
                 */
-               _scsih_init_warpdrive_properties(ioc, raid_device);
-#endif
+               mpt3sas_init_warpdrive_properties(ioc, raid_device);
 
                /* RAID Queue Depth Support
                 * IS volume = underlying qdepth of drive type, either
@@ -1896,7 +1899,7 @@ scsih_slave_configure(struct scsi_device *sdev)
 
                /* raid transport support */
                if (!ioc->is_warpdrive)
-                       _scsih_set_level(sdev, raid_device->volume_type);
+                       _scsih_set_level(ioc, sdev, raid_device->volume_type);
                return 0;
        }
 
@@ -3523,7 +3526,7 @@ _scsih_set_volume_delete_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle)
        unsigned long flags;
 
        spin_lock_irqsave(&ioc->raid_device_lock, flags);
-       raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+       raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
        if (raid_device && raid_device->starget &&
            raid_device->starget->hostdata) {
                sas_target_priv_data =
@@ -3841,9 +3844,7 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
        struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
        struct MPT3SAS_DEVICE *sas_device_priv_data;
        struct MPT3SAS_TARGET *sas_target_priv_data;
-#ifdef SCSI_MPT2SAS
        struct _raid_device *raid_device;
-#endif
        Mpi2SCSIIORequest_t *mpi_request;
        u32 mpi_control;
        u16 smid;
@@ -3947,21 +3948,17 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
        } else
                ioc->build_zero_len_sge(ioc, &mpi_request->SGL);
 
-#ifdef SCSI_MPT2SAS
        raid_device = sas_target_priv_data->raid_device;
        if (raid_device && raid_device->direct_io_enabled)
-               _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request,
+               mpt3sas_setup_direct_io(ioc, scmd, raid_device, mpi_request,
                    smid);
-#endif
 
        if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) {
-#ifndef SCSI_MPT2SAS
                if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) {
                        mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len |
                            MPI25_SCSIIO_IOFLAGS_FAST_PATH);
                        mpt3sas_base_put_smid_fast_path(ioc, smid, handle);
                } else
-#endif
                        mpt3sas_base_put_smid_scsi_io(ioc, smid,
                            le16_to_cpu(mpi_request->DevHandle));
        } else
@@ -4422,9 +4419,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
        u32 log_info;
        struct MPT3SAS_DEVICE *sas_device_priv_data;
        u32 response_code = 0;
-#ifdef SCSI_MPT2SAS
        unsigned long flags;
-#endif
 
        mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
        scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
@@ -4446,18 +4441,17 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
        }
        ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
 
-#ifdef SCSI_MPT2SAS
        /*
         * WARPDRIVE: If direct_io is set then it is directIO,
         * the failed direct I/O should be redirected to volume
         */
-       if (_scsih_scsi_direct_io_get(ioc, smid) &&
+       if (mpt3sas_scsi_direct_io_get(ioc, smid) &&
             ((ioc_status & MPI2_IOCSTATUS_MASK)
              != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
                spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
                ioc->scsi_lookup[smid - 1].scmd = scmd;
                spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-               _scsih_scsi_direct_io_set(ioc, smid, 0);
+               mpt3sas_scsi_direct_io_set(ioc, smid, 0);
                memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
                mpi_request->DevHandle =
                    cpu_to_le16(sas_device_priv_data->sas_target->handle);
@@ -4465,7 +4459,6 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
                    sas_device_priv_data->sas_target->handle);
                return 0;
        }
-#endif
        /* turning off TLR */
        scsi_state = mpi_reply->SCSIState;
        if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
@@ -4475,10 +4468,11 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
                sas_device_priv_data->tlr_snoop_check++;
                if (!ioc->is_warpdrive &&
                    !scsih_is_raid(&scmd->device->sdev_gendev) &&
-                   (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
-                   response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
-                       sas_device_priv_data->flags &=
-                           ~MPT_DEVICE_TLR_ON;
+                   sas_is_tlr_enabled(scmd->device) &&
+                   response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
+                       sas_disable_tlr(scmd->device);
+                       sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
+               }
        }
 
        xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
@@ -5309,10 +5303,8 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
        sas_device->device_info = device_info;
        sas_device->sas_address = sas_address;
        sas_device->phy = sas_device_pg0.PhyNum;
-#ifndef SCSI_MPT2SAS
        sas_device->fast_path = (le16_to_cpu(sas_device_pg0.Flags) &
            MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) ? 1 : 0;
-#endif
 
        if (sas_device_pg0.Flags & MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) {
                sas_device->enclosure_level =
@@ -6014,7 +6006,6 @@ _scsih_sas_discovery_event(struct MPT3SAS_ADAPTER *ioc,
        }
 }
 
-#ifndef SCSI_MPT2SAS
 /**
  * _scsih_ir_fastpath - turn on fastpath for IR physdisk
  * @ioc: per adapter object
@@ -6034,6 +6025,9 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
        u16 ioc_status;
        u32 log_info;
 
+       if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+               return rc;
+
        mutex_lock(&ioc->scsih_cmds.mutex);
 
        if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) {
@@ -6108,8 +6102,6 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
                    FORCE_BIG_HAMMER);
        return rc;
 }
-/* End of not defined SCSI_MPT2SAS */
-#endif
 
 /**
  * _scsih_reprobe_lun - reprobing lun
@@ -6202,7 +6194,7 @@ _scsih_sas_volume_delete(struct MPT3SAS_ADAPTER *ioc, u16 handle)
        struct scsi_target *starget = NULL;
 
        spin_lock_irqsave(&ioc->raid_device_lock, flags);
-       raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+       raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
        if (raid_device) {
                if (raid_device->starget) {
                        starget = raid_device->starget;
@@ -6304,10 +6296,9 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc,
        if (!sas_device)
                return;
 
-#ifndef SCSI_MPT2SAS
        /* hiding raid component */
        _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum);
-#endif
+
        if (starget)
                starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);
 
@@ -6355,9 +6346,7 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
 
        sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
        if (sas_device) {
-#ifndef SCSI_MPT2SAS
                _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum);
-#endif
                sas_device_put(sas_device);
                return;
        }
@@ -6382,9 +6371,7 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
                mpt3sas_transport_update_links(ioc, sas_address, handle,
                    sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
 
-#ifndef SCSI_MPT2SAS
        _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum);
-#endif
        _scsih_add_device(ioc, handle, 0, 1);
 }
 
@@ -6495,15 +6482,14 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc,
            MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
 
        element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
-       if (ioc->shost_recovery) {
-#ifndef SCSI_MPT2SAS
+       if (ioc->shost_recovery &&
+           ioc->hba_mpi_version_belonged != MPI2_VERSION) {
                for (i = 0; i < event_data->NumElements; i++, element++) {
                        if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_HIDE)
                                _scsih_ir_fastpath(ioc,
                                        le16_to_cpu(element->PhysDiskDevHandle),
                                        element->PhysDiskNum);
                }
-#endif
                return;
        }
 
@@ -6586,7 +6572,7 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc,
        case MPI2_RAID_VOL_STATE_OPTIMAL:
 
                spin_lock_irqsave(&ioc->raid_device_lock, flags);
-               raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+               raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
                spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
 
                if (raid_device)
@@ -6782,7 +6768,7 @@ _scsih_sas_ir_operation_status_event(struct MPT3SAS_ADAPTER *ioc,
 
                spin_lock_irqsave(&ioc->raid_device_lock, flags);
                handle = le16_to_cpu(event_data->VolDevHandle);
-               raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+               raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
                if (raid_device)
                        raid_device->percent_complete =
                            event_data->PercentComplete;
@@ -6964,14 +6950,12 @@ _scsih_mark_responding_raid_device(struct MPT3SAS_ADAPTER *ioc, u64 wwid,
                            "handle(0x%04x), wwid(0x%016llx)\n", handle,
                            (unsigned long long)raid_device->wwid);
 
-#ifdef SCSI_MPT2SAS
                        /*
                         * WARPDRIVE: The handles of the PDs might have changed
                         * across the host reset so re-initialize the
                         * required data for Direct IO
                         */
-                       _scsih_init_warpdrive_properties(ioc, raid_device);
-#endif
+                       mpt3sas_init_warpdrive_properties(ioc, raid_device);
                        spin_lock_irqsave(&ioc->raid_device_lock, flags);
                        if (raid_device->handle == handle) {
                                spin_unlock_irqrestore(&ioc->raid_device_lock,
@@ -8326,13 +8310,96 @@ scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
        return 1;
 }
 
-void
-_scsih_determine_hba_mpi_version(struct MPT3SAS_ADAPTER *ioc) {
+/* shost template for SAS 2.0 HBA devices */
+static struct scsi_host_template mpt2sas_driver_template = {
+       .module                         = THIS_MODULE,
+       .name                           = "Fusion MPT SAS Host",
+       .proc_name                      = MPT2SAS_DRIVER_NAME,
+       .queuecommand                   = scsih_qcmd,
+       .target_alloc                   = scsih_target_alloc,
+       .slave_alloc                    = scsih_slave_alloc,
+       .slave_configure                = scsih_slave_configure,
+       .target_destroy                 = scsih_target_destroy,
+       .slave_destroy                  = scsih_slave_destroy,
+       .scan_finished                  = scsih_scan_finished,
+       .scan_start                     = scsih_scan_start,
+       .change_queue_depth             = scsih_change_queue_depth,
+       .eh_abort_handler               = scsih_abort,
+       .eh_device_reset_handler        = scsih_dev_reset,
+       .eh_target_reset_handler        = scsih_target_reset,
+       .eh_host_reset_handler          = scsih_host_reset,
+       .bios_param                     = scsih_bios_param,
+       .can_queue                      = 1,
+       .this_id                        = -1,
+       .sg_tablesize                   = MPT2SAS_SG_DEPTH,
+       .max_sectors                    = 32767,
+       .cmd_per_lun                    = 7,
+       .use_clustering                 = ENABLE_CLUSTERING,
+       .shost_attrs                    = mpt3sas_host_attrs,
+       .sdev_attrs                     = mpt3sas_dev_attrs,
+       .track_queue_depth              = 1,
+};
+
+/* raid transport support for SAS 2.0 HBA devices */
+static struct raid_function_template mpt2sas_raid_functions = {
+       .cookie         = &mpt2sas_driver_template,
+       .is_raid        = scsih_is_raid,
+       .get_resync     = scsih_get_resync,
+       .get_state      = scsih_get_state,
+};
 
-       switch (ioc->pdev->device) {
+/* shost template for SAS 3.0 HBA devices */
+static struct scsi_host_template mpt3sas_driver_template = {
+       .module                         = THIS_MODULE,
+       .name                           = "Fusion MPT SAS Host",
+       .proc_name                      = MPT3SAS_DRIVER_NAME,
+       .queuecommand                   = scsih_qcmd,
+       .target_alloc                   = scsih_target_alloc,
+       .slave_alloc                    = scsih_slave_alloc,
+       .slave_configure                = scsih_slave_configure,
+       .target_destroy                 = scsih_target_destroy,
+       .slave_destroy                  = scsih_slave_destroy,
+       .scan_finished                  = scsih_scan_finished,
+       .scan_start                     = scsih_scan_start,
+       .change_queue_depth             = scsih_change_queue_depth,
+       .eh_abort_handler               = scsih_abort,
+       .eh_device_reset_handler        = scsih_dev_reset,
+       .eh_target_reset_handler        = scsih_target_reset,
+       .eh_host_reset_handler          = scsih_host_reset,
+       .bios_param                     = scsih_bios_param,
+       .can_queue                      = 1,
+       .this_id                        = -1,
+       .sg_tablesize                   = MPT3SAS_SG_DEPTH,
+       .max_sectors                    = 32767,
+       .cmd_per_lun                    = 7,
+       .use_clustering                 = ENABLE_CLUSTERING,
+       .shost_attrs                    = mpt3sas_host_attrs,
+       .sdev_attrs                     = mpt3sas_dev_attrs,
+       .track_queue_depth              = 1,
+};
+
+/* raid transport support for SAS 3.0 HBA devices */
+static struct raid_function_template mpt3sas_raid_functions = {
+       .cookie         = &mpt3sas_driver_template,
+       .is_raid        = scsih_is_raid,
+       .get_resync     = scsih_get_resync,
+       .get_state      = scsih_get_state,
+};
+
+/**
+ * _scsih_determine_hba_mpi_version - determine in which MPI version class
+ *                                     this device belongs to.
+ * @pdev: PCI device struct
+ *
+ * return MPI2_VERSION for SAS 2.0 HBA devices,
+ *     MPI25_VERSION for SAS 3.0 HBA devices.
+ */
+u16
+_scsih_determine_hba_mpi_version(struct pci_dev *pdev)
+{
+
+       switch (pdev->device) {
        case MPI2_MFGPAGE_DEVID_SSS6200:
-               ioc->is_warpdrive = 1;
-               ioc->hide_ir_msg = 1;
        case MPI2_MFGPAGE_DEVID_SAS2004:
        case MPI2_MFGPAGE_DEVID_SAS2008:
        case MPI2_MFGPAGE_DEVID_SAS2108_1:
@@ -8349,52 +8416,91 @@ _scsih_determine_hba_mpi_version(struct MPT3SAS_ADAPTER *ioc) {
        case MPI2_MFGPAGE_DEVID_SAS2308_1:
        case MPI2_MFGPAGE_DEVID_SAS2308_2:
        case MPI2_MFGPAGE_DEVID_SAS2308_3:
-               ioc->hba_mpi_version_belonged = MPI2_VERSION;
-               break;
+               return MPI2_VERSION;
        case MPI25_MFGPAGE_DEVID_SAS3004:
        case MPI25_MFGPAGE_DEVID_SAS3008:
        case MPI25_MFGPAGE_DEVID_SAS3108_1:
        case MPI25_MFGPAGE_DEVID_SAS3108_2:
        case MPI25_MFGPAGE_DEVID_SAS3108_5:
        case MPI25_MFGPAGE_DEVID_SAS3108_6:
-               ioc->hba_mpi_version_belonged = MPI25_VERSION;
-
-               /* Check whether the controller revision is C0 or above.
-                * only C0 and above revision controllers support 96 MSI-X
-                * vectors.
-                */
-               if (ioc->pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION)
-                       ioc->msix96_vector = 1;
-               break;
+               return MPI25_VERSION;
        }
-
-       if ((ioc->pdev->device != MPI2_MFGPAGE_DEVID_SSS6200) &&
-           (ioc->hba_mpi_version_belonged == MPI2_VERSION))
-               ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
+       return 0;
 }
 
 /**
- * scsih_probe - attach and add scsi host
+ * _scsih_probe - attach and add scsi host
  * @pdev: PCI device struct
  * @id: pci device id
  *
  * Returns 0 success, anything else error.
  */
 int
-scsih_probe(struct pci_dev *pdev, struct Scsi_Host *shost)
+_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct MPT3SAS_ADAPTER *ioc;
+       struct Scsi_Host *shost = NULL;
        int rv;
+       u16 hba_mpi_version;
+
+       /* Determine in which MPI version class this pci device belongs */
+       hba_mpi_version = _scsih_determine_hba_mpi_version(pdev);
+       if (hba_mpi_version == 0)
+               return -ENODEV;
+
+       /* Enumerate only SAS 2.0 HBA's if hbas_to_enumerate is one,
+        * for other generation HBA's return with -ENODEV
+        */
+       if ((hbas_to_enumerate == 1) && (hba_mpi_version !=  MPI2_VERSION))
+               return -ENODEV;
+
+       /* Enumerate only SAS 3.0 HBA's if hbas_to_enumerate is two,
+        * for other generation HBA's return with -ENODEV
+        */
+       if ((hbas_to_enumerate == 2) && (hba_mpi_version !=  MPI25_VERSION))
+               return -ENODEV;
+
+       switch (hba_mpi_version) {
+       case MPI2_VERSION:
+               /* Use mpt2sas driver host template for SAS 2.0 HBA's */
+               shost = scsi_host_alloc(&mpt2sas_driver_template,
+                 sizeof(struct MPT3SAS_ADAPTER));
+               if (!shost)
+                       return -ENODEV;
+               ioc = shost_priv(shost);
+               memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER));
+               ioc->hba_mpi_version_belonged = hba_mpi_version;
+               ioc->id = mpt2_ids++;
+               sprintf(ioc->driver_name, "%s", MPT2SAS_DRIVER_NAME);
+               if (pdev->device == MPI2_MFGPAGE_DEVID_SSS6200) {
+                       ioc->is_warpdrive = 1;
+                       ioc->hide_ir_msg = 1;
+               } else
+                       ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
+               break;
+       case MPI25_VERSION:
+               /* Use mpt3sas driver host template for SAS 3.0 HBA's */
+               shost = scsi_host_alloc(&mpt3sas_driver_template,
+                 sizeof(struct MPT3SAS_ADAPTER));
+               if (!shost)
+                       return -ENODEV;
+               ioc = shost_priv(shost);
+               memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER));
+               ioc->hba_mpi_version_belonged = hba_mpi_version;
+               ioc->id = mpt3_ids++;
+               sprintf(ioc->driver_name, "%s", MPT3SAS_DRIVER_NAME);
+               if (pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION)
+                       ioc->msix96_vector = 1;
+               break;
+       default:
+               return -ENODEV;
+       }
 
-       /* init local params */
-       ioc = shost_priv(shost);
-       memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER));
        INIT_LIST_HEAD(&ioc->list);
        spin_lock(&gioc_lock);
        list_add_tail(&ioc->list, &mpt3sas_ioc_list);
        spin_unlock(&gioc_lock);
        ioc->shost = shost;
-       ioc->id = mpt_ids++;
        ioc->pdev = pdev;
        ioc->scsi_io_cb_idx = scsi_io_cb_idx;
        ioc->tm_cb_idx = tm_cb_idx;
@@ -8431,8 +8537,7 @@ scsih_probe(struct pci_dev *pdev, struct Scsi_Host *shost)
        INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
        INIT_LIST_HEAD(&ioc->reply_queue_list);
 
-       _scsih_determine_hba_mpi_version(ioc);
-       sprintf(ioc->name, "%s_cm%d", driver_name, ioc->id);
+       sprintf(ioc->name, "%s_cm%d", ioc->driver_name, ioc->id);
 
        /* init shost parameters */
        shost->max_cmd_len = 32;
@@ -8472,7 +8577,7 @@ scsih_probe(struct pci_dev *pdev, struct Scsi_Host *shost)
 
        /* event thread */
        snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
-           "fw_event%d", ioc->id);
+           "fw_event_%s%d", ioc->driver_name, ioc->id);
        ioc->firmware_event_thread = alloc_ordered_workqueue(
            ioc->firmware_event_name, WQ_MEM_RECLAIM);
        if (!ioc->firmware_event_thread) {
@@ -8490,21 +8595,19 @@ scsih_probe(struct pci_dev *pdev, struct Scsi_Host *shost)
                goto out_attach_fail;
        }
 
-#ifdef SCSI_MPT2SAS
        if (ioc->is_warpdrive) {
                if (ioc->mfg_pg10_hide_flag ==  MFG_PAGE10_EXPOSE_ALL_DISKS)
                        ioc->hide_drives = 0;
                else if (ioc->mfg_pg10_hide_flag ==  MFG_PAGE10_HIDE_ALL_DISKS)
                        ioc->hide_drives = 1;
                else {
-                       if (_scsih_get_num_volumes(ioc))
+                       if (mpt3sas_get_num_volumes(ioc))
                                ioc->hide_drives = 1;
                        else
                                ioc->hide_drives = 0;
                }
        } else
                ioc->hide_drives = 0;
-#endif
 
        rv = scsi_add_host(shost, &pdev->dev);
        if (rv) {
@@ -8705,6 +8808,89 @@ scsih_pci_mmio_enabled(struct pci_dev *pdev)
        return PCI_ERS_RESULT_NEED_RESET;
 }
 
+/*
+ * The pci device ids are defined in mpi/mpi2_cnfg.h.
+ */
+static const struct pci_device_id mpt3sas_pci_table[] = {
+       /* Spitfire ~ 2004 */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
+               PCI_ANY_ID, PCI_ANY_ID },
+       /* Falcon ~ 2008 */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
+               PCI_ANY_ID, PCI_ANY_ID },
+       /* Liberator ~ 2108 */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
+               PCI_ANY_ID, PCI_ANY_ID },
+       /* Meteor ~ 2116 */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
+               PCI_ANY_ID, PCI_ANY_ID },
+       /* Thunderbolt ~ 2208 */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
+               PCI_ANY_ID, PCI_ANY_ID },
+       /* Mustang ~ 2308 */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
+               PCI_ANY_ID, PCI_ANY_ID },
+       /* SSS6200 */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
+               PCI_ANY_ID, PCI_ANY_ID },
+       /* Fury ~ 3004 and 3008 */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008,
+               PCI_ANY_ID, PCI_ANY_ID },
+       /* Invader ~ 3108 */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6,
+               PCI_ANY_ID, PCI_ANY_ID },
+       {0}     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table);
+
+static struct pci_error_handlers _mpt3sas_err_handler = {
+       .error_detected = scsih_pci_error_detected,
+       .mmio_enabled   = scsih_pci_mmio_enabled,
+       .slot_reset     = scsih_pci_slot_reset,
+       .resume         = scsih_pci_resume,
+};
+
+static struct pci_driver mpt3sas_driver = {
+       .name           = MPT3SAS_DRIVER_NAME,
+       .id_table       = mpt3sas_pci_table,
+       .probe          = _scsih_probe,
+       .remove         = scsih_remove,
+       .shutdown       = scsih_shutdown,
+       .err_handler    = &_mpt3sas_err_handler,
+#ifdef CONFIG_PM
+       .suspend        = scsih_suspend,
+       .resume         = scsih_resume,
+#endif
+};
+
 /**
  * scsih_init - main entry point for this driver.
  *
@@ -8713,7 +8899,8 @@ scsih_pci_mmio_enabled(struct pci_dev *pdev)
 int
 scsih_init(void)
 {
-       mpt_ids = 0;
+       mpt2_ids = 0;
+       mpt3_ids = 0;
 
        mpt3sas_base_initialize_callback_handler();
 
@@ -8777,10 +8964,86 @@ scsih_exit(void)
        mpt3sas_base_release_callback_handler(tm_sas_control_cb_idx);
 
 /* raid transport support */
-       raid_class_release(mpt3sas_raid_template);
+       if (hbas_to_enumerate != 1)
+               raid_class_release(mpt3sas_raid_template);
+       if (hbas_to_enumerate != 2)
+               raid_class_release(mpt2sas_raid_template);
        sas_release_transport(mpt3sas_transport_template);
 }
 
-#ifdef SCSI_MPT2SAS
-#include "../mpt2sas/mpt2sas_warpdrive.c"
-#endif
+/**
+ * _mpt3sas_init - main entry point for this driver.
+ *
+ * Returns 0 success, anything else error.
+ */
+static int __init
+_mpt3sas_init(void)
+{
+       int error;
+
+       pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME,
+                                       MPT3SAS_DRIVER_VERSION);
+
+       mpt3sas_transport_template =
+           sas_attach_transport(&mpt3sas_transport_functions);
+       if (!mpt3sas_transport_template)
+               return -ENODEV;
+
+       /* No need attach mpt3sas raid functions template
+        * if hbas_to_enumarate value is one.
+        */
+       if (hbas_to_enumerate != 1) {
+               mpt3sas_raid_template =
+                               raid_class_attach(&mpt3sas_raid_functions);
+               if (!mpt3sas_raid_template) {
+                       sas_release_transport(mpt3sas_transport_template);
+                       return -ENODEV;
+               }
+       }
+
+       /* No need to attach mpt2sas raid functions template
+        * if hbas_to_enumarate value is two
+        */
+       if (hbas_to_enumerate != 2) {
+               mpt2sas_raid_template =
+                               raid_class_attach(&mpt2sas_raid_functions);
+               if (!mpt2sas_raid_template) {
+                       sas_release_transport(mpt3sas_transport_template);
+                       return -ENODEV;
+               }
+       }
+
+       error = scsih_init();
+       if (error) {
+               scsih_exit();
+               return error;
+       }
+
+       mpt3sas_ctl_init(hbas_to_enumerate);
+
+       error = pci_register_driver(&mpt3sas_driver);
+       if (error)
+               scsih_exit();
+
+       return error;
+}
+
+/**
+ * _mpt3sas_exit - exit point for this driver (when it is a module).
+ *
+ */
+static void __exit
+_mpt3sas_exit(void)
+{
+       pr_info("mpt3sas version %s unloading\n",
+                               MPT3SAS_DRIVER_VERSION);
+
+       pci_unregister_driver(&mpt3sas_driver);
+
+       mpt3sas_ctl_exit(hbas_to_enumerate);
+
+       scsih_exit();
+}
+
+module_init(_mpt3sas_init);
+module_exit(_mpt3sas_exit);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c
new file mode 100644 (file)
index 0000000..540bd50
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Scsi Host Layer for MPT (Message Passing Technology) based controllers
+ *
+ * Copyright (C) 2012-2014  LSI Corporation
+ * Copyright (C) 2013-2015 Avago Technologies
+ *  (mailto: MPT-FusionLinux.pdl@avagotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <asm/unaligned.h>
+
+#include "mpt3sas_base.h"
+
+/**
+ * _warpdrive_disable_ddio - Disable direct I/O for all the volumes
+ * @ioc: per adapter object
+ */
+static void
+_warpdrive_disable_ddio(struct MPT3SAS_ADAPTER *ioc)
+{
+       Mpi2RaidVolPage1_t vol_pg1;
+       Mpi2ConfigReply_t mpi_reply;
+       struct _raid_device *raid_device;
+       u16 handle;
+       u16 ioc_status;
+       unsigned long flags;
+
+       handle = 0xFFFF;
+       while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
+           &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+               ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+                   MPI2_IOCSTATUS_MASK;
+               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+                       break;
+               handle = le16_to_cpu(vol_pg1.DevHandle);
+               spin_lock_irqsave(&ioc->raid_device_lock, flags);
+               raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
+               if (raid_device)
+                       raid_device->direct_io_enabled = 0;
+               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+       }
+       return;
+}
+
+
+/**
+ * mpt3sas_get_num_volumes - Get number of volumes in the ioc
+ * @ioc: per adapter object
+ */
+u8
+mpt3sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc)
+{
+       Mpi2RaidVolPage1_t vol_pg1;
+       Mpi2ConfigReply_t mpi_reply;
+       u16 handle;
+       u8 vol_cnt = 0;
+       u16 ioc_status;
+
+       handle = 0xFFFF;
+       while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
+           &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+               ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+                   MPI2_IOCSTATUS_MASK;
+               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+                       break;
+               vol_cnt++;
+               handle = le16_to_cpu(vol_pg1.DevHandle);
+       }
+       return vol_cnt;
+}
+
+
+/**
+ * mpt3sas_init_warpdrive_properties - Set properties for warpdrive direct I/O.
+ * @ioc: per adapter object
+ * @raid_device: the raid_device object
+ */
+void
+mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
+       struct _raid_device *raid_device)
+{
+       Mpi2RaidVolPage0_t *vol_pg0;
+       Mpi2RaidPhysDiskPage0_t pd_pg0;
+       Mpi2ConfigReply_t mpi_reply;
+       u16 sz;
+       u8 num_pds, count;
+       unsigned long stripe_sz, block_sz;
+       u8 stripe_exp, block_exp;
+       u64 dev_max_lba;
+
+       if (!ioc->is_warpdrive)
+               return;
+
+       if (ioc->mfg_pg10_hide_flag ==  MFG_PAGE10_EXPOSE_ALL_DISKS) {
+               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+                   "globally as drives are exposed\n", ioc->name);
+               return;
+       }
+       if (mpt3sas_get_num_volumes(ioc) > 1) {
+               _warpdrive_disable_ddio(ioc);
+               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+                   "globally as number of drives > 1\n", ioc->name);
+               return;
+       }
+       if ((mpt3sas_config_get_number_pds(ioc, raid_device->handle,
+           &num_pds)) || !num_pds) {
+               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+                   "Failure in computing number of drives\n", ioc->name);
+               return;
+       }
+
+       sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
+           sizeof(Mpi2RaidVol0PhysDisk_t));
+       vol_pg0 = kzalloc(sz, GFP_KERNEL);
+       if (!vol_pg0) {
+               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+                   "Memory allocation failure for RVPG0\n", ioc->name);
+               return;
+       }
+
+       if ((mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
+            MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
+               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+                   "Failure in retrieving RVPG0\n", ioc->name);
+               kfree(vol_pg0);
+               return;
+       }
+
+       /*
+        * WARPDRIVE:If number of physical disks in a volume exceeds the max pds
+        * assumed for WARPDRIVE, disable direct I/O
+        */
+       if (num_pds > MPT_MAX_WARPDRIVE_PDS) {
+               pr_warn(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+                   "for the drive with handle(0x%04x): num_mem=%d, "
+                   "max_mem_allowed=%d\n", ioc->name, raid_device->handle,
+                   num_pds, MPT_MAX_WARPDRIVE_PDS);
+               kfree(vol_pg0);
+               return;
+       }
+       for (count = 0; count < num_pds; count++) {
+               if (mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
+                   &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
+                   vol_pg0->PhysDisk[count].PhysDiskNum) ||
+                   pd_pg0.DevHandle == MPT3SAS_INVALID_DEVICE_HANDLE) {
+                       pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
+                           "disabled for the drive with handle(0x%04x) member"
+                           "handle retrieval failed for member number=%d\n",
+                           ioc->name, raid_device->handle,
+                           vol_pg0->PhysDisk[count].PhysDiskNum);
+                       goto out_error;
+               }
+               /* Disable direct I/O if member drive lba exceeds 4 bytes */
+               dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA);
+               if (dev_max_lba >> 32) {
+                       pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
+                           "disabled for the drive with handle(0x%04x) member"
+                           " handle (0x%04x) unsupported max lba 0x%016llx\n",
+                           ioc->name, raid_device->handle,
+                           le16_to_cpu(pd_pg0.DevHandle),
+                           (unsigned long long)dev_max_lba);
+                       goto out_error;
+               }
+
+               raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle);
+       }
+
+       /*
+        * Assumption for WD: Direct I/O is not supported if the volume is
+        * not RAID0
+        */
+       if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) {
+               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+                   "for the drive with handle(0x%04x): type=%d, "
+                   "s_sz=%uK, blk_size=%u\n", ioc->name,
+                   raid_device->handle, raid_device->volume_type,
+                   (le32_to_cpu(vol_pg0->StripeSize) *
+                   le16_to_cpu(vol_pg0->BlockSize)) / 1024,
+                   le16_to_cpu(vol_pg0->BlockSize));
+               goto out_error;
+       }
+
+       stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
+       stripe_exp = find_first_bit(&stripe_sz, 32);
+       if (stripe_exp == 32) {
+               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+               "for the drive with handle(0x%04x) invalid stripe sz %uK\n",
+                   ioc->name, raid_device->handle,
+                   (le32_to_cpu(vol_pg0->StripeSize) *
+                   le16_to_cpu(vol_pg0->BlockSize)) / 1024);
+               goto out_error;
+       }
+       raid_device->stripe_exponent = stripe_exp;
+       block_sz = le16_to_cpu(vol_pg0->BlockSize);
+       block_exp = find_first_bit(&block_sz, 16);
+       if (block_exp == 16) {
+               pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+                   "for the drive with handle(0x%04x) invalid block sz %u\n",
+                   ioc->name, raid_device->handle,
+                   le16_to_cpu(vol_pg0->BlockSize));
+               goto out_error;
+       }
+       raid_device->block_exponent = block_exp;
+       raid_device->direct_io_enabled = 1;
+
+       pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is Enabled for the drive"
+           " with handle(0x%04x)\n", ioc->name, raid_device->handle);
+       /*
+        * WARPDRIVE: Though the following fields are not used for direct IO,
+        * stored for future purpose:
+        */
+       raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA);
+       raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
+       raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize);
+
+
+       kfree(vol_pg0);
+       return;
+
+out_error:
+       raid_device->direct_io_enabled = 0;
+       for (count = 0; count < num_pds; count++)
+               raid_device->pd_handle[count] = 0;
+       kfree(vol_pg0);
+       return;
+}
+
+/**
+ * mpt3sas_scsi_direct_io_get - returns direct io flag
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns the smid stored scmd pointer.
+ */
+inline u8
+mpt3sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+       return ioc->scsi_lookup[smid - 1].direct_io;
+}
+
+/**
+ * mpt3sas_scsi_direct_io_set - sets direct io flag
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @direct_io: Zero or non-zero value to set in the direct_io flag
+ *
+ * Returns Nothing.
+ */
+inline void
+mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io)
+{
+       ioc->scsi_lookup[smid - 1].direct_io = direct_io;
+}
+
+/**
+ * mpt3sas_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O
+ * @ioc: per adapter object
+ * @scmd: pointer to scsi command object
+ * @raid_device: pointer to raid device data structure
+ * @mpi_request: pointer to the SCSI_IO reqest message frame
+ * @smid: system request message index
+ *
+ * Returns nothing
+ */
+void
+mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
+       struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
+       u16 smid)
+{
+       sector_t v_lba, p_lba, stripe_off, column, io_size;
+       u32 stripe_sz, stripe_exp;
+       u8 num_pds, cmd = scmd->cmnd[0];
+
+       if (cmd != READ_10 && cmd != WRITE_10 &&
+           cmd != READ_16 && cmd != WRITE_16)
+               return;
+
+       if (cmd == READ_10 || cmd == WRITE_10)
+               v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]);
+       else
+               v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]);
+
+       io_size = scsi_bufflen(scmd) >> raid_device->block_exponent;
+
+       if (v_lba + io_size - 1 > raid_device->max_lba)
+               return;
+
+       stripe_sz = raid_device->stripe_sz;
+       stripe_exp = raid_device->stripe_exponent;
+       stripe_off = v_lba & (stripe_sz - 1);
+
+       /* Return unless IO falls within a stripe */
+       if (stripe_off + io_size > stripe_sz)
+               return;
+
+       num_pds = raid_device->num_pds;
+       p_lba = v_lba >> stripe_exp;
+       column = sector_div(p_lba, num_pds);
+       p_lba = (p_lba << stripe_exp) + stripe_off;
+       mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]);
+
+       if (cmd == READ_10 || cmd == WRITE_10)
+               put_unaligned_be32(lower_32_bits(p_lba),
+                                  &mpi_request->CDB.CDB32[2]);
+       else
+               put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]);
+
+       mpt3sas_scsi_direct_io_set(ioc, smid, 1);
+}