diff mbox series

[02/24] mpi3mr: base driver code

Message ID 20201222101156.98308-3-kashyap.desai@broadcom.com (mailing list archive)
State Changes Requested
Headers show
Series Introducing mpi3mr driver | expand

Commit Message

Kashyap Desai Dec. 22, 2020, 10:11 a.m. UTC
This patch covers basic pci device driver requirements -
device probe, memory allocation, mapping system registers,
allocate irq lines etc.

Source is managed in mainly three different files.

mpi3mr_fw.c -	Keep common code which interact with underlying fw/hw.
mpi3mr_os.c -	Keep common code which interact with scsi midlayer.
mpi3mr_app.c -	Keep common code which interact with application/ioctl.
		This is currently work in progress.

Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com>
Cc: sathya.prakash@broadcom.com
---
 drivers/scsi/mpi3mr/Makefile       |    4 +
 drivers/scsi/mpi3mr/mpi3mr.h       |  526 ++++++++
 drivers/scsi/mpi3mr/mpi3mr_debug.h |   60 +
 drivers/scsi/mpi3mr/mpi3mr_fw.c    | 1819 ++++++++++++++++++++++++++++
 drivers/scsi/mpi3mr/mpi3mr_os.c    |  368 ++++++
 5 files changed, 2777 insertions(+)
 create mode 100644 drivers/scsi/mpi3mr/Makefile
 create mode 100644 drivers/scsi/mpi3mr/mpi3mr.h
 create mode 100644 drivers/scsi/mpi3mr/mpi3mr_debug.h
 create mode 100644 drivers/scsi/mpi3mr/mpi3mr_fw.c
 create mode 100644 drivers/scsi/mpi3mr/mpi3mr_os.c

Comments

kernel test robot Dec. 27, 2020, 2:14 p.m. UTC | #1
Hi Kashyap,

I love your patch! Yet something to improve:

[auto build test ERROR on mkp-scsi/for-next]
[also build test ERROR on scsi/for-next v5.10 next-20201223]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Kashyap-Desai/Introducing-mpi3mr-driver/20201222-181732
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next
config: arc-allyesconfig (attached as .config)
compiler: arceb-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/f1507bd10ed4f38cbe02ec83c46bcac080b681cb
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Kashyap-Desai/Introducing-mpi3mr-driver/20201222-181732
        git checkout f1507bd10ed4f38cbe02ec83c46bcac080b681cb
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All error/warnings (new ones prefixed by >>):

   drivers/scsi/mpi3mr/mpi3mr_fw.c: In function 'mpi3mr_isr':
   drivers/scsi/mpi3mr/mpi3mr_fw.c:315:6: warning: variable 'midx' set but not used [-Wunused-but-set-variable]
     315 |  u16 midx;
         |      ^~~~
   drivers/scsi/mpi3mr/mpi3mr_fw.c:314:21: warning: variable 'mrioc' set but not used [-Wunused-but-set-variable]
     314 |  struct mpi3mr_ioc *mrioc;
         |                     ^~~~~
   In file included from include/linux/printk.h:7,
                    from include/linux/kernel.h:16,
                    from include/linux/list.h:9,
                    from include/linux/rculist.h:10,
                    from include/linux/pid.h:5,
                    from include/linux/sched.h:14,
                    from include/linux/blkdev.h:5,
                    from drivers/scsi/mpi3mr/mpi3mr.h:13,
                    from drivers/scsi/mpi3mr/mpi3mr_fw.c:10:
   drivers/scsi/mpi3mr/mpi3mr_fw.c: In function 'mpi3mr_process_factsdata':
   include/linux/kern_levels.h:5:18: warning: format '%ld' expects argument of type 'long int', but argument 3 has type 'unsigned int' [-Wformat=]
       5 | #define KERN_SOH "\001"  /* ASCII Start Of Header */
         |                  ^~~~~~
   include/linux/kern_levels.h:12:22: note: in expansion of macro 'KERN_SOH'
      12 | #define KERN_WARNING KERN_SOH "4" /* warning conditions */
         |                      ^~~~~~~~
   include/linux/printk.h:353:9: note: in expansion of macro 'KERN_WARNING'
     353 |  printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
         |         ^~~~~~~~~~~~
   drivers/scsi/mpi3mr/mpi3mr_debug.h:49:2: note: in expansion of macro 'pr_warn'
      49 |  pr_warn("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
         |  ^~~~~~~
   drivers/scsi/mpi3mr/mpi3mr_fw.c:933:3: note: in expansion of macro 'ioc_warn'
     933 |   ioc_warn(mrioc,
         |   ^~~~~~~~
   drivers/scsi/mpi3mr/mpi3mr_fw.c:934:49: note: format string is defined here
     934 |       "IOCFactsdata length mismatch driver_sz(%ld) firmware_sz(%d)\n",
         |                                               ~~^
         |                                                 |
         |                                                 long int
         |                                               %d
   drivers/scsi/mpi3mr/mpi3mr_fw.c: In function 'mpi3mr_cleanup_resources':
>> drivers/scsi/mpi3mr/mpi3mr_fw.c:1332:16: warning: passing argument 1 of 'iounmap' discards 'volatile' qualifier from pointer target type [-Wdiscarded-qualifiers]
    1332 |   iounmap(mrioc->sysif_regs);
         |           ~~~~~^~~~~~~~~~~~
   In file included from include/linux/io.h:13,
                    from include/linux/irq.h:20,
                    from include/asm-generic/hardirq.h:13,
                    from ./arch/arc/include/generated/asm/hardirq.h:1,
                    from include/linux/hardirq.h:10,
                    from include/linux/highmem.h:10,
                    from include/linux/pagemap.h:11,
                    from include/linux/blkdev.h:14,
                    from drivers/scsi/mpi3mr/mpi3mr.h:13,
                    from drivers/scsi/mpi3mr/mpi3mr_fw.c:10:
   arch/arc/include/asm/io.h:35:41: note: expected 'const void *' but argument is of type 'volatile Mpi3SysIfRegs_t *' {aka 'volatile struct _MPI3_SYSIF_REGISTERS *'}
      35 | extern void iounmap(const void __iomem *addr);
         |                     ~~~~~~~~~~~~~~~~~~~~^~~~
   drivers/scsi/mpi3mr/mpi3mr_fw.c: In function 'mpi3mr_init_ioc':
>> drivers/scsi/mpi3mr/mpi3mr_fw.c:1476:14: error: implicit declaration of function 'readq'; did you mean 'readl'? [-Werror=implicit-function-declaration]
    1476 |  base_info = readq(&mrioc->sysif_regs->IOCInformation);
         |              ^~~~~
         |              readl
   cc1: some warnings being treated as errors


vim +1476 drivers/scsi/mpi3mr/mpi3mr_fw.c

  1315	
  1316	
  1317	/**
  1318	 * mpi3mr_cleanup_resources - Free PCI resources
  1319	 * @mrioc: Adapter instance reference
  1320	 *
  1321	 * Unmap PCI device memory and disable PCI device.
  1322	 *
  1323	 * Return: 0 on success and non-zero on failure.
  1324	 */
  1325	void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc)
  1326	{
  1327		struct pci_dev *pdev = mrioc->pdev;
  1328	
  1329		mpi3mr_cleanup_isr(mrioc);
  1330	
  1331		if (mrioc->sysif_regs) {
> 1332			iounmap(mrioc->sysif_regs);
  1333			mrioc->sysif_regs = NULL;
  1334		}
  1335	
  1336		if (pci_is_enabled(pdev)) {
  1337			if (mrioc->bars)
  1338				pci_release_selected_regions(pdev, mrioc->bars);
  1339			pci_disable_device(pdev);
  1340		}
  1341	}
  1342	
  1343	/**
  1344	 * mpi3mr_setup_resources - Enable PCI resources
  1345	 * @mrioc: Adapter instance reference
  1346	 *
  1347	 * Enable PCI device memory, MSI-x registers and set DMA mask.
  1348	 *
  1349	 * Return: 0 on success and non-zero on failure.
  1350	 */
  1351	int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc)
  1352	{
  1353		struct pci_dev *pdev = mrioc->pdev;
  1354		u32 memap_sz = 0;
  1355		int i, retval = 0, capb = 0;
  1356		u16 message_control;
  1357		u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask :
  1358		    (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) &&
  1359		    (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64):DMA_BIT_MASK(32));
  1360	
  1361		if (pci_enable_device_mem(pdev)) {
  1362			ioc_err(mrioc, "pci_enable_device_mem: failed\n");
  1363			retval = -ENODEV;
  1364			goto out_failed;
  1365		}
  1366	
  1367		capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
  1368		if (!capb) {
  1369			ioc_err(mrioc, "Unable to find MSI-X Capabilities\n");
  1370			retval = -ENODEV;
  1371			goto out_failed;
  1372		}
  1373		mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
  1374	
  1375		if (pci_request_selected_regions(pdev, mrioc->bars,
  1376		    mrioc->driver_name)) {
  1377			ioc_err(mrioc, "pci_request_selected_regions: failed\n");
  1378			retval = -ENODEV;
  1379			goto out_failed;
  1380		}
  1381	
  1382		for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) {
  1383			if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
  1384				mrioc->sysif_regs_phys = pci_resource_start(pdev, i);
  1385				memap_sz = pci_resource_len(pdev, i);
  1386				mrioc->sysif_regs =
  1387				    ioremap(mrioc->sysif_regs_phys, memap_sz);
  1388				break;
  1389			}
  1390		}
  1391	
  1392		pci_set_master(pdev);
  1393	
  1394		retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
  1395		if (retval) {
  1396			if (dma_mask != DMA_BIT_MASK(32)) {
  1397				ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n");
  1398				dma_mask = DMA_BIT_MASK(32);
  1399				retval = dma_set_mask_and_coherent(&pdev->dev,
  1400				    dma_mask);
  1401			}
  1402			if (retval) {
  1403				mrioc->dma_mask = 0;
  1404				ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n");
  1405				goto out_failed;
  1406			}
  1407		}
  1408		mrioc->dma_mask = dma_mask;
  1409	
  1410		if (mrioc->sysif_regs == NULL) {
  1411			ioc_err(mrioc,
  1412			    "Unable to map adapter memory or resource not found\n");
  1413			retval = -EINVAL;
  1414			goto out_failed;
  1415		}
  1416	
  1417		pci_read_config_word(pdev, capb + 2, &message_control);
  1418		mrioc->msix_count = (message_control & 0x3FF) + 1;
  1419	
  1420		pci_save_state(pdev);
  1421	
  1422		pci_set_drvdata(pdev, mrioc->shost);
  1423	
  1424		mpi3mr_ioc_disable_intr(mrioc);
  1425	
  1426		ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
  1427		    (unsigned long long)mrioc->sysif_regs_phys,
  1428		    mrioc->sysif_regs, memap_sz);
  1429		ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n",
  1430		    mrioc->msix_count);
  1431		return retval;
  1432	
  1433	out_failed:
  1434		mpi3mr_cleanup_resources(mrioc);
  1435		return retval;
  1436	}
  1437	
  1438	/**
  1439	 * mpi3mr_init_ioc - Initialize the controller
  1440	 * @mrioc: Adapter instance reference
  1441	 *
  1442	 * This the controller initialization routine, executed either
  1443	 * after soft reset or from pci probe callback.
  1444	 * Setup the required resources, memory map the controller
  1445	 * registers, create admin and operational reply queue pairs,
  1446	 * allocate required memory for reply pool, sense buffer pool,
  1447	 * issue IOC init request to the firmware, unmask the events and
  1448	 * issue port enable to discover SAS/SATA/NVMe devies and RAID
  1449	 * volumes.
  1450	 *
  1451	 * Return: 0 on success and non-zero on failure.
  1452	 */
  1453	int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
  1454	{
  1455		int retval = 0;
  1456		enum mpi3mr_iocstate ioc_state;
  1457		u64 base_info;
  1458		u32 timeout;
  1459		u32 ioc_status, ioc_config;
  1460		Mpi3IOCFactsData_t facts_data;
  1461	
  1462		mrioc->change_count = 0;
  1463		mrioc->cpu_count = num_online_cpus();
  1464		retval = mpi3mr_setup_resources(mrioc);
  1465		if (retval) {
  1466			ioc_err(mrioc, "Failed to setup resources:error %d\n",
  1467			    retval);
  1468			goto out_nocleanup;
  1469		}
  1470		ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
  1471		ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
  1472	
  1473		ioc_info(mrioc, "SOD status %x configuration %x\n",
  1474		    ioc_status, ioc_config);
  1475	
> 1476		base_info = readq(&mrioc->sysif_regs->IOCInformation);
  1477		ioc_info(mrioc, "SOD base_info %llx\n",	base_info);
  1478	
  1479		/*The timeout value is in 2sec unit, changing it to seconds*/
  1480		mrioc->ready_timeout =
  1481		    ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
  1482		    MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
  1483	
  1484		ioc_info(mrioc, "IOC ready timeout %d\n", mrioc->ready_timeout);
  1485	
  1486		ioc_state = mpi3mr_get_iocstate(mrioc);
  1487		ioc_info(mrioc, "IOC in %s state during detection\n",
  1488		    mpi3mr_iocstate_name(ioc_state));
  1489	
  1490		if (ioc_state == MRIOC_STATE_BECOMING_READY ||
  1491				ioc_state == MRIOC_STATE_RESET_REQUESTED) {
  1492			timeout = mrioc->ready_timeout * 10;
  1493			do {
  1494				msleep(100);
  1495			} while (--timeout);
  1496	
  1497			ioc_state = mpi3mr_get_iocstate(mrioc);
  1498			ioc_info(mrioc,
  1499				"IOC in %s state after waiting for reset time\n",
  1500				mpi3mr_iocstate_name(ioc_state));
  1501		}
  1502	
  1503		if (ioc_state == MRIOC_STATE_READY) {
  1504			retval = mpi3mr_issue_and_process_mur(mrioc,
  1505			    MPI3MR_RESET_FROM_BRINGUP);
  1506			if (retval) {
  1507				ioc_err(mrioc, "Failed to MU reset IOC error %d\n",
  1508				    retval);
  1509			}
  1510			ioc_state = mpi3mr_get_iocstate(mrioc);
  1511		}
  1512		if (ioc_state != MRIOC_STATE_RESET) {
  1513			mpi3mr_print_fault_info(mrioc);
  1514			retval = mpi3mr_issue_reset(mrioc,
  1515			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
  1516			    MPI3MR_RESET_FROM_BRINGUP);
  1517			if (retval) {
  1518				ioc_err(mrioc,
  1519				    "%s :Failed to soft reset IOC error %d\n",
  1520				    __func__, retval);
  1521				goto out_failed;
  1522			}
  1523		}
  1524		ioc_state = mpi3mr_get_iocstate(mrioc);
  1525		if (ioc_state != MRIOC_STATE_RESET) {
  1526			ioc_err(mrioc, "Cannot bring IOC to reset state\n");
  1527			goto out_failed;
  1528		}
  1529	
  1530		retval = mpi3mr_setup_admin_qpair(mrioc);
  1531		if (retval) {
  1532			ioc_err(mrioc, "Failed to setup admin Qs: error %d\n",
  1533			    retval);
  1534			goto out_failed;
  1535		}
  1536	
  1537		retval = mpi3mr_bring_ioc_ready(mrioc);
  1538		if (retval) {
  1539			ioc_err(mrioc, "Failed to bring ioc ready: error %d\n",
  1540			    retval);
  1541			goto out_failed;
  1542		}
  1543	
  1544		retval = mpi3mr_setup_isr(mrioc, 1);
  1545		if (retval) {
  1546			ioc_err(mrioc, "Failed to setup ISR error %d\n",
  1547			    retval);
  1548			goto out_failed;
  1549		}
  1550	
  1551		retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
  1552		if (retval) {
  1553			ioc_err(mrioc, "Failed to Issue IOC Facts %d\n",
  1554			    retval);
  1555			goto out_failed;
  1556		}
  1557	
  1558		mpi3mr_process_factsdata(mrioc, &facts_data);
  1559		retval = mpi3mr_check_reset_dma_mask(mrioc);
  1560		if (retval) {
  1561			ioc_err(mrioc, "Resetting dma mask failed %d\n",
  1562			    retval);
  1563			goto out_failed;
  1564		}
  1565	
  1566		retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
  1567		if (retval) {
  1568			ioc_err(mrioc,
  1569			    "%s :Failed to allocated reply sense buffers %d\n",
  1570			    __func__, retval);
  1571			goto out_failed;
  1572		}
  1573	
  1574		retval = mpi3mr_alloc_chain_bufs(mrioc);
  1575		if (retval) {
  1576			ioc_err(mrioc, "Failed to allocated chain buffers %d\n",
  1577			    retval);
  1578			goto out_failed;
  1579		}
  1580	
  1581		retval = mpi3mr_issue_iocinit(mrioc);
  1582		if (retval) {
  1583			ioc_err(mrioc, "Failed to Issue IOC Init %d\n",
  1584			    retval);
  1585			goto out_failed;
  1586		}
  1587		mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs;
  1588		writel(mrioc->reply_free_queue_host_index,
  1589		    &mrioc->sysif_regs->ReplyFreeHostIndex);
  1590	
  1591		mrioc->sbq_host_index = mrioc->num_sense_bufs;
  1592		writel(mrioc->sbq_host_index,
  1593		    &mrioc->sysif_regs->SenseBufferFreeHostIndex);
  1594	
  1595		retval = mpi3mr_setup_isr(mrioc, 0);
  1596		if (retval) {
  1597			ioc_err(mrioc, "Failed to re-setup ISR, error %d\n",
  1598			    retval);
  1599			goto out_failed;
  1600		}
  1601	
  1602		return retval;
  1603	
  1604	out_failed:
  1605		mpi3mr_cleanup_ioc(mrioc);
  1606	out_nocleanup:
  1607		return retval;
  1608	}
  1609	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hannes Reinecke Feb. 23, 2021, 12:55 p.m. UTC | #2
On 12/22/20 11:11 AM, Kashyap Desai wrote:
> This patch covers basic pci device driver requirements -
> device probe, memory allocation, mapping system registers,
> allocate irq lines etc.
> 
> Source is managed in mainly three different files.
> 
> mpi3mr_fw.c -	Keep common code which interact with underlying fw/hw.
> mpi3mr_os.c -	Keep common code which interact with scsi midlayer.
> mpi3mr_app.c -	Keep common code which interact with application/ioctl.
> 		This is currently work in progress.
> 
> Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com>
> Cc: sathya.prakash@broadcom.com
> ---
>  drivers/scsi/mpi3mr/Makefile       |    4 +
>  drivers/scsi/mpi3mr/mpi3mr.h       |  526 ++++++++
>  drivers/scsi/mpi3mr/mpi3mr_debug.h |   60 +
>  drivers/scsi/mpi3mr/mpi3mr_fw.c    | 1819 ++++++++++++++++++++++++++++
>  drivers/scsi/mpi3mr/mpi3mr_os.c    |  368 ++++++
>  5 files changed, 2777 insertions(+)
>  create mode 100644 drivers/scsi/mpi3mr/Makefile
>  create mode 100644 drivers/scsi/mpi3mr/mpi3mr.h
>  create mode 100644 drivers/scsi/mpi3mr/mpi3mr_debug.h
>  create mode 100644 drivers/scsi/mpi3mr/mpi3mr_fw.c
>  create mode 100644 drivers/scsi/mpi3mr/mpi3mr_os.c
> 
> diff --git a/drivers/scsi/mpi3mr/Makefile b/drivers/scsi/mpi3mr/Makefile
> new file mode 100644
> index 000000000000..7c2063e04c81
> --- /dev/null
> +++ b/drivers/scsi/mpi3mr/Makefile
> @@ -0,0 +1,4 @@
> +# mpi3mr makefile
> +obj-m += mpi3mr.o
> +mpi3mr-y +=  mpi3mr_os.o     \
> +		mpi3mr_fw.o \
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> new file mode 100644
> index 000000000000..dd79b12218e1
> --- /dev/null
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -0,0 +1,526 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Driver for Broadcom MPI3 Storage Controllers
> + *
> + * Copyright (C) 2017-2020 Broadcom Inc.
> + *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
> + *
> + */
> +
> +#ifndef MPI3MR_H_INCLUDED
> +#define MPI3MR_H_INCLUDED
> +
> +#include <linux/blkdev.h>
> +#include <linux/blk-mq.h>
> +#include <linux/blk-mq-pci.h>
> +#include <linux/delay.h>
> +#include <linux/dmapool.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/poll.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include <linux/uaccess.h>
> +#include <linux/utsname.h>
> +#include <linux/version.h>
> +#include <linux/workqueue.h>
> +#include <asm/unaligned.h>
> +#include <scsi/scsi.h>
> +#include <scsi/scsi_cmnd.h>
> +#include <scsi/scsi_dbg.h>
> +#include <scsi/scsi_device.h>
> +#include <scsi/scsi_host.h>
> +#include <scsi/scsi_tcq.h>
> +
> +#include "mpi/mpi30_api.h"
> +#include "mpi3mr_debug.h"
> +
> +/* Global list and lock for storing multiple adapters managed by the driver */
> +extern spinlock_t mrioc_list_lock;
> +extern struct list_head mrioc_list;
> +
> +#define MPI3MR_DRIVER_VERSION	"00.255.45.01"
> +#define MPI3MR_DRIVER_RELDATE	"12-December-2020"
> +
> +#define MPI3MR_DRIVER_NAME	"mpi3mr"
> +#define MPI3MR_DRIVER_LICENSE	"GPL"
> +#define MPI3MR_DRIVER_AUTHOR	"Broadcom Inc. <mpi3mr-linuxdrv.pdl@broadcom.com>"
> +#define MPI3MR_DRIVER_DESC	"MPI3 Storage Controller Device Driver"
> +
> +#define MPI3MR_NAME_LENGTH	32
> +#define IOCNAME			"%s: "
> +
> +/* Definitions for internal SGL and Chain SGL buffers */
> +#define MPI3MR_PAGE_SIZE_4K		4096
> +#define MPI3MR_SG_DEPTH		(PAGE_SIZE/sizeof(Mpi3SGESimple_t))
> +
> +/* Definitions for MAX values for shost */
> +#define MPI3MR_MAX_CMDS_LUN	7
> +#define MPI3MR_MAX_CDB_LENGTH	32
> +
> +/* Admin queue management definitions */
> +#define MPI3MR_ADMIN_REQ_Q_SIZE		(2 * MPI3MR_PAGE_SIZE_4K)
> +#define MPI3MR_ADMIN_REPLY_Q_SIZE	(4 * MPI3MR_PAGE_SIZE_4K)
> +#define MPI3MR_ADMIN_REQ_FRAME_SZ	128
> +#define MPI3MR_ADMIN_REPLY_FRAME_SZ	16
> +
> +
> +/* Reserved Host Tag definitions */
> +#define MPI3MR_HOSTTAG_INVALID		0xFFFF
> +#define MPI3MR_HOSTTAG_INITCMDS		1
> +#define MPI3MR_HOSTTAG_IOCTLCMDS	2
> +#define MPI3MR_HOSTTAG_BLK_TMS		5
> +
> +#define MPI3MR_NUM_DEVRMCMD		1
> +#define MPI3MR_HOSTTAG_DEVRMCMD_MIN	(MPI3MR_HOSTTAG_BLK_TMS + 1)
> +#define MPI3MR_HOSTTAG_DEVRMCMD_MAX	(MPI3MR_HOSTTAG_DEVRMCMD_MIN + \
> +						MPI3MR_NUM_DEVRMCMD - 1)
> +
> +#define MPI3MR_INTERNAL_CMDS_RESVD     MPI3MR_HOSTTAG_DEVRMCMD_MAX
> +
> +/* Reduced resource count definition for crash kernel */
> +#define MPI3MR_HOST_IOS_KDUMP		128
> +
> +/* command/controller interaction timeout definitions in seconds */
> +#define MPI3MR_INTADMCMD_TIMEOUT		10
> +#define MPI3MR_RESETTM_TIMEOUT			30
> +#define MPI3MR_DEFAULT_SHUTDOWN_TIME		120
> +
> +#define MPI3MR_WATCHDOG_INTERVAL		1000 /* in milli seconds */
> +
> +/* Internal admin command state definitions*/
> +#define MPI3MR_CMD_NOTUSED	0x8000
> +#define MPI3MR_CMD_COMPLETE	0x0001
> +#define MPI3MR_CMD_PENDING	0x0002
> +#define MPI3MR_CMD_REPLY_VALID	0x0004
> +#define MPI3MR_CMD_RESET	0x0008
> +
> +/* Definitions for Event replies and sense buffer allocated per controller */
> +#define MPI3MR_NUM_EVT_REPLIES	64
> +#define MPI3MR_SENSEBUF_SZ	256
> +#define MPI3MR_SENSEBUF_FACTOR	3
> +#define MPI3MR_CHAINBUF_FACTOR	3
> +
> +/* Invalid target device handle */
> +#define MPI3MR_INVALID_DEV_HANDLE	0xFFFF
> +
> +/* Controller Reset related definitions */
> +#define MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT	5
> +#define MPI3MR_MAX_RESET_RETRY_COUNT		3
> +
> +/* ResponseCode definitions */
> +#define MPI3MR_RI_MASK_RESPCODE		(0x000000FF)
> +#define MPI3MR_RSP_TM_COMPLETE		0x00
> +#define MPI3MR_RSP_INVALID_FRAME	0x02
> +#define MPI3MR_RSP_TM_NOT_SUPPORTED	0x04
> +#define MPI3MR_RSP_TM_FAILED		0x05
> +#define MPI3MR_RSP_TM_SUCCEEDED		0x08
> +#define MPI3MR_RSP_TM_INVALID_LUN	0x09
> +#define MPI3MR_RSP_TM_OVERLAPPED_TAG	0x0A
> +#define MPI3MR_RSP_IO_QUEUED_ON_IOC \
> +			MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC
> +
> +/* SGE Flag definition */
> +#define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \
> +	(MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \
> +	MPI3_SGE_FLAGS_END_OF_LIST)
> +
> +/* IOC State definitions */
> +enum mpi3mr_iocstate {
> +	MRIOC_STATE_READY = 1,
> +	MRIOC_STATE_RESET,
> +	MRIOC_STATE_FAULT,
> +	MRIOC_STATE_BECOMING_READY,
> +	MRIOC_STATE_RESET_REQUESTED,
> +	MRIOC_STATE_UNRECOVERABLE,
> +};
> +
> +/* Reset reason code definitions*/
> +enum mpi3mr_reset_reason {
> +	MPI3MR_RESET_FROM_BRINGUP = 1,
> +	MPI3MR_RESET_FROM_FAULT_WATCH = 2,
> +	MPI3MR_RESET_FROM_IOCTL = 3,
> +	MPI3MR_RESET_FROM_EH_HOS = 4,
> +	MPI3MR_RESET_FROM_TM_TIMEOUT = 5,
> +	MPI3MR_RESET_FROM_IOCTL_TIMEOUT = 6,
> +	MPI3MR_RESET_FROM_MUR_FAILURE = 7,
> +	MPI3MR_RESET_FROM_CTLR_CLEANUP = 8,
> +	MPI3MR_RESET_FROM_CIACTIV_FAULT = 9,
> +	MPI3MR_RESET_FROM_PE_TIMEOUT = 10,
> +	MPI3MR_RESET_FROM_TSU_TIMEOUT = 11,
> +	MPI3MR_RESET_FROM_DELREQQ_TIMEOUT = 12,
> +	MPI3MR_RESET_FROM_DELREPQ_TIMEOUT = 13,
> +	MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT = 14,
> +	MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT = 15,
> +	MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT = 16,
> +	MPI3MR_RESET_FROM_IOCINIT_TIMEOUT = 17,
> +	MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT = 18,
> +	MPI3MR_RESET_FROM_EVTACK_TIMEOUT = 19,
> +	MPI3MR_RESET_FROM_CIACTVRST_TIMER = 20,
> +	MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT = 21,
> +};
> +
> +/**
> + * struct mpi3mr_compimg_ver - replica of component image
> + * version defined in mpi30_image.h in host endianness
> + *
> + */
> +struct mpi3mr_compimg_ver {
> +	u16 build_num;
> +	u16 cust_id;
> +	u8 ph_minor;
> +	u8 ph_major;
> +	u8 gen_minor;
> +	u8 gen_major;
> +};
> +
> +/**
> + * struct mpi3mr_ioc_facs - replica of component image version
> + * defined in mpi30_ioc.h in host endianness
> + *
> + */
> +struct mpi3mr_ioc_facts {
> +	u32 ioc_capabilities;
> +	struct mpi3mr_compimg_ver fw_ver;
> +	u32 mpi_version;
> +	u16 max_reqs;
> +	u16 product_id;
> +	u16 op_req_sz;
> +	u16 reply_sz;
> +	u16 exceptions;
> +	u16 max_perids;
> +	u16 max_pds;
> +	u16 max_sasexpanders;
> +	u16 max_sasinitiators;
> +	u16 max_enclosures;
> +	u16 max_pcieswitches;
> +	u16 max_nvme;
> +	u16 max_vds;
> +	u16 max_hpds;
> +	u16 max_advhpds;
> +	u16 max_raidpds;
> +	u16 min_devhandle;
> +	u16 max_devhandle;
> +	u16 max_op_req_q;
> +	u16 max_op_reply_q;
> +	u16 shutdown_timeout;
> +	u8 ioc_num;
> +	u8 who_init;
> +	u16 max_msix_vectors;
> +	u8 personality;
> +	u8 dma_mask;
> +	u8 protocol_flags;
> +	u8 sge_mod_mask;
> +	u8 sge_mod_value;
> +	u8 sge_mod_shift;
> +};
> +
> +/**
> + * struct op_req_qinfo -  Operational Request Queue Information
> + *
> + * @ci: consumer index
> + * @pi: producer index
> + */
> +struct op_req_qinfo {
> +	u16 ci;
> +	u16 pi;
> +};
> +
> +/**
> + * struct op_reply_qinfo -  Operational Reply Queue Information
> + *
> + * @ci: consumer index
> + * @qid: Queue Id starting from 1
> + */
> +struct op_reply_qinfo {
> +	u16 ci;
> +	u16 qid;
> +};
> +
> +/**
> + * struct mpi3mr_intr_info -  Interrupt cookie information
> + *
> + * @mrioc: Adapter instance reference
> + * @msix_index: MSIx index
> + * @op_reply_q: Associated operational reply queue
> + * @name: Dev name for the irq claiming device
> + */
> +struct mpi3mr_intr_info {
> +	struct mpi3mr_ioc *mrioc;
> +	u16 msix_index;
> +	struct op_reply_qinfo *op_reply_q;
> +	char name[MPI3MR_NAME_LENGTH];
> +};
> +
> +
> +typedef struct mpi3mr_drv_cmd DRV_CMD;
> +typedef void (*DRV_CMD_CALLBACK)(struct mpi3mr_ioc *mrioc,
> +	DRV_CMD *drv_cmd);
> +
> +/**
> + * struct mpi3mr_drv_cmd - Internal command tracker
> + *
> + * @mutex: Command mutex
> + * @done: Completeor for wakeup
> + * @reply: Firmware reply for internal commands
> + * @sensebuf: Sensebuf for SCSI IO commands
> + * @state: Command State
> + * @dev_handle: Firmware handle for device specific commands
> + * @ioc_status: IOC status from the firmware
> + * @ioc_loginfo:IOC log info from the firmware
> + * @is_waiting: Is the command issued in block mode
> + * @retry_count: Retry count for retriable commands
> + * @host_tag: Host tag used by the command
> + * @callback: Callback for non blocking commands
> + */
> +struct mpi3mr_drv_cmd {
> +	struct mutex mutex;
> +	struct completion done;
> +	void *reply;
> +	u8 *sensebuf;
> +	u16 state;
> +	u16 dev_handle;
> +	u16 ioc_status;
> +	u32 ioc_loginfo;
> +	u8 is_waiting;
> +	u8 retry_count;
> +	u16 host_tag;
> +	DRV_CMD_CALLBACK callback;
> +};
> +
> +
> +/**
> + * struct chain_element - memory descriptor structure to store
> + * virtual and dma addresses for chain elements.
> + *
> + * @addr: virtual address
> + * @dma_addr: dma address
> + */
> +struct chain_element {
> +	void *addr;
> +	dma_addr_t dma_addr;
> +};
> +
> +/**
> + * struct scmd_priv - SCSI command private data
> + *
> + * @host_tag: Host tag specific to operational queue
> + * @in_lld_scope: Command in LLD scope or not
> + * @scmd: SCSI Command pointer
> + * @req_q_idx: Operational request queue index
> + * @chain_idx: Chain frame index
> + * @mpi3mr_scsiio_req: MPI SCSI IO request
> + */
> +struct scmd_priv {
> +	u16 host_tag;
> +	u8 in_lld_scope;
> +	struct scsi_cmnd *scmd;
> +	u16 req_q_idx;
> +	int chain_idx;
> +	u8 mpi3mr_scsiio_req[MPI3MR_ADMIN_REQ_FRAME_SZ];
> +};
> +
> +/**
> + * struct mpi3mr_ioc - Adapter anchor structure stored in shost
> + * private data
> + *
> + * @list: List pointer
> + * @pdev: PCI device pointer
> + * @shost: Scsi_Host pointer
> + * @id: Controller ID
> + * @cpu_count: Number of online CPUs
> + * @name: Controller ASCII name
> + * @driver_name: Driver ASCII name
> + * @sysif_regs: System interface registers virtual address
> + * @sysif_regs_phys: System interface registers physical address
> + * @bars: PCI BARS
> + * @dma_mask: DMA mask
> + * @msix_count: Number of MSIX vectors used
> + * @intr_enabled: Is interrupts enabled
> + * @num_admin_req: Number of admin requests
> + * @admin_req_q_sz: Admin request queue size
> + * @admin_req_pi: Admin request queue producer index
> + * @admin_req_ci: Admin request queue consumer index
> + * @admin_req_base: Admin request queue base virtual address
> + * @admin_req_dma: Admin request queue base dma address
> + * @admin_req_lock: Admin queue access lock
> + * @num_admin_replies: Number of admin replies
> + * @admin_reply_q_sz: Admin reply queue size
> + * @admin_reply_ci: Admin reply queue consumer index
> + * @admin_reply_ephase:Admin reply queue expected phase
> + * @admin_reply_base: Admin reply queue base virtual address
> + * @admin_reply_dma: Admin reply queue base dma address
> + * @ready_timeout: Controller ready timeout
> + * @intr_info: Interrupt cookie pointer
> + * @intr_info_count: Number of interrupt cookies
> + * @num_queues: Number of operational queues
> + * @num_op_req_q: Number of operational request queues
> + * @req_qinfo: Operational request queue info pointer
> + * @num_op_reply_q: Number of operational reply queues
> + * @op_reply_qinfo: Operational reply queue info pointer
> + * @init_cmds: Command tracker for initialization commands
> + * @facts: Cached IOC facts data
> + * @op_reply_desc_sz: Operational reply descriptor size
> + * @num_reply_bufs: Number of reply buffers allocated
> + * @reply_buf_pool: Reply buffer pool
> + * @reply_buf: Reply buffer base virtual address
> + * @reply_buf_dma: Reply buffer DMA address
> + * @reply_buf_dma_max_address: Reply DMA address max limit
> + * @reply_free_qsz: Reply free queue size
> + * @reply_free_q_pool: Reply free queue pool
> + * @reply_free_q: Reply free queue base virtual address
> + * @reply_free_q_dma: Reply free queue base DMA address
> + * @reply_free_queue_lock: Reply free queue lock
> + * @reply_free_queue_host_index: Reply free queue host index
> + * @num_sense_bufs: Number of sense buffers
> + * @sense_buf_pool: Sense buffer pool
> + * @sense_buf: Sense buffer base virtual address
> + * @sense_buf_dma: Sense buffer base DMA address
> + * @sense_buf_q_sz: Sense buffer queue size
> + * @sense_buf_q_pool: Sense buffer queue pool
> + * @sense_buf_q: Sense buffer queue virtual address
> + * @sense_buf_q_dma: Sense buffer queue DMA address
> + * @sbq_lock: Sense buffer queue lock
> + * @sbq_host_index: Sense buffer queuehost index
> + * @is_driver_loading: Is driver still loading
> + * @max_host_ios: Maximum host I/O count
> + * @chain_buf_count: Chain buffer count
> + * @chain_buf_pool: Chain buffer pool
> + * @chain_sgl_list: Chain SGL list
> + * @chain_bitmap_sz: Chain buffer allocator bitmap size
> + * @chain_bitmap: Chain buffer allocator bitmap
> + * @reset_in_progress: Reset in progress flag
> + * @unrecoverable: Controller unrecoverable flag
> + * @logging_level: Controller debug logging level
> + * @current_event: Firmware event currently in process
> + * @driver_info: Driver, Kernel, OS information to firmware
> + * @change_count: Topology change count
> + */
> +struct mpi3mr_ioc {
> +	struct list_head list;
> +	struct pci_dev *pdev;
> +	struct Scsi_Host *shost;
> +	u8 id;
> +	int cpu_count;
> +
> +	char name[MPI3MR_NAME_LENGTH];
> +	char driver_name[MPI3MR_NAME_LENGTH];
> +
> +	Mpi3SysIfRegs_t __iomem *sysif_regs;
> +	resource_size_t sysif_regs_phys;
> +	int bars;
> +	u64 dma_mask;
> +
> +	u16 msix_count;
> +	u8 intr_enabled;
> +
> +	u16 num_admin_req;
> +	u32 admin_req_q_sz;
> +	u16 admin_req_pi;
> +	u16 admin_req_ci;
> +	void *admin_req_base;
> +	dma_addr_t admin_req_dma;
> +	spinlock_t admin_req_lock;
> +
> +	u16 num_admin_replies;
> +	u32 admin_reply_q_sz;
> +	u16 admin_reply_ci;
> +	u8 admin_reply_ephase;
> +	void *admin_reply_base;
> +	dma_addr_t admin_reply_dma;
> +
> +	u32 ready_timeout;
> +
> +	struct mpi3mr_intr_info *intr_info;

Please, be consistent.
If you must introduce typedefs for your internal structures, okay.
But then introduce typedefs for _all_ internal structures.
Or leave the typedefs and just use 'struct XXX'; which actually is the
recommended way for linux.

> +	u16 intr_info_count;
> +
> +	u16 num_queues;
> +	u16 num_op_req_q;
> +	struct op_req_qinfo *req_qinfo;
> +
> +	u16 num_op_reply_q;
> +	struct op_reply_qinfo *op_reply_qinfo;
> +
> +	struct mpi3mr_drv_cmd init_cmds;
> +	struct mpi3mr_ioc_facts facts;
> +	u16 op_reply_desc_sz;
> +
> +	u32 num_reply_bufs;
> +	struct dma_pool *reply_buf_pool;
> +	u8 *reply_buf;
> +	dma_addr_t reply_buf_dma;
> +	dma_addr_t reply_buf_dma_max_address;
> +
> +	u16 reply_free_qsz;
> +	struct dma_pool *reply_free_q_pool;
> +	U64 *reply_free_q;
> +	dma_addr_t reply_free_q_dma;
> +	spinlock_t reply_free_queue_lock;
> +	u32 reply_free_queue_host_index;
> +
> +	u32 num_sense_bufs;
> +	struct dma_pool *sense_buf_pool;
> +	u8 *sense_buf;
> +	dma_addr_t sense_buf_dma;
> +
> +	u16 sense_buf_q_sz;
> +	struct dma_pool *sense_buf_q_pool;
> +	U64 *sense_buf_q;
> +	dma_addr_t sense_buf_q_dma;
> +	spinlock_t sbq_lock;
> +	u32 sbq_host_index;
> +
> +	u8 is_driver_loading;
> +
> +	u16 max_host_ios;
> +
> +	u32 chain_buf_count;
> +	struct dma_pool *chain_buf_pool;
> +	struct chain_element *chain_sgl_list;
> +	u16  chain_bitmap_sz;
> +	void *chain_bitmap;
> +
> +	u8 reset_in_progress;
> +	u8 unrecoverable;
> +
> +	int logging_level;
> +
> +	struct mpi3mr_fwevt *current_event;
> +	Mpi3DriverInfoLayout_t driver_info;

See my comment about struct typedefs above.

> +	u16 change_count;
> +};
> +
> +int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc);
> +void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc);
> +int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc);
> +void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc);
> +int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
> +u16 admin_req_sz, u8 ignore_reset);
> +void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length,
> +			  dma_addr_t dma_addr);
> +void mpi3mr_build_zero_len_sge(void *paddr);
> +void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc,
> +				     dma_addr_t phys_addr);
> +void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
> +				     dma_addr_t phys_addr);
> +void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
> +				     u64 sense_buf_dma);
> +
> +void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc);
> +void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc);
> +
> +int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
> +			      u32 reset_reason, u8 snapdump);
> +void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc);
> +void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc);
> +
> +enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc);
> +
> +#endif /*MPI3MR_H_INCLUDED*/
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_debug.h b/drivers/scsi/mpi3mr/mpi3mr_debug.h
> new file mode 100644
> index 000000000000..d35f296d9325
> --- /dev/null
> +++ b/drivers/scsi/mpi3mr/mpi3mr_debug.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Driver for Broadcom MPI3 Storage Controllers
> + *
> + * Copyright (C) 2017-2020 Broadcom Inc.
> + *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
> + *
> + */
> +
> +#ifndef MPI3SAS_DEBUG_H_INCLUDED
> +
> +#define MPI3SAS_DEBUG_H_INCLUDED
> +
> +/*
> + * debug levels
> + */
> +#define MPI3_DEBUG			0x00000001
> +#define MPI3_DEBUG_MSG_FRAME		0x00000002
> +#define MPI3_DEBUG_SG			0x00000004
> +#define MPI3_DEBUG_EVENTS		0x00000008
> +#define MPI3_DEBUG_EVENT_WORK_TASK	0x00000010
> +#define MPI3_DEBUG_INIT			0x00000020
> +#define MPI3_DEBUG_EXIT			0x00000040
> +#define MPI3_DEBUG_FAIL			0x00000080
> +#define MPI3_DEBUG_TM			0x00000100
> +#define MPI3_DEBUG_REPLY		0x00000200
> +#define MPI3_DEBUG_HANDSHAKE		0x00000400
> +#define MPI3_DEBUG_CONFIG		0x00000800
> +#define MPI3_DEBUG_DL			0x00001000
> +#define MPI3_DEBUG_RESET		0x00002000
> +#define MPI3_DEBUG_SCSI			0x00004000
> +#define MPI3_DEBUG_IOCTL		0x00008000
> +#define MPI3_DEBUG_CSMISAS		0x00010000
> +#define MPI3_DEBUG_SAS			0x00020000
> +#define MPI3_DEBUG_TRANSPORT		0x00040000
> +#define MPI3_DEBUG_TASK_SET_FULL	0x00080000
> +#define MPI3_DEBUG_TRIGGER_DIAG		0x00200000
> +
> +
> +/*
> + * debug macros
> + */
> +
> +#define ioc_err(ioc, fmt, ...) \
> +	pr_err("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
> +#define ioc_notice(ioc, fmt, ...) \
> +	pr_notice("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
> +#define ioc_warn(ioc, fmt, ...) \
> +	pr_warn("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
> +#define ioc_info(ioc, fmt, ...) \
> +	pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
> +
> +
> +#define dbgprint(IOC, FMT, ...) \
> +	do { \
> +		if (IOC->logging_level & MPI3_DEBUG) \
> +			pr_info("%s: " FMT, (IOC)->name, ##__VA_ARGS__); \
> +	} while (0)
> +
> +#endif /* MPT3SAS_DEBUG_H_INCLUDED */
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> new file mode 100644
> index 000000000000..97eb7e6ec5c6
> --- /dev/null
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -0,0 +1,1819 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Driver for Broadcom MPI3 Storage Controllers
> + *
> + * Copyright (C) 2017-2020 Broadcom Inc.
> + *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
> + *
> + */
> +
> +#include "mpi3mr.h"
> +
> +#if defined(writeq) && defined(CONFIG_64BIT)
> +static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
> +{
> +	writeq(b, addr);
> +}
> +#else
> +static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
> +{
> +	__u64 data_out = b;
> +
> +	writel((u32)(data_out), addr);
> +	writel((u32)(data_out >> 32), (addr + 4));
> +}
> +#endif
> +
> +static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc)
> +{
> +	u16 i, max_vectors;
> +
> +	max_vectors = mrioc->intr_info_count;
> +
> +	for (i = 0; i < max_vectors; i++)
> +		synchronize_irq(pci_irq_vector(mrioc->pdev, i));
> +}
> +
> +void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc)
> +{
> +	mrioc->intr_enabled = 0;
> +	mpi3mr_sync_irqs(mrioc);
> +}
> +
> +void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc)
> +{
> +	mrioc->intr_enabled = 1;
> +}
> +
> +static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc)
> +{
> +	u16 i;
> +
> +	mpi3mr_ioc_disable_intr(mrioc);
> +
> +	if (!mrioc->intr_info)
> +		return;
> +
> +	for (i = 0; i < mrioc->intr_info_count; i++)
> +		free_irq(pci_irq_vector(mrioc->pdev, i),
> +		    (mrioc->intr_info + i));
> +
> +	kfree(mrioc->intr_info);
> +	mrioc->intr_info = NULL;
> +	mrioc->intr_info_count = 0;
> +	pci_free_irq_vectors(mrioc->pdev);
> +}
> +
> +void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length,
> +	dma_addr_t dma_addr)
> +{
> +	Mpi3SGESimple_t *sgel = paddr;
> +
> +	sgel->Flags = flags;
> +	sgel->Length = cpu_to_le32(length);
> +	sgel->Address = cpu_to_le64(dma_addr);
> +}
> +
> +void mpi3mr_build_zero_len_sge(void *paddr)
> +{
> +	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
> +
> +	mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1);
> +
> +}
> +void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
> +	dma_addr_t phys_addr)
> +{
> +	if (!phys_addr)
> +		return NULL;
> +
> +	if ((phys_addr < mrioc->reply_buf_dma) ||
> +	    (phys_addr > mrioc->reply_buf_dma_max_address))
> +		return NULL;
> +
> +	return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma);
> +}
> +
> +void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc,
> +	dma_addr_t phys_addr)
> +{
> +	if (!phys_addr)
> +		return NULL;
> +
> +	return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma);
> +}
> +
> +static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc,
> +	u64 reply_dma)
> +{
> +	u32 old_idx = 0;
> +
> +	spin_lock(&mrioc->reply_free_queue_lock);
> +	old_idx  =  mrioc->reply_free_queue_host_index;
> +	mrioc->reply_free_queue_host_index = (
> +	    (mrioc->reply_free_queue_host_index ==
> +	    (mrioc->reply_free_qsz - 1)) ? 0 :
> +	    (mrioc->reply_free_queue_host_index + 1));
> +	mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma);
> +	writel(mrioc->reply_free_queue_host_index,
> +	    &mrioc->sysif_regs->ReplyFreeHostIndex);
> +	spin_unlock(&mrioc->reply_free_queue_lock);
> +}
> +
> +void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
> +	u64 sense_buf_dma)
> +{
> +	u32 old_idx = 0;
> +
> +	spin_lock(&mrioc->sbq_lock);
> +	old_idx  =  mrioc->sbq_host_index;
> +	mrioc->sbq_host_index = ((mrioc->sbq_host_index ==
> +	    (mrioc->sense_buf_q_sz - 1)) ? 0 :
> +	    (mrioc->sbq_host_index + 1));
> +	mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma);
> +	writel(mrioc->sbq_host_index,
> +	    &mrioc->sysif_regs->SenseBufferFreeHostIndex);
> +	spin_unlock(&mrioc->sbq_lock);
> +}
> +
> +static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc,
> +	Mpi3DefaultReply_t *def_reply)
> +{
> +	Mpi3EventNotificationReply_t *event_reply =
> +	    (Mpi3EventNotificationReply_t *)def_reply;
> +
> +	mrioc->change_count = le16_to_cpu(event_reply->IOCChangeCount);
> +}
> +
> +static struct mpi3mr_drv_cmd *
> +mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
> +	Mpi3DefaultReply_t *def_reply)
> +{
> +	switch (host_tag) {
> +	case MPI3MR_HOSTTAG_INITCMDS:
> +		return &mrioc->init_cmds;
> +	case MPI3MR_HOSTTAG_INVALID:
> +		if (def_reply && def_reply->Function ==
> +		    MPI3_FUNCTION_EVENT_NOTIFICATION)
> +			mpi3mr_handle_events(mrioc, def_reply);
> +		return NULL;
> +	default:
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
> +	Mpi3DefaultReplyDescriptor_t *reply_desc, u64 *reply_dma)
> +{
> +	u16 reply_desc_type, host_tag = 0;
> +	u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
> +	u32 ioc_loginfo = 0;
> +	Mpi3StatusReplyDescriptor_t *status_desc;
> +	Mpi3AddressReplyDescriptor_t *addr_desc;
> +	Mpi3SuccessReplyDescriptor_t *success_desc;
> +	Mpi3DefaultReply_t *def_reply = NULL;
> +	struct mpi3mr_drv_cmd *cmdptr = NULL;
> +	Mpi3SCSIIOReply_t *scsi_reply;
> +	u8 *sense_buf = NULL;
> +
> +	*reply_dma = 0;
> +	reply_desc_type = le16_to_cpu(reply_desc->ReplyFlags) &
> +	    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
> +	switch (reply_desc_type) {
> +	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
> +		status_desc = (Mpi3StatusReplyDescriptor_t *)reply_desc;
> +		host_tag = le16_to_cpu(status_desc->HostTag);
> +		ioc_status = le16_to_cpu(status_desc->IOCStatus);
> +		if (ioc_status &
> +		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
> +			ioc_loginfo = le32_to_cpu(status_desc->IOCLogInfo);
> +		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
> +		break;
> +	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
> +		addr_desc = (Mpi3AddressReplyDescriptor_t *)reply_desc;
> +		*reply_dma = le64_to_cpu(addr_desc->ReplyFrameAddress);
> +		def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma);
> +		if (!def_reply)
> +			goto out;
> +		host_tag = le16_to_cpu(def_reply->HostTag);
> +		ioc_status = le16_to_cpu(def_reply->IOCStatus);
> +		if (ioc_status &
> +		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
> +			ioc_loginfo = le32_to_cpu(def_reply->IOCLogInfo);
> +		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
> +		if (def_reply->Function == MPI3_FUNCTION_SCSI_IO) {
> +			scsi_reply = (Mpi3SCSIIOReply_t *)def_reply;
> +			sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
> +			    le64_to_cpu(scsi_reply->SenseDataBufferAddress));
> +		}
> +		break;
> +	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
> +		success_desc = (Mpi3SuccessReplyDescriptor_t *)reply_desc;
> +		host_tag = le16_to_cpu(success_desc->HostTag);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply);
> +	if (cmdptr) {
> +		if (cmdptr->state & MPI3MR_CMD_PENDING) {
> +			cmdptr->state |= MPI3MR_CMD_COMPLETE;
> +			cmdptr->ioc_loginfo = ioc_loginfo;
> +			cmdptr->ioc_status = ioc_status;
> +			cmdptr->state &= ~MPI3MR_CMD_PENDING;
> +			if (def_reply) {
> +				cmdptr->state |= MPI3MR_CMD_REPLY_VALID;
> +				memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
> +				    mrioc->facts.reply_sz);
> +			}
> +			if (cmdptr->is_waiting) {
> +				complete(&cmdptr->done);
> +				cmdptr->is_waiting = 0;
> +			} else if (cmdptr->callback)
> +				cmdptr->callback(mrioc, cmdptr);
> +		}
> +	}
> +out:
> +	if (sense_buf)
> +		mpi3mr_repost_sense_buf(mrioc,
> +		    le64_to_cpu(scsi_reply->SenseDataBufferAddress));
> +}
> +
> +static int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
> +{
> +	u32 exp_phase = mrioc->admin_reply_ephase;
> +	u32 admin_reply_ci = mrioc->admin_reply_ci;
> +	u32 num_admin_replies = 0;
> +	u64 reply_dma = 0;
> +	Mpi3DefaultReplyDescriptor_t *reply_desc;
> +
> +	reply_desc = (Mpi3DefaultReplyDescriptor_t *)mrioc->admin_reply_base +
> +	    admin_reply_ci;
> +
> +	if ((le16_to_cpu(reply_desc->ReplyFlags) &
> +	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
> +		return 0;
> +
> +	do {
> +		mrioc->admin_req_ci = le16_to_cpu(reply_desc->RequestQueueCI);
> +		mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma);
> +		if (reply_dma)
> +			mpi3mr_repost_reply_buf(mrioc, reply_dma);
> +		num_admin_replies++;
> +		if (++admin_reply_ci == mrioc->num_admin_replies) {
> +			admin_reply_ci = 0;
> +			exp_phase ^= 1;
> +		}
> +		reply_desc =
> +		    (Mpi3DefaultReplyDescriptor_t *)mrioc->admin_reply_base +
> +		    admin_reply_ci;
> +		if ((le16_to_cpu(reply_desc->ReplyFlags) &
> +		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
> +			break;
> +	} while (1);
> +
> +	writel(admin_reply_ci, &mrioc->sysif_regs->AdminReplyQueueCI);
> +	mrioc->admin_reply_ci = admin_reply_ci;
> +	mrioc->admin_reply_ephase = exp_phase;
> +
> +	return num_admin_replies;
> +}
> +
> +static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
> +{
> +	struct mpi3mr_intr_info *intr_info = privdata;
> +	struct mpi3mr_ioc *mrioc;
> +	u16 midx;
> +	u32 num_admin_replies = 0;
> +
> +	if (!intr_info)
> +		return IRQ_NONE;
> +
> +	mrioc = intr_info->mrioc;
> +
> +	if (!mrioc->intr_enabled)
> +		return IRQ_NONE;
> +
> +	midx = intr_info->msix_index;
> +
> +	if (!midx)
> +		num_admin_replies = mpi3mr_process_admin_reply_q(mrioc);
> +
> +	if (num_admin_replies)
> +		return IRQ_HANDLED;
> +	else
> +		return IRQ_NONE;
> +}
> +
> +static irqreturn_t mpi3mr_isr(int irq, void *privdata)
> +{
> +	struct mpi3mr_intr_info *intr_info = privdata;
> +	struct mpi3mr_ioc *mrioc;
> +	u16 midx;
> +	int ret;
> +
> +	if (!intr_info)
> +		return IRQ_NONE;
> +
> +	mrioc = intr_info->mrioc;
> +	midx = intr_info->msix_index;
> +	/* Call primary ISR routine */
> +	ret = mpi3mr_isr_primary(irq, privdata);
> +
> +	return ret;
> +}
> +
> +/**
> + * mpi3mr_isr_poll - Reply queue polling routine
> + * @irq: IRQ
> + * @privdata: Interrupt info
> + *
> + * poll for pending I/O completions in a loop until pending I/Os
> + * present or controller queue depth I/Os are processed.
> + *
> + * Return: IRQ_NONE or IRQ_HANDLED
> + */
> +static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
> +{
> +	return IRQ_HANDLED;
> +}
> +
> +/**
> + * mpi3mr_request_irq - Request IRQ and register ISR
> + * @mrioc: Adapter instance reference
> + * @index: IRQ vector index
> + *
> + * Request threaded ISR with primary ISR and secondary
> + *
> + * Return: 0 on success and non zero on failures.
> + */
> +static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index)
> +{
> +	struct pci_dev *pdev = mrioc->pdev;
> +	struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index;
> +	int retval = 0;
> +
> +	intr_info->mrioc = mrioc;
> +	intr_info->msix_index = index;
> +	intr_info->op_reply_q = NULL;
> +
> +	snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d",
> +	    mrioc->driver_name, mrioc->id, index);
> +
> +	retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr,
> +	    mpi3mr_isr_poll, IRQF_ONESHOT, intr_info->name, intr_info);
> +	if (retval) {
> +		ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n",
> +		    intr_info->name, pci_irq_vector(pdev, index));
> +		return retval;
> +	}
> +

The point of having 'mpi3mr_isr_poll()' here is what exactly?

> +	return retval;
> +}
> +
> +/**
> + * mpi3mr_setup_isr - Setup ISR for the controller
> + * @mrioc: Adapter instance reference
> + * @setup_one: Request one IRQ or more
> + *
> + * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR
> + *
> + * Return: 0 on success and non zero on failures.
> + */
> +static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one)
> +{
> +	unsigned int irq_flags = PCI_IRQ_MSIX;
> +	u16 max_vectors = 0, i;
> +	int retval = 0;
> +	struct irq_affinity desc = { .pre_vectors =  1};
> +
> +
> +	mpi3mr_cleanup_isr(mrioc);
> +
> +	if (setup_one || reset_devices)
> +		max_vectors = 1;
> +	else {
> +		max_vectors =
> +		    min_t(int, mrioc->cpu_count + 1, mrioc->msix_count);
> +
> +		ioc_info(mrioc,
> +		    "MSI-X vectors supported: %d, no of cores: %d,",
> +		    mrioc->msix_count, mrioc->cpu_count);
> +		ioc_info(mrioc,
> +		    "MSI-x vectors requested: %d\n", max_vectors);
> +	}
> +
> +	irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
> +
> +	i = pci_alloc_irq_vectors_affinity(mrioc->pdev,
> +	    1, max_vectors, irq_flags, &desc);
> +	if (i <= 0) {
> +		ioc_err(mrioc, "Cannot alloc irq vectors\n");
> +		goto out_failed;
> +	}
> +	if (i != max_vectors) {
> +		ioc_info(mrioc,
> +		    "allocated vectors (%d) are less than configured (%d)\n",
> +		    i, max_vectors);
> +
> +		max_vectors = i;
> +	}
> +	mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info)*max_vectors,
> +	    GFP_KERNEL);
> +	if (!mrioc->intr_info) {
> +		retval = -1;
> +		pci_free_irq_vectors(mrioc->pdev);
> +		goto out_failed;
> +	}
> +	for (i = 0; i < max_vectors; i++) {
> +		retval = mpi3mr_request_irq(mrioc, i);
> +		if (retval) {
> +			mrioc->intr_info_count = i;
> +			goto out_failed;
> +		}
> +	}
> +	mrioc->intr_info_count = max_vectors;
> +	mpi3mr_ioc_enable_intr(mrioc);
> +	return retval;
> +out_failed:
> +	mpi3mr_cleanup_isr(mrioc);
> +
> +	return retval;
> +}
> +
> +static const struct {
> +	enum mpi3mr_iocstate value;
> +	char *name;
> +} mrioc_states[] = {
> +	{ MRIOC_STATE_READY, "ready" },
> +	{ MRIOC_STATE_FAULT, "fault" },
> +	{ MRIOC_STATE_RESET, "reset" },
> +	{ MRIOC_STATE_BECOMING_READY, "becoming ready" },
> +	{ MRIOC_STATE_RESET_REQUESTED, "reset requested" },
> +	{ MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" },
> +};
> +
> +static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)
> +{
> +	int i;
> +	char *name = NULL;
> +
> +	for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) {
> +		if (mrioc_states[i].value == mrioc_state) {
> +			name = mrioc_states[i].name;
> +			break;
> +		}
> +	}
> +	return name;
> +}
> +
> +
> +/**
> + * mpi3mr_print_fault_info - Display fault information
> + * @mrioc: Adapter instance reference
> + *
> + * Display the controller fault information if there is a
> + * controller fault.
> + *
> + * Return: Nothing.
> + */
> +static void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc)
> +{
> +	u32 ioc_status, code, code1, code2, code3;
> +
> +	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
> +
> +	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
> +		code = readl(&mrioc->sysif_regs->Fault);
> +		code1 = readl(&mrioc->sysif_regs->FaultInfo[0]);
> +		code2 = readl(&mrioc->sysif_regs->FaultInfo[1]);
> +		code3 = readl(&mrioc->sysif_regs->FaultInfo[2]);
> +
> +		ioc_info(mrioc,
> +		    "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n",
> +		    code, code1, code2, code3);
> +	}
> +}
> +
> +/**
> + * mpi3mr_get_iocstate - Get IOC State
> + * @mrioc: Adapter instance reference
> + *
> + * Return a proper IOC state enum based on the IOC status and
> + * IOC configuration and unrcoverable state of the controller.
> + *
> + * Return: Current IOC state.
> + */
> +enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc)
> +{
> +	u32 ioc_status, ioc_config;
> +	u8 ready, enabled;
> +
> +	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
> +	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
> +
> +	if (mrioc->unrecoverable)
> +		return MRIOC_STATE_UNRECOVERABLE;
> +	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)
> +		return MRIOC_STATE_FAULT;
> +
> +	ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY);
> +	enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC);
> +
> +	if (ready && enabled)
> +		return MRIOC_STATE_READY;
> +	if ((!ready) && (!enabled))
> +		return MRIOC_STATE_RESET;
> +	if ((!ready) && (enabled))
> +		return MRIOC_STATE_BECOMING_READY;
> +
> +	return MRIOC_STATE_RESET_REQUESTED;
> +}
> +
> +/**
> + * mpi3mr_clear_reset_history - Clear reset history
> + * @mrioc: Adapter instance reference
> + *
> + * Write the reset history bit in IOC Status to clear the bit,
> + * if it is already set.
> + *
> + * Return: Nothing.
> + */
> +static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc)
> +{
> +	u32 ioc_status;
> +
> +	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
> +	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
> +		writel(ioc_status, &mrioc->sysif_regs->IOCStatus);
> +
> +}
> +
> +/**
> + * mpi3mr_issue_and_process_mur - Message Unit Reset handler
> + * @mrioc: Adapter instance reference
> + * @reset_reason: Reset reason code
> + *
> + * Issue Message Unit Reset to the controller and wait for it to
> + * be complete.
> + *
> + * Return: 0 on success, -1 on failure.
> + */
> +static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
> +					u32 reset_reason)
> +{
> +	u32 ioc_config, timeout, ioc_status;
> +	int retval = -1;
> +
> +	ioc_info(mrioc, "Issuing Message Unit Reset(MUR)\n");
> +	if (mrioc->unrecoverable) {
> +		ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n");
> +		return retval;
> +	}
> +	mpi3mr_clear_reset_history(mrioc);
> +	writel(reset_reason, &mrioc->sysif_regs->Scratchpad[0]);
> +	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
> +	ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
> +	writel(ioc_config, &mrioc->sysif_regs->IOCConfiguration);
> +
> +	timeout = mrioc->ready_timeout * 10;
> +	do {
> +		ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
> +		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
> +			mpi3mr_clear_reset_history(mrioc);
> +			ioc_config =
> +			    readl(&mrioc->sysif_regs->IOCConfiguration);
> +			if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
> +			    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
> +			    (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) {
> +				retval = 0;
> +				break;
> +			}
> +		}
> +		msleep(100);
> +	} while (--timeout);
> +
> +	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
> +	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
> +
> +	ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n",
> +	    (!retval) ? "successful" : "failed", ioc_status, ioc_config);
> +	return retval;
> +}
> +
> +/**
> + * mpi3mr_bring_ioc_ready - Bring controller to ready state
> + * @mrioc: Adapter instance reference
> + *
> + * Set Enable IOC bit in IOC configuration register and wait for
> + * the controller to become ready.
> + *
> + * Return: 0 on success, -1 on failure.
> + */
> +static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
> +{
> +	u32 ioc_config, timeout;
> +	enum mpi3mr_iocstate current_state;
> +
> +	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
> +	ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
> +	writel(ioc_config, &mrioc->sysif_regs->IOCConfiguration);
> +
> +	timeout = mrioc->ready_timeout * 10;
> +	do {
> +		current_state = mpi3mr_get_iocstate(mrioc);
> +		if (current_state == MRIOC_STATE_READY)
> +			return 0;
> +		msleep(100);
> +	} while (--timeout);
> +
> +	return -1;
> +}
> +
> +/**
> + * mpi3mr_set_diagsave - Set diag save bit for snapdump
> + * @mrioc: Adapter reference
> + *
> + * Set diag save bit in IOC configuration register to enable
> + * snapdump.
> + *
> + * Return: Nothing.
> + */
> +static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc)
> +{
> +	u32 ioc_config;
> +
> +	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
> +	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE;
> +	writel(ioc_config, &mrioc->sysif_regs->IOCConfiguration);
> +}
> +
> +/**
> + * mpi3mr_issue_reset - Issue reset to the controller
> + * @mrioc: Adapter reference
> + * @reset_type: Reset type
> + * @reset_reason: Reset reason code
> + *
> + * TBD
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
> +	u32 reset_reason)
> +{
> +	return 0;
> +}
> +
> +/**
> + * mpi3mr_admin_request_post - Post request to admin queue
> + * @mrioc: Adapter reference
> + * @admin_req: MPI3 request
> + * @admin_req_sz: Request size
> + * @ignore_reset: Ignore reset in process
> + *
> + * Post the MPI3 request into admin request queue and
> + * inform the controller, if the queue is full return
> + * appropriate error.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
> +	u16 admin_req_sz, u8 ignore_reset)
> +{
> +	u16 areq_pi = 0, areq_ci = 0, max_entries = 0;
> +	int retval = 0;
> +	unsigned long flags;
> +	u8 *areq_entry;
> +
> +
> +	if (mrioc->unrecoverable) {
> +		ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__);
> +		return -EFAULT;
> +	}
> +
> +	spin_lock_irqsave(&mrioc->admin_req_lock, flags);
> +	areq_pi = mrioc->admin_req_pi;
> +	areq_ci = mrioc->admin_req_ci;
> +	max_entries = mrioc->num_admin_req;
> +	if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) &&
> +	    (areq_pi == (max_entries - 1)))) {
> +		ioc_err(mrioc, "AdminReqQ full condition detected\n");
> +		retval = -EAGAIN;
> +		goto out;
> +	}
> +	if (!ignore_reset && mrioc->reset_in_progress) {
> +		ioc_err(mrioc, "AdminReqQ submit reset in progress\n");
> +		retval = -EAGAIN;
> +		goto out;
> +	}
> +	areq_entry = (u8 *)mrioc->admin_req_base +
> +	    (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
> +	memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
> +	memcpy(areq_entry, (u8 *)admin_req, admin_req_sz);
> +
> +	if (++areq_pi == max_entries)
> +		areq_pi = 0;
> +	mrioc->admin_req_pi = areq_pi;
> +
> +	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->AdminRequestQueuePI);
> +
> +out:
> +	spin_unlock_irqrestore(&mrioc->admin_req_lock, flags);
> +
> +	return retval;
> +}
> +

It might be an idea to have an 'admin' queue structure; keeping the
values all within the main IOC structure might cause cache misses and a
degraded performance.

> +
> +/**
> + * mpi3mr_setup_admin_qpair - Setup admin queue pair
> + * @mrioc: Adapter instance reference
> + *
> + * Allocate memory for admin queue pair if required and register
> + * the admin queue with the controller.
> + *
> + * Return: 0 on success, non-zero on failures.
> + */
> +static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
> +{
> +	int retval = 0;
> +	u32 num_admin_entries = 0;
> +
> +	mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE;
> +	mrioc->num_admin_req = mrioc->admin_req_q_sz /
> +	    MPI3MR_ADMIN_REQ_FRAME_SZ;
> +	mrioc->admin_req_ci = mrioc->admin_req_pi = 0;
> +	mrioc->admin_req_base = NULL;
> +
> +	mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE;
> +	mrioc->num_admin_replies = mrioc->admin_reply_q_sz /
> +	    MPI3MR_ADMIN_REPLY_FRAME_SZ;
> +	mrioc->admin_reply_ci = 0;
> +	mrioc->admin_reply_ephase = 1;
> +	mrioc->admin_reply_base = NULL;
> +
> +	if (!mrioc->admin_req_base) {
> +		mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev,
> +		    mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL);
> +
> +		if (!mrioc->admin_req_base) {
> +			retval = -1;
> +			goto out_failed;
> +		}
> +
> +		mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev,
> +		    mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma,
> +		    GFP_KERNEL);
> +
> +		if (!mrioc->admin_reply_base) {
> +			retval = -1;
> +			goto out_failed;
> +		}
> +
> +	}
> +
> +	num_admin_entries = (mrioc->num_admin_replies << 16) |
> +	    (mrioc->num_admin_req);
> +	writel(num_admin_entries, &mrioc->sysif_regs->AdminQueueNumEntries);
> +	mpi3mr_writeq(mrioc->admin_req_dma,
> +	    &mrioc->sysif_regs->AdminRequestQueueAddress);
> +	mpi3mr_writeq(mrioc->admin_reply_dma,
> +	    &mrioc->sysif_regs->AdminReplyQueueAddress);
> +	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->AdminRequestQueuePI);
> +	writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->AdminReplyQueueCI);
> +	return retval;
> +
> +out_failed:
> +
> +	if (mrioc->admin_reply_base) {
> +		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
> +		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
> +		mrioc->admin_reply_base = NULL;
> +	}
> +	if (mrioc->admin_req_base) {
> +		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
> +		    mrioc->admin_req_base, mrioc->admin_req_dma);
> +		mrioc->admin_req_base = NULL;
> +	}
> +	return retval;
> +}
> +
> +/**
> + * mpi3mr_issue_iocfacts - Send IOC Facts
> + * @mrioc: Adapter instance reference
> + *
> + * Issue IOC Facts MPI request through admin queue and wait for
> + * the completion of it or time out.
> + *
> + * Return: 0 on success, non-zero on failures.
> + */
> +static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc,
> +	Mpi3IOCFactsData_t *facts_data)
> +{
> +	Mpi3IOCFactsRequest_t iocfacts_req;
> +	void *data = NULL;
> +	dma_addr_t data_dma;
> +	u32 data_len = sizeof(*facts_data);
> +	int retval = 0;
> +	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
> +
> +	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
> +	    GFP_KERNEL);
> +
> +	if (!data) {
> +		retval = -1;
> +		goto out;
> +	}
> +
> +	memset(&iocfacts_req, 0, sizeof(iocfacts_req));
> +	mutex_lock(&mrioc->init_cmds.mutex);
> +	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
> +		retval = -1;
> +		ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n");
> +		mutex_unlock(&mrioc->init_cmds.mutex);
> +		goto out;
> +	}
> +	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
> +	mrioc->init_cmds.is_waiting = 1;
> +	mrioc->init_cmds.callback = NULL;
> +	iocfacts_req.HostTag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
> +	iocfacts_req.Function = MPI3_FUNCTION_IOC_FACTS;
> +
> +	mpi3mr_add_sg_single(&iocfacts_req.SGL, sgl_flags, data_len,
> +	    data_dma);
> +
> +	init_completion(&mrioc->init_cmds.done);
> +	retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req,
> +	    sizeof(iocfacts_req), 1);
> +	if (retval) {
> +		ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n");
> +		goto out_unlock;
> +	}
> +	wait_for_completion_timeout(&mrioc->init_cmds.done,
> +	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
> +	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
> +		ioc_err(mrioc, "Issue IOCFacts: command timed out\n");
> +		mpi3mr_set_diagsave(mrioc);
> +		mpi3mr_issue_reset(mrioc,
> +		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
> +		    MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT);
> +		mrioc->unrecoverable = 1;
> +		retval = -1;
> +		goto out_unlock;
> +	}
> +	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
> +	    != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc,
> +		    "Issue IOCFacts: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n",
> +		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
> +		    mrioc->init_cmds.ioc_loginfo);
> +		retval = -1;
> +		goto out_unlock;
> +	}
> +	memcpy(facts_data, (u8 *)data, data_len);
> +out_unlock:
> +	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
> +	mutex_unlock(&mrioc->init_cmds.mutex);
> +
> +out:
> +	if (data)
> +		dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma);
> +
> +	return retval;
> +}
> +
> +/**
> + * mpi3mr_check_reset_dma_mask - Process IOC facts data
> + * @mrioc: Adapter instance reference
> + *
> + * Check whether the new DMA mask requested through IOCFacts by
> + * firmware needs to be set, if so set it .
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc)
> +{
> +	struct pci_dev *pdev = mrioc->pdev;
> +	int r;
> +	u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask);
> +
> +	if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask))
> +		return 0;
> +
> +	ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n",
> +	    mrioc->dma_mask, facts_dma_mask);
> +
> +	r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask);
> +	if (r) {
> +		ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n",
> +		    facts_dma_mask, r);
> +		return r;
> +	}
> +	mrioc->dma_mask = facts_dma_mask;
> +	return r;
> +}
> +/**
> + * mpi3mr_process_factsdata - Process IOC facts data
> + * @mrioc: Adapter instance reference
> + *
> + * Convert IOC facts data into cpu endianness and cache it in
> + * the driver .
> + *
> + * Return: Nothing.
> + */
> +static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
> +	Mpi3IOCFactsData_t *facts_data)
> +{
> +	u32 ioc_config, req_sz, facts_flags;
> +
> +	if ((le16_to_cpu(facts_data->IOCFactsDataLength)) !=
> +	    (sizeof(*facts_data)/4)) {
> +		ioc_warn(mrioc,
> +		    "IOCFactsdata length mismatch driver_sz(%ld) firmware_sz(%d)\n",
> +		    sizeof(*facts_data),
> +		    le16_to_cpu(facts_data->IOCFactsDataLength) * 4);
> +	}
> +
> +	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
> +	req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >>
> +	    MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT);
> +	if (le16_to_cpu(facts_data->IOCRequestFrameSize) != (req_sz/4)) {
> +		ioc_err(mrioc,
> +		    "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n",
> +		    req_sz/4, le16_to_cpu(facts_data->IOCRequestFrameSize));
> +	}
> +
> +	memset(&mrioc->facts, 0, sizeof(mrioc->facts));
> +
> +	facts_flags = le32_to_cpu(facts_data->Flags);
> +	mrioc->facts.op_req_sz = req_sz;
> +	mrioc->op_reply_desc_sz = 1 << ((ioc_config &
> +	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >>
> +	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT);
> +
> +	mrioc->facts.ioc_num = facts_data->IOCNumber;
> +	mrioc->facts.who_init = facts_data->WhoInit;
> +	mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->MaxMSIxVectors);
> +	mrioc->facts.personality = (facts_flags &
> +	    MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK);
> +	mrioc->facts.dma_mask = (facts_flags &
> +	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
> +	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
> +	mrioc->facts.protocol_flags = facts_data->ProtocolFlags;
> +	mrioc->facts.mpi_version = le32_to_cpu(facts_data->MPIVersion.Word);
> +	mrioc->facts.max_reqs = le16_to_cpu(facts_data->MaxOutstandingRequest);
> +	mrioc->facts.product_id = le16_to_cpu(facts_data->ProductID);
> +	mrioc->facts.reply_sz = le16_to_cpu(facts_data->ReplyFrameSize) * 4;
> +	mrioc->facts.exceptions = le16_to_cpu(facts_data->IOCExceptions);
> +	mrioc->facts.max_perids = le16_to_cpu(facts_data->MaxPersistentID);
> +	mrioc->facts.max_pds = le16_to_cpu(facts_data->MaxPDs);
> +	mrioc->facts.max_vds = le16_to_cpu(facts_data->MaxVDs);
> +	mrioc->facts.max_hpds = le16_to_cpu(facts_data->MaxHostPDs);
> +	mrioc->facts.max_advhpds = le16_to_cpu(facts_data->MaxAdvancedHostPDs);
> +	mrioc->facts.max_raidpds = le16_to_cpu(facts_data->MaxRAIDPDs);
> +	mrioc->facts.max_nvme = le16_to_cpu(facts_data->MaxNVMe);
> +	mrioc->facts.max_pcieswitches =
> +	    le16_to_cpu(facts_data->MaxPCIeSwitches);
> +	mrioc->facts.max_sasexpanders =
> +	    le16_to_cpu(facts_data->MaxSASExpanders);
> +	mrioc->facts.max_sasinitiators =
> +	    le16_to_cpu(facts_data->MaxSASInitiators);
> +	mrioc->facts.max_enclosures = le16_to_cpu(facts_data->MaxEnclosures);
> +	mrioc->facts.min_devhandle = le16_to_cpu(facts_data->MinDevHandle);
> +	mrioc->facts.max_devhandle = le16_to_cpu(facts_data->MaxDevHandle);
> +	mrioc->facts.max_op_req_q =
> +	    le16_to_cpu(facts_data->MaxOperationalRequestQueues);
> +	mrioc->facts.max_op_reply_q =
> +	    le16_to_cpu(facts_data->MaxOperationalReplyQueues);
> +	mrioc->facts.ioc_capabilities =
> +	    le32_to_cpu(facts_data->IOCCapabilities);
> +	mrioc->facts.fw_ver.build_num =
> +	    le16_to_cpu(facts_data->FWVersion.BuildNum);
> +	mrioc->facts.fw_ver.cust_id =
> +	    le16_to_cpu(facts_data->FWVersion.CustomerID);
> +	mrioc->facts.fw_ver.ph_minor = facts_data->FWVersion.PhaseMinor;
> +	mrioc->facts.fw_ver.ph_major = facts_data->FWVersion.PhaseMajor;
> +	mrioc->facts.fw_ver.gen_minor = facts_data->FWVersion.GenMinor;
> +	mrioc->facts.fw_ver.gen_major = facts_data->FWVersion.GenMajor;
> +	mrioc->msix_count = min_t(int, mrioc->msix_count,
> +	    mrioc->facts.max_msix_vectors);
> +	mrioc->facts.sge_mod_mask = facts_data->SGEModifierMask;
> +	mrioc->facts.sge_mod_value = facts_data->SGEModifierValue;
> +	mrioc->facts.sge_mod_shift = facts_data->SGEModifierShift;
> +	mrioc->facts.shutdown_timeout =
> +	    le16_to_cpu(facts_data->ShutdownTimeout);
> +
> +	ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),",
> +	    mrioc->facts.ioc_num, mrioc->facts.max_op_req_q,
> +	    mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle);
> +	ioc_info(mrioc,
> +	    "maxreqs(%d), mindh(%d) maxPDs(%d) maxvectors(%d) maxperids(%d)\n",
> +	    mrioc->facts.max_reqs, mrioc->facts.min_devhandle,
> +	    mrioc->facts.max_pds, mrioc->facts.max_msix_vectors,
> +	    mrioc->facts.max_perids);
> +	ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ",
> +	    mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value,
> +	    mrioc->facts.sge_mod_shift);
> +	ioc_info(mrioc, "DMA Mask %d InitialPE Status 0x%x\n",
> +	    mrioc->facts.dma_mask, (facts_flags &
> +	    MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK));
> +
> +	mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD;
> +
> +	if (reset_devices)
> +		mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
> +		    MPI3MR_HOST_IOS_KDUMP);
> +
> +}
> +
> +/**
> + * mpi3mr_alloc_reply_sense_bufs - Send IOC Init
> + * @mrioc: Adapter instance reference
> + *
> + * Allocate and initialize the reply free buffers, sense
> + * buffers, reply free queue and sense buffer queue.
> + *
> + * Return: 0 on success, non-zero on failures.
> + */
> +static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
> +{
> +	int retval = 0;
> +	u32 sz, i;
> +	dma_addr_t phy_addr;
> +
> +	if (mrioc->init_cmds.reply)
> +		goto post_reply_sbuf;
> +
> +	mrioc->init_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL);
> +	if (!mrioc->init_cmds.reply)
> +		goto out_failed;
> +
> +
> +	mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES;
> +	mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1;
> +	mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
> +	mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1;
> +
> +	/* reply buffer pool, 16 byte align */
> +	sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
> +	mrioc->reply_buf_pool = dma_pool_create("reply_buf pool",
> +	    &mrioc->pdev->dev, sz, 16, 0);
> +	if (!mrioc->reply_buf_pool) {
> +		ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n");
> +		goto out_failed;
> +	}
> +
> +	mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL,
> +	    &mrioc->reply_buf_dma);
> +	if (!mrioc->reply_buf)
> +		goto out_failed;
> +
> +	mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz;
> +
> +	/* reply free queue, 8 byte align */
> +	sz = mrioc->reply_free_qsz * 8;
> +	mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool",
> +	    &mrioc->pdev->dev, sz, 8, 0);
> +	if (!mrioc->reply_free_q_pool) {
> +		ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n");
> +		goto out_failed;
> +	}
> +	mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool,
> +	    GFP_KERNEL, &mrioc->reply_free_q_dma);
> +	if (!mrioc->reply_free_q)
> +		goto out_failed;
> +
> +	/* sense buffer pool,  4 byte align */
> +	sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
> +	mrioc->sense_buf_pool = dma_pool_create("sense_buf pool",
> +	    &mrioc->pdev->dev, sz, 4, 0);
> +	if (!mrioc->sense_buf_pool) {
> +		ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n");
> +		goto out_failed;
> +	}
> +	mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL,
> +	    &mrioc->sense_buf_dma);
> +	if (!mrioc->sense_buf)
> +		goto out_failed;
> +
> +	/* sense buffer queue, 8 byte align */
> +	sz = mrioc->sense_buf_q_sz * 8;
> +	mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool",
> +	    &mrioc->pdev->dev, sz, 8, 0);
> +	if (!mrioc->sense_buf_q_pool) {
> +		ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n");
> +		goto out_failed;
> +	}
> +	mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool,
> +	    GFP_KERNEL, &mrioc->sense_buf_q_dma);
> +	if (!mrioc->sense_buf_q)
> +		goto out_failed;
> +
> +post_reply_sbuf:
> +	sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
> +	ioc_info(mrioc,
> +	    "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
> +	    mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->facts.reply_sz,
> +	    (sz / 1024), (unsigned long long)mrioc->reply_buf_dma);
> +	sz = mrioc->reply_free_qsz * 8;
> +	ioc_info(mrioc,
> +	    "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
> +	    mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024),
> +	    (unsigned long long)mrioc->reply_free_q_dma);
> +	sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
> +	ioc_info(mrioc,
> +	    "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
> +	    mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSEBUF_SZ,
> +	    (sz / 1024), (unsigned long long)mrioc->sense_buf_dma);
> +	sz = mrioc->sense_buf_q_sz * 8;
> +	ioc_info(mrioc,
> +	    "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
> +	    mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024),
> +	    (unsigned long long)mrioc->sense_buf_q_dma);
> +
> +	/* initialize Reply buffer Queue */
> +	for (i = 0, phy_addr = mrioc->reply_buf_dma;
> +	    i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->facts.reply_sz)
> +		mrioc->reply_free_q[i] = cpu_to_le64(phy_addr);
> +	mrioc->reply_free_q[i] = cpu_to_le64(0);
> +
> +	/* initialize Sense Buffer Queue */
> +	for (i = 0, phy_addr = mrioc->sense_buf_dma;
> +	    i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSEBUF_SZ)
> +		mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr);
> +	mrioc->sense_buf_q[i] = cpu_to_le64(0);
> +	return retval;
> +
> +out_failed:
> +	retval = -1;
> +	return retval;
> +}
> +
> +/**
> + * mpi3mr_issue_iocinit - Send IOC Init
> + * @mrioc: Adapter instance reference
> + *
> + * Issue IOC Init MPI request through admin queue and wait for
> + * the completion of it or time out.
> + *
> + * Return: 0 on success, non-zero on failures.
> + */
> +static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc)
> +{
> +	Mpi3IOCInitRequest_t iocinit_req;
> +	Mpi3DriverInfoLayout_t *drv_info;
> +	dma_addr_t data_dma;
> +	u32 data_len = sizeof(*drv_info);
> +	int retval = 0;
> +	ktime_t current_time;
> +
> +	drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
> +	    GFP_KERNEL);
> +	if (!drv_info) {
> +		retval = -1;
> +		goto out;
> +	}
> +	drv_info->InformationLength = cpu_to_le32(data_len);
> +	strcpy(drv_info->DriverSignature, "Broadcom");
> +	strcpy(drv_info->OsName, utsname()->sysname);
> +	drv_info->OsName[sizeof(drv_info->OsName)-1] = 0;
> +	strcpy(drv_info->OsVersion, utsname()->release);
> +	drv_info->OsVersion[sizeof(drv_info->OsVersion)-1] = 0;
> +	strcpy(drv_info->DriverName, MPI3MR_DRIVER_NAME);
> +	strcpy(drv_info->DriverVersion, MPI3MR_DRIVER_VERSION);
> +	strcpy(drv_info->DriverReleaseDate, MPI3MR_DRIVER_RELDATE);
> +	drv_info->DriverCapabilities = 0;
> +	memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info,
> +	    sizeof(mrioc->driver_info));
> +
> +	memset(&iocinit_req, 0, sizeof(iocinit_req));
> +	mutex_lock(&mrioc->init_cmds.mutex);
> +	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
> +		retval = -1;
> +		ioc_err(mrioc, "Issue IOCInit: Init command is in use\n");
> +		mutex_unlock(&mrioc->init_cmds.mutex);
> +		goto out;
> +	}
> +	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
> +	mrioc->init_cmds.is_waiting = 1;
> +	mrioc->init_cmds.callback = NULL;
> +	iocinit_req.HostTag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
> +	iocinit_req.Function = MPI3_FUNCTION_IOC_INIT;
> +	iocinit_req.MPIVersion.Struct.Dev = MPI3_VERSION_DEV;
> +	iocinit_req.MPIVersion.Struct.Unit = MPI3_VERSION_UNIT;
> +	iocinit_req.MPIVersion.Struct.Major = MPI3_VERSION_MAJOR;
> +	iocinit_req.MPIVersion.Struct.Minor = MPI3_VERSION_MINOR;
> +	iocinit_req.WhoInit = MPI3_WHOINIT_HOST_DRIVER;
> +	iocinit_req.ReplyFreeQueueDepth = cpu_to_le16(mrioc->reply_free_qsz);
> +	iocinit_req.ReplyFreeQueueAddress =
> +	    cpu_to_le64(mrioc->reply_free_q_dma);
> +	iocinit_req.SenseBufferLength = cpu_to_le16(MPI3MR_SENSEBUF_SZ);
> +	iocinit_req.SenseBufferFreeQueueDepth =
> +	    cpu_to_le16(mrioc->sense_buf_q_sz);
> +	iocinit_req.SenseBufferFreeQueueAddress =
> +	    cpu_to_le64(mrioc->sense_buf_q_dma);
> +	iocinit_req.DriverInformationAddress = cpu_to_le64(data_dma);
> +
> +	current_time = ktime_get_real();
> +	iocinit_req.TimeStamp = cpu_to_le64(ktime_to_ms(current_time));
> +
> +	init_completion(&mrioc->init_cmds.done);
> +	retval = mpi3mr_admin_request_post(mrioc, &iocinit_req,
> +	    sizeof(iocinit_req), 1);
> +	if (retval) {
> +		ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n");
> +		goto out_unlock;
> +	}
> +	wait_for_completion_timeout(&mrioc->init_cmds.done,
> +	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
> +	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
> +		mpi3mr_set_diagsave(mrioc);
> +		mpi3mr_issue_reset(mrioc,
> +		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
> +		    MPI3MR_RESET_FROM_IOCINIT_TIMEOUT);
> +		mrioc->unrecoverable = 1;
> +		ioc_err(mrioc, "Issue IOCInit: command timed out\n");
> +		retval = -1;
> +		goto out_unlock;
> +	}
> +	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
> +	    != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc,
> +		    "Issue IOCInit: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n",
> +		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
> +		    mrioc->init_cmds.ioc_loginfo);
> +		retval = -1;
> +		goto out_unlock;
> +	}
> +
> +out_unlock:
> +	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
> +	mutex_unlock(&mrioc->init_cmds.mutex);
> +
> +out:
> +	if (drv_info)
> +		dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info,
> +		    data_dma);
> +
> +	return retval;
> +}
> +
> +
> +/**
> + * mpi3mr_alloc_chain_bufs - Allocate chain buffers
> + * @mrioc: Adapter instance reference
> + *
> + * Allocate chain buffers and set a bitmap to indicate free
> + * chain buffers. Chain buffers are used to pass the SGE
> + * information along with MPI3 SCSI IO requests for host I/O.
> + *
> + * Return: 0 on success, non-zero on failure
> + */
> +static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc)
> +{
> +	int retval = 0;
> +	u32 sz, i;
> +	u16 num_chains;
> +
> +	num_chains = mrioc->max_host_ios/MPI3MR_CHAINBUF_FACTOR;
> +
> +	mrioc->chain_buf_count = num_chains;
> +	sz = sizeof(struct chain_element) * num_chains;
> +	mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL);
> +	if (!mrioc->chain_sgl_list)
> +		goto out_failed;
> +
> +	sz = MPI3MR_PAGE_SIZE_4K;
> +	mrioc->chain_buf_pool = dma_pool_create("chain_buf pool",
> +	    &mrioc->pdev->dev, sz, 16, 0);
> +	if (!mrioc->chain_buf_pool) {
> +		ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n");
> +		goto out_failed;
> +	}
> +
> +	for (i = 0; i < num_chains; i++) {
> +		mrioc->chain_sgl_list[i].addr =
> +		    dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL,
> +		    &mrioc->chain_sgl_list[i].dma_addr);
> +
> +		if (!mrioc->chain_sgl_list[i].addr)
> +			goto out_failed;
> +	}
> +	mrioc->chain_bitmap_sz = num_chains / 8;
> +	if (num_chains % 8)
> +		mrioc->chain_bitmap_sz++;
> +	mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL);
> +	if (!mrioc->chain_bitmap)
> +		goto out_failed;
> +	return retval;
> +out_failed:
> +	retval = -1;
> +	return retval;
> +}
> +
> +
> +/**
> + * mpi3mr_cleanup_resources - Free PCI resources
> + * @mrioc: Adapter instance reference
> + *
> + * Unmap PCI device memory and disable PCI device.
> + *
> + * Return: 0 on success and non-zero on failure.
> + */
> +void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc)
> +{
> +	struct pci_dev *pdev = mrioc->pdev;
> +
> +	mpi3mr_cleanup_isr(mrioc);
> +
> +	if (mrioc->sysif_regs) {
> +		iounmap(mrioc->sysif_regs);
> +		mrioc->sysif_regs = NULL;
> +	}
> +
> +	if (pci_is_enabled(pdev)) {
> +		if (mrioc->bars)
> +			pci_release_selected_regions(pdev, mrioc->bars);
> +		pci_disable_device(pdev);
> +	}
> +}
> +
> +/**
> + * mpi3mr_setup_resources - Enable PCI resources
> + * @mrioc: Adapter instance reference
> + *
> + * Enable PCI device memory, MSI-x registers and set DMA mask.
> + *
> + * Return: 0 on success and non-zero on failure.
> + */
> +int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc)
> +{
> +	struct pci_dev *pdev = mrioc->pdev;
> +	u32 memap_sz = 0;
> +	int i, retval = 0, capb = 0;
> +	u16 message_control;
> +	u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask :
> +	    (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) &&
> +	    (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64):DMA_BIT_MASK(32));
> +
> +	if (pci_enable_device_mem(pdev)) {
> +		ioc_err(mrioc, "pci_enable_device_mem: failed\n");
> +		retval = -ENODEV;
> +		goto out_failed;
> +	}
> +
> +	capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
> +	if (!capb) {
> +		ioc_err(mrioc, "Unable to find MSI-X Capabilities\n");
> +		retval = -ENODEV;
> +		goto out_failed;
> +	}
> +	mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
> +
> +	if (pci_request_selected_regions(pdev, mrioc->bars,
> +	    mrioc->driver_name)) {
> +		ioc_err(mrioc, "pci_request_selected_regions: failed\n");
> +		retval = -ENODEV;
> +		goto out_failed;
> +	}
> +
> +	for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) {
> +		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
> +			mrioc->sysif_regs_phys = pci_resource_start(pdev, i);
> +			memap_sz = pci_resource_len(pdev, i);
> +			mrioc->sysif_regs =
> +			    ioremap(mrioc->sysif_regs_phys, memap_sz);
> +			break;
> +		}
> +	}
> +
> +	pci_set_master(pdev);
> +
> +	retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
> +	if (retval) {
> +		if (dma_mask != DMA_BIT_MASK(32)) {
> +			ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n");
> +			dma_mask = DMA_BIT_MASK(32);
> +			retval = dma_set_mask_and_coherent(&pdev->dev,
> +			    dma_mask);
> +		}
> +		if (retval) {
> +			mrioc->dma_mask = 0;
> +			ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n");
> +			goto out_failed;
> +		}
> +	}
> +	mrioc->dma_mask = dma_mask;
> +
> +	if (mrioc->sysif_regs == NULL) {
> +		ioc_err(mrioc,
> +		    "Unable to map adapter memory or resource not found\n");
> +		retval = -EINVAL;
> +		goto out_failed;
> +	}
> +
> +	pci_read_config_word(pdev, capb + 2, &message_control);
> +	mrioc->msix_count = (message_control & 0x3FF) + 1;
> +
> +	pci_save_state(pdev);
> +
> +	pci_set_drvdata(pdev, mrioc->shost);
> +
> +	mpi3mr_ioc_disable_intr(mrioc);
> +
> +	ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
> +	    (unsigned long long)mrioc->sysif_regs_phys,
> +	    mrioc->sysif_regs, memap_sz);
> +	ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n",
> +	    mrioc->msix_count);
> +	return retval;
> +
> +out_failed:
> +	mpi3mr_cleanup_resources(mrioc);
> +	return retval;
> +}
> +
> +/**
> + * mpi3mr_init_ioc - Initialize the controller
> + * @mrioc: Adapter instance reference
> + *
> + * This the controller initialization routine, executed either
> + * after soft reset or from pci probe callback.
> + * Setup the required resources, memory map the controller
> + * registers, create admin and operational reply queue pairs,
> + * allocate required memory for reply pool, sense buffer pool,
> + * issue IOC init request to the firmware, unmask the events and
> + * issue port enable to discover SAS/SATA/NVMe devies and RAID
> + * volumes.
> + *
> + * Return: 0 on success and non-zero on failure.
> + */
> +int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
> +{
> +	int retval = 0;
> +	enum mpi3mr_iocstate ioc_state;
> +	u64 base_info;
> +	u32 timeout;
> +	u32 ioc_status, ioc_config;
> +	Mpi3IOCFactsData_t facts_data;
> +
> +	mrioc->change_count = 0;
> +	mrioc->cpu_count = num_online_cpus();

What about CPU hotplug?

> +	retval = mpi3mr_setup_resources(mrioc);
> +	if (retval) {
> +		ioc_err(mrioc, "Failed to setup resources:error %d\n",
> +		    retval);
> +		goto out_nocleanup;
> +	}
> +	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
> +	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
> +
> +	ioc_info(mrioc, "SOD status %x configuration %x\n",
> +	    ioc_status, ioc_config);
> +
> +	base_info = readq(&mrioc->sysif_regs->IOCInformation);
> +	ioc_info(mrioc, "SOD base_info %llx\n",	base_info);
> +
> +	/*The timeout value is in 2sec unit, changing it to seconds*/
> +	mrioc->ready_timeout =
> +	    ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
> +	    MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
> +
> +	ioc_info(mrioc, "IOC ready timeout %d\n", mrioc->ready_timeout);
> +
> +	ioc_state = mpi3mr_get_iocstate(mrioc);
> +	ioc_info(mrioc, "IOC in %s state during detection\n",
> +	    mpi3mr_iocstate_name(ioc_state));
> +
> +	if (ioc_state == MRIOC_STATE_BECOMING_READY ||
> +			ioc_state == MRIOC_STATE_RESET_REQUESTED) {
> +		timeout = mrioc->ready_timeout * 10;
> +		do {
> +			msleep(100);
> +		} while (--timeout);
> +
> +		ioc_state = mpi3mr_get_iocstate(mrioc);
> +		ioc_info(mrioc,
> +			"IOC in %s state after waiting for reset time\n",
> +			mpi3mr_iocstate_name(ioc_state));
> +	}
> +
> +	if (ioc_state == MRIOC_STATE_READY) {
> +		retval = mpi3mr_issue_and_process_mur(mrioc,
> +		    MPI3MR_RESET_FROM_BRINGUP);
> +		if (retval) {
> +			ioc_err(mrioc, "Failed to MU reset IOC error %d\n",
> +			    retval);
> +		}
> +		ioc_state = mpi3mr_get_iocstate(mrioc);
> +	}
> +	if (ioc_state != MRIOC_STATE_RESET) {
> +		mpi3mr_print_fault_info(mrioc);
> +		retval = mpi3mr_issue_reset(mrioc,
> +		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
> +		    MPI3MR_RESET_FROM_BRINGUP);
> +		if (retval) {
> +			ioc_err(mrioc,
> +			    "%s :Failed to soft reset IOC error %d\n",
> +			    __func__, retval);
> +			goto out_failed;
> +		}
> +	}
> +	ioc_state = mpi3mr_get_iocstate(mrioc);
> +	if (ioc_state != MRIOC_STATE_RESET) {
> +		ioc_err(mrioc, "Cannot bring IOC to reset state\n");
> +		goto out_failed;
> +	}
> +
> +	retval = mpi3mr_setup_admin_qpair(mrioc);
> +	if (retval) {
> +		ioc_err(mrioc, "Failed to setup admin Qs: error %d\n",
> +		    retval);
> +		goto out_failed;
> +	}
> +
> +	retval = mpi3mr_bring_ioc_ready(mrioc);
> +	if (retval) {
> +		ioc_err(mrioc, "Failed to bring ioc ready: error %d\n",
> +		    retval);
> +		goto out_failed;
> +	}
> +
> +	retval = mpi3mr_setup_isr(mrioc, 1);
> +	if (retval) {
> +		ioc_err(mrioc, "Failed to setup ISR error %d\n",
> +		    retval);
> +		goto out_failed;
> +	}
> +
> +	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
> +	if (retval) {
> +		ioc_err(mrioc, "Failed to Issue IOC Facts %d\n",
> +		    retval);
> +		goto out_failed;
> +	}
> +
> +	mpi3mr_process_factsdata(mrioc, &facts_data);
> +	retval = mpi3mr_check_reset_dma_mask(mrioc);
> +	if (retval) {
> +		ioc_err(mrioc, "Resetting dma mask failed %d\n",
> +		    retval);
> +		goto out_failed;
> +	}
> +
> +	retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
> +	if (retval) {
> +		ioc_err(mrioc,
> +		    "%s :Failed to allocated reply sense buffers %d\n",
> +		    __func__, retval);
> +		goto out_failed;
> +	}
> +
> +	retval = mpi3mr_alloc_chain_bufs(mrioc);
> +	if (retval) {
> +		ioc_err(mrioc, "Failed to allocated chain buffers %d\n",
> +		    retval);
> +		goto out_failed;
> +	}
> +
> +	retval = mpi3mr_issue_iocinit(mrioc);
> +	if (retval) {
> +		ioc_err(mrioc, "Failed to Issue IOC Init %d\n",
> +		    retval);
> +		goto out_failed;
> +	}
> +	mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs;
> +	writel(mrioc->reply_free_queue_host_index,
> +	    &mrioc->sysif_regs->ReplyFreeHostIndex);
> +
> +	mrioc->sbq_host_index = mrioc->num_sense_bufs;
> +	writel(mrioc->sbq_host_index,
> +	    &mrioc->sysif_regs->SenseBufferFreeHostIndex);
> +
> +	retval = mpi3mr_setup_isr(mrioc, 0);
> +	if (retval) {
> +		ioc_err(mrioc, "Failed to re-setup ISR, error %d\n",
> +		    retval);
> +		goto out_failed;
> +	}
> +
> +	return retval;
> +
> +out_failed:
> +	mpi3mr_cleanup_ioc(mrioc);
> +out_nocleanup:
> +	return retval;
> +}
> +
> +
> +/**
> + * mpi3mr_free_mem - Free memory allocated for a controller
> + * @mrioc: Adapter instance reference
> + *
> + * Free all the memory allocated for a controller.
> + *
> + * Return: Nothing.
> + */
> +static void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
> +{
> +	u16 i;
> +	struct mpi3mr_intr_info *intr_info;
> +
> +	if (mrioc->sense_buf_pool) {
> +		if (mrioc->sense_buf)
> +			dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf,
> +			    mrioc->sense_buf_dma);
> +		dma_pool_destroy(mrioc->sense_buf_pool);
> +		mrioc->sense_buf = NULL;
> +		mrioc->sense_buf_pool = NULL;
> +	}
> +	if (mrioc->sense_buf_q_pool) {
> +		if (mrioc->sense_buf_q)
> +			dma_pool_free(mrioc->sense_buf_q_pool,
> +			    mrioc->sense_buf_q, mrioc->sense_buf_q_dma);
> +		dma_pool_destroy(mrioc->sense_buf_q_pool);
> +		mrioc->sense_buf_q = NULL;
> +		mrioc->sense_buf_q_pool = NULL;
> +	}
> +
> +	if (mrioc->reply_buf_pool) {
> +		if (mrioc->reply_buf)
> +			dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf,
> +			    mrioc->reply_buf_dma);
> +		dma_pool_destroy(mrioc->reply_buf_pool);
> +		mrioc->reply_buf = NULL;
> +		mrioc->reply_buf_pool = NULL;
> +	}
> +	if (mrioc->reply_free_q_pool) {
> +		if (mrioc->reply_free_q)
> +			dma_pool_free(mrioc->reply_free_q_pool,
> +			    mrioc->reply_free_q, mrioc->reply_free_q_dma);
> +		dma_pool_destroy(mrioc->reply_free_q_pool);
> +		mrioc->reply_free_q = NULL;
> +		mrioc->reply_free_q_pool = NULL;
> +	}
> +
> +	for (i = 0; i < mrioc->intr_info_count; i++) {
> +		intr_info = mrioc->intr_info + i;
> +		if (intr_info)
> +			intr_info->op_reply_q = NULL;
> +	}
> +
> +	kfree(mrioc->req_qinfo);
> +	mrioc->req_qinfo = NULL;
> +	mrioc->num_op_req_q = 0;
> +
> +	kfree(mrioc->op_reply_qinfo);
> +	mrioc->op_reply_qinfo = NULL;
> +	mrioc->num_op_reply_q = 0;
> +
> +	kfree(mrioc->init_cmds.reply);
> +	mrioc->init_cmds.reply = NULL;
> +
> +	kfree(mrioc->chain_bitmap);
> +	mrioc->chain_bitmap = NULL;
> +
> +	if (mrioc->chain_buf_pool) {
> +		for (i = 0; i < mrioc->chain_buf_count; i++) {
> +			if (mrioc->chain_sgl_list[i].addr) {
> +				dma_pool_free(mrioc->chain_buf_pool,
> +				    mrioc->chain_sgl_list[i].addr,
> +				    mrioc->chain_sgl_list[i].dma_addr);
> +				mrioc->chain_sgl_list[i].addr = NULL;
> +			}
> +		}
> +		dma_pool_destroy(mrioc->chain_buf_pool);
> +		mrioc->chain_buf_pool = NULL;
> +	}
> +
> +	kfree(mrioc->chain_sgl_list);
> +	mrioc->chain_sgl_list = NULL;
> +
> +	if (mrioc->admin_reply_base) {
> +		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
> +		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
> +		mrioc->admin_reply_base = NULL;
> +	}
> +	if (mrioc->admin_req_base) {
> +		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
> +		    mrioc->admin_req_base, mrioc->admin_req_dma);
> +		mrioc->admin_req_base = NULL;
> +	}
> +
> +}
> +
> +/**
> + * mpi3mr_issue_ioc_shutdown - Shutdown controller
> + * @mrioc: Adapter instance reference
> + *
> + * Send shutodwn notification to the controller and wait for the
> + * shutdown_timeout for it to be completed.
> + *
> + * Return: Nothing.
> + */
> +static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
> +{
> +	u32 ioc_config, ioc_status;
> +	u8 retval = 1;
> +	u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10;
> +
> +	ioc_info(mrioc, "Issuing Shutdown Notification\n");
> +	if (mrioc->unrecoverable) {
> +		ioc_warn(mrioc,
> +		    "IOC is unrecoverable Shutdown is not issued\n");
> +		return;
> +	}
> +	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
> +	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
> +	    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) {
> +		ioc_info(mrioc, "Shutdown already in progress\n");
> +		return;
> +	}
> +
> +	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
> +	ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
> +	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN;
> +
> +	writel(ioc_config, &mrioc->sysif_regs->IOCConfiguration);
> +
> +	if (mrioc->facts.shutdown_timeout)
> +		timeout = mrioc->facts.shutdown_timeout * 10;
> +
> +	do {
> +		ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
> +		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
> +		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) {
> +			retval = 0;
> +			break;
> +		}
> +		msleep(100);
> +	} while (--timeout);
> +
> +
> +	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
> +	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
> +
> +	if (retval) {
> +		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
> +		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
> +			ioc_warn(mrioc,
> +			    "Shutdown still in progress after timeout\n");
> +	}
> +
> +	ioc_info(mrioc,
> +	    "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n",
> +	    (!retval)?"successful":"failed", ioc_status,
> +	    ioc_config);
> +}
> +
> +/**
> + * mpi3mr_cleanup_ioc - Cleanup controller
> + * @mrioc: Adapter instance reference
> + *
> + * Controller cleanup handler, Message unit reset or soft reset
> + * and shutdown notification is issued to the controller and the
> + * associated memory resources are freed.
> + *
> + * Return: Nothing.
> + */
> +void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc)
> +{
> +	enum mpi3mr_iocstate ioc_state;
> +
> +	mpi3mr_ioc_disable_intr(mrioc);
> +
> +	ioc_state = mpi3mr_get_iocstate(mrioc);
> +
> +	if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) &&
> +	     (ioc_state == MRIOC_STATE_READY)) {
> +		if (mpi3mr_issue_and_process_mur(mrioc,
> +		    MPI3MR_RESET_FROM_CTLR_CLEANUP))
> +			mpi3mr_issue_reset(mrioc,
> +			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
> +			    MPI3MR_RESET_FROM_MUR_FAILURE);
> +
> +		 mpi3mr_issue_ioc_shutdown(mrioc);
> +	}
> +
> +	mpi3mr_free_mem(mrioc);
> +	mpi3mr_cleanup_resources(mrioc);
> +}
> +
> +
> +/**
> + * mpi3mr_soft_reset_handler - Reset the controller
> + * @mrioc: Adapter instance reference
> + * @reset_reason: Reset reason code
> + * @snapdump: Flag to generate snapdump in firmware or not
> + *
> + * TBD
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
> +	u32 reset_reason, u8 snapdump)
> +{
> +	return 0;
> +}
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> new file mode 100644
> index 000000000000..c31ec9883152
> --- /dev/null
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -0,0 +1,368 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Driver for Broadcom MPI3 Storage Controllers
> + *
> + * Copyright (C) 2017-2020 Broadcom Inc.
> + *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
> + *
> + */
> +
> +#include "mpi3mr.h"
> +
> +/* global driver scop variables */
> +LIST_HEAD(mrioc_list);
> +DEFINE_SPINLOCK(mrioc_list_lock);
> +static int mrioc_ids;
> +static int warn_non_secure_ctlr;
> +
> +MODULE_AUTHOR(MPI3MR_DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(MPI3MR_DRIVER_DESC);
> +MODULE_LICENSE(MPI3MR_DRIVER_LICENSE);
> +MODULE_VERSION(MPI3MR_DRIVER_VERSION);
> +
> +/* Module parameters*/
> +int logging_level;
> +module_param(logging_level, int, 0);
> +MODULE_PARM_DESC(logging_level,
> +	" bits for enabling additional logging info (default=0)");
> +
> +
> +/**
> + * mpi3mr_map_queues - Map queues callback handler
> + * @shost: SCSI host reference
> + *
> + * Call the blk_mq_pci_map_queues with from which operational
> + * queue the mapping has to be done
> + *
> + * Return: return of blk_mq_pci_map_queues
> + */
> +static int mpi3mr_map_queues(struct Scsi_Host *shost)
> +{
> +	struct mpi3mr_ioc *mrioc = shost_priv(shost);
> +
> +	return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
> +	    mrioc->pdev, 0);
> +}
> +

What happened to polling?
You did some patches for megaraid_sas, so I would have expected them to
be here, too ...

> +/**
> + * mpi3mr_slave_destroy - Slave destroy callback handler
> + * @sdev: SCSI device reference
> + *
> + * Cleanup and free per device(LUN) private data.
> + *
> + * Return: Nothing.
> + */
> +static void mpi3mr_slave_destroy(struct scsi_device *sdev)
> +{
> +}
> +
> +/**
> + * mpi3mr_target_destroy - Target destroy callback handler
> + * @starget: SCSI target reference
> + *
> + * Cleanup and free per target private data.
> + *
> + * Return: Nothing.
> + */
> +static void mpi3mr_target_destroy(struct scsi_target *starget)
> +{
> +}
> +
> +/**
> + * mpi3mr_slave_configure - Slave configure callback handler
> + * @sdev: SCSI device reference
> + *
> + * Configure queue depth, max hardware sectors and virt boundary
> + * as required
> + *
> + * Return: 0 always.
> + */
> +static int mpi3mr_slave_configure(struct scsi_device *sdev)
> +{
> +	int retval = 0;
> +	return retval;
> +}
> +
> +/**
> + * mpi3mr_slave_alloc -Slave alloc callback handler
> + * @sdev: SCSI device reference
> + *
> + * Allocate per device(LUN) private data and initialize it.
> + *
> + * Return: 0 on success -ENOMEM on memory allocation failure.
> + */
> +static int mpi3mr_slave_alloc(struct scsi_device *sdev)
> +{
> +	int retval = 0;
> +	return retval;
> +}
> +
> +/**
> + * mpi3mr_target_alloc - Target alloc callback handler
> + * @starget: SCSI target reference
> + *
> + * Allocate per target private data and initialize it.
> + *
> + * Return: 0 on success -ENOMEM on memory allocation failure.
> + */
> +static int mpi3mr_target_alloc(struct scsi_target *starget)
> +{
> +	int retval = -ENODEV;
> +	return retval;
> +}
> +
> +/**
> + * mpi3mr_qcmd - I/O request despatcher
> + * @shost: SCSI Host reference
> + * @scmd: SCSI Command reference
> + *
> + * Issues the SCSI Command as an MPI3 request.
> + *
> + * Return: 0 on successful queueing of the request or if the
> + *         request is completed with failure.
> + *         SCSI_MLQUEUE_DEVICE_BUSY when the device is busy.
> + *         SCSI_MLQUEUE_HOST_BUSY when the host queue is full.
> + */
> +static int mpi3mr_qcmd(struct Scsi_Host *shost,
> +	struct scsi_cmnd *scmd)
> +{
> +	int retval = 0;
> +
> +	scmd->result = DID_NO_CONNECT << 16;
> +	scmd->scsi_done(scmd);
> +	return retval;
> +}
> +
> +static struct scsi_host_template mpi3mr_driver_template = {
> +	.module				= THIS_MODULE,
> +	.name				= "MPI3 Storage Controller",
> +	.proc_name			= MPI3MR_DRIVER_NAME,
> +	.queuecommand			= mpi3mr_qcmd,
> +	.target_alloc			= mpi3mr_target_alloc,
> +	.slave_alloc			= mpi3mr_slave_alloc,
> +	.slave_configure		= mpi3mr_slave_configure,
> +	.target_destroy			= mpi3mr_target_destroy,
> +	.slave_destroy			= mpi3mr_slave_destroy,
> +	.map_queues			= mpi3mr_map_queues,
> +	.no_write_same			= 1,
> +	.can_queue			= 1,
> +	.this_id			= -1,
> +	.sg_tablesize			= MPI3MR_SG_DEPTH,
> +	/* max xfer supported is 1M (2K in 512 byte sized sectors)
> +	 */
> +	.max_sectors			= 2048,
> +	.cmd_per_lun			= MPI3MR_MAX_CMDS_LUN,
> +	.track_queue_depth		= 1,
> +	.cmd_size			= sizeof(struct scmd_priv),
> +};
> +
> +
> +/**
> + * mpi3mr_init_drv_cmd - Initialize internal command tracker
> + * @cmdptr: Internal command tracker
> + * @host_tag: Host tag used for the specific command
> + *
> + * Initialize the internal command tracker structure with
> + * specified host tag.
> + *
> + * Return: Nothing.
> + */
> +static inline void mpi3mr_init_drv_cmd(struct mpi3mr_drv_cmd *cmdptr,
> +	u16 host_tag)
> +{
> +	mutex_init(&cmdptr->mutex);
> +	cmdptr->reply = NULL;
> +	cmdptr->state = MPI3MR_CMD_NOTUSED;
> +	cmdptr->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
> +	cmdptr->host_tag = host_tag;
> +}
> +
> +/**
> + * mpi3mr_probe - PCI probe callback
> + * @pdev: PCI device instance
> + * @id: PCI device ID details
> + *
> + * Controller initialization routine. Checks the security status
> + * of the controller and if it is invalid or tampered return the
> + * probe without initializing the controller. Otherwise,
> + * allocate per adapter instance through shost_priv and
> + * initialize controller specific data structures, initializae
> + * the controller hardware, add shost to the SCSI subsystem.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +
> +static int
> +mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> +{
> +	struct mpi3mr_ioc *mrioc = NULL;
> +	struct Scsi_Host *shost = NULL;
> +	int retval = 0;
> +
> +	shost = scsi_host_alloc(&mpi3mr_driver_template,
> +	    sizeof(struct mpi3mr_ioc));
> +	if (!shost) {
> +		retval = -ENODEV;
> +		goto shost_failed;
> +	}
> +
> +	mrioc = shost_priv(shost);
> +	mrioc->id = mrioc_ids++;
> +	sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME);
> +	sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id);
> +	INIT_LIST_HEAD(&mrioc->list);
> +	spin_lock(&mrioc_list_lock);
> +	list_add_tail(&mrioc->list, &mrioc_list);
> +	spin_unlock(&mrioc_list_lock);
> +
> +	spin_lock_init(&mrioc->admin_req_lock);
> +	spin_lock_init(&mrioc->reply_free_queue_lock);
> +	spin_lock_init(&mrioc->sbq_lock);
> +
> +	mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
> +
> +	mrioc->logging_level = logging_level;
> +	mrioc->shost = shost;
> +	mrioc->pdev = pdev;
> +
> +	/* init shost parameters */
> +	shost->max_cmd_len = MPI3MR_MAX_CDB_LENGTH;
> +	shost->max_lun = -1;
> +	shost->unique_id = mrioc->id;
> +
> +	shost->max_channel = 1;
> +	shost->max_id = 0xFFFFFFFF;
> +
> +	mrioc->is_driver_loading = 1;
> +	if (mpi3mr_init_ioc(mrioc)) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		retval = -ENODEV;
> +		goto out_iocinit_failed;
> +	}
> +
> +	shost->nr_hw_queues = mrioc->num_op_reply_q;
> +	shost->can_queue = mrioc->max_host_ios;
> +	shost->sg_tablesize = MPI3MR_SG_DEPTH;
> +	shost->max_id = mrioc->facts.max_perids;
> +
> +	retval = scsi_add_host(shost, &pdev->dev);
> +	if (retval) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		goto addhost_failed;
> +	}
> +
> +	scsi_scan_host(shost);
> +	return retval;
> +
> +addhost_failed:
> +	mpi3mr_cleanup_ioc(mrioc);
> +out_iocinit_failed:
> +	spin_lock(&mrioc_list_lock);
> +	list_del(&mrioc->list);
> +	spin_unlock(&mrioc_list_lock);
> +	scsi_host_put(shost);
> +shost_failed:
> +	return retval;
> +}
> +
> +/**
> + * mpi3mr_remove - PCI remove callback
> + * @pdev: PCI device instance
> + *
> + * Free up all memory and resources associated with the
> + * controllerand target devices, unregister the shost.
> + *
> + * Return: Nothing.
> + */
> +static void mpi3mr_remove(struct pci_dev *pdev)
> +{
> +	struct Scsi_Host *shost = pci_get_drvdata(pdev);
> +	struct mpi3mr_ioc *mrioc;
> +
> +	mrioc = shost_priv(shost);
> +	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
> +		ssleep(1);
> +
> +
> +	scsi_remove_host(shost);
> +
> +	mpi3mr_cleanup_ioc(mrioc);
> +
> +	spin_lock(&mrioc_list_lock);
> +	list_del(&mrioc->list);
> +	spin_unlock(&mrioc_list_lock);
> +
> +	scsi_host_put(shost);
> +}
> +
> +/**
> + * mpi3mr_shutdown - PCI shutdown callback
> + * @pdev: PCI device instance
> + *
> + * Free up all memory and resources associated with the
> + * controller
> + *
> + * Return: Nothing.
> + */
> +static void mpi3mr_shutdown(struct pci_dev *pdev)
> +{
> +	struct Scsi_Host *shost = pci_get_drvdata(pdev);
> +	struct mpi3mr_ioc *mrioc;
> +
> +	if (!shost)
> +		return;
> +
> +	mrioc = shost_priv(shost);
> +	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
> +		ssleep(1);
> +
> +	mpi3mr_cleanup_ioc(mrioc);
> +
> +}
> +
> +static const struct pci_device_id mpi3mr_pci_id_table[] = {
> +	{
> +		PCI_DEVICE_SUB(PCI_VENDOR_ID_LSI_LOGIC, 0x00A5,
> +		    PCI_ANY_ID, PCI_ANY_ID)
> +	},
> +	{ 0 }
> +};
> +MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table);
> +
> +static struct pci_driver mpi3mr_pci_driver = {
> +	.name = MPI3MR_DRIVER_NAME,
> +	.id_table = mpi3mr_pci_id_table,
> +	.probe = mpi3mr_probe,
> +	.remove = mpi3mr_remove,
> +	.shutdown = mpi3mr_shutdown,
> +};
> +
> +static int __init mpi3mr_init(void)
> +{
> +	int ret_val;
> +
> +	pr_info("Loading %s version %s\n", MPI3MR_DRIVER_NAME,
> +	    MPI3MR_DRIVER_VERSION);
> +
> +	ret_val = pci_register_driver(&mpi3mr_pci_driver);
> +
> +	return ret_val;
> +}
> +
> +static void __exit mpi3mr_exit(void)
> +{
> +	if (warn_non_secure_ctlr)
> +		pr_warn(
> +		    "Unloading %s version %s while managing a non secure controller\n",
> +		    MPI3MR_DRIVER_NAME, MPI3MR_DRIVER_VERSION);
> +	else
> +		pr_info("Unloading %s version %s\n", MPI3MR_DRIVER_NAME,
> +		    MPI3MR_DRIVER_VERSION);
> +
> +	pci_unregister_driver(&mpi3mr_pci_driver);
> +}
> +
> +module_init(mpi3mr_init);
> +module_exit(mpi3mr_exit);
> 
Cheers,

Hannes
Kashyap Desai March 2, 2021, 6:36 p.m. UTC | #3
> > +struct mpi3mr_ioc {
> > +	struct list_head list;
> > +	struct pci_dev *pdev;
> > +	struct Scsi_Host *shost;
> > +	u8 id;
> > +	int cpu_count;
> > +
> > +	char name[MPI3MR_NAME_LENGTH];
> > +	char driver_name[MPI3MR_NAME_LENGTH];
> > +
> > +	Mpi3SysIfRegs_t __iomem *sysif_regs;
> > +	resource_size_t sysif_regs_phys;
> > +	int bars;
> > +	u64 dma_mask;
> > +
> > +	u16 msix_count;
> > +	u8 intr_enabled;
> > +
> > +	u16 num_admin_req;
> > +	u32 admin_req_q_sz;
> > +	u16 admin_req_pi;
> > +	u16 admin_req_ci;
> > +	void *admin_req_base;
> > +	dma_addr_t admin_req_dma;
> > +	spinlock_t admin_req_lock;
> > +
> > +	u16 num_admin_replies;
> > +	u32 admin_reply_q_sz;
> > +	u16 admin_reply_ci;
> > +	u8 admin_reply_ephase;
> > +	void *admin_reply_base;
> > +	dma_addr_t admin_reply_dma;
> > +
> > +	u32 ready_timeout;
> > +
> > +	struct mpi3mr_intr_info *intr_info;
>
> Please, be consistent.
> If you must introduce typedefs for your internal structures, okay.
> But then introduce typedefs for _all_ internal structures.
> Or leave the typedefs and just use 'struct XXX'; which actually is the
> recommended way for linux.

Are you referring " typedef struct mpi3mr_drv_" ?. This is because of some
inter-operability issue of different kernel version. I will remove this
typedef in my V2.
Usually, our goal is not to have typedef in drivers except mpi3.0 header
files. I will scan such instances in and will update all the places.

>
> > +	u16 intr_info_count;
> > +
> > +	u16 num_queues;
> > +	u16 num_op_req_q;
> > +	struct op_req_qinfo *req_qinfo;
> > +
> > +	u16 num_op_reply_q;
> > +	struct op_reply_qinfo *op_reply_qinfo;
> > +
> > +	struct mpi3mr_drv_cmd init_cmds;
> > +	struct mpi3mr_ioc_facts facts;
> > +	u16 op_reply_desc_sz;
> > +
> > +	u32 num_reply_bufs;
> > +	struct dma_pool *reply_buf_pool;
> > +	u8 *reply_buf;
> > +	dma_addr_t reply_buf_dma;
> > +	dma_addr_t reply_buf_dma_max_address;
> > +
> > +	u16 reply_free_qsz;
> > +	struct dma_pool *reply_free_q_pool;
> > +	U64 *reply_free_q;
> > +	dma_addr_t reply_free_q_dma;
> > +	spinlock_t reply_free_queue_lock;
> > +	u32 reply_free_queue_host_index;
> > +
> > +	u32 num_sense_bufs;
> > +	struct dma_pool *sense_buf_pool;
> > +	u8 *sense_buf;
> > +	dma_addr_t sense_buf_dma;
> > +
> > +	u16 sense_buf_q_sz;
> > +	struct dma_pool *sense_buf_q_pool;
> > +	U64 *sense_buf_q;
> > +	dma_addr_t sense_buf_q_dma;
> > +	spinlock_t sbq_lock;
> > +	u32 sbq_host_index;
> > +
> > +	u8 is_driver_loading;
> > +
> > +	u16 max_host_ios;
> > +
> > +	u32 chain_buf_count;
> > +	struct dma_pool *chain_buf_pool;
> > +	struct chain_element *chain_sgl_list;
> > +	u16  chain_bitmap_sz;
> > +	void *chain_bitmap;
> > +
> > +	u8 reset_in_progress;
> > +	u8 unrecoverable;
> > +
> > +	int logging_level;
> > +
> > +	struct mpi3mr_fwevt *current_event;
> > +	Mpi3DriverInfoLayout_t driver_info;
>
> See my comment about struct typedefs above.

I will remove this typedef and similar instances.

> > +static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16
index)
> > +{
> > +	struct pci_dev *pdev = mrioc->pdev;
> > +	struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index;
> > +	int retval = 0;
> > +
> > +	intr_info->mrioc = mrioc;
> > +	intr_info->msix_index = index;
> > +	intr_info->op_reply_q = NULL;
> > +
> > +	snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d",
> > +	    mrioc->driver_name, mrioc->id, index);
> > +
> > +	retval = request_threaded_irq(pci_irq_vector(pdev, index),
> mpi3mr_isr,
> > +	    mpi3mr_isr_poll, IRQF_ONESHOT, intr_info->name, intr_info);
> > +	if (retval) {
> > +		ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n",
> > +		    intr_info->name, pci_irq_vector(pdev, index));
> > +		return retval;
> > +	}
> > +
>
> The point of having 'mpi3mr_isr_poll()' here is what exactly?

This is a place holder and actual use case is handled in " [17/24] mpi3mr:
add support of threaded isr"
For easy review, I have created separate patch " [17/24] mpi3mr: add
support of threaded isr"
> > +	areq_entry = (u8 *)mrioc->admin_req_base +
> > +	    (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
> > +	memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
> > +	memcpy(areq_entry, (u8 *)admin_req, admin_req_sz);
> > +
> > +	if (++areq_pi == max_entries)
> > +		areq_pi = 0;
> > +	mrioc->admin_req_pi = areq_pi;
> > +
> > +	writel(mrioc->admin_req_pi, &mrioc->sysif_regs-
> >AdminRequestQueuePI);
> > +
> > +out:
> > +	spin_unlock_irqrestore(&mrioc->admin_req_lock, flags);
> > +
> > +	return retval;
> > +}
> > +
>
> It might be an idea to have an 'admin' queue structure; keeping the
> values all within the main IOC structure might cause cache misses and a
> degraded performance.

Noted your point. We can do it in future update. I think it make sense for
code readability as well.

> > +int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
> > +{
> > +	int retval = 0;
> > +	enum mpi3mr_iocstate ioc_state;
> > +	u64 base_info;
> > +	u32 timeout;
> > +	u32 ioc_status, ioc_config;
> > +	Mpi3IOCFactsData_t facts_data;
> > +
> > +	mrioc->change_count = 0;
> > +	mrioc->cpu_count = num_online_cpus();
>
> What about CPU hotplug?


We have to use num_available_cpus() to get benefit of cpu hotplug. In next
update it will be available.

> > +
> > +/* global driver scop variables */
> > +LIST_HEAD(mrioc_list);
> > +DEFINE_SPINLOCK(mrioc_list_lock);
> > +static int mrioc_ids;
> > +static int warn_non_secure_ctlr;
> > +
> > +MODULE_AUTHOR(MPI3MR_DRIVER_AUTHOR);
> > +MODULE_DESCRIPTION(MPI3MR_DRIVER_DESC);
> > +MODULE_LICENSE(MPI3MR_DRIVER_LICENSE);
> > +MODULE_VERSION(MPI3MR_DRIVER_VERSION);
> > +
> > +/* Module parameters*/
> > +int logging_level;
> > +module_param(logging_level, int, 0);
> > +MODULE_PARM_DESC(logging_level,
> > +	" bits for enabling additional logging info (default=0)");
> > +
> > +
> > +/**
> > + * mpi3mr_map_queues - Map queues callback handler
> > + * @shost: SCSI host reference
> > + *
> > + * Call the blk_mq_pci_map_queues with from which operational
> > + * queue the mapping has to be done
> > + *
> > + * Return: return of blk_mq_pci_map_queues
> > + */
> > +static int mpi3mr_map_queues(struct Scsi_Host *shost)
> > +{
> > +	struct mpi3mr_ioc *mrioc = shost_priv(shost);
> > +
> > +	return blk_mq_pci_map_queues(&shost-
> >tag_set.map[HCTX_TYPE_DEFAULT],
> > +	    mrioc->pdev, 0);
> > +}
> > +
>
> What happened to polling?
> You did some patches for megaraid_sas, so I would have expected them to
> be here, too ...

Internally, Io_uring iopoll is also completed for this driver as well, but
it is under testing and may be available in next update.

> > +module_init(mpi3mr_init);
> > +module_exit(mpi3mr_exit);
> >
> Cheers,

Hannes -

Thanks for the feedback. I am working on all the comments and soon I will
be posting V2.

Kashyap
>
> Hannes
> --
> Dr. Hannes Reinecke		           Kernel Storage Architect
> hare@suse.de			                  +49 911 74053 688
> SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg
> HRB 36809 (AG Nürnberg), GF: Felix Imendörffer
diff mbox series

Patch

diff --git a/drivers/scsi/mpi3mr/Makefile b/drivers/scsi/mpi3mr/Makefile
new file mode 100644
index 000000000000..7c2063e04c81
--- /dev/null
+++ b/drivers/scsi/mpi3mr/Makefile
@@ -0,0 +1,4 @@ 
+# mpi3mr makefile
+obj-m += mpi3mr.o
+mpi3mr-y +=  mpi3mr_os.o     \
+		mpi3mr_fw.o \
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
new file mode 100644
index 000000000000..dd79b12218e1
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -0,0 +1,526 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Driver for Broadcom MPI3 Storage Controllers
+ *
+ * Copyright (C) 2017-2020 Broadcom Inc.
+ *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
+ *
+ */
+
+#ifndef MPI3MR_H_INCLUDED
+#define MPI3MR_H_INCLUDED
+
+#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
+#include <linux/blk-mq-pci.h>
+#include <linux/delay.h>
+#include <linux/dmapool.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+#include "mpi/mpi30_api.h"
+#include "mpi3mr_debug.h"
+
+/* Global list and lock for storing multiple adapters managed by the driver */
+extern spinlock_t mrioc_list_lock;
+extern struct list_head mrioc_list;
+
+#define MPI3MR_DRIVER_VERSION	"00.255.45.01"
+#define MPI3MR_DRIVER_RELDATE	"12-December-2020"
+
+#define MPI3MR_DRIVER_NAME	"mpi3mr"
+#define MPI3MR_DRIVER_LICENSE	"GPL"
+#define MPI3MR_DRIVER_AUTHOR	"Broadcom Inc. <mpi3mr-linuxdrv.pdl@broadcom.com>"
+#define MPI3MR_DRIVER_DESC	"MPI3 Storage Controller Device Driver"
+
+#define MPI3MR_NAME_LENGTH	32
+#define IOCNAME			"%s: "
+
+/* Definitions for internal SGL and Chain SGL buffers */
+#define MPI3MR_PAGE_SIZE_4K		4096
+#define MPI3MR_SG_DEPTH		(PAGE_SIZE/sizeof(Mpi3SGESimple_t))
+
+/* Definitions for MAX values for shost */
+#define MPI3MR_MAX_CMDS_LUN	7
+#define MPI3MR_MAX_CDB_LENGTH	32
+
+/* Admin queue management definitions */
+#define MPI3MR_ADMIN_REQ_Q_SIZE		(2 * MPI3MR_PAGE_SIZE_4K)
+#define MPI3MR_ADMIN_REPLY_Q_SIZE	(4 * MPI3MR_PAGE_SIZE_4K)
+#define MPI3MR_ADMIN_REQ_FRAME_SZ	128
+#define MPI3MR_ADMIN_REPLY_FRAME_SZ	16
+
+
+/* Reserved Host Tag definitions */
+#define MPI3MR_HOSTTAG_INVALID		0xFFFF
+#define MPI3MR_HOSTTAG_INITCMDS		1
+#define MPI3MR_HOSTTAG_IOCTLCMDS	2
+#define MPI3MR_HOSTTAG_BLK_TMS		5
+
+#define MPI3MR_NUM_DEVRMCMD		1
+#define MPI3MR_HOSTTAG_DEVRMCMD_MIN	(MPI3MR_HOSTTAG_BLK_TMS + 1)
+#define MPI3MR_HOSTTAG_DEVRMCMD_MAX	(MPI3MR_HOSTTAG_DEVRMCMD_MIN + \
+						MPI3MR_NUM_DEVRMCMD - 1)
+
+#define MPI3MR_INTERNAL_CMDS_RESVD     MPI3MR_HOSTTAG_DEVRMCMD_MAX
+
+/* Reduced resource count definition for crash kernel */
+#define MPI3MR_HOST_IOS_KDUMP		128
+
+/* command/controller interaction timeout definitions in seconds */
+#define MPI3MR_INTADMCMD_TIMEOUT		10
+#define MPI3MR_RESETTM_TIMEOUT			30
+#define MPI3MR_DEFAULT_SHUTDOWN_TIME		120
+
+#define MPI3MR_WATCHDOG_INTERVAL		1000 /* in milli seconds */
+
+/* Internal admin command state definitions*/
+#define MPI3MR_CMD_NOTUSED	0x8000
+#define MPI3MR_CMD_COMPLETE	0x0001
+#define MPI3MR_CMD_PENDING	0x0002
+#define MPI3MR_CMD_REPLY_VALID	0x0004
+#define MPI3MR_CMD_RESET	0x0008
+
+/* Definitions for Event replies and sense buffer allocated per controller */
+#define MPI3MR_NUM_EVT_REPLIES	64
+#define MPI3MR_SENSEBUF_SZ	256
+#define MPI3MR_SENSEBUF_FACTOR	3
+#define MPI3MR_CHAINBUF_FACTOR	3
+
+/* Invalid target device handle */
+#define MPI3MR_INVALID_DEV_HANDLE	0xFFFF
+
+/* Controller Reset related definitions */
+#define MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT	5
+#define MPI3MR_MAX_RESET_RETRY_COUNT		3
+
+/* ResponseCode definitions */
+#define MPI3MR_RI_MASK_RESPCODE		(0x000000FF)
+#define MPI3MR_RSP_TM_COMPLETE		0x00
+#define MPI3MR_RSP_INVALID_FRAME	0x02
+#define MPI3MR_RSP_TM_NOT_SUPPORTED	0x04
+#define MPI3MR_RSP_TM_FAILED		0x05
+#define MPI3MR_RSP_TM_SUCCEEDED		0x08
+#define MPI3MR_RSP_TM_INVALID_LUN	0x09
+#define MPI3MR_RSP_TM_OVERLAPPED_TAG	0x0A
+#define MPI3MR_RSP_IO_QUEUED_ON_IOC \
+			MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC
+
+/* SGE Flag definition */
+#define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \
+	(MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \
+	MPI3_SGE_FLAGS_END_OF_LIST)
+
+/* IOC State definitions */
+enum mpi3mr_iocstate {
+	MRIOC_STATE_READY = 1,
+	MRIOC_STATE_RESET,
+	MRIOC_STATE_FAULT,
+	MRIOC_STATE_BECOMING_READY,
+	MRIOC_STATE_RESET_REQUESTED,
+	MRIOC_STATE_UNRECOVERABLE,
+};
+
+/* Reset reason code definitions*/
+enum mpi3mr_reset_reason {
+	MPI3MR_RESET_FROM_BRINGUP = 1,
+	MPI3MR_RESET_FROM_FAULT_WATCH = 2,
+	MPI3MR_RESET_FROM_IOCTL = 3,
+	MPI3MR_RESET_FROM_EH_HOS = 4,
+	MPI3MR_RESET_FROM_TM_TIMEOUT = 5,
+	MPI3MR_RESET_FROM_IOCTL_TIMEOUT = 6,
+	MPI3MR_RESET_FROM_MUR_FAILURE = 7,
+	MPI3MR_RESET_FROM_CTLR_CLEANUP = 8,
+	MPI3MR_RESET_FROM_CIACTIV_FAULT = 9,
+	MPI3MR_RESET_FROM_PE_TIMEOUT = 10,
+	MPI3MR_RESET_FROM_TSU_TIMEOUT = 11,
+	MPI3MR_RESET_FROM_DELREQQ_TIMEOUT = 12,
+	MPI3MR_RESET_FROM_DELREPQ_TIMEOUT = 13,
+	MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT = 14,
+	MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT = 15,
+	MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT = 16,
+	MPI3MR_RESET_FROM_IOCINIT_TIMEOUT = 17,
+	MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT = 18,
+	MPI3MR_RESET_FROM_EVTACK_TIMEOUT = 19,
+	MPI3MR_RESET_FROM_CIACTVRST_TIMER = 20,
+	MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT = 21,
+};
+
+/**
+ * struct mpi3mr_compimg_ver - replica of component image
+ * version defined in mpi30_image.h in host endianness
+ *
+ */
+struct mpi3mr_compimg_ver {
+	u16 build_num;
+	u16 cust_id;
+	u8 ph_minor;
+	u8 ph_major;
+	u8 gen_minor;
+	u8 gen_major;
+};
+
+/**
+ * struct mpi3mr_ioc_facs - replica of component image version
+ * defined in mpi30_ioc.h in host endianness
+ *
+ */
+struct mpi3mr_ioc_facts {
+	u32 ioc_capabilities;
+	struct mpi3mr_compimg_ver fw_ver;
+	u32 mpi_version;
+	u16 max_reqs;
+	u16 product_id;
+	u16 op_req_sz;
+	u16 reply_sz;
+	u16 exceptions;
+	u16 max_perids;
+	u16 max_pds;
+	u16 max_sasexpanders;
+	u16 max_sasinitiators;
+	u16 max_enclosures;
+	u16 max_pcieswitches;
+	u16 max_nvme;
+	u16 max_vds;
+	u16 max_hpds;
+	u16 max_advhpds;
+	u16 max_raidpds;
+	u16 min_devhandle;
+	u16 max_devhandle;
+	u16 max_op_req_q;
+	u16 max_op_reply_q;
+	u16 shutdown_timeout;
+	u8 ioc_num;
+	u8 who_init;
+	u16 max_msix_vectors;
+	u8 personality;
+	u8 dma_mask;
+	u8 protocol_flags;
+	u8 sge_mod_mask;
+	u8 sge_mod_value;
+	u8 sge_mod_shift;
+};
+
+/**
+ * struct op_req_qinfo -  Operational Request Queue Information
+ *
+ * @ci: consumer index
+ * @pi: producer index
+ */
+struct op_req_qinfo {
+	u16 ci;
+	u16 pi;
+};
+
+/**
+ * struct op_reply_qinfo -  Operational Reply Queue Information
+ *
+ * @ci: consumer index
+ * @qid: Queue Id starting from 1
+ */
+struct op_reply_qinfo {
+	u16 ci;
+	u16 qid;
+};
+
+/**
+ * struct mpi3mr_intr_info -  Interrupt cookie information
+ *
+ * @mrioc: Adapter instance reference
+ * @msix_index: MSIx index
+ * @op_reply_q: Associated operational reply queue
+ * @name: Dev name for the irq claiming device
+ */
+struct mpi3mr_intr_info {
+	struct mpi3mr_ioc *mrioc;
+	u16 msix_index;
+	struct op_reply_qinfo *op_reply_q;
+	char name[MPI3MR_NAME_LENGTH];
+};
+
+
+typedef struct mpi3mr_drv_cmd DRV_CMD;
+typedef void (*DRV_CMD_CALLBACK)(struct mpi3mr_ioc *mrioc,
+	DRV_CMD *drv_cmd);
+
+/**
+ * struct mpi3mr_drv_cmd - Internal command tracker
+ *
+ * @mutex: Command mutex
+ * @done: Completeor for wakeup
+ * @reply: Firmware reply for internal commands
+ * @sensebuf: Sensebuf for SCSI IO commands
+ * @state: Command State
+ * @dev_handle: Firmware handle for device specific commands
+ * @ioc_status: IOC status from the firmware
+ * @ioc_loginfo:IOC log info from the firmware
+ * @is_waiting: Is the command issued in block mode
+ * @retry_count: Retry count for retriable commands
+ * @host_tag: Host tag used by the command
+ * @callback: Callback for non blocking commands
+ */
+struct mpi3mr_drv_cmd {
+	struct mutex mutex;
+	struct completion done;
+	void *reply;
+	u8 *sensebuf;
+	u16 state;
+	u16 dev_handle;
+	u16 ioc_status;
+	u32 ioc_loginfo;
+	u8 is_waiting;
+	u8 retry_count;
+	u16 host_tag;
+	DRV_CMD_CALLBACK callback;
+};
+
+
+/**
+ * struct chain_element - memory descriptor structure to store
+ * virtual and dma addresses for chain elements.
+ *
+ * @addr: virtual address
+ * @dma_addr: dma address
+ */
+struct chain_element {
+	void *addr;
+	dma_addr_t dma_addr;
+};
+
+/**
+ * struct scmd_priv - SCSI command private data
+ *
+ * @host_tag: Host tag specific to operational queue
+ * @in_lld_scope: Command in LLD scope or not
+ * @scmd: SCSI Command pointer
+ * @req_q_idx: Operational request queue index
+ * @chain_idx: Chain frame index
+ * @mpi3mr_scsiio_req: MPI SCSI IO request
+ */
+struct scmd_priv {
+	u16 host_tag;
+	u8 in_lld_scope;
+	struct scsi_cmnd *scmd;
+	u16 req_q_idx;
+	int chain_idx;
+	u8 mpi3mr_scsiio_req[MPI3MR_ADMIN_REQ_FRAME_SZ];
+};
+
+/**
+ * struct mpi3mr_ioc - Adapter anchor structure stored in shost
+ * private data
+ *
+ * @list: List pointer
+ * @pdev: PCI device pointer
+ * @shost: Scsi_Host pointer
+ * @id: Controller ID
+ * @cpu_count: Number of online CPUs
+ * @name: Controller ASCII name
+ * @driver_name: Driver ASCII name
+ * @sysif_regs: System interface registers virtual address
+ * @sysif_regs_phys: System interface registers physical address
+ * @bars: PCI BARS
+ * @dma_mask: DMA mask
+ * @msix_count: Number of MSIX vectors used
+ * @intr_enabled: Is interrupts enabled
+ * @num_admin_req: Number of admin requests
+ * @admin_req_q_sz: Admin request queue size
+ * @admin_req_pi: Admin request queue producer index
+ * @admin_req_ci: Admin request queue consumer index
+ * @admin_req_base: Admin request queue base virtual address
+ * @admin_req_dma: Admin request queue base dma address
+ * @admin_req_lock: Admin queue access lock
+ * @num_admin_replies: Number of admin replies
+ * @admin_reply_q_sz: Admin reply queue size
+ * @admin_reply_ci: Admin reply queue consumer index
+ * @admin_reply_ephase:Admin reply queue expected phase
+ * @admin_reply_base: Admin reply queue base virtual address
+ * @admin_reply_dma: Admin reply queue base dma address
+ * @ready_timeout: Controller ready timeout
+ * @intr_info: Interrupt cookie pointer
+ * @intr_info_count: Number of interrupt cookies
+ * @num_queues: Number of operational queues
+ * @num_op_req_q: Number of operational request queues
+ * @req_qinfo: Operational request queue info pointer
+ * @num_op_reply_q: Number of operational reply queues
+ * @op_reply_qinfo: Operational reply queue info pointer
+ * @init_cmds: Command tracker for initialization commands
+ * @facts: Cached IOC facts data
+ * @op_reply_desc_sz: Operational reply descriptor size
+ * @num_reply_bufs: Number of reply buffers allocated
+ * @reply_buf_pool: Reply buffer pool
+ * @reply_buf: Reply buffer base virtual address
+ * @reply_buf_dma: Reply buffer DMA address
+ * @reply_buf_dma_max_address: Reply DMA address max limit
+ * @reply_free_qsz: Reply free queue size
+ * @reply_free_q_pool: Reply free queue pool
+ * @reply_free_q: Reply free queue base virtual address
+ * @reply_free_q_dma: Reply free queue base DMA address
+ * @reply_free_queue_lock: Reply free queue lock
+ * @reply_free_queue_host_index: Reply free queue host index
+ * @num_sense_bufs: Number of sense buffers
+ * @sense_buf_pool: Sense buffer pool
+ * @sense_buf: Sense buffer base virtual address
+ * @sense_buf_dma: Sense buffer base DMA address
+ * @sense_buf_q_sz: Sense buffer queue size
+ * @sense_buf_q_pool: Sense buffer queue pool
+ * @sense_buf_q: Sense buffer queue virtual address
+ * @sense_buf_q_dma: Sense buffer queue DMA address
+ * @sbq_lock: Sense buffer queue lock
+ * @sbq_host_index: Sense buffer queuehost index
+ * @is_driver_loading: Is driver still loading
+ * @max_host_ios: Maximum host I/O count
+ * @chain_buf_count: Chain buffer count
+ * @chain_buf_pool: Chain buffer pool
+ * @chain_sgl_list: Chain SGL list
+ * @chain_bitmap_sz: Chain buffer allocator bitmap size
+ * @chain_bitmap: Chain buffer allocator bitmap
+ * @reset_in_progress: Reset in progress flag
+ * @unrecoverable: Controller unrecoverable flag
+ * @logging_level: Controller debug logging level
+ * @current_event: Firmware event currently in process
+ * @driver_info: Driver, Kernel, OS information to firmware
+ * @change_count: Topology change count
+ */
+struct mpi3mr_ioc {
+	struct list_head list;
+	struct pci_dev *pdev;
+	struct Scsi_Host *shost;
+	u8 id;
+	int cpu_count;
+
+	char name[MPI3MR_NAME_LENGTH];
+	char driver_name[MPI3MR_NAME_LENGTH];
+
+	Mpi3SysIfRegs_t __iomem *sysif_regs;
+	resource_size_t sysif_regs_phys;
+	int bars;
+	u64 dma_mask;
+
+	u16 msix_count;
+	u8 intr_enabled;
+
+	u16 num_admin_req;
+	u32 admin_req_q_sz;
+	u16 admin_req_pi;
+	u16 admin_req_ci;
+	void *admin_req_base;
+	dma_addr_t admin_req_dma;
+	spinlock_t admin_req_lock;
+
+	u16 num_admin_replies;
+	u32 admin_reply_q_sz;
+	u16 admin_reply_ci;
+	u8 admin_reply_ephase;
+	void *admin_reply_base;
+	dma_addr_t admin_reply_dma;
+
+	u32 ready_timeout;
+
+	struct mpi3mr_intr_info *intr_info;
+	u16 intr_info_count;
+
+	u16 num_queues;
+	u16 num_op_req_q;
+	struct op_req_qinfo *req_qinfo;
+
+	u16 num_op_reply_q;
+	struct op_reply_qinfo *op_reply_qinfo;
+
+	struct mpi3mr_drv_cmd init_cmds;
+	struct mpi3mr_ioc_facts facts;
+	u16 op_reply_desc_sz;
+
+	u32 num_reply_bufs;
+	struct dma_pool *reply_buf_pool;
+	u8 *reply_buf;
+	dma_addr_t reply_buf_dma;
+	dma_addr_t reply_buf_dma_max_address;
+
+	u16 reply_free_qsz;
+	struct dma_pool *reply_free_q_pool;
+	U64 *reply_free_q;
+	dma_addr_t reply_free_q_dma;
+	spinlock_t reply_free_queue_lock;
+	u32 reply_free_queue_host_index;
+
+	u32 num_sense_bufs;
+	struct dma_pool *sense_buf_pool;
+	u8 *sense_buf;
+	dma_addr_t sense_buf_dma;
+
+	u16 sense_buf_q_sz;
+	struct dma_pool *sense_buf_q_pool;
+	U64 *sense_buf_q;
+	dma_addr_t sense_buf_q_dma;
+	spinlock_t sbq_lock;
+	u32 sbq_host_index;
+
+	u8 is_driver_loading;
+
+	u16 max_host_ios;
+
+	u32 chain_buf_count;
+	struct dma_pool *chain_buf_pool;
+	struct chain_element *chain_sgl_list;
+	u16  chain_bitmap_sz;
+	void *chain_bitmap;
+
+	u8 reset_in_progress;
+	u8 unrecoverable;
+
+	int logging_level;
+
+	struct mpi3mr_fwevt *current_event;
+	Mpi3DriverInfoLayout_t driver_info;
+	u16 change_count;
+};
+
+int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc);
+void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc);
+int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc);
+void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc);
+int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
+u16 admin_req_sz, u8 ignore_reset);
+void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length,
+			  dma_addr_t dma_addr);
+void mpi3mr_build_zero_len_sge(void *paddr);
+void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc,
+				     dma_addr_t phys_addr);
+void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
+				     dma_addr_t phys_addr);
+void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
+				     u64 sense_buf_dma);
+
+void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc);
+void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc);
+
+int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
+			      u32 reset_reason, u8 snapdump);
+void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc);
+void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc);
+
+enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc);
+
+#endif /*MPI3MR_H_INCLUDED*/
diff --git a/drivers/scsi/mpi3mr/mpi3mr_debug.h b/drivers/scsi/mpi3mr/mpi3mr_debug.h
new file mode 100644
index 000000000000..d35f296d9325
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi3mr_debug.h
@@ -0,0 +1,60 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Driver for Broadcom MPI3 Storage Controllers
+ *
+ * Copyright (C) 2017-2020 Broadcom Inc.
+ *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
+ *
+ */
+
+#ifndef MPI3SAS_DEBUG_H_INCLUDED
+
+#define MPI3SAS_DEBUG_H_INCLUDED
+
+/*
+ * debug levels
+ */
+#define MPI3_DEBUG			0x00000001
+#define MPI3_DEBUG_MSG_FRAME		0x00000002
+#define MPI3_DEBUG_SG			0x00000004
+#define MPI3_DEBUG_EVENTS		0x00000008
+#define MPI3_DEBUG_EVENT_WORK_TASK	0x00000010
+#define MPI3_DEBUG_INIT			0x00000020
+#define MPI3_DEBUG_EXIT			0x00000040
+#define MPI3_DEBUG_FAIL			0x00000080
+#define MPI3_DEBUG_TM			0x00000100
+#define MPI3_DEBUG_REPLY		0x00000200
+#define MPI3_DEBUG_HANDSHAKE		0x00000400
+#define MPI3_DEBUG_CONFIG		0x00000800
+#define MPI3_DEBUG_DL			0x00001000
+#define MPI3_DEBUG_RESET		0x00002000
+#define MPI3_DEBUG_SCSI			0x00004000
+#define MPI3_DEBUG_IOCTL		0x00008000
+#define MPI3_DEBUG_CSMISAS		0x00010000
+#define MPI3_DEBUG_SAS			0x00020000
+#define MPI3_DEBUG_TRANSPORT		0x00040000
+#define MPI3_DEBUG_TASK_SET_FULL	0x00080000
+#define MPI3_DEBUG_TRIGGER_DIAG		0x00200000
+
+
+/*
+ * debug macros
+ */
+
+#define ioc_err(ioc, fmt, ...) \
+	pr_err("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
+#define ioc_notice(ioc, fmt, ...) \
+	pr_notice("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
+#define ioc_warn(ioc, fmt, ...) \
+	pr_warn("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
+#define ioc_info(ioc, fmt, ...) \
+	pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
+
+
+#define dbgprint(IOC, FMT, ...) \
+	do { \
+		if (IOC->logging_level & MPI3_DEBUG) \
+			pr_info("%s: " FMT, (IOC)->name, ##__VA_ARGS__); \
+	} while (0)
+
+#endif /* MPT3SAS_DEBUG_H_INCLUDED */
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
new file mode 100644
index 000000000000..97eb7e6ec5c6
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -0,0 +1,1819 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Broadcom MPI3 Storage Controllers
+ *
+ * Copyright (C) 2017-2020 Broadcom Inc.
+ *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
+ *
+ */
+
+#include "mpi3mr.h"
+
+#if defined(writeq) && defined(CONFIG_64BIT)
+static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
+{
+	writeq(b, addr);
+}
+#else
+static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
+{
+	__u64 data_out = b;
+
+	writel((u32)(data_out), addr);
+	writel((u32)(data_out >> 32), (addr + 4));
+}
+#endif
+
+static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc)
+{
+	u16 i, max_vectors;
+
+	max_vectors = mrioc->intr_info_count;
+
+	for (i = 0; i < max_vectors; i++)
+		synchronize_irq(pci_irq_vector(mrioc->pdev, i));
+}
+
+void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc)
+{
+	mrioc->intr_enabled = 0;
+	mpi3mr_sync_irqs(mrioc);
+}
+
+void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc)
+{
+	mrioc->intr_enabled = 1;
+}
+
+static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc)
+{
+	u16 i;
+
+	mpi3mr_ioc_disable_intr(mrioc);
+
+	if (!mrioc->intr_info)
+		return;
+
+	for (i = 0; i < mrioc->intr_info_count; i++)
+		free_irq(pci_irq_vector(mrioc->pdev, i),
+		    (mrioc->intr_info + i));
+
+	kfree(mrioc->intr_info);
+	mrioc->intr_info = NULL;
+	mrioc->intr_info_count = 0;
+	pci_free_irq_vectors(mrioc->pdev);
+}
+
+void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length,
+	dma_addr_t dma_addr)
+{
+	Mpi3SGESimple_t *sgel = paddr;
+
+	sgel->Flags = flags;
+	sgel->Length = cpu_to_le32(length);
+	sgel->Address = cpu_to_le64(dma_addr);
+}
+
+void mpi3mr_build_zero_len_sge(void *paddr)
+{
+	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
+
+	mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1);
+
+}
+void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
+	dma_addr_t phys_addr)
+{
+	if (!phys_addr)
+		return NULL;
+
+	if ((phys_addr < mrioc->reply_buf_dma) ||
+	    (phys_addr > mrioc->reply_buf_dma_max_address))
+		return NULL;
+
+	return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma);
+}
+
+void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc,
+	dma_addr_t phys_addr)
+{
+	if (!phys_addr)
+		return NULL;
+
+	return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma);
+}
+
+static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc,
+	u64 reply_dma)
+{
+	u32 old_idx = 0;
+
+	spin_lock(&mrioc->reply_free_queue_lock);
+	old_idx  =  mrioc->reply_free_queue_host_index;
+	mrioc->reply_free_queue_host_index = (
+	    (mrioc->reply_free_queue_host_index ==
+	    (mrioc->reply_free_qsz - 1)) ? 0 :
+	    (mrioc->reply_free_queue_host_index + 1));
+	mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma);
+	writel(mrioc->reply_free_queue_host_index,
+	    &mrioc->sysif_regs->ReplyFreeHostIndex);
+	spin_unlock(&mrioc->reply_free_queue_lock);
+}
+
+void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
+	u64 sense_buf_dma)
+{
+	u32 old_idx = 0;
+
+	spin_lock(&mrioc->sbq_lock);
+	old_idx  =  mrioc->sbq_host_index;
+	mrioc->sbq_host_index = ((mrioc->sbq_host_index ==
+	    (mrioc->sense_buf_q_sz - 1)) ? 0 :
+	    (mrioc->sbq_host_index + 1));
+	mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma);
+	writel(mrioc->sbq_host_index,
+	    &mrioc->sysif_regs->SenseBufferFreeHostIndex);
+	spin_unlock(&mrioc->sbq_lock);
+}
+
+static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc,
+	Mpi3DefaultReply_t *def_reply)
+{
+	Mpi3EventNotificationReply_t *event_reply =
+	    (Mpi3EventNotificationReply_t *)def_reply;
+
+	mrioc->change_count = le16_to_cpu(event_reply->IOCChangeCount);
+}
+
+static struct mpi3mr_drv_cmd *
+mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
+	Mpi3DefaultReply_t *def_reply)
+{
+	switch (host_tag) {
+	case MPI3MR_HOSTTAG_INITCMDS:
+		return &mrioc->init_cmds;
+	case MPI3MR_HOSTTAG_INVALID:
+		if (def_reply && def_reply->Function ==
+		    MPI3_FUNCTION_EVENT_NOTIFICATION)
+			mpi3mr_handle_events(mrioc, def_reply);
+		return NULL;
+	default:
+		break;
+	}
+
+	return NULL;
+}
+
+static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
+	Mpi3DefaultReplyDescriptor_t *reply_desc, u64 *reply_dma)
+{
+	u16 reply_desc_type, host_tag = 0;
+	u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
+	u32 ioc_loginfo = 0;
+	Mpi3StatusReplyDescriptor_t *status_desc;
+	Mpi3AddressReplyDescriptor_t *addr_desc;
+	Mpi3SuccessReplyDescriptor_t *success_desc;
+	Mpi3DefaultReply_t *def_reply = NULL;
+	struct mpi3mr_drv_cmd *cmdptr = NULL;
+	Mpi3SCSIIOReply_t *scsi_reply;
+	u8 *sense_buf = NULL;
+
+	*reply_dma = 0;
+	reply_desc_type = le16_to_cpu(reply_desc->ReplyFlags) &
+	    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
+	switch (reply_desc_type) {
+	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
+		status_desc = (Mpi3StatusReplyDescriptor_t *)reply_desc;
+		host_tag = le16_to_cpu(status_desc->HostTag);
+		ioc_status = le16_to_cpu(status_desc->IOCStatus);
+		if (ioc_status &
+		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
+			ioc_loginfo = le32_to_cpu(status_desc->IOCLogInfo);
+		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+		break;
+	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
+		addr_desc = (Mpi3AddressReplyDescriptor_t *)reply_desc;
+		*reply_dma = le64_to_cpu(addr_desc->ReplyFrameAddress);
+		def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma);
+		if (!def_reply)
+			goto out;
+		host_tag = le16_to_cpu(def_reply->HostTag);
+		ioc_status = le16_to_cpu(def_reply->IOCStatus);
+		if (ioc_status &
+		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
+			ioc_loginfo = le32_to_cpu(def_reply->IOCLogInfo);
+		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+		if (def_reply->Function == MPI3_FUNCTION_SCSI_IO) {
+			scsi_reply = (Mpi3SCSIIOReply_t *)def_reply;
+			sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
+			    le64_to_cpu(scsi_reply->SenseDataBufferAddress));
+		}
+		break;
+	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
+		success_desc = (Mpi3SuccessReplyDescriptor_t *)reply_desc;
+		host_tag = le16_to_cpu(success_desc->HostTag);
+		break;
+	default:
+		break;
+	}
+
+	cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply);
+	if (cmdptr) {
+		if (cmdptr->state & MPI3MR_CMD_PENDING) {
+			cmdptr->state |= MPI3MR_CMD_COMPLETE;
+			cmdptr->ioc_loginfo = ioc_loginfo;
+			cmdptr->ioc_status = ioc_status;
+			cmdptr->state &= ~MPI3MR_CMD_PENDING;
+			if (def_reply) {
+				cmdptr->state |= MPI3MR_CMD_REPLY_VALID;
+				memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
+				    mrioc->facts.reply_sz);
+			}
+			if (cmdptr->is_waiting) {
+				complete(&cmdptr->done);
+				cmdptr->is_waiting = 0;
+			} else if (cmdptr->callback)
+				cmdptr->callback(mrioc, cmdptr);
+		}
+	}
+out:
+	if (sense_buf)
+		mpi3mr_repost_sense_buf(mrioc,
+		    le64_to_cpu(scsi_reply->SenseDataBufferAddress));
+}
+
+static int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
+{
+	u32 exp_phase = mrioc->admin_reply_ephase;
+	u32 admin_reply_ci = mrioc->admin_reply_ci;
+	u32 num_admin_replies = 0;
+	u64 reply_dma = 0;
+	Mpi3DefaultReplyDescriptor_t *reply_desc;
+
+	reply_desc = (Mpi3DefaultReplyDescriptor_t *)mrioc->admin_reply_base +
+	    admin_reply_ci;
+
+	if ((le16_to_cpu(reply_desc->ReplyFlags) &
+	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
+		return 0;
+
+	do {
+		mrioc->admin_req_ci = le16_to_cpu(reply_desc->RequestQueueCI);
+		mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma);
+		if (reply_dma)
+			mpi3mr_repost_reply_buf(mrioc, reply_dma);
+		num_admin_replies++;
+		if (++admin_reply_ci == mrioc->num_admin_replies) {
+			admin_reply_ci = 0;
+			exp_phase ^= 1;
+		}
+		reply_desc =
+		    (Mpi3DefaultReplyDescriptor_t *)mrioc->admin_reply_base +
+		    admin_reply_ci;
+		if ((le16_to_cpu(reply_desc->ReplyFlags) &
+		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
+			break;
+	} while (1);
+
+	writel(admin_reply_ci, &mrioc->sysif_regs->AdminReplyQueueCI);
+	mrioc->admin_reply_ci = admin_reply_ci;
+	mrioc->admin_reply_ephase = exp_phase;
+
+	return num_admin_replies;
+}
+
+static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
+{
+	struct mpi3mr_intr_info *intr_info = privdata;
+	struct mpi3mr_ioc *mrioc;
+	u16 midx;
+	u32 num_admin_replies = 0;
+
+	if (!intr_info)
+		return IRQ_NONE;
+
+	mrioc = intr_info->mrioc;
+
+	if (!mrioc->intr_enabled)
+		return IRQ_NONE;
+
+	midx = intr_info->msix_index;
+
+	if (!midx)
+		num_admin_replies = mpi3mr_process_admin_reply_q(mrioc);
+
+	if (num_admin_replies)
+		return IRQ_HANDLED;
+	else
+		return IRQ_NONE;
+}
+
+static irqreturn_t mpi3mr_isr(int irq, void *privdata)
+{
+	struct mpi3mr_intr_info *intr_info = privdata;
+	struct mpi3mr_ioc *mrioc;
+	u16 midx;
+	int ret;
+
+	if (!intr_info)
+		return IRQ_NONE;
+
+	mrioc = intr_info->mrioc;
+	midx = intr_info->msix_index;
+	/* Call primary ISR routine */
+	ret = mpi3mr_isr_primary(irq, privdata);
+
+	return ret;
+}
+
+/**
+ * mpi3mr_isr_poll - Reply queue polling routine
+ * @irq: IRQ
+ * @privdata: Interrupt info
+ *
+ * poll for pending I/O completions in a loop until pending I/Os
+ * present or controller queue depth I/Os are processed.
+ *
+ * Return: IRQ_NONE or IRQ_HANDLED
+ */
+static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
+{
+	return IRQ_HANDLED;
+}
+
+/**
+ * mpi3mr_request_irq - Request IRQ and register ISR
+ * @mrioc: Adapter instance reference
+ * @index: IRQ vector index
+ *
+ * Request threaded ISR with primary ISR and secondary
+ *
+ * Return: 0 on success and non zero on failures.
+ */
+static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index)
+{
+	struct pci_dev *pdev = mrioc->pdev;
+	struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index;
+	int retval = 0;
+
+	intr_info->mrioc = mrioc;
+	intr_info->msix_index = index;
+	intr_info->op_reply_q = NULL;
+
+	snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d",
+	    mrioc->driver_name, mrioc->id, index);
+
+	retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr,
+	    mpi3mr_isr_poll, IRQF_ONESHOT, intr_info->name, intr_info);
+	if (retval) {
+		ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n",
+		    intr_info->name, pci_irq_vector(pdev, index));
+		return retval;
+	}
+
+	return retval;
+}
+
+/**
+ * mpi3mr_setup_isr - Setup ISR for the controller
+ * @mrioc: Adapter instance reference
+ * @setup_one: Request one IRQ or more
+ *
+ * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR
+ *
+ * Return: 0 on success and non zero on failures.
+ */
+static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one)
+{
+	unsigned int irq_flags = PCI_IRQ_MSIX;
+	u16 max_vectors = 0, i;
+	int retval = 0;
+	struct irq_affinity desc = { .pre_vectors =  1};
+
+
+	mpi3mr_cleanup_isr(mrioc);
+
+	if (setup_one || reset_devices)
+		max_vectors = 1;
+	else {
+		max_vectors =
+		    min_t(int, mrioc->cpu_count + 1, mrioc->msix_count);
+
+		ioc_info(mrioc,
+		    "MSI-X vectors supported: %d, no of cores: %d,",
+		    mrioc->msix_count, mrioc->cpu_count);
+		ioc_info(mrioc,
+		    "MSI-x vectors requested: %d\n", max_vectors);
+	}
+
+	irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
+
+	i = pci_alloc_irq_vectors_affinity(mrioc->pdev,
+	    1, max_vectors, irq_flags, &desc);
+	if (i <= 0) {
+		ioc_err(mrioc, "Cannot alloc irq vectors\n");
+		goto out_failed;
+	}
+	if (i != max_vectors) {
+		ioc_info(mrioc,
+		    "allocated vectors (%d) are less than configured (%d)\n",
+		    i, max_vectors);
+
+		max_vectors = i;
+	}
+	mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info)*max_vectors,
+	    GFP_KERNEL);
+	if (!mrioc->intr_info) {
+		retval = -1;
+		pci_free_irq_vectors(mrioc->pdev);
+		goto out_failed;
+	}
+	for (i = 0; i < max_vectors; i++) {
+		retval = mpi3mr_request_irq(mrioc, i);
+		if (retval) {
+			mrioc->intr_info_count = i;
+			goto out_failed;
+		}
+	}
+	mrioc->intr_info_count = max_vectors;
+	mpi3mr_ioc_enable_intr(mrioc);
+	return retval;
+out_failed:
+	mpi3mr_cleanup_isr(mrioc);
+
+	return retval;
+}
+
+static const struct {
+	enum mpi3mr_iocstate value;
+	char *name;
+} mrioc_states[] = {
+	{ MRIOC_STATE_READY, "ready" },
+	{ MRIOC_STATE_FAULT, "fault" },
+	{ MRIOC_STATE_RESET, "reset" },
+	{ MRIOC_STATE_BECOMING_READY, "becoming ready" },
+	{ MRIOC_STATE_RESET_REQUESTED, "reset requested" },
+	{ MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" },
+};
+
+static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)
+{
+	int i;
+	char *name = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) {
+		if (mrioc_states[i].value == mrioc_state) {
+			name = mrioc_states[i].name;
+			break;
+		}
+	}
+	return name;
+}
+
+
+/**
+ * mpi3mr_print_fault_info - Display fault information
+ * @mrioc: Adapter instance reference
+ *
+ * Display the controller fault information if there is a
+ * controller fault.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc)
+{
+	u32 ioc_status, code, code1, code2, code3;
+
+	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
+
+	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
+		code = readl(&mrioc->sysif_regs->Fault);
+		code1 = readl(&mrioc->sysif_regs->FaultInfo[0]);
+		code2 = readl(&mrioc->sysif_regs->FaultInfo[1]);
+		code3 = readl(&mrioc->sysif_regs->FaultInfo[2]);
+
+		ioc_info(mrioc,
+		    "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n",
+		    code, code1, code2, code3);
+	}
+}
+
+/**
+ * mpi3mr_get_iocstate - Get IOC State
+ * @mrioc: Adapter instance reference
+ *
+ * Return a proper IOC state enum based on the IOC status and
+ * IOC configuration and unrcoverable state of the controller.
+ *
+ * Return: Current IOC state.
+ */
+enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc)
+{
+	u32 ioc_status, ioc_config;
+	u8 ready, enabled;
+
+	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
+	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
+
+	if (mrioc->unrecoverable)
+		return MRIOC_STATE_UNRECOVERABLE;
+	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)
+		return MRIOC_STATE_FAULT;
+
+	ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY);
+	enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC);
+
+	if (ready && enabled)
+		return MRIOC_STATE_READY;
+	if ((!ready) && (!enabled))
+		return MRIOC_STATE_RESET;
+	if ((!ready) && (enabled))
+		return MRIOC_STATE_BECOMING_READY;
+
+	return MRIOC_STATE_RESET_REQUESTED;
+}
+
+/**
+ * mpi3mr_clear_reset_history - Clear reset history
+ * @mrioc: Adapter instance reference
+ *
+ * Write the reset history bit in IOC Status to clear the bit,
+ * if it is already set.
+ *
+ * Return: Nothing.
+ */
+static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc)
+{
+	u32 ioc_status;
+
+	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
+	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
+		writel(ioc_status, &mrioc->sysif_regs->IOCStatus);
+
+}
+
+/**
+ * mpi3mr_issue_and_process_mur - Message Unit Reset handler
+ * @mrioc: Adapter instance reference
+ * @reset_reason: Reset reason code
+ *
+ * Issue Message Unit Reset to the controller and wait for it to
+ * be complete.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
+					u32 reset_reason)
+{
+	u32 ioc_config, timeout, ioc_status;
+	int retval = -1;
+
+	ioc_info(mrioc, "Issuing Message Unit Reset(MUR)\n");
+	if (mrioc->unrecoverable) {
+		ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n");
+		return retval;
+	}
+	mpi3mr_clear_reset_history(mrioc);
+	writel(reset_reason, &mrioc->sysif_regs->Scratchpad[0]);
+	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
+	ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
+	writel(ioc_config, &mrioc->sysif_regs->IOCConfiguration);
+
+	timeout = mrioc->ready_timeout * 10;
+	do {
+		ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
+		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
+			mpi3mr_clear_reset_history(mrioc);
+			ioc_config =
+			    readl(&mrioc->sysif_regs->IOCConfiguration);
+			if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
+			    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
+			    (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) {
+				retval = 0;
+				break;
+			}
+		}
+		msleep(100);
+	} while (--timeout);
+
+	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
+	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
+
+	ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n",
+	    (!retval) ? "successful" : "failed", ioc_status, ioc_config);
+	return retval;
+}
+
+/**
+ * mpi3mr_bring_ioc_ready - Bring controller to ready state
+ * @mrioc: Adapter instance reference
+ *
+ * Set Enable IOC bit in IOC configuration register and wait for
+ * the controller to become ready.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
+{
+	u32 ioc_config, timeout;
+	enum mpi3mr_iocstate current_state;
+
+	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
+	ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
+	writel(ioc_config, &mrioc->sysif_regs->IOCConfiguration);
+
+	timeout = mrioc->ready_timeout * 10;
+	do {
+		current_state = mpi3mr_get_iocstate(mrioc);
+		if (current_state == MRIOC_STATE_READY)
+			return 0;
+		msleep(100);
+	} while (--timeout);
+
+	return -1;
+}
+
+/**
+ * mpi3mr_set_diagsave - Set diag save bit for snapdump
+ * @mrioc: Adapter reference
+ *
+ * Set diag save bit in IOC configuration register to enable
+ * snapdump.
+ *
+ * Return: Nothing.
+ */
+static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc)
+{
+	u32 ioc_config;
+
+	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
+	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE;
+	writel(ioc_config, &mrioc->sysif_regs->IOCConfiguration);
+}
+
+/**
+ * mpi3mr_issue_reset - Issue reset to the controller
+ * @mrioc: Adapter reference
+ * @reset_type: Reset type
+ * @reset_reason: Reset reason code
+ *
+ * TBD
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
+	u32 reset_reason)
+{
+	return 0;
+}
+
+/**
+ * mpi3mr_admin_request_post - Post request to admin queue
+ * @mrioc: Adapter reference
+ * @admin_req: MPI3 request
+ * @admin_req_sz: Request size
+ * @ignore_reset: Ignore reset in process
+ *
+ * Post the MPI3 request into admin request queue and
+ * inform the controller, if the queue is full return
+ * appropriate error.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
+	u16 admin_req_sz, u8 ignore_reset)
+{
+	u16 areq_pi = 0, areq_ci = 0, max_entries = 0;
+	int retval = 0;
+	unsigned long flags;
+	u8 *areq_entry;
+
+
+	if (mrioc->unrecoverable) {
+		ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__);
+		return -EFAULT;
+	}
+
+	spin_lock_irqsave(&mrioc->admin_req_lock, flags);
+	areq_pi = mrioc->admin_req_pi;
+	areq_ci = mrioc->admin_req_ci;
+	max_entries = mrioc->num_admin_req;
+	if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) &&
+	    (areq_pi == (max_entries - 1)))) {
+		ioc_err(mrioc, "AdminReqQ full condition detected\n");
+		retval = -EAGAIN;
+		goto out;
+	}
+	if (!ignore_reset && mrioc->reset_in_progress) {
+		ioc_err(mrioc, "AdminReqQ submit reset in progress\n");
+		retval = -EAGAIN;
+		goto out;
+	}
+	areq_entry = (u8 *)mrioc->admin_req_base +
+	    (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
+	memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
+	memcpy(areq_entry, (u8 *)admin_req, admin_req_sz);
+
+	if (++areq_pi == max_entries)
+		areq_pi = 0;
+	mrioc->admin_req_pi = areq_pi;
+
+	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->AdminRequestQueuePI);
+
+out:
+	spin_unlock_irqrestore(&mrioc->admin_req_lock, flags);
+
+	return retval;
+}
+
+
+/**
+ * mpi3mr_setup_admin_qpair - Setup admin queue pair
+ * @mrioc: Adapter instance reference
+ *
+ * Allocate memory for admin queue pair if required and register
+ * the admin queue with the controller.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
+{
+	int retval = 0;
+	u32 num_admin_entries = 0;
+
+	mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE;
+	mrioc->num_admin_req = mrioc->admin_req_q_sz /
+	    MPI3MR_ADMIN_REQ_FRAME_SZ;
+	mrioc->admin_req_ci = mrioc->admin_req_pi = 0;
+	mrioc->admin_req_base = NULL;
+
+	mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE;
+	mrioc->num_admin_replies = mrioc->admin_reply_q_sz /
+	    MPI3MR_ADMIN_REPLY_FRAME_SZ;
+	mrioc->admin_reply_ci = 0;
+	mrioc->admin_reply_ephase = 1;
+	mrioc->admin_reply_base = NULL;
+
+	if (!mrioc->admin_req_base) {
+		mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev,
+		    mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL);
+
+		if (!mrioc->admin_req_base) {
+			retval = -1;
+			goto out_failed;
+		}
+
+		mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev,
+		    mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma,
+		    GFP_KERNEL);
+
+		if (!mrioc->admin_reply_base) {
+			retval = -1;
+			goto out_failed;
+		}
+
+	}
+
+	num_admin_entries = (mrioc->num_admin_replies << 16) |
+	    (mrioc->num_admin_req);
+	writel(num_admin_entries, &mrioc->sysif_regs->AdminQueueNumEntries);
+	mpi3mr_writeq(mrioc->admin_req_dma,
+	    &mrioc->sysif_regs->AdminRequestQueueAddress);
+	mpi3mr_writeq(mrioc->admin_reply_dma,
+	    &mrioc->sysif_regs->AdminReplyQueueAddress);
+	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->AdminRequestQueuePI);
+	writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->AdminReplyQueueCI);
+	return retval;
+
+out_failed:
+
+	if (mrioc->admin_reply_base) {
+		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
+		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
+		mrioc->admin_reply_base = NULL;
+	}
+	if (mrioc->admin_req_base) {
+		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
+		    mrioc->admin_req_base, mrioc->admin_req_dma);
+		mrioc->admin_req_base = NULL;
+	}
+	return retval;
+}
+
+/**
+ * mpi3mr_issue_iocfacts - Send IOC Facts
+ * @mrioc: Adapter instance reference
+ *
+ * Issue IOC Facts MPI request through admin queue and wait for
+ * the completion of it or time out.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc,
+	Mpi3IOCFactsData_t *facts_data)
+{
+	Mpi3IOCFactsRequest_t iocfacts_req;
+	void *data = NULL;
+	dma_addr_t data_dma;
+	u32 data_len = sizeof(*facts_data);
+	int retval = 0;
+	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
+
+	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
+	    GFP_KERNEL);
+
+	if (!data) {
+		retval = -1;
+		goto out;
+	}
+
+	memset(&iocfacts_req, 0, sizeof(iocfacts_req));
+	mutex_lock(&mrioc->init_cmds.mutex);
+	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+		retval = -1;
+		ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n");
+		mutex_unlock(&mrioc->init_cmds.mutex);
+		goto out;
+	}
+	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+	mrioc->init_cmds.is_waiting = 1;
+	mrioc->init_cmds.callback = NULL;
+	iocfacts_req.HostTag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+	iocfacts_req.Function = MPI3_FUNCTION_IOC_FACTS;
+
+	mpi3mr_add_sg_single(&iocfacts_req.SGL, sgl_flags, data_len,
+	    data_dma);
+
+	init_completion(&mrioc->init_cmds.done);
+	retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req,
+	    sizeof(iocfacts_req), 1);
+	if (retval) {
+		ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n");
+		goto out_unlock;
+	}
+	wait_for_completion_timeout(&mrioc->init_cmds.done,
+	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+		ioc_err(mrioc, "Issue IOCFacts: command timed out\n");
+		mpi3mr_set_diagsave(mrioc);
+		mpi3mr_issue_reset(mrioc,
+		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
+		    MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT);
+		mrioc->unrecoverable = 1;
+		retval = -1;
+		goto out_unlock;
+	}
+	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+	    != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc,
+		    "Issue IOCFacts: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n",
+		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+		    mrioc->init_cmds.ioc_loginfo);
+		retval = -1;
+		goto out_unlock;
+	}
+	memcpy(facts_data, (u8 *)data, data_len);
+out_unlock:
+	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+	mutex_unlock(&mrioc->init_cmds.mutex);
+
+out:
+	if (data)
+		dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma);
+
+	return retval;
+}
+
+/**
+ * mpi3mr_check_reset_dma_mask - Process IOC facts data
+ * @mrioc: Adapter instance reference
+ *
+ * Check whether the new DMA mask requested through IOCFacts by
+ * firmware needs to be set, if so set it .
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc)
+{
+	struct pci_dev *pdev = mrioc->pdev;
+	int r;
+	u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask);
+
+	if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask))
+		return 0;
+
+	ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n",
+	    mrioc->dma_mask, facts_dma_mask);
+
+	r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask);
+	if (r) {
+		ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n",
+		    facts_dma_mask, r);
+		return r;
+	}
+	mrioc->dma_mask = facts_dma_mask;
+	return r;
+}
+/**
+ * mpi3mr_process_factsdata - Process IOC facts data
+ * @mrioc: Adapter instance reference
+ *
+ * Convert IOC facts data into cpu endianness and cache it in
+ * the driver .
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
+	Mpi3IOCFactsData_t *facts_data)
+{
+	u32 ioc_config, req_sz, facts_flags;
+
+	if ((le16_to_cpu(facts_data->IOCFactsDataLength)) !=
+	    (sizeof(*facts_data)/4)) {
+		ioc_warn(mrioc,
+		    "IOCFactsdata length mismatch driver_sz(%ld) firmware_sz(%d)\n",
+		    sizeof(*facts_data),
+		    le16_to_cpu(facts_data->IOCFactsDataLength) * 4);
+	}
+
+	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
+	req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >>
+	    MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT);
+	if (le16_to_cpu(facts_data->IOCRequestFrameSize) != (req_sz/4)) {
+		ioc_err(mrioc,
+		    "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n",
+		    req_sz/4, le16_to_cpu(facts_data->IOCRequestFrameSize));
+	}
+
+	memset(&mrioc->facts, 0, sizeof(mrioc->facts));
+
+	facts_flags = le32_to_cpu(facts_data->Flags);
+	mrioc->facts.op_req_sz = req_sz;
+	mrioc->op_reply_desc_sz = 1 << ((ioc_config &
+	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >>
+	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT);
+
+	mrioc->facts.ioc_num = facts_data->IOCNumber;
+	mrioc->facts.who_init = facts_data->WhoInit;
+	mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->MaxMSIxVectors);
+	mrioc->facts.personality = (facts_flags &
+	    MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK);
+	mrioc->facts.dma_mask = (facts_flags &
+	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
+	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
+	mrioc->facts.protocol_flags = facts_data->ProtocolFlags;
+	mrioc->facts.mpi_version = le32_to_cpu(facts_data->MPIVersion.Word);
+	mrioc->facts.max_reqs = le16_to_cpu(facts_data->MaxOutstandingRequest);
+	mrioc->facts.product_id = le16_to_cpu(facts_data->ProductID);
+	mrioc->facts.reply_sz = le16_to_cpu(facts_data->ReplyFrameSize) * 4;
+	mrioc->facts.exceptions = le16_to_cpu(facts_data->IOCExceptions);
+	mrioc->facts.max_perids = le16_to_cpu(facts_data->MaxPersistentID);
+	mrioc->facts.max_pds = le16_to_cpu(facts_data->MaxPDs);
+	mrioc->facts.max_vds = le16_to_cpu(facts_data->MaxVDs);
+	mrioc->facts.max_hpds = le16_to_cpu(facts_data->MaxHostPDs);
+	mrioc->facts.max_advhpds = le16_to_cpu(facts_data->MaxAdvancedHostPDs);
+	mrioc->facts.max_raidpds = le16_to_cpu(facts_data->MaxRAIDPDs);
+	mrioc->facts.max_nvme = le16_to_cpu(facts_data->MaxNVMe);
+	mrioc->facts.max_pcieswitches =
+	    le16_to_cpu(facts_data->MaxPCIeSwitches);
+	mrioc->facts.max_sasexpanders =
+	    le16_to_cpu(facts_data->MaxSASExpanders);
+	mrioc->facts.max_sasinitiators =
+	    le16_to_cpu(facts_data->MaxSASInitiators);
+	mrioc->facts.max_enclosures = le16_to_cpu(facts_data->MaxEnclosures);
+	mrioc->facts.min_devhandle = le16_to_cpu(facts_data->MinDevHandle);
+	mrioc->facts.max_devhandle = le16_to_cpu(facts_data->MaxDevHandle);
+	mrioc->facts.max_op_req_q =
+	    le16_to_cpu(facts_data->MaxOperationalRequestQueues);
+	mrioc->facts.max_op_reply_q =
+	    le16_to_cpu(facts_data->MaxOperationalReplyQueues);
+	mrioc->facts.ioc_capabilities =
+	    le32_to_cpu(facts_data->IOCCapabilities);
+	mrioc->facts.fw_ver.build_num =
+	    le16_to_cpu(facts_data->FWVersion.BuildNum);
+	mrioc->facts.fw_ver.cust_id =
+	    le16_to_cpu(facts_data->FWVersion.CustomerID);
+	mrioc->facts.fw_ver.ph_minor = facts_data->FWVersion.PhaseMinor;
+	mrioc->facts.fw_ver.ph_major = facts_data->FWVersion.PhaseMajor;
+	mrioc->facts.fw_ver.gen_minor = facts_data->FWVersion.GenMinor;
+	mrioc->facts.fw_ver.gen_major = facts_data->FWVersion.GenMajor;
+	mrioc->msix_count = min_t(int, mrioc->msix_count,
+	    mrioc->facts.max_msix_vectors);
+	mrioc->facts.sge_mod_mask = facts_data->SGEModifierMask;
+	mrioc->facts.sge_mod_value = facts_data->SGEModifierValue;
+	mrioc->facts.sge_mod_shift = facts_data->SGEModifierShift;
+	mrioc->facts.shutdown_timeout =
+	    le16_to_cpu(facts_data->ShutdownTimeout);
+
+	ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),",
+	    mrioc->facts.ioc_num, mrioc->facts.max_op_req_q,
+	    mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle);
+	ioc_info(mrioc,
+	    "maxreqs(%d), mindh(%d) maxPDs(%d) maxvectors(%d) maxperids(%d)\n",
+	    mrioc->facts.max_reqs, mrioc->facts.min_devhandle,
+	    mrioc->facts.max_pds, mrioc->facts.max_msix_vectors,
+	    mrioc->facts.max_perids);
+	ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ",
+	    mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value,
+	    mrioc->facts.sge_mod_shift);
+	ioc_info(mrioc, "DMA Mask %d InitialPE Status 0x%x\n",
+	    mrioc->facts.dma_mask, (facts_flags &
+	    MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK));
+
+	mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD;
+
+	if (reset_devices)
+		mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
+		    MPI3MR_HOST_IOS_KDUMP);
+
+}
+
+/**
+ * mpi3mr_alloc_reply_sense_bufs - Send IOC Init
+ * @mrioc: Adapter instance reference
+ *
+ * Allocate and initialize the reply free buffers, sense
+ * buffers, reply free queue and sense buffer queue.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
+{
+	int retval = 0;
+	u32 sz, i;
+	dma_addr_t phy_addr;
+
+	if (mrioc->init_cmds.reply)
+		goto post_reply_sbuf;
+
+	mrioc->init_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL);
+	if (!mrioc->init_cmds.reply)
+		goto out_failed;
+
+
+	mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES;
+	mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1;
+	mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
+	mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1;
+
+	/* reply buffer pool, 16 byte align */
+	sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
+	mrioc->reply_buf_pool = dma_pool_create("reply_buf pool",
+	    &mrioc->pdev->dev, sz, 16, 0);
+	if (!mrioc->reply_buf_pool) {
+		ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n");
+		goto out_failed;
+	}
+
+	mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL,
+	    &mrioc->reply_buf_dma);
+	if (!mrioc->reply_buf)
+		goto out_failed;
+
+	mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz;
+
+	/* reply free queue, 8 byte align */
+	sz = mrioc->reply_free_qsz * 8;
+	mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool",
+	    &mrioc->pdev->dev, sz, 8, 0);
+	if (!mrioc->reply_free_q_pool) {
+		ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n");
+		goto out_failed;
+	}
+	mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool,
+	    GFP_KERNEL, &mrioc->reply_free_q_dma);
+	if (!mrioc->reply_free_q)
+		goto out_failed;
+
+	/* sense buffer pool,  4 byte align */
+	sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
+	mrioc->sense_buf_pool = dma_pool_create("sense_buf pool",
+	    &mrioc->pdev->dev, sz, 4, 0);
+	if (!mrioc->sense_buf_pool) {
+		ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n");
+		goto out_failed;
+	}
+	mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL,
+	    &mrioc->sense_buf_dma);
+	if (!mrioc->sense_buf)
+		goto out_failed;
+
+	/* sense buffer queue, 8 byte align */
+	sz = mrioc->sense_buf_q_sz * 8;
+	mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool",
+	    &mrioc->pdev->dev, sz, 8, 0);
+	if (!mrioc->sense_buf_q_pool) {
+		ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n");
+		goto out_failed;
+	}
+	mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool,
+	    GFP_KERNEL, &mrioc->sense_buf_q_dma);
+	if (!mrioc->sense_buf_q)
+		goto out_failed;
+
+post_reply_sbuf:
+	sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
+	ioc_info(mrioc,
+	    "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
+	    mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->facts.reply_sz,
+	    (sz / 1024), (unsigned long long)mrioc->reply_buf_dma);
+	sz = mrioc->reply_free_qsz * 8;
+	ioc_info(mrioc,
+	    "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
+	    mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024),
+	    (unsigned long long)mrioc->reply_free_q_dma);
+	sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
+	ioc_info(mrioc,
+	    "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
+	    mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSEBUF_SZ,
+	    (sz / 1024), (unsigned long long)mrioc->sense_buf_dma);
+	sz = mrioc->sense_buf_q_sz * 8;
+	ioc_info(mrioc,
+	    "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
+	    mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024),
+	    (unsigned long long)mrioc->sense_buf_q_dma);
+
+	/* initialize Reply buffer Queue */
+	for (i = 0, phy_addr = mrioc->reply_buf_dma;
+	    i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->facts.reply_sz)
+		mrioc->reply_free_q[i] = cpu_to_le64(phy_addr);
+	mrioc->reply_free_q[i] = cpu_to_le64(0);
+
+	/* initialize Sense Buffer Queue */
+	for (i = 0, phy_addr = mrioc->sense_buf_dma;
+	    i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSEBUF_SZ)
+		mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr);
+	mrioc->sense_buf_q[i] = cpu_to_le64(0);
+	return retval;
+
+out_failed:
+	retval = -1;
+	return retval;
+}
+
+/**
+ * mpi3mr_issue_iocinit - Send IOC Init
+ * @mrioc: Adapter instance reference
+ *
+ * Issue IOC Init MPI request through admin queue and wait for
+ * the completion of it or time out.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc)
+{
+	Mpi3IOCInitRequest_t iocinit_req;
+	Mpi3DriverInfoLayout_t *drv_info;
+	dma_addr_t data_dma;
+	u32 data_len = sizeof(*drv_info);
+	int retval = 0;
+	ktime_t current_time;
+
+	drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
+	    GFP_KERNEL);
+	if (!drv_info) {
+		retval = -1;
+		goto out;
+	}
+	drv_info->InformationLength = cpu_to_le32(data_len);
+	strcpy(drv_info->DriverSignature, "Broadcom");
+	strcpy(drv_info->OsName, utsname()->sysname);
+	drv_info->OsName[sizeof(drv_info->OsName)-1] = 0;
+	strcpy(drv_info->OsVersion, utsname()->release);
+	drv_info->OsVersion[sizeof(drv_info->OsVersion)-1] = 0;
+	strcpy(drv_info->DriverName, MPI3MR_DRIVER_NAME);
+	strcpy(drv_info->DriverVersion, MPI3MR_DRIVER_VERSION);
+	strcpy(drv_info->DriverReleaseDate, MPI3MR_DRIVER_RELDATE);
+	drv_info->DriverCapabilities = 0;
+	memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info,
+	    sizeof(mrioc->driver_info));
+
+	memset(&iocinit_req, 0, sizeof(iocinit_req));
+	mutex_lock(&mrioc->init_cmds.mutex);
+	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+		retval = -1;
+		ioc_err(mrioc, "Issue IOCInit: Init command is in use\n");
+		mutex_unlock(&mrioc->init_cmds.mutex);
+		goto out;
+	}
+	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+	mrioc->init_cmds.is_waiting = 1;
+	mrioc->init_cmds.callback = NULL;
+	iocinit_req.HostTag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+	iocinit_req.Function = MPI3_FUNCTION_IOC_INIT;
+	iocinit_req.MPIVersion.Struct.Dev = MPI3_VERSION_DEV;
+	iocinit_req.MPIVersion.Struct.Unit = MPI3_VERSION_UNIT;
+	iocinit_req.MPIVersion.Struct.Major = MPI3_VERSION_MAJOR;
+	iocinit_req.MPIVersion.Struct.Minor = MPI3_VERSION_MINOR;
+	iocinit_req.WhoInit = MPI3_WHOINIT_HOST_DRIVER;
+	iocinit_req.ReplyFreeQueueDepth = cpu_to_le16(mrioc->reply_free_qsz);
+	iocinit_req.ReplyFreeQueueAddress =
+	    cpu_to_le64(mrioc->reply_free_q_dma);
+	iocinit_req.SenseBufferLength = cpu_to_le16(MPI3MR_SENSEBUF_SZ);
+	iocinit_req.SenseBufferFreeQueueDepth =
+	    cpu_to_le16(mrioc->sense_buf_q_sz);
+	iocinit_req.SenseBufferFreeQueueAddress =
+	    cpu_to_le64(mrioc->sense_buf_q_dma);
+	iocinit_req.DriverInformationAddress = cpu_to_le64(data_dma);
+
+	current_time = ktime_get_real();
+	iocinit_req.TimeStamp = cpu_to_le64(ktime_to_ms(current_time));
+
+	init_completion(&mrioc->init_cmds.done);
+	retval = mpi3mr_admin_request_post(mrioc, &iocinit_req,
+	    sizeof(iocinit_req), 1);
+	if (retval) {
+		ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n");
+		goto out_unlock;
+	}
+	wait_for_completion_timeout(&mrioc->init_cmds.done,
+	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+		mpi3mr_set_diagsave(mrioc);
+		mpi3mr_issue_reset(mrioc,
+		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
+		    MPI3MR_RESET_FROM_IOCINIT_TIMEOUT);
+		mrioc->unrecoverable = 1;
+		ioc_err(mrioc, "Issue IOCInit: command timed out\n");
+		retval = -1;
+		goto out_unlock;
+	}
+	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+	    != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc,
+		    "Issue IOCInit: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n",
+		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+		    mrioc->init_cmds.ioc_loginfo);
+		retval = -1;
+		goto out_unlock;
+	}
+
+out_unlock:
+	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+	mutex_unlock(&mrioc->init_cmds.mutex);
+
+out:
+	if (drv_info)
+		dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info,
+		    data_dma);
+
+	return retval;
+}
+
+
+/**
+ * mpi3mr_alloc_chain_bufs - Allocate chain buffers
+ * @mrioc: Adapter instance reference
+ *
+ * Allocate chain buffers and set a bitmap to indicate free
+ * chain buffers. Chain buffers are used to pass the SGE
+ * information along with MPI3 SCSI IO requests for host I/O.
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc)
+{
+	int retval = 0;
+	u32 sz, i;
+	u16 num_chains;
+
+	num_chains = mrioc->max_host_ios/MPI3MR_CHAINBUF_FACTOR;
+
+	mrioc->chain_buf_count = num_chains;
+	sz = sizeof(struct chain_element) * num_chains;
+	mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL);
+	if (!mrioc->chain_sgl_list)
+		goto out_failed;
+
+	sz = MPI3MR_PAGE_SIZE_4K;
+	mrioc->chain_buf_pool = dma_pool_create("chain_buf pool",
+	    &mrioc->pdev->dev, sz, 16, 0);
+	if (!mrioc->chain_buf_pool) {
+		ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n");
+		goto out_failed;
+	}
+
+	for (i = 0; i < num_chains; i++) {
+		mrioc->chain_sgl_list[i].addr =
+		    dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL,
+		    &mrioc->chain_sgl_list[i].dma_addr);
+
+		if (!mrioc->chain_sgl_list[i].addr)
+			goto out_failed;
+	}
+	mrioc->chain_bitmap_sz = num_chains / 8;
+	if (num_chains % 8)
+		mrioc->chain_bitmap_sz++;
+	mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL);
+	if (!mrioc->chain_bitmap)
+		goto out_failed;
+	return retval;
+out_failed:
+	retval = -1;
+	return retval;
+}
+
+
+/**
+ * mpi3mr_cleanup_resources - Free PCI resources
+ * @mrioc: Adapter instance reference
+ *
+ * Unmap PCI device memory and disable PCI device.
+ *
+ * Return: 0 on success and non-zero on failure.
+ */
+void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc)
+{
+	struct pci_dev *pdev = mrioc->pdev;
+
+	mpi3mr_cleanup_isr(mrioc);
+
+	if (mrioc->sysif_regs) {
+		iounmap(mrioc->sysif_regs);
+		mrioc->sysif_regs = NULL;
+	}
+
+	if (pci_is_enabled(pdev)) {
+		if (mrioc->bars)
+			pci_release_selected_regions(pdev, mrioc->bars);
+		pci_disable_device(pdev);
+	}
+}
+
+/**
+ * mpi3mr_setup_resources - Enable PCI resources
+ * @mrioc: Adapter instance reference
+ *
+ * Enable PCI device memory, MSI-x registers and set DMA mask.
+ *
+ * Return: 0 on success and non-zero on failure.
+ */
+int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc)
+{
+	struct pci_dev *pdev = mrioc->pdev;
+	u32 memap_sz = 0;
+	int i, retval = 0, capb = 0;
+	u16 message_control;
+	u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask :
+	    (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) &&
+	    (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64):DMA_BIT_MASK(32));
+
+	if (pci_enable_device_mem(pdev)) {
+		ioc_err(mrioc, "pci_enable_device_mem: failed\n");
+		retval = -ENODEV;
+		goto out_failed;
+	}
+
+	capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+	if (!capb) {
+		ioc_err(mrioc, "Unable to find MSI-X Capabilities\n");
+		retval = -ENODEV;
+		goto out_failed;
+	}
+	mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
+
+	if (pci_request_selected_regions(pdev, mrioc->bars,
+	    mrioc->driver_name)) {
+		ioc_err(mrioc, "pci_request_selected_regions: failed\n");
+		retval = -ENODEV;
+		goto out_failed;
+	}
+
+	for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) {
+		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+			mrioc->sysif_regs_phys = pci_resource_start(pdev, i);
+			memap_sz = pci_resource_len(pdev, i);
+			mrioc->sysif_regs =
+			    ioremap(mrioc->sysif_regs_phys, memap_sz);
+			break;
+		}
+	}
+
+	pci_set_master(pdev);
+
+	retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
+	if (retval) {
+		if (dma_mask != DMA_BIT_MASK(32)) {
+			ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n");
+			dma_mask = DMA_BIT_MASK(32);
+			retval = dma_set_mask_and_coherent(&pdev->dev,
+			    dma_mask);
+		}
+		if (retval) {
+			mrioc->dma_mask = 0;
+			ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n");
+			goto out_failed;
+		}
+	}
+	mrioc->dma_mask = dma_mask;
+
+	if (mrioc->sysif_regs == NULL) {
+		ioc_err(mrioc,
+		    "Unable to map adapter memory or resource not found\n");
+		retval = -EINVAL;
+		goto out_failed;
+	}
+
+	pci_read_config_word(pdev, capb + 2, &message_control);
+	mrioc->msix_count = (message_control & 0x3FF) + 1;
+
+	pci_save_state(pdev);
+
+	pci_set_drvdata(pdev, mrioc->shost);
+
+	mpi3mr_ioc_disable_intr(mrioc);
+
+	ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
+	    (unsigned long long)mrioc->sysif_regs_phys,
+	    mrioc->sysif_regs, memap_sz);
+	ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n",
+	    mrioc->msix_count);
+	return retval;
+
+out_failed:
+	mpi3mr_cleanup_resources(mrioc);
+	return retval;
+}
+
+/**
+ * mpi3mr_init_ioc - Initialize the controller
+ * @mrioc: Adapter instance reference
+ *
+ * This the controller initialization routine, executed either
+ * after soft reset or from pci probe callback.
+ * Setup the required resources, memory map the controller
+ * registers, create admin and operational reply queue pairs,
+ * allocate required memory for reply pool, sense buffer pool,
+ * issue IOC init request to the firmware, unmask the events and
+ * issue port enable to discover SAS/SATA/NVMe devies and RAID
+ * volumes.
+ *
+ * Return: 0 on success and non-zero on failure.
+ */
+int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
+{
+	int retval = 0;
+	enum mpi3mr_iocstate ioc_state;
+	u64 base_info;
+	u32 timeout;
+	u32 ioc_status, ioc_config;
+	Mpi3IOCFactsData_t facts_data;
+
+	mrioc->change_count = 0;
+	mrioc->cpu_count = num_online_cpus();
+	retval = mpi3mr_setup_resources(mrioc);
+	if (retval) {
+		ioc_err(mrioc, "Failed to setup resources:error %d\n",
+		    retval);
+		goto out_nocleanup;
+	}
+	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
+	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
+
+	ioc_info(mrioc, "SOD status %x configuration %x\n",
+	    ioc_status, ioc_config);
+
+	base_info = readq(&mrioc->sysif_regs->IOCInformation);
+	ioc_info(mrioc, "SOD base_info %llx\n",	base_info);
+
+	/*The timeout value is in 2sec unit, changing it to seconds*/
+	mrioc->ready_timeout =
+	    ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
+	    MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
+
+	ioc_info(mrioc, "IOC ready timeout %d\n", mrioc->ready_timeout);
+
+	ioc_state = mpi3mr_get_iocstate(mrioc);
+	ioc_info(mrioc, "IOC in %s state during detection\n",
+	    mpi3mr_iocstate_name(ioc_state));
+
+	if (ioc_state == MRIOC_STATE_BECOMING_READY ||
+			ioc_state == MRIOC_STATE_RESET_REQUESTED) {
+		timeout = mrioc->ready_timeout * 10;
+		do {
+			msleep(100);
+		} while (--timeout);
+
+		ioc_state = mpi3mr_get_iocstate(mrioc);
+		ioc_info(mrioc,
+			"IOC in %s state after waiting for reset time\n",
+			mpi3mr_iocstate_name(ioc_state));
+	}
+
+	if (ioc_state == MRIOC_STATE_READY) {
+		retval = mpi3mr_issue_and_process_mur(mrioc,
+		    MPI3MR_RESET_FROM_BRINGUP);
+		if (retval) {
+			ioc_err(mrioc, "Failed to MU reset IOC error %d\n",
+			    retval);
+		}
+		ioc_state = mpi3mr_get_iocstate(mrioc);
+	}
+	if (ioc_state != MRIOC_STATE_RESET) {
+		mpi3mr_print_fault_info(mrioc);
+		retval = mpi3mr_issue_reset(mrioc,
+		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
+		    MPI3MR_RESET_FROM_BRINGUP);
+		if (retval) {
+			ioc_err(mrioc,
+			    "%s :Failed to soft reset IOC error %d\n",
+			    __func__, retval);
+			goto out_failed;
+		}
+	}
+	ioc_state = mpi3mr_get_iocstate(mrioc);
+	if (ioc_state != MRIOC_STATE_RESET) {
+		ioc_err(mrioc, "Cannot bring IOC to reset state\n");
+		goto out_failed;
+	}
+
+	retval = mpi3mr_setup_admin_qpair(mrioc);
+	if (retval) {
+		ioc_err(mrioc, "Failed to setup admin Qs: error %d\n",
+		    retval);
+		goto out_failed;
+	}
+
+	retval = mpi3mr_bring_ioc_ready(mrioc);
+	if (retval) {
+		ioc_err(mrioc, "Failed to bring ioc ready: error %d\n",
+		    retval);
+		goto out_failed;
+	}
+
+	retval = mpi3mr_setup_isr(mrioc, 1);
+	if (retval) {
+		ioc_err(mrioc, "Failed to setup ISR error %d\n",
+		    retval);
+		goto out_failed;
+	}
+
+	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
+	if (retval) {
+		ioc_err(mrioc, "Failed to Issue IOC Facts %d\n",
+		    retval);
+		goto out_failed;
+	}
+
+	mpi3mr_process_factsdata(mrioc, &facts_data);
+	retval = mpi3mr_check_reset_dma_mask(mrioc);
+	if (retval) {
+		ioc_err(mrioc, "Resetting dma mask failed %d\n",
+		    retval);
+		goto out_failed;
+	}
+
+	retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
+	if (retval) {
+		ioc_err(mrioc,
+		    "%s :Failed to allocated reply sense buffers %d\n",
+		    __func__, retval);
+		goto out_failed;
+	}
+
+	retval = mpi3mr_alloc_chain_bufs(mrioc);
+	if (retval) {
+		ioc_err(mrioc, "Failed to allocated chain buffers %d\n",
+		    retval);
+		goto out_failed;
+	}
+
+	retval = mpi3mr_issue_iocinit(mrioc);
+	if (retval) {
+		ioc_err(mrioc, "Failed to Issue IOC Init %d\n",
+		    retval);
+		goto out_failed;
+	}
+	mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs;
+	writel(mrioc->reply_free_queue_host_index,
+	    &mrioc->sysif_regs->ReplyFreeHostIndex);
+
+	mrioc->sbq_host_index = mrioc->num_sense_bufs;
+	writel(mrioc->sbq_host_index,
+	    &mrioc->sysif_regs->SenseBufferFreeHostIndex);
+
+	retval = mpi3mr_setup_isr(mrioc, 0);
+	if (retval) {
+		ioc_err(mrioc, "Failed to re-setup ISR, error %d\n",
+		    retval);
+		goto out_failed;
+	}
+
+	return retval;
+
+out_failed:
+	mpi3mr_cleanup_ioc(mrioc);
+out_nocleanup:
+	return retval;
+}
+
+
+/**
+ * mpi3mr_free_mem - Free memory allocated for a controller
+ * @mrioc: Adapter instance reference
+ *
+ * Free all the memory allocated for a controller.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
+{
+	u16 i;
+	struct mpi3mr_intr_info *intr_info;
+
+	if (mrioc->sense_buf_pool) {
+		if (mrioc->sense_buf)
+			dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf,
+			    mrioc->sense_buf_dma);
+		dma_pool_destroy(mrioc->sense_buf_pool);
+		mrioc->sense_buf = NULL;
+		mrioc->sense_buf_pool = NULL;
+	}
+	if (mrioc->sense_buf_q_pool) {
+		if (mrioc->sense_buf_q)
+			dma_pool_free(mrioc->sense_buf_q_pool,
+			    mrioc->sense_buf_q, mrioc->sense_buf_q_dma);
+		dma_pool_destroy(mrioc->sense_buf_q_pool);
+		mrioc->sense_buf_q = NULL;
+		mrioc->sense_buf_q_pool = NULL;
+	}
+
+	if (mrioc->reply_buf_pool) {
+		if (mrioc->reply_buf)
+			dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf,
+			    mrioc->reply_buf_dma);
+		dma_pool_destroy(mrioc->reply_buf_pool);
+		mrioc->reply_buf = NULL;
+		mrioc->reply_buf_pool = NULL;
+	}
+	if (mrioc->reply_free_q_pool) {
+		if (mrioc->reply_free_q)
+			dma_pool_free(mrioc->reply_free_q_pool,
+			    mrioc->reply_free_q, mrioc->reply_free_q_dma);
+		dma_pool_destroy(mrioc->reply_free_q_pool);
+		mrioc->reply_free_q = NULL;
+		mrioc->reply_free_q_pool = NULL;
+	}
+
+	for (i = 0; i < mrioc->intr_info_count; i++) {
+		intr_info = mrioc->intr_info + i;
+		if (intr_info)
+			intr_info->op_reply_q = NULL;
+	}
+
+	kfree(mrioc->req_qinfo);
+	mrioc->req_qinfo = NULL;
+	mrioc->num_op_req_q = 0;
+
+	kfree(mrioc->op_reply_qinfo);
+	mrioc->op_reply_qinfo = NULL;
+	mrioc->num_op_reply_q = 0;
+
+	kfree(mrioc->init_cmds.reply);
+	mrioc->init_cmds.reply = NULL;
+
+	kfree(mrioc->chain_bitmap);
+	mrioc->chain_bitmap = NULL;
+
+	if (mrioc->chain_buf_pool) {
+		for (i = 0; i < mrioc->chain_buf_count; i++) {
+			if (mrioc->chain_sgl_list[i].addr) {
+				dma_pool_free(mrioc->chain_buf_pool,
+				    mrioc->chain_sgl_list[i].addr,
+				    mrioc->chain_sgl_list[i].dma_addr);
+				mrioc->chain_sgl_list[i].addr = NULL;
+			}
+		}
+		dma_pool_destroy(mrioc->chain_buf_pool);
+		mrioc->chain_buf_pool = NULL;
+	}
+
+	kfree(mrioc->chain_sgl_list);
+	mrioc->chain_sgl_list = NULL;
+
+	if (mrioc->admin_reply_base) {
+		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
+		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
+		mrioc->admin_reply_base = NULL;
+	}
+	if (mrioc->admin_req_base) {
+		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
+		    mrioc->admin_req_base, mrioc->admin_req_dma);
+		mrioc->admin_req_base = NULL;
+	}
+
+}
+
+/**
+ * mpi3mr_issue_ioc_shutdown - Shutdown controller
+ * @mrioc: Adapter instance reference
+ *
+ * Send shutodwn notification to the controller and wait for the
+ * shutdown_timeout for it to be completed.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
+{
+	u32 ioc_config, ioc_status;
+	u8 retval = 1;
+	u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10;
+
+	ioc_info(mrioc, "Issuing Shutdown Notification\n");
+	if (mrioc->unrecoverable) {
+		ioc_warn(mrioc,
+		    "IOC is unrecoverable Shutdown is not issued\n");
+		return;
+	}
+	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
+	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
+	    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) {
+		ioc_info(mrioc, "Shutdown already in progress\n");
+		return;
+	}
+
+	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
+	ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
+	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN;
+
+	writel(ioc_config, &mrioc->sysif_regs->IOCConfiguration);
+
+	if (mrioc->facts.shutdown_timeout)
+		timeout = mrioc->facts.shutdown_timeout * 10;
+
+	do {
+		ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
+		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
+		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) {
+			retval = 0;
+			break;
+		}
+		msleep(100);
+	} while (--timeout);
+
+
+	ioc_status = readl(&mrioc->sysif_regs->IOCStatus);
+	ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration);
+
+	if (retval) {
+		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
+		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
+			ioc_warn(mrioc,
+			    "Shutdown still in progress after timeout\n");
+	}
+
+	ioc_info(mrioc,
+	    "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n",
+	    (!retval)?"successful":"failed", ioc_status,
+	    ioc_config);
+}
+
+/**
+ * mpi3mr_cleanup_ioc - Cleanup controller
+ * @mrioc: Adapter instance reference
+ *
+ * Controller cleanup handler, Message unit reset or soft reset
+ * and shutdown notification is issued to the controller and the
+ * associated memory resources are freed.
+ *
+ * Return: Nothing.
+ */
+void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc)
+{
+	enum mpi3mr_iocstate ioc_state;
+
+	mpi3mr_ioc_disable_intr(mrioc);
+
+	ioc_state = mpi3mr_get_iocstate(mrioc);
+
+	if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) &&
+	     (ioc_state == MRIOC_STATE_READY)) {
+		if (mpi3mr_issue_and_process_mur(mrioc,
+		    MPI3MR_RESET_FROM_CTLR_CLEANUP))
+			mpi3mr_issue_reset(mrioc,
+			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
+			    MPI3MR_RESET_FROM_MUR_FAILURE);
+
+		 mpi3mr_issue_ioc_shutdown(mrioc);
+	}
+
+	mpi3mr_free_mem(mrioc);
+	mpi3mr_cleanup_resources(mrioc);
+}
+
+
+/**
+ * mpi3mr_soft_reset_handler - Reset the controller
+ * @mrioc: Adapter instance reference
+ * @reset_reason: Reset reason code
+ * @snapdump: Flag to generate snapdump in firmware or not
+ *
+ * TBD
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
+	u32 reset_reason, u8 snapdump)
+{
+	return 0;
+}
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
new file mode 100644
index 000000000000..c31ec9883152
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -0,0 +1,368 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Broadcom MPI3 Storage Controllers
+ *
+ * Copyright (C) 2017-2020 Broadcom Inc.
+ *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
+ *
+ */
+
+#include "mpi3mr.h"
+
+/* global driver scop variables */
+LIST_HEAD(mrioc_list);
+DEFINE_SPINLOCK(mrioc_list_lock);
+static int mrioc_ids;
+static int warn_non_secure_ctlr;
+
+MODULE_AUTHOR(MPI3MR_DRIVER_AUTHOR);
+MODULE_DESCRIPTION(MPI3MR_DRIVER_DESC);
+MODULE_LICENSE(MPI3MR_DRIVER_LICENSE);
+MODULE_VERSION(MPI3MR_DRIVER_VERSION);
+
+/* Module parameters*/
+int logging_level;
+module_param(logging_level, int, 0);
+MODULE_PARM_DESC(logging_level,
+	" bits for enabling additional logging info (default=0)");
+
+
+/**
+ * mpi3mr_map_queues - Map queues callback handler
+ * @shost: SCSI host reference
+ *
+ * Call the blk_mq_pci_map_queues with from which operational
+ * queue the mapping has to be done
+ *
+ * Return: return of blk_mq_pci_map_queues
+ */
+static int mpi3mr_map_queues(struct Scsi_Host *shost)
+{
+	struct mpi3mr_ioc *mrioc = shost_priv(shost);
+
+	return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
+	    mrioc->pdev, 0);
+}
+
+/**
+ * mpi3mr_slave_destroy - Slave destroy callback handler
+ * @sdev: SCSI device reference
+ *
+ * Cleanup and free per device(LUN) private data.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_slave_destroy(struct scsi_device *sdev)
+{
+}
+
+/**
+ * mpi3mr_target_destroy - Target destroy callback handler
+ * @starget: SCSI target reference
+ *
+ * Cleanup and free per target private data.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_target_destroy(struct scsi_target *starget)
+{
+}
+
+/**
+ * mpi3mr_slave_configure - Slave configure callback handler
+ * @sdev: SCSI device reference
+ *
+ * Configure queue depth, max hardware sectors and virt boundary
+ * as required
+ *
+ * Return: 0 always.
+ */
+static int mpi3mr_slave_configure(struct scsi_device *sdev)
+{
+	int retval = 0;
+	return retval;
+}
+
+/**
+ * mpi3mr_slave_alloc -Slave alloc callback handler
+ * @sdev: SCSI device reference
+ *
+ * Allocate per device(LUN) private data and initialize it.
+ *
+ * Return: 0 on success -ENOMEM on memory allocation failure.
+ */
+static int mpi3mr_slave_alloc(struct scsi_device *sdev)
+{
+	int retval = 0;
+	return retval;
+}
+
+/**
+ * mpi3mr_target_alloc - Target alloc callback handler
+ * @starget: SCSI target reference
+ *
+ * Allocate per target private data and initialize it.
+ *
+ * Return: 0 on success -ENOMEM on memory allocation failure.
+ */
+static int mpi3mr_target_alloc(struct scsi_target *starget)
+{
+	int retval = -ENODEV;
+	return retval;
+}
+
+/**
+ * mpi3mr_qcmd - I/O request despatcher
+ * @shost: SCSI Host reference
+ * @scmd: SCSI Command reference
+ *
+ * Issues the SCSI Command as an MPI3 request.
+ *
+ * Return: 0 on successful queueing of the request or if the
+ *         request is completed with failure.
+ *         SCSI_MLQUEUE_DEVICE_BUSY when the device is busy.
+ *         SCSI_MLQUEUE_HOST_BUSY when the host queue is full.
+ */
+static int mpi3mr_qcmd(struct Scsi_Host *shost,
+	struct scsi_cmnd *scmd)
+{
+	int retval = 0;
+
+	scmd->result = DID_NO_CONNECT << 16;
+	scmd->scsi_done(scmd);
+	return retval;
+}
+
+static struct scsi_host_template mpi3mr_driver_template = {
+	.module				= THIS_MODULE,
+	.name				= "MPI3 Storage Controller",
+	.proc_name			= MPI3MR_DRIVER_NAME,
+	.queuecommand			= mpi3mr_qcmd,
+	.target_alloc			= mpi3mr_target_alloc,
+	.slave_alloc			= mpi3mr_slave_alloc,
+	.slave_configure		= mpi3mr_slave_configure,
+	.target_destroy			= mpi3mr_target_destroy,
+	.slave_destroy			= mpi3mr_slave_destroy,
+	.map_queues			= mpi3mr_map_queues,
+	.no_write_same			= 1,
+	.can_queue			= 1,
+	.this_id			= -1,
+	.sg_tablesize			= MPI3MR_SG_DEPTH,
+	/* max xfer supported is 1M (2K in 512 byte sized sectors)
+	 */
+	.max_sectors			= 2048,
+	.cmd_per_lun			= MPI3MR_MAX_CMDS_LUN,
+	.track_queue_depth		= 1,
+	.cmd_size			= sizeof(struct scmd_priv),
+};
+
+
+/**
+ * mpi3mr_init_drv_cmd - Initialize internal command tracker
+ * @cmdptr: Internal command tracker
+ * @host_tag: Host tag used for the specific command
+ *
+ * Initialize the internal command tracker structure with
+ * specified host tag.
+ *
+ * Return: Nothing.
+ */
+static inline void mpi3mr_init_drv_cmd(struct mpi3mr_drv_cmd *cmdptr,
+	u16 host_tag)
+{
+	mutex_init(&cmdptr->mutex);
+	cmdptr->reply = NULL;
+	cmdptr->state = MPI3MR_CMD_NOTUSED;
+	cmdptr->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
+	cmdptr->host_tag = host_tag;
+}
+
+/**
+ * mpi3mr_probe - PCI probe callback
+ * @pdev: PCI device instance
+ * @id: PCI device ID details
+ *
+ * Controller initialization routine. Checks the security status
+ * of the controller and if it is invalid or tampered return the
+ * probe without initializing the controller. Otherwise,
+ * allocate per adapter instance through shost_priv and
+ * initialize controller specific data structures, initializae
+ * the controller hardware, add shost to the SCSI subsystem.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+
+static int
+mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct mpi3mr_ioc *mrioc = NULL;
+	struct Scsi_Host *shost = NULL;
+	int retval = 0;
+
+	shost = scsi_host_alloc(&mpi3mr_driver_template,
+	    sizeof(struct mpi3mr_ioc));
+	if (!shost) {
+		retval = -ENODEV;
+		goto shost_failed;
+	}
+
+	mrioc = shost_priv(shost);
+	mrioc->id = mrioc_ids++;
+	sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME);
+	sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id);
+	INIT_LIST_HEAD(&mrioc->list);
+	spin_lock(&mrioc_list_lock);
+	list_add_tail(&mrioc->list, &mrioc_list);
+	spin_unlock(&mrioc_list_lock);
+
+	spin_lock_init(&mrioc->admin_req_lock);
+	spin_lock_init(&mrioc->reply_free_queue_lock);
+	spin_lock_init(&mrioc->sbq_lock);
+
+	mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
+
+	mrioc->logging_level = logging_level;
+	mrioc->shost = shost;
+	mrioc->pdev = pdev;
+
+	/* init shost parameters */
+	shost->max_cmd_len = MPI3MR_MAX_CDB_LENGTH;
+	shost->max_lun = -1;
+	shost->unique_id = mrioc->id;
+
+	shost->max_channel = 1;
+	shost->max_id = 0xFFFFFFFF;
+
+	mrioc->is_driver_loading = 1;
+	if (mpi3mr_init_ioc(mrioc)) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		retval = -ENODEV;
+		goto out_iocinit_failed;
+	}
+
+	shost->nr_hw_queues = mrioc->num_op_reply_q;
+	shost->can_queue = mrioc->max_host_ios;
+	shost->sg_tablesize = MPI3MR_SG_DEPTH;
+	shost->max_id = mrioc->facts.max_perids;
+
+	retval = scsi_add_host(shost, &pdev->dev);
+	if (retval) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		goto addhost_failed;
+	}
+
+	scsi_scan_host(shost);
+	return retval;
+
+addhost_failed:
+	mpi3mr_cleanup_ioc(mrioc);
+out_iocinit_failed:
+	spin_lock(&mrioc_list_lock);
+	list_del(&mrioc->list);
+	spin_unlock(&mrioc_list_lock);
+	scsi_host_put(shost);
+shost_failed:
+	return retval;
+}
+
+/**
+ * mpi3mr_remove - PCI remove callback
+ * @pdev: PCI device instance
+ *
+ * Free up all memory and resources associated with the
+ * controllerand target devices, unregister the shost.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_remove(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct mpi3mr_ioc *mrioc;
+
+	mrioc = shost_priv(shost);
+	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
+		ssleep(1);
+
+
+	scsi_remove_host(shost);
+
+	mpi3mr_cleanup_ioc(mrioc);
+
+	spin_lock(&mrioc_list_lock);
+	list_del(&mrioc->list);
+	spin_unlock(&mrioc_list_lock);
+
+	scsi_host_put(shost);
+}
+
+/**
+ * mpi3mr_shutdown - PCI shutdown callback
+ * @pdev: PCI device instance
+ *
+ * Free up all memory and resources associated with the
+ * controller
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_shutdown(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct mpi3mr_ioc *mrioc;
+
+	if (!shost)
+		return;
+
+	mrioc = shost_priv(shost);
+	while (mrioc->reset_in_progress || mrioc->is_driver_loading)
+		ssleep(1);
+
+	mpi3mr_cleanup_ioc(mrioc);
+
+}
+
+static const struct pci_device_id mpi3mr_pci_id_table[] = {
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_LSI_LOGIC, 0x00A5,
+		    PCI_ANY_ID, PCI_ANY_ID)
+	},
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table);
+
+static struct pci_driver mpi3mr_pci_driver = {
+	.name = MPI3MR_DRIVER_NAME,
+	.id_table = mpi3mr_pci_id_table,
+	.probe = mpi3mr_probe,
+	.remove = mpi3mr_remove,
+	.shutdown = mpi3mr_shutdown,
+};
+
+static int __init mpi3mr_init(void)
+{
+	int ret_val;
+
+	pr_info("Loading %s version %s\n", MPI3MR_DRIVER_NAME,
+	    MPI3MR_DRIVER_VERSION);
+
+	ret_val = pci_register_driver(&mpi3mr_pci_driver);
+
+	return ret_val;
+}
+
+static void __exit mpi3mr_exit(void)
+{
+	if (warn_non_secure_ctlr)
+		pr_warn(
+		    "Unloading %s version %s while managing a non secure controller\n",
+		    MPI3MR_DRIVER_NAME, MPI3MR_DRIVER_VERSION);
+	else
+		pr_info("Unloading %s version %s\n", MPI3MR_DRIVER_NAME,
+		    MPI3MR_DRIVER_VERSION);
+
+	pci_unregister_driver(&mpi3mr_pci_driver);
+}
+
+module_init(mpi3mr_init);
+module_exit(mpi3mr_exit);