[kernel] r19615 - in dists/squeeze/linux-2.6/debian: . patches/features/all/megaraid_sas patches/series
Ben Hutchings
benh at alioth.debian.org
Sun Dec 16 23:23:22 UTC 2012
Author: benh
Date: Sun Dec 16 23:23:22 2012
New Revision: 19615
Log:
megaraid_sas: Backport changes up to Linux 3.0.56 (Closes: #666108)
Added:
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0006-megaraid_sas-infrastructure-to-get-pds-from-fw.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0007-megaraid_sas-add-the-support-for-updating-the-os-after-adding-removing-the-devices-from-fw.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0008-megaraid_sas-add-the-logical-drive-list-to-driver.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0009-megaraid_sas-driver-fixed-the-device-update-issue.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0010-megaraid_sas-add-the-ieee-sge-support-to-sas2-controller.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0011-megaraid_sas-add-online-controller-reset-to-megaraid-sas-drive.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0012-megaraid_sas-rename-megaraid_sas.c-to-megaraid_sas_base.c.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0013-megaraid_sas-add-msi-x-support-and-msix_disable-module-parameter.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0014-megaraid_sas-make-driver-pci-legacy-i-o-port-free-driver.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0015-megaraid_sas-use-lowest-memory-bar-for-sr-iov-vf-support.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0016-megaraid_sas-add-struct-megasas_instance_template-changes.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0017-megaraid_sas-add-9565-9285-specific-code.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0018-megaraid_sas-fix-instance-access-in-megasas_reset_timer.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0019-megaraid_sas-tape-drive-support-fix.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0020-megaraid_sas-report-system-pds-to-os.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0021-megaraid_sas-use-the-firmware-boot-timeout-when-waiting-for-commands.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0022-megaraid_sas-update-version-number-and-documentation.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0023-megaraid_sas-zero-pad_0-in-mfi-structure.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0024-megaraid_sas-version-and-documentation-update.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0025-megaraid_sas-support-devices-update-flag.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0026-megaraid_sas-add-input-parameter-for-max_sectors.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0027-megaraid_sas-add-three-times-online-controller-reset.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0028-megaraid_sas-version-and-documentation-update.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0029-megaraid_sas-update-gpl-headers.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0030-megaraid_sas-fix-failure-gotos.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0031-megaraid_sas-add-missing-check_and_restore_queue_depth-call.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0032-megaraid_sas-enable-msi-x-before-calling-megasas_init_fw.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0033-megaraid_sas-call-tasklet_schedule-for-msi-x.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0034-megaraid_sas-fix-probe_one-to-clear-msi-x-flags-in-kdump.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0035-megaraid_sas-fix-megasas_build_dcdb_fusion-to-not-filter-by-type_disk.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0036-megaraid_sas-fix-megasas_build_dcdb_fusion-to-use-correct-lun-field.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0037-megaraid_sas-add-cfg_cleared-aen.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0038-megaraid_sas-fix-tasklet_init-call.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0039-megaraid_sas-fix-fault-state-handling.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0040-megaraid_sas-fix-max_sectors-for-ieee-sgl.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0041-megaraid_sas-fix-imr-ocr-support-to-work-correctly.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0042-megaraid_sas-documentation-update.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0043-megaraid_sas-add-9565-9285-specific-code-version-bump.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0044-megaraid_sas-version-and-changelog-update.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0045-megaraid_sas-remove-msi-x-black-list-use-mfi_reg_state-instead.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0046-megaraid_sas-remove-un-used-function.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0047-megaraid_sas-check-mfi_reg_state.fault.resetadapter.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0048-megaraid_sas-disable-interrupts-free_irq-in-megasas_shutdown.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0049-megaraid_sas-fix-bug-where-aens-could-be-lost-in-probe-and-resume.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0050-megaraid_sas-convert-6-10-12-byte-cdb-s-for-fastpath-io.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0051-megaraid_sas-add-1078-ocr-support.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0052-megaraid_sas-version-and-changelog-update.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0053-megaraid_sas-move-poll_aen_lock-initializer.patch
dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0054-megaraid_sas-cosmetic-changes.patch
Modified:
dists/squeeze/linux-2.6/debian/changelog
dists/squeeze/linux-2.6/debian/patches/series/47
Modified: dists/squeeze/linux-2.6/debian/changelog
==============================================================================
--- dists/squeeze/linux-2.6/debian/changelog Sun Dec 16 22:31:39 2012 (r19614)
+++ dists/squeeze/linux-2.6/debian/changelog Sun Dec 16 23:23:22 2012 (r19615)
@@ -8,6 +8,9 @@
* nfsv4: Fix kernel panic when mounting NFSv4 (Closes: #695872)
* hpsa: Backport changes up to Linux 3.2.35 (Closes: #690100)
+ [ Jonathan Nieder ]
+ * megaraid_sas: Backport changes up to Linux 3.0.56 (Closes: #666108)
+
-- Ben Hutchings <ben at decadent.org.uk> Mon, 08 Oct 2012 00:26:11 +0100
linux-2.6 (2.6.32-46) stable; urgency=high
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0006-megaraid_sas-infrastructure-to-get-pds-from-fw.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0006-megaraid_sas-infrastructure-to-get-pds-from-fw.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,273 @@
+From c8055e5e18540af704c3202fa9e90729bba6ffc4 Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Tue, 6 Oct 2009 14:27:54 -0600
+Subject: [PATCH 06/53] [SCSI] megaraid_sas: infrastructure to get PDs from FW
+
+commit 81e403ce3c6a34cd705bf54d4cdeefdeb7068a8d upstream.
+
+Add system PDs to OS. Driver implemented the get_pd_list function to
+get the system PD from FW.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.c | 96 ++++++++++++++++++++++++++++++++++++
+ drivers/scsi/megaraid/megaraid_sas.h | 88 ++++++++++++++++++++++++++++++++-
+ 2 files changed, 182 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
+index 28b27ce1a914..38abd98a1ffb 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.c
++++ b/drivers/scsi/megaraid/megaraid_sas.c
+@@ -2057,6 +2057,98 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
+ return 0;
+ }
+
++/*
++ * megasas_get_pd_list_info - Returns FW's pd_list structure
++ * @instance: Adapter soft state
++ * @pd_list: pd_list structure
++ *
++ * Issues an internal command (DCMD) to get the FW's controller PD
++ * list structure. This information is mainly used to find out SYSTEM
++ * supported by the FW.
++ */
++static int
++megasas_get_pd_list(struct megasas_instance *instance)
++{
++ int ret = 0, pd_index = 0;
++ struct megasas_cmd *cmd;
++ struct megasas_dcmd_frame *dcmd;
++ struct MR_PD_LIST *ci;
++ struct MR_PD_ADDRESS *pd_addr;
++ dma_addr_t ci_h = 0;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd) {
++ printk(KERN_DEBUG "megasas (get_pd_list): Failed to get cmd\n");
++ return -ENOMEM;
++ }
++
++ dcmd = &cmd->frame->dcmd;
++
++ ci = pci_alloc_consistent(instance->pdev,
++ MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), &ci_h);
++
++ if (!ci) {
++ printk(KERN_DEBUG "Failed to alloc mem for pd_list\n");
++ megasas_return_cmd(instance, cmd);
++ return -ENOMEM;
++ }
++
++ memset(ci, 0, sizeof(*ci));
++ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
++
++ dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
++ dcmd->mbox.b[1] = 0;
++ dcmd->cmd = MFI_CMD_DCMD;
++ dcmd->cmd_status = 0xFF;
++ dcmd->sge_count = 1;
++ dcmd->flags = MFI_FRAME_DIR_READ;
++ dcmd->timeout = 0;
++ dcmd->data_xfer_len = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
++ dcmd->opcode = MR_DCMD_PD_LIST_QUERY;
++ dcmd->sgl.sge32[0].phys_addr = ci_h;
++ dcmd->sgl.sge32[0].length = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
++
++ if (!megasas_issue_polled(instance, cmd)) {
++ ret = 0;
++ } else {
++ ret = -1;
++ }
++
++ /*
++ * the following function will get the instance PD LIST.
++ */
++
++ pd_addr = ci->addr;
++
++ if ( ret == 0 &&
++ (ci->count <
++ (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) {
++
++ memset(instance->pd_list, 0,
++ MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
++
++ for (pd_index = 0; pd_index < ci->count; pd_index++) {
++
++ instance->pd_list[pd_addr->deviceId].tid =
++ pd_addr->deviceId;
++ instance->pd_list[pd_addr->deviceId].driveType =
++ pd_addr->scsiDevType;
++ instance->pd_list[pd_addr->deviceId].driveState =
++ MR_PD_STATE_SYSTEM;
++ pd_addr++;
++ }
++ }
++
++ pci_free_consistent(instance->pdev,
++ MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
++ ci, ci_h);
++ megasas_return_cmd(instance, cmd);
++
++ return ret;
++}
++
++
+ /**
+ * megasas_get_controller_info - Returns FW's controller structure
+ * @instance: Adapter soft state
+@@ -2347,6 +2439,10 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ if (megasas_issue_init_mfi(instance))
+ goto fail_fw_init;
+
++ memset(instance->pd_list, 0 ,
++ (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
++ megasas_get_pd_list(instance);
++
+ ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
+
+ /*
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 3b1eed1bbbe0..dc88ea79b0db 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -133,6 +133,7 @@
+ #define MR_DCMD_CLUSTER 0x08000000
+ #define MR_DCMD_CLUSTER_RESET_ALL 0x08010100
+ #define MR_DCMD_CLUSTER_RESET_LD 0x08010200
++#define MR_DCMD_PD_LIST_QUERY 0x02010100
+
+ /*
+ * MFI command completion codes
+@@ -253,9 +254,89 @@ enum MR_EVT_ARGS {
+ MR_EVT_ARGS_STR,
+ MR_EVT_ARGS_TIME,
+ MR_EVT_ARGS_ECC,
++ MR_EVT_ARGS_LD_PROP,
++ MR_EVT_ARGS_PD_SPARE,
++ MR_EVT_ARGS_PD_INDEX,
++ MR_EVT_ARGS_DIAG_PASS,
++ MR_EVT_ARGS_DIAG_FAIL,
++ MR_EVT_ARGS_PD_LBA_LBA,
++ MR_EVT_ARGS_PORT_PHY,
++ MR_EVT_ARGS_PD_MISSING,
++ MR_EVT_ARGS_PD_ADDRESS,
++ MR_EVT_ARGS_BITMAP,
++ MR_EVT_ARGS_CONNECTOR,
++ MR_EVT_ARGS_PD_PD,
++ MR_EVT_ARGS_PD_FRU,
++ MR_EVT_ARGS_PD_PATHINFO,
++ MR_EVT_ARGS_PD_POWER_STATE,
++ MR_EVT_ARGS_GENERIC,
++};
+
++/*
++ * define constants for device list query options
++ */
++enum MR_PD_QUERY_TYPE {
++ MR_PD_QUERY_TYPE_ALL = 0,
++ MR_PD_QUERY_TYPE_STATE = 1,
++ MR_PD_QUERY_TYPE_POWER_STATE = 2,
++ MR_PD_QUERY_TYPE_MEDIA_TYPE = 3,
++ MR_PD_QUERY_TYPE_SPEED = 4,
++ MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5,
+ };
+
++enum MR_PD_STATE {
++ MR_PD_STATE_UNCONFIGURED_GOOD = 0x00,
++ MR_PD_STATE_UNCONFIGURED_BAD = 0x01,
++ MR_PD_STATE_HOT_SPARE = 0x02,
++ MR_PD_STATE_OFFLINE = 0x10,
++ MR_PD_STATE_FAILED = 0x11,
++ MR_PD_STATE_REBUILD = 0x14,
++ MR_PD_STATE_ONLINE = 0x18,
++ MR_PD_STATE_COPYBACK = 0x20,
++ MR_PD_STATE_SYSTEM = 0x40,
++ };
++
++
++ /*
++ * defines the physical drive address structure
++ */
++struct MR_PD_ADDRESS {
++ u16 deviceId;
++ u16 enclDeviceId;
++
++ union {
++ struct {
++ u8 enclIndex;
++ u8 slotNumber;
++ } mrPdAddress;
++ struct {
++ u8 enclPosition;
++ u8 enclConnectorIndex;
++ } mrEnclAddress;
++ };
++ u8 scsiDevType;
++ union {
++ u8 connectedPortBitmap;
++ u8 connectedPortNumbers;
++ };
++ u64 sasAddr[2];
++} __packed;
++
++/*
++ * defines the physical drive list structure
++ */
++struct MR_PD_LIST {
++ u32 size;
++ u32 count;
++ struct MR_PD_ADDRESS addr[1];
++} __packed;
++
++struct megasas_pd_list {
++ u16 tid;
++ u8 driveType;
++ u8 driveState;
++} __packed;
++
+ /*
+ * SAS controller properties
+ */
+@@ -284,7 +365,7 @@ struct megasas_ctrl_prop {
+ u8 expose_encl_devices;
+ u8 reserved[38];
+
+-} __attribute__ ((packed));
++} __packed;
+
+ /*
+ * SAS controller information
+@@ -527,7 +608,7 @@ struct megasas_ctrl_info {
+
+ u8 pad[0x800 - 0x6a0];
+
+-} __attribute__ ((packed));
++} __packed;
+
+ /*
+ * ===============================
+@@ -542,6 +623,8 @@ struct megasas_ctrl_info {
+ #define MEGASAS_DEFAULT_INIT_ID -1
+ #define MEGASAS_MAX_LUN 8
+ #define MEGASAS_MAX_LD 64
++#define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \
++ MEGASAS_MAX_DEV_PER_CHANNEL)
+
+ #define MEGASAS_DBG_LVL 1
+
+@@ -1079,6 +1162,7 @@ struct megasas_instance {
+ unsigned long base_addr;
+ struct megasas_register_set __iomem *reg_set;
+
++ struct megasas_pd_list pd_list[MEGASAS_MAX_PD];
+ s8 init_id;
+
+ u16 max_num_sge;
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0007-megaraid_sas-add-the-support-for-updating-the-os-after-adding-removing-the-devices-from-fw.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0007-megaraid_sas-add-the-support-for-updating-the-os-after-adding-removing-the-devices-from-fw.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,255 @@
+From c7d26f96f235b911dfbeab7fa31aeab64d436825 Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Tue, 6 Oct 2009 14:50:17 -0600
+Subject: [PATCH 07/53] [SCSI] megaraid_sas: Add the support for updating the OS after adding/removing the devices from FW
+
+commit 7e8a75f4dfbff173977b2f58799c3eceb7b09afd upstream.
+
+Driver will update the OS devices after adding and deleting the device
+from FW. When driver receive add or delete AEN from FW, driver will
+send the DCMD cmd to get the System PD list from FW. Then driver will
+check if this device already in the OS: If add event and OS don't have
+the device (but it is in the list), driver add the device to OS,
+otherwise driver will not add. If remove event, driver will check the
+list, if is not in the list, but OS have the device, driver will
+remove the device.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.c | 125 ++++++++++++++++++++++++++++++++++-
+ drivers/scsi/megaraid/megaraid_sas.h | 17 +++++
+ 2 files changed, 141 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
+index 38abd98a1ffb..b690c8ca75cc 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.c
++++ b/drivers/scsi/megaraid/megaraid_sas.c
+@@ -1402,6 +1402,8 @@ megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+ return 0;
+ }
+
++static void megasas_aen_polling(struct work_struct *work);
++
+ /**
+ * megasas_service_aen - Processes an event notification
+ * @instance: Adapter soft state
+@@ -1433,6 +1435,20 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
+
+ instance->aen_cmd = NULL;
+ megasas_return_cmd(instance, cmd);
++
++ if (instance->unload == 0) {
++ struct megasas_aen_event *ev;
++ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
++ if (!ev) {
++ printk(KERN_ERR "megasas_service_aen: out of memory\n");
++ } else {
++ ev->instance = instance;
++ instance->ev = ev;
++ INIT_WORK(&ev->hotplug_work, megasas_aen_polling);
++ schedule_delayed_work(
++ (struct delayed_work *)&ev->hotplug_work, 0);
++ }
++ }
+ }
+
+ /*
+@@ -1952,6 +1968,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
+ }
+
+ cmd->frame->io.context = cmd->index;
++ cmd->frame->io.pad_0 = 0;
+ }
+
+ return 0;
+@@ -2148,7 +2165,6 @@ megasas_get_pd_list(struct megasas_instance *instance)
+ return ret;
+ }
+
+-
+ /**
+ * megasas_get_controller_info - Returns FW's controller structure
+ * @instance: Adapter soft state
+@@ -2857,6 +2873,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ *instance->producer = 0;
+ *instance->consumer = 0;
+ megasas_poll_wait_aen = 0;
++ instance->ev = NULL;
+
+ instance->evt_detail = pci_alloc_consistent(pdev,
+ sizeof(struct
+@@ -3079,6 +3096,16 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
+
+ megasas_flush_cache(instance);
+ megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
++
++ /* cancel the delayed work if this work still in queue */
++ if (instance->ev != NULL) {
++ struct megasas_aen_event *ev = instance->ev;
++ cancel_delayed_work(
++ (struct delayed_work *)&ev->hotplug_work);
++ flush_scheduled_work();
++ instance->ev = NULL;
++ }
++
+ tasklet_kill(&instance->isr_tasklet);
+
+ pci_set_drvdata(instance->pdev, instance);
+@@ -3219,6 +3246,16 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
+ scsi_remove_host(instance->host);
+ megasas_flush_cache(instance);
+ megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
++
++ /* cancel the delayed work if this work still in queue*/
++ if (instance->ev != NULL) {
++ struct megasas_aen_event *ev = instance->ev;
++ cancel_delayed_work(
++ (struct delayed_work *)&ev->hotplug_work);
++ flush_scheduled_work();
++ instance->ev = NULL;
++ }
++
+ tasklet_kill(&instance->isr_tasklet);
+
+ /*
+@@ -3814,6 +3851,92 @@ out:
+ return retval;
+ }
+
++static void
++megasas_aen_polling(struct work_struct *work)
++{
++ struct megasas_aen_event *ev =
++ container_of(work, struct megasas_aen_event, hotplug_work);
++ struct megasas_instance *instance = ev->instance;
++ union megasas_evt_class_locale class_locale;
++ struct Scsi_Host *host;
++ struct scsi_device *sdev1;
++ u16 pd_index = 0;
++ int i, j, doscan = 0;
++ u32 seq_num;
++ int error;
++
++ if (!instance) {
++ printk(KERN_ERR "invalid instance!\n");
++ kfree(ev);
++ return;
++ }
++ instance->ev = NULL;
++ host = instance->host;
++ if (instance->evt_detail) {
++
++ switch (instance->evt_detail->code) {
++ case MR_EVT_PD_INSERTED:
++ case MR_EVT_PD_REMOVED:
++ case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
++ doscan = 1;
++ break;
++ default:
++ doscan = 0;
++ break;
++ }
++ } else {
++ printk(KERN_ERR "invalid evt_detail!\n");
++ kfree(ev);
++ return;
++ }
++
++ if (doscan) {
++ printk(KERN_INFO "scanning ...\n");
++ megasas_get_pd_list(instance);
++ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
++ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
++ pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
++ sdev1 = scsi_device_lookup(host, i, j, 0);
++ if (instance->pd_list[pd_index].driveState ==
++ MR_PD_STATE_SYSTEM) {
++ if (!sdev1) {
++ scsi_add_device(host, i, j, 0);
++ }
++ if (sdev1)
++ scsi_device_put(sdev1);
++ } else {
++ if (sdev1) {
++ scsi_remove_device(sdev1);
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ }
++ }
++
++ if ( instance->aen_cmd != NULL ) {
++ kfree(ev);
++ return ;
++ }
++
++ seq_num = instance->evt_detail->seq_num + 1;
++
++ /* Register AEN with FW for latest sequence number plus 1 */
++ class_locale.members.reserved = 0;
++ class_locale.members.locale = MR_EVT_LOCALE_ALL;
++ class_locale.members.class = MR_EVT_CLASS_DEBUG;
++ mutex_lock(&instance->aen_mutex);
++ error = megasas_register_aen(instance, seq_num,
++ class_locale.word);
++ mutex_unlock(&instance->aen_mutex);
++
++ if (error)
++ printk(KERN_ERR "register aen failed error %x\n", error);
++
++ kfree(ev);
++}
++
++
+ static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUSR,
+ megasas_sysfs_show_poll_mode_io,
+ megasas_sysfs_set_poll_mode_io);
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index dc88ea79b0db..b0a85fc72d8d 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -284,6 +284,17 @@ enum MR_PD_QUERY_TYPE {
+ MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5,
+ };
+
++#define MR_EVT_CFG_CLEARED 0x0004
++#define MR_EVT_LD_STATE_CHANGE 0x0051
++#define MR_EVT_PD_INSERTED 0x005b
++#define MR_EVT_PD_REMOVED 0x0070
++#define MR_EVT_LD_CREATED 0x008a
++#define MR_EVT_LD_DELETED 0x008b
++#define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db
++#define MR_EVT_LD_OFFLINE 0x00fc
++#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152
++#define MAX_LOGICAL_DRIVES 64
++
+ enum MR_PD_STATE {
+ MR_PD_STATE_UNCONFIGURED_GOOD = 0x00,
+ MR_PD_STATE_UNCONFIGURED_BAD = 0x01,
+@@ -1149,6 +1160,11 @@ struct megasas_evt_detail {
+
+ } __attribute__ ((packed));
+
++struct megasas_aen_event {
++ struct work_struct hotplug_work;
++ struct megasas_instance *instance;
++};
++
+ struct megasas_instance {
+
+ u32 *producer;
+@@ -1168,6 +1184,7 @@ struct megasas_instance {
+ u16 max_num_sge;
+ u16 max_fw_cmds;
+ u32 max_sectors_per_req;
++ struct megasas_aen_event *ev;
+
+ struct megasas_cmd **cmd_list;
+ struct list_head cmd_pool;
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0008-megaraid_sas-add-the-logical-drive-list-to-driver.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0008-megaraid_sas-add-the-logical-drive-list-to-driver.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,212 @@
+From 9b1a265b1f243f1f9dad1b4883f8b123b3ff023b Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Sun, 6 Dec 2009 08:30:19 -0700
+Subject: [PATCH 08/53] [SCSI] megaraid_sas: add the logical drive list to driver
+
+commit bdc6fb8d69fab7b4b7f70823e3932bd8e4cfd7db upstream.
+
+Driver issue the get ld list to fw to get the logic drive list.
+Driver will keep the logic drive list for the internal use after
+driver load.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.c | 95 ++++++++++++++++++++++++++++++++++++
+ drivers/scsi/megaraid/megaraid_sas.h | 30 ++++++++++++
+ 2 files changed, 125 insertions(+)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
+index b690c8ca75cc..3a35e27e1ab8 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.c
++++ b/drivers/scsi/megaraid/megaraid_sas.c
+@@ -817,6 +817,12 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ pthru->sge_count = megasas_make_sgl32(instance, scp,
+ &pthru->sgl);
+
++ if (pthru->sge_count > instance->max_num_sge) {
++ printk(KERN_ERR "megasas: DCDB two many SGE NUM=%x\n",
++ pthru->sge_count);
++ return 0;
++ }
++
+ /*
+ * Sense info specific
+ */
+@@ -935,6 +941,12 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ } else
+ ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl);
+
++ if (ldio->sge_count > instance->max_num_sge) {
++ printk(KERN_ERR "megasas: build_ld_io: sge_count = %x\n",
++ ldio->sge_count);
++ return 0;
++ }
++
+ /*
+ * Sense info specific
+ */
+@@ -2165,6 +2177,86 @@ megasas_get_pd_list(struct megasas_instance *instance)
+ return ret;
+ }
+
++/*
++ * megasas_get_ld_list_info - Returns FW's ld_list structure
++ * @instance: Adapter soft state
++ * @ld_list: ld_list structure
++ *
++ * Issues an internal command (DCMD) to get the FW's controller PD
++ * list structure. This information is mainly used to find out SYSTEM
++ * supported by the FW.
++ */
++static int
++megasas_get_ld_list(struct megasas_instance *instance)
++{
++ int ret = 0, ld_index = 0, ids = 0;
++ struct megasas_cmd *cmd;
++ struct megasas_dcmd_frame *dcmd;
++ struct MR_LD_LIST *ci;
++ dma_addr_t ci_h = 0;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd) {
++ printk(KERN_DEBUG "megasas_get_ld_list: Failed to get cmd\n");
++ return -ENOMEM;
++ }
++
++ dcmd = &cmd->frame->dcmd;
++
++ ci = pci_alloc_consistent(instance->pdev,
++ sizeof(struct MR_LD_LIST),
++ &ci_h);
++
++ if (!ci) {
++ printk(KERN_DEBUG "Failed to alloc mem in get_ld_list\n");
++ megasas_return_cmd(instance, cmd);
++ return -ENOMEM;
++ }
++
++ memset(ci, 0, sizeof(*ci));
++ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
++
++ dcmd->cmd = MFI_CMD_DCMD;
++ dcmd->cmd_status = 0xFF;
++ dcmd->sge_count = 1;
++ dcmd->flags = MFI_FRAME_DIR_READ;
++ dcmd->timeout = 0;
++ dcmd->data_xfer_len = sizeof(struct MR_LD_LIST);
++ dcmd->opcode = MR_DCMD_LD_GET_LIST;
++ dcmd->sgl.sge32[0].phys_addr = ci_h;
++ dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST);
++ dcmd->pad_0 = 0;
++
++ if (!megasas_issue_polled(instance, cmd)) {
++ ret = 0;
++ } else {
++ ret = -1;
++ }
++
++ /* the following function will get the instance PD LIST */
++
++ if ((ret == 0) && (ci->ldCount < MAX_LOGICAL_DRIVES)) {
++ memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
++
++ for (ld_index = 0; ld_index < ci->ldCount; ld_index++) {
++ if (ci->ldList[ld_index].state != 0) {
++ ids = ci->ldList[ld_index].ref.targetId;
++ instance->ld_ids[ids] =
++ ci->ldList[ld_index].ref.targetId;
++ }
++ }
++ }
++
++ pci_free_consistent(instance->pdev,
++ sizeof(struct MR_LD_LIST),
++ ci,
++ ci_h);
++
++ megasas_return_cmd(instance, cmd);
++ return ret;
++}
++
+ /**
+ * megasas_get_controller_info - Returns FW's controller structure
+ * @instance: Adapter soft state
+@@ -2459,6 +2551,9 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
+ megasas_get_pd_list(instance);
+
++ memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
++ megasas_get_ld_list(instance);
++
+ ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
+
+ /*
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index b0a85fc72d8d..29cd2c877952 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -116,6 +116,7 @@
+ #define MFI_CMD_STP 0x08
+
+ #define MR_DCMD_CTRL_GET_INFO 0x01010000
++#define MR_DCMD_LD_GET_LIST 0x03010000
+
+ #define MR_DCMD_CTRL_CACHE_FLUSH 0x01101000
+ #define MR_FLUSH_CTRL_CACHE 0x01
+@@ -348,6 +349,32 @@ struct megasas_pd_list {
+ u8 driveState;
+ } __packed;
+
++ /*
++ * defines the logical drive reference structure
++ */
++union MR_LD_REF {
++ struct {
++ u8 targetId;
++ u8 reserved;
++ u16 seqNum;
++ };
++ u32 ref;
++} __packed;
++
++/*
++ * defines the logical drive list structure
++ */
++struct MR_LD_LIST {
++ u32 ldCount;
++ u32 reserved;
++ struct {
++ union MR_LD_REF ref;
++ u8 state;
++ u8 reserved[3];
++ u64 size;
++ } ldList[MAX_LOGICAL_DRIVES];
++} __packed;
++
+ /*
+ * SAS controller properties
+ */
+@@ -636,6 +663,8 @@ struct megasas_ctrl_info {
+ #define MEGASAS_MAX_LD 64
+ #define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \
+ MEGASAS_MAX_DEV_PER_CHANNEL)
++#define MEGASAS_MAX_LD_IDS (MEGASAS_MAX_LD_CHANNELS * \
++ MEGASAS_MAX_DEV_PER_CHANNEL)
+
+ #define MEGASAS_DBG_LVL 1
+
+@@ -1179,6 +1208,7 @@ struct megasas_instance {
+ struct megasas_register_set __iomem *reg_set;
+
+ struct megasas_pd_list pd_list[MEGASAS_MAX_PD];
++ u8 ld_ids[MEGASAS_MAX_LD_IDS];
+ s8 init_id;
+
+ u16 max_num_sge;
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0009-megaraid_sas-driver-fixed-the-device-update-issue.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0009-megaraid_sas-driver-fixed-the-device-update-issue.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,190 @@
+From b3d3d3e77c8850222a5a210855e0e7b3d0a2ac71 Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Sun, 6 Dec 2009 08:39:25 -0700
+Subject: [PATCH 09/53] [SCSI] megaraid_sas: driver fixed the device update issue
+
+commit c978684254d11e3768c5a0b2780302fb0cada29c upstream.
+
+driver fixed the device update issue after get the AEN PD delete/ADD
+and LD add/delete from FW.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.c | 142 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 142 insertions(+)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
+index 3a35e27e1ab8..c7e1e40ad24a 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.c
++++ b/drivers/scsi/megaraid/megaraid_sas.c
+@@ -3956,6 +3956,7 @@ megasas_aen_polling(struct work_struct *work)
+ struct Scsi_Host *host;
+ struct scsi_device *sdev1;
+ u16 pd_index = 0;
++ u16 ld_index = 0;
+ int i, j, doscan = 0;
+ u32 seq_num;
+ int error;
+@@ -3971,8 +3972,124 @@ megasas_aen_polling(struct work_struct *work)
+
+ switch (instance->evt_detail->code) {
+ case MR_EVT_PD_INSERTED:
++ if (megasas_get_pd_list(instance) == 0) {
++ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
++ for (j = 0;
++ j < MEGASAS_MAX_DEV_PER_CHANNEL;
++ j++) {
++
++ pd_index =
++ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
++
++ sdev1 =
++ scsi_device_lookup(host, i, j, 0);
++
++ if (instance->pd_list[pd_index].driveState
++ == MR_PD_STATE_SYSTEM) {
++ if (!sdev1) {
++ scsi_add_device(host, i, j, 0);
++ }
++
++ if (sdev1)
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ }
++ doscan = 0;
++ break;
++
+ case MR_EVT_PD_REMOVED:
++ if (megasas_get_pd_list(instance) == 0) {
++ megasas_get_pd_list(instance);
++ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
++ for (j = 0;
++ j < MEGASAS_MAX_DEV_PER_CHANNEL;
++ j++) {
++
++ pd_index =
++ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
++
++ sdev1 =
++ scsi_device_lookup(host, i, j, 0);
++
++ if (instance->pd_list[pd_index].driveState
++ == MR_PD_STATE_SYSTEM) {
++ if (sdev1) {
++ scsi_device_put(sdev1);
++ }
++ } else {
++ if (sdev1) {
++ scsi_remove_device(sdev1);
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ }
++ }
++ doscan = 0;
++ break;
++
++ case MR_EVT_LD_OFFLINE:
++ case MR_EVT_LD_DELETED:
++ megasas_get_ld_list(instance);
++ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
++ for (j = 0;
++ j < MEGASAS_MAX_DEV_PER_CHANNEL;
++ j++) {
++
++ ld_index =
++ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
++
++ sdev1 = scsi_device_lookup(host,
++ i + MEGASAS_MAX_LD_CHANNELS,
++ j,
++ 0);
++
++ if (instance->ld_ids[ld_index] != 0xff) {
++ if (sdev1) {
++ scsi_device_put(sdev1);
++ }
++ } else {
++ if (sdev1) {
++ scsi_remove_device(sdev1);
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ }
++ doscan = 0;
++ break;
++ case MR_EVT_LD_CREATED:
++ megasas_get_ld_list(instance);
++ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
++ for (j = 0;
++ j < MEGASAS_MAX_DEV_PER_CHANNEL;
++ j++) {
++ ld_index =
++ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
++
++ sdev1 = scsi_device_lookup(host,
++ i+MEGASAS_MAX_LD_CHANNELS,
++ j, 0);
++
++ if (instance->ld_ids[ld_index] !=
++ 0xff) {
++ if (!sdev1) {
++ scsi_add_device(host,
++ i + 2,
++ j, 0);
++ }
++ }
++ if (sdev1) {
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ doscan = 0;
++ break;
+ case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
++ case MR_EVT_FOREIGN_CFG_IMPORTED:
+ doscan = 1;
+ break;
+ default:
+@@ -4007,6 +4124,31 @@ megasas_aen_polling(struct work_struct *work)
+ }
+ }
+ }
++
++ megasas_get_ld_list(instance);
++ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
++ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
++ ld_index =
++ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
++
++ sdev1 = scsi_device_lookup(host,
++ i+MEGASAS_MAX_LD_CHANNELS, j, 0);
++ if (instance->ld_ids[ld_index] != 0xff) {
++ if (!sdev1) {
++ scsi_add_device(host,
++ i+2,
++ j, 0);
++ } else {
++ scsi_device_put(sdev1);
++ }
++ } else {
++ if (sdev1) {
++ scsi_remove_device(sdev1);
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ }
+ }
+
+ if ( instance->aen_cmd != NULL ) {
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0010-megaraid_sas-add-the-ieee-sge-support-to-sas2-controller.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0010-megaraid_sas-add-the-ieee-sge-support-to-sas2-controller.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,246 @@
+From 10ff204feef80b5d19d325573dfd0fa35aa4f800 Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Tue, 6 Oct 2009 14:43:28 -0600
+Subject: [PATCH 10/53] [SCSI] megaraid_sas: add the IEEE SGE support to SAS2 controller
+
+commit f4c9a1317d32bb0af7546ef0c1dcc3be52dc8d0a upstream.
+
+To increase the performance, megaraid sas driver added the IEEE SGE
+support to support SAS2 controller.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.c | 80 ++++++++++++++++++++++++++++++++----
+ drivers/scsi/megaraid/megaraid_sas.h | 9 ++++
+ 2 files changed, 82 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
+index c7e1e40ad24a..2b9e3c68c3e7 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.c
++++ b/drivers/scsi/megaraid/megaraid_sas.c
+@@ -712,6 +712,35 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ return sge_count;
+ }
+
++/**
++ * megasas_make_sgl_skinny - Prepares IEEE SGL
++ * @instance: Adapter soft state
++ * @scp: SCSI command from the mid-layer
++ * @mfi_sgl: SGL to be filled in
++ *
++ * If successful, this function returns the number of SG elements. Otherwise,
++ * it returnes -1.
++ */
++static int
++megasas_make_sgl_skinny(struct megasas_instance *instance,
++ struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl)
++{
++ int i;
++ int sge_count;
++ struct scatterlist *os_sgl;
++
++ sge_count = scsi_dma_map(scp);
++
++ if (sge_count) {
++ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
++ mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
++ mfi_sgl->sge_skinny[i].phys_addr =
++ sg_dma_address(os_sgl);
++ }
++ }
++ return sge_count;
++}
++
+ /**
+ * megasas_get_frame_count - Computes the number of frames
+ * @frame_type : type of frame- io or pthru frame
+@@ -720,7 +749,8 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ * Returns the number of frames required for numnber of sge's (sge_count)
+ */
+
+-static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
++static u32 megasas_get_frame_count(struct megasas_instance *instance,
++ u8 sge_count, u8 frame_type)
+ {
+ int num_cnt;
+ int sge_bytes;
+@@ -730,6 +760,10 @@ static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
+ sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+ sizeof(struct megasas_sge32);
+
++ if (instance->flag_ieee) {
++ sge_sz = sizeof(struct megasas_sge_skinny);
++ }
++
+ /*
+ * Main frame can contain 2 SGEs for 64-bit SGLs and
+ * 3 SGEs for 32-bit SGLs for ldio &
+@@ -737,12 +771,16 @@ static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
+ * 2 SGEs for 32-bit SGLs for pthru frame
+ */
+ if (unlikely(frame_type == PTHRU_FRAME)) {
+- if (IS_DMA64)
++ if (instance->flag_ieee == 1) {
++ num_cnt = sge_count - 1;
++ } else if (IS_DMA64)
+ num_cnt = sge_count - 1;
+ else
+ num_cnt = sge_count - 2;
+ } else {
+- if (IS_DMA64)
++ if (instance->flag_ieee == 1) {
++ num_cnt = sge_count - 1;
++ } else if (IS_DMA64)
+ num_cnt = sge_count - 2;
+ else
+ num_cnt = sge_count - 3;
+@@ -791,6 +829,10 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ else if (scp->sc_data_direction == PCI_DMA_NONE)
+ flags = MFI_FRAME_DIR_NONE;
+
++ if (instance->flag_ieee == 1) {
++ flags |= MFI_FRAME_IEEE;
++ }
++
+ /*
+ * Prepare the DCDB frame
+ */
+@@ -809,7 +851,11 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ /*
+ * Construct SGL
+ */
+- if (IS_DMA64) {
++ if (instance->flag_ieee == 1) {
++ pthru->flags |= MFI_FRAME_SGL64;
++ pthru->sge_count = megasas_make_sgl_skinny(instance, scp,
++ &pthru->sgl);
++ } else if (IS_DMA64) {
+ pthru->flags |= MFI_FRAME_SGL64;
+ pthru->sge_count = megasas_make_sgl64(instance, scp,
+ &pthru->sgl);
+@@ -834,7 +880,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ * Compute the total number of frames this command consumes. FW uses
+ * this number to pull sufficient number of frames from host memory.
+ */
+- cmd->frame_count = megasas_get_frame_count(pthru->sge_count,
++ cmd->frame_count = megasas_get_frame_count(instance, pthru->sge_count,
+ PTHRU_FRAME);
+
+ return cmd->frame_count;
+@@ -865,6 +911,10 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ flags = MFI_FRAME_DIR_READ;
+
++ if (instance->flag_ieee == 1) {
++ flags |= MFI_FRAME_IEEE;
++ }
++
+ /*
+ * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
+ */
+@@ -935,7 +985,11 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ /*
+ * Construct SGL
+ */
+- if (IS_DMA64) {
++ if (instance->flag_ieee) {
++ ldio->flags |= MFI_FRAME_SGL64;
++ ldio->sge_count = megasas_make_sgl_skinny(instance, scp,
++ &ldio->sgl);
++ } else if (IS_DMA64) {
+ ldio->flags |= MFI_FRAME_SGL64;
+ ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
+ } else
+@@ -958,7 +1012,8 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ * Compute the total number of frames this command consumes. FW uses
+ * this number to pull sufficient number of frames from host memory.
+ */
+- cmd->frame_count = megasas_get_frame_count(ldio->sge_count, IO_FRAME);
++ cmd->frame_count = megasas_get_frame_count(instance,
++ ldio->sge_count, IO_FRAME);
+
+ return cmd->frame_count;
+ }
+@@ -1918,6 +1973,10 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
+ sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+ sizeof(struct megasas_sge32);
+
++ if (instance->flag_ieee) {
++ sge_sz = sizeof(struct megasas_sge_skinny);
++ }
++
+ /*
+ * Calculated the number of 64byte frames required for SGL
+ */
+@@ -2797,6 +2856,11 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
+ dcmd->sgl.sge32[0].phys_addr = (u32) instance->evt_detail_h;
+ dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_detail);
+
++ if (instance->aen_cmd != NULL) {
++ megasas_return_cmd(instance, cmd);
++ return 0;
++ }
++
+ /*
+ * Store reference to the cmd used to register for AEN. When an
+ * application wants us to register for AEN, we have to abort this
+@@ -2968,6 +3032,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ *instance->producer = 0;
+ *instance->consumer = 0;
+ megasas_poll_wait_aen = 0;
++ instance->flag_ieee = 0;
+ instance->ev = NULL;
+
+ instance->evt_detail = pci_alloc_consistent(pdev,
+@@ -3008,6 +3073,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ instance->flag_ieee = 1;
+ sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
+ } else
+ sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 29cd2c877952..a22d8d48b7dd 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -96,6 +96,7 @@
+ #define MFI_FRAME_DIR_WRITE 0x0008
+ #define MFI_FRAME_DIR_READ 0x0010
+ #define MFI_FRAME_DIR_BOTH 0x0018
++#define MFI_FRAME_IEEE 0x0020
+
+ /*
+ * Definition for cmd_status
+@@ -772,10 +773,17 @@ struct megasas_sge64 {
+
+ } __attribute__ ((packed));
+
++struct megasas_sge_skinny {
++ u64 phys_addr;
++ u32 length;
++ u32 flag;
++} __packed;
++
+ union megasas_sgl {
+
+ struct megasas_sge32 sge32[1];
+ struct megasas_sge64 sge64[1];
++ struct megasas_sge_skinny sge_skinny[1];
+
+ } __attribute__ ((packed));
+
+@@ -1248,6 +1256,7 @@ struct megasas_instance {
+
+ u8 flag;
+ u8 unload;
++ u8 flag_ieee;
+ unsigned long last_time;
+
+ struct timer_list io_completion_timer;
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0011-megaraid_sas-add-online-controller-reset-to-megaraid-sas-drive.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0011-megaraid_sas-add-online-controller-reset-to-megaraid-sas-drive.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,1391 @@
+From dd7927ad22329bf32c0a8a8d1168b370c89b7594 Mon Sep 17 00:00:00 2001
+From: bo yang <boyang1288 at gmail.com>
+Date: Wed, 22 Sep 2010 22:36:29 -0400
+Subject: [PATCH 11/53] [SCSI] megaraid_sas: Add Online Controller Reset to MegaRAID SAS drive
+
+commit 39a985547cbfcbb0b23667b69b8ae82a6cf312ac upstream.
+
+To add the Online controller reset support, driver need to do:
+a). reset the controller chips -- Xscale and Gen2 which will change
+the function calls and add the reset function related to this two
+chips.
+b). during the reset, driver will store the pending cmds which not
+returned by FW to driver's pending queue. Driver will re-issue those
+pending cmds again to FW after the OCR finished.
+c). In driver's timeout routine, driver will report to OS as reset.
+Also driver's queue routine will block the cmds until the OCR
+finished.
+d). in Driver's ISR routine, if driver get the FW state as state
+change, FW in Failure status and FW support online controller
+reset (OCR), driver will start to do the controller reset.
+e). In driver's IOCTL routine, the application cmds will wait for the
+OCR to finish, then issue the cmds to FW.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.c | 756 ++++++++++++++++++++++++++++++++---
+ drivers/scsi/megaraid/megaraid_sas.h | 88 +++-
+ 2 files changed, 787 insertions(+), 57 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
+index 2b9e3c68c3e7..72c925d9e0f3 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.c
++++ b/drivers/scsi/megaraid/megaraid_sas.c
+@@ -61,6 +61,11 @@ MODULE_VERSION(MEGASAS_VERSION);
+ MODULE_AUTHOR("megaraidlinux at lsi.com");
+ MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
+
++static int megasas_transition_to_ready(struct megasas_instance *instance);
++static int megasas_get_pd_list(struct megasas_instance *instance);
++static int megasas_issue_init_mfi(struct megasas_instance *instance);
++static int megasas_register_aen(struct megasas_instance *instance,
++ u32 seq_num, u32 class_locale_word);
+ /*
+ * PCI ID table for all supported controllers
+ */
+@@ -163,7 +168,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
+ static inline void
+ megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
+ {
+- writel(1, &(regs)->outbound_intr_mask);
++ writel(0, &(regs)->outbound_intr_mask);
+
+ /* Dummy readl to force pci flush */
+ readl(®s->outbound_intr_mask);
+@@ -199,24 +204,27 @@ static int
+ megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
+ {
+ u32 status;
++ u32 mfiStatus = 0;
+ /*
+ * Check if it is our interrupt
+ */
+ status = readl(®s->outbound_intr_status);
+
+- if (!(status & MFI_OB_INTR_STATUS_MASK)) {
+- return 1;
+- }
++ if (status & MFI_OB_INTR_STATUS_MASK)
++ mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
++ if (status & MFI_XSCALE_OMR0_CHANGE_INTERRUPT)
++ mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
+
+ /*
+ * Clear the interrupt by writing back the same value
+ */
+- writel(status, ®s->outbound_intr_status);
++ if (mfiStatus)
++ writel(status, ®s->outbound_intr_status);
+
+ /* Dummy readl to force pci flush */
+ readl(®s->outbound_intr_status);
+
+- return 0;
++ return mfiStatus;
+ }
+
+ /**
+@@ -231,8 +239,69 @@ megasas_fire_cmd_xscale(struct megasas_instance *instance,
+ u32 frame_count,
+ struct megasas_register_set __iomem *regs)
+ {
++ unsigned long flags;
++ spin_lock_irqsave(&instance->hba_lock, flags);
+ writel((frame_phys_addr >> 3)|(frame_count),
+ &(regs)->inbound_queue_port);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++}
++
++/**
++ * megasas_adp_reset_xscale - For controller reset
++ * @regs: MFI register set
++ */
++static int
++megasas_adp_reset_xscale(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ u32 i;
++ u32 pcidata;
++ writel(MFI_ADP_RESET, ®s->inbound_doorbell);
++
++ for (i = 0; i < 3; i++)
++ msleep(1000); /* sleep for 3 secs */
++ pcidata = 0;
++ pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata);
++ printk(KERN_NOTICE "pcidata = %x\n", pcidata);
++ if (pcidata & 0x2) {
++ printk(KERN_NOTICE "mfi 1068 offset read=%x\n", pcidata);
++ pcidata &= ~0x2;
++ pci_write_config_dword(instance->pdev,
++ MFI_1068_PCSR_OFFSET, pcidata);
++
++ for (i = 0; i < 2; i++)
++ msleep(1000); /* need to wait 2 secs again */
++
++ pcidata = 0;
++ pci_read_config_dword(instance->pdev,
++ MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata);
++ printk(KERN_NOTICE "1068 offset handshake read=%x\n", pcidata);
++ if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) {
++ printk(KERN_NOTICE "1068 offset pcidt=%x\n", pcidata);
++ pcidata = 0;
++ pci_write_config_dword(instance->pdev,
++ MFI_1068_FW_HANDSHAKE_OFFSET, pcidata);
++ }
++ }
++ return 0;
++}
++
++/**
++ * megasas_check_reset_xscale - For controller reset check
++ * @regs: MFI register set
++ */
++static int
++megasas_check_reset_xscale(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ u32 consumer;
++ consumer = *instance->consumer;
++
++ if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
++ (*instance->consumer == MEGASAS_ADPRESET_INPROG_SIGN)) {
++ return 1;
++ }
++ return 0;
+ }
+
+ static struct megasas_instance_template megasas_instance_template_xscale = {
+@@ -242,6 +311,8 @@ static struct megasas_instance_template megasas_instance_template_xscale = {
+ .disable_intr = megasas_disable_intr_xscale,
+ .clear_intr = megasas_clear_intr_xscale,
+ .read_fw_status_reg = megasas_read_fw_status_reg_xscale,
++ .adp_reset = megasas_adp_reset_xscale,
++ .check_reset = megasas_check_reset_xscale,
+ };
+
+ /**
+@@ -263,7 +334,7 @@ megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs)
+ {
+ writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
+
+- writel(~0x80000004, &(regs)->outbound_intr_mask);
++ writel(~0x80000000, &(regs)->outbound_intr_mask);
+
+ /* Dummy readl to force pci flush */
+ readl(®s->outbound_intr_mask);
+@@ -306,7 +377,7 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
+ status = readl(®s->outbound_intr_status);
+
+ if (!(status & MFI_REPLY_1078_MESSAGE_INTERRUPT)) {
+- return 1;
++ return 0;
+ }
+
+ /*
+@@ -317,7 +388,7 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
+ /* Dummy readl to force pci flush */
+ readl(®s->outbound_doorbell_clear);
+
+- return 0;
++ return 1;
+ }
+ /**
+ * megasas_fire_cmd_ppc - Sends command to the FW
+@@ -331,10 +402,34 @@ megasas_fire_cmd_ppc(struct megasas_instance *instance,
+ u32 frame_count,
+ struct megasas_register_set __iomem *regs)
+ {
++ unsigned long flags;
++ spin_lock_irqsave(&instance->hba_lock, flags);
+ writel((frame_phys_addr | (frame_count<<1))|1,
+ &(regs)->inbound_queue_port);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
+ }
+
++/**
++ * megasas_adp_reset_ppc - For controller reset
++ * @regs: MFI register set
++ */
++static int
++megasas_adp_reset_ppc(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
++}
++
++/**
++ * megasas_check_reset_ppc - For controller reset check
++ * @regs: MFI register set
++ */
++static int
++megasas_check_reset_ppc(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
++}
+ static struct megasas_instance_template megasas_instance_template_ppc = {
+
+ .fire_cmd = megasas_fire_cmd_ppc,
+@@ -342,6 +437,8 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
+ .disable_intr = megasas_disable_intr_ppc,
+ .clear_intr = megasas_clear_intr_ppc,
+ .read_fw_status_reg = megasas_read_fw_status_reg_ppc,
++ .adp_reset = megasas_adp_reset_ppc,
++ .check_reset = megasas_check_reset_ppc,
+ };
+
+ /**
+@@ -396,7 +493,7 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
+ status = readl(®s->outbound_intr_status);
+
+ if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) {
+- return 1;
++ return 0;
+ }
+
+ /*
+@@ -409,7 +506,7 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
+ */
+ readl(®s->outbound_intr_status);
+
+- return 0;
++ return 1;
+ }
+
+ /**
+@@ -425,11 +522,33 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance,
+ struct megasas_register_set __iomem *regs)
+ {
+ unsigned long flags;
+- spin_lock_irqsave(&instance->fire_lock, flags);
++ spin_lock_irqsave(&instance->hba_lock, flags);
+ writel(0, &(regs)->inbound_high_queue_port);
+ writel((frame_phys_addr | (frame_count<<1))|1,
+ &(regs)->inbound_low_queue_port);
+- spin_unlock_irqrestore(&instance->fire_lock, flags);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++}
++
++/**
++ * megasas_adp_reset_skinny - For controller reset
++ * @regs: MFI register set
++ */
++static int
++megasas_adp_reset_skinny(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
++}
++
++/**
++ * megasas_check_reset_skinny - For controller reset check
++ * @regs: MFI register set
++ */
++static int
++megasas_check_reset_skinny(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
+ }
+
+ static struct megasas_instance_template megasas_instance_template_skinny = {
+@@ -439,6 +558,8 @@ static struct megasas_instance_template megasas_instance_template_skinny = {
+ .disable_intr = megasas_disable_intr_skinny,
+ .clear_intr = megasas_clear_intr_skinny,
+ .read_fw_status_reg = megasas_read_fw_status_reg_skinny,
++ .adp_reset = megasas_adp_reset_skinny,
++ .check_reset = megasas_check_reset_skinny,
+ };
+
+
+@@ -494,23 +615,29 @@ static int
+ megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
+ {
+ u32 status;
++ u32 mfiStatus = 0;
+ /*
+ * Check if it is our interrupt
+ */
+ status = readl(®s->outbound_intr_status);
+
+- if (!(status & MFI_GEN2_ENABLE_INTERRUPT_MASK))
+- return 1;
++ if (status & MFI_GEN2_ENABLE_INTERRUPT_MASK) {
++ mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
++ }
++ if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) {
++ mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
++ }
+
+ /*
+ * Clear the interrupt by writing back the same value
+ */
+- writel(status, ®s->outbound_doorbell_clear);
++ if (mfiStatus)
++ writel(status, ®s->outbound_doorbell_clear);
+
+ /* Dummy readl to force pci flush */
+ readl(®s->outbound_intr_status);
+
+- return 0;
++ return mfiStatus;
+ }
+ /**
+ * megasas_fire_cmd_gen2 - Sends command to the FW
+@@ -524,8 +651,74 @@ megasas_fire_cmd_gen2(struct megasas_instance *instance,
+ u32 frame_count,
+ struct megasas_register_set __iomem *regs)
+ {
++ unsigned long flags;
++ spin_lock_irqsave(&instance->hba_lock, flags);
+ writel((frame_phys_addr | (frame_count<<1))|1,
+ &(regs)->inbound_queue_port);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++}
++
++/**
++ * megasas_adp_reset_gen2 - For controller reset
++ * @regs: MFI register set
++ */
++static int
++megasas_adp_reset_gen2(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *reg_set)
++{
++ u32 retry = 0 ;
++ u32 HostDiag;
++
++ writel(0, ®_set->seq_offset);
++ writel(4, ®_set->seq_offset);
++ writel(0xb, ®_set->seq_offset);
++ writel(2, ®_set->seq_offset);
++ writel(7, ®_set->seq_offset);
++ writel(0xd, ®_set->seq_offset);
++ msleep(1000);
++
++ HostDiag = (u32)readl(®_set->host_diag);
++
++ while ( !( HostDiag & DIAG_WRITE_ENABLE) ) {
++ msleep(100);
++ HostDiag = (u32)readl(®_set->host_diag);
++ printk(KERN_NOTICE "RESETGEN2: retry=%x, hostdiag=%x\n",
++ retry, HostDiag);
++
++ if (retry++ >= 100)
++ return 1;
++
++ }
++
++ printk(KERN_NOTICE "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag);
++
++ writel((HostDiag | DIAG_RESET_ADAPTER), ®_set->host_diag);
++
++ ssleep(10);
++
++ HostDiag = (u32)readl(®_set->host_diag);
++ while ( ( HostDiag & DIAG_RESET_ADAPTER) ) {
++ msleep(100);
++ HostDiag = (u32)readl(®_set->host_diag);
++ printk(KERN_NOTICE "RESET_GEN2: retry=%x, hostdiag=%x\n",
++ retry, HostDiag);
++
++ if (retry++ >= 1000)
++ return 1;
++
++ }
++ return 0;
++}
++
++/**
++ * megasas_check_reset_gen2 - For controller reset check
++ * @regs: MFI register set
++ */
++static int
++megasas_check_reset_gen2(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
+ }
+
+ static struct megasas_instance_template megasas_instance_template_gen2 = {
+@@ -535,11 +728,13 @@ static struct megasas_instance_template megasas_instance_template_gen2 = {
+ .disable_intr = megasas_disable_intr_gen2,
+ .clear_intr = megasas_clear_intr_gen2,
+ .read_fw_status_reg = megasas_read_fw_status_reg_gen2,
++ .adp_reset = megasas_adp_reset_gen2,
++ .check_reset = megasas_check_reset_gen2,
+ };
+
+ /**
+ * This is the end of set of functions & definitions
+-* specific to ppc (deviceid : 0x60) controllers
++* specific to gen2 (deviceid : 0x78, 0x79) controllers
+ */
+
+ /**
+@@ -598,8 +793,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
+ instance->instancet->fire_cmd(instance,
+ cmd->frame_phys_addr, 0, instance->reg_set);
+
+- wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
+- MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
++ wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA);
+
+ return 0;
+ }
+@@ -647,8 +841,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
+ /*
+ * Wait for this cmd to complete
+ */
+- wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF),
+- MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
++ wait_event(instance->abort_cmd_wait_q, cmd->cmd_status != 0xFF);
++ cmd->sync_cmd = 0;
+
+ megasas_return_cmd(instance, cmd);
+ return 0;
+@@ -1118,14 +1312,22 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
+ u32 frame_count;
+ struct megasas_cmd *cmd;
+ struct megasas_instance *instance;
++ unsigned long flags;
+
+ instance = (struct megasas_instance *)
+ scmd->device->host->hostdata;
+
+- /* Don't process if we have already declared adapter dead */
+- if (instance->hw_crit_error)
++ if (instance->issuepend_done == 0)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ return SCSI_MLQUEUE_HOST_BUSY;
++ }
++
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
+ scmd->scsi_done = done;
+ scmd->result = 0;
+
+@@ -1209,6 +1411,18 @@ static int megasas_slave_configure(struct scsi_device *sdev)
+ return 0;
+ }
+
++static void megaraid_sas_kill_hba(struct megasas_instance *instance)
++{
++ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ writel(MFI_STOP_ADP,
++ &instance->reg_set->reserved_0[0]);
++ } else {
++ writel(MFI_STOP_ADP,
++ &instance->reg_set->inbound_doorbell);
++ }
++}
++
+ /**
+ * megasas_complete_cmd_dpc - Returns FW's controller structure
+ * @instance_addr: Address of adapter soft state
+@@ -1226,7 +1440,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+ unsigned long flags;
+
+ /* If we have already declared adapter dead, donot complete cmds */
+- if (instance->hw_crit_error)
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR )
+ return;
+
+ spin_lock_irqsave(&instance->completion_lock, flags);
+@@ -1236,6 +1450,11 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+
+ while (consumer != producer) {
+ context = instance->reply_queue[consumer];
++ if (context >= instance->max_fw_cmds) {
++ printk(KERN_ERR "Unexpected context value %x\n",
++ context);
++ BUG();
++ }
+
+ cmd = instance->cmd_list[context];
+
+@@ -1285,7 +1504,76 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
+ {
+ int i;
++ u32 reset_index;
+ u32 wait_time = MEGASAS_RESET_WAIT_TIME;
++ u8 adprecovery;
++ unsigned long flags;
++ struct list_head clist_local;
++ struct megasas_cmd *reset_cmd;
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ adprecovery = instance->adprecovery;
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
++
++ INIT_LIST_HEAD(&clist_local);
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ list_splice_init(&instance->internal_reset_pending_q,
++ &clist_local);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ printk(KERN_NOTICE "megasas: HBA reset wait ...\n");
++ for (i = 0; i < wait_time; i++) {
++ msleep(1000);
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ adprecovery = instance->adprecovery;
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ if (adprecovery == MEGASAS_HBA_OPERATIONAL)
++ break;
++ }
++
++ if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
++ printk(KERN_NOTICE "megasas: reset: Stopping HBA.\n");
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ return FAILED;
++ }
++
++ reset_index = 0;
++ while (!list_empty(&clist_local)) {
++ reset_cmd = list_entry((&clist_local)->next,
++ struct megasas_cmd, list);
++ list_del_init(&reset_cmd->list);
++ if (reset_cmd->scmd) {
++ reset_cmd->scmd->result = DID_RESET << 16;
++ printk(KERN_NOTICE "%d:%p reset [%02x], %#lx\n",
++ reset_index, reset_cmd,
++ reset_cmd->scmd->cmnd[0],
++ reset_cmd->scmd->serial_number);
++
++ reset_cmd->scmd->scsi_done(reset_cmd->scmd);
++ megasas_return_cmd(instance, reset_cmd);
++ } else if (reset_cmd->sync_cmd) {
++ printk(KERN_NOTICE "megasas:%p synch cmds"
++ "reset queue\n",
++ reset_cmd);
++
++ reset_cmd->cmd_status = ENODATA;
++ instance->instancet->fire_cmd(instance,
++ reset_cmd->frame_phys_addr,
++ 0, instance->reg_set);
++ } else {
++ printk(KERN_NOTICE "megasas: %p unexpected"
++ "cmds lst\n",
++ reset_cmd);
++ }
++ reset_index++;
++ }
++
++ return SUCCESS;
++ }
+
+ for (i = 0; i < wait_time; i++) {
+
+@@ -1308,6 +1596,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
+ }
+
+ if (atomic_read(&instance->fw_outstanding)) {
++ printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n");
+ /*
+ * Send signal to FW to stop processing any pending cmds.
+ * The controller will be taken offline by the OS now.
+@@ -1323,10 +1612,14 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
+ &instance->reg_set->inbound_doorbell);
+ }
+ megasas_dump_pending_frames(instance);
+- instance->hw_crit_error = 1;
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
+ return FAILED;
+ }
+
++ printk(KERN_NOTICE "megaraid_sas: no pending cmds after reset\n");
++
+ return SUCCESS;
+ }
+
+@@ -1348,7 +1641,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
+ scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n",
+ scmd->serial_number, scmd->cmnd[0], scmd->retries);
+
+- if (instance->hw_crit_error) {
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ printk(KERN_ERR "megasas: cannot recover from previous reset "
+ "failures\n");
+ return FAILED;
+@@ -1503,7 +1796,8 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
+ instance->aen_cmd = NULL;
+ megasas_return_cmd(instance, cmd);
+
+- if (instance->unload == 0) {
++ if ((instance->unload == 0) &&
++ ((instance->issuepend_done == 1))) {
+ struct megasas_aen_event *ev;
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (!ev) {
+@@ -1597,6 +1891,9 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ struct megasas_header *hdr = &cmd->frame->hdr;
+ unsigned long flags;
+
++ /* flag for the retry reset */
++ cmd->retry_for_fw_reset = 0;
++
+ if (cmd->scmd)
+ cmd->scmd->SCp.ptr = NULL;
+
+@@ -1717,39 +2014,301 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ }
+
+ /**
++ * megasas_issue_pending_cmds_again - issue all pending cmds
++ * in FW again because of the fw reset
++ * @instance: Adapter soft state
++ */
++static inline void
++megasas_issue_pending_cmds_again(struct megasas_instance *instance)
++{
++ struct megasas_cmd *cmd;
++ struct list_head clist_local;
++ union megasas_evt_class_locale class_locale;
++ unsigned long flags;
++ u32 seq_num;
++
++ INIT_LIST_HEAD(&clist_local);
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ list_splice_init(&instance->internal_reset_pending_q, &clist_local);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ while (!list_empty(&clist_local)) {
++ cmd = list_entry((&clist_local)->next,
++ struct megasas_cmd, list);
++ list_del_init(&cmd->list);
++
++ if (cmd->sync_cmd || cmd->scmd) {
++ printk(KERN_NOTICE "megaraid_sas: command %p, %p:%d"
++ "detected to be pending while HBA reset.\n",
++ cmd, cmd->scmd, cmd->sync_cmd);
++
++ cmd->retry_for_fw_reset++;
++
++ if (cmd->retry_for_fw_reset == 3) {
++ printk(KERN_NOTICE "megaraid_sas: cmd %p, %p:%d"
++ "was tried multiple times during reset."
++ "Shutting down the HBA\n",
++ cmd, cmd->scmd, cmd->sync_cmd);
++ megaraid_sas_kill_hba(instance);
++
++ instance->adprecovery =
++ MEGASAS_HW_CRITICAL_ERROR;
++ return;
++ }
++ }
++
++ if (cmd->sync_cmd == 1) {
++ if (cmd->scmd) {
++ printk(KERN_NOTICE "megaraid_sas: unexpected"
++ "cmd attached to internal command!\n");
++ }
++ printk(KERN_NOTICE "megasas: %p synchronous cmd"
++ "on the internal reset queue,"
++ "issue it again.\n", cmd);
++ cmd->cmd_status = ENODATA;
++ instance->instancet->fire_cmd(instance,
++ cmd->frame_phys_addr ,
++ 0, instance->reg_set);
++ } else if (cmd->scmd) {
++ printk(KERN_NOTICE "megasas: %p scsi cmd [%02x],%#lx"
++ "detected on the internal queue, issue again.\n",
++ cmd, cmd->scmd->cmnd[0], cmd->scmd->serial_number);
++
++ atomic_inc(&instance->fw_outstanding);
++ instance->instancet->fire_cmd(instance,
++ cmd->frame_phys_addr,
++ cmd->frame_count-1, instance->reg_set);
++ } else {
++ printk(KERN_NOTICE "megasas: %p unexpected cmd on the"
++ "internal reset defer list while re-issue!!\n",
++ cmd);
++ }
++ }
++
++ if (instance->aen_cmd) {
++ printk(KERN_NOTICE "megaraid_sas: aen_cmd in def process\n");
++ megasas_return_cmd(instance, instance->aen_cmd);
++
++ instance->aen_cmd = NULL;
++ }
++
++ /*
++ * Initiate AEN (Asynchronous Event Notification)
++ */
++ seq_num = instance->last_seq_num;
++ class_locale.members.reserved = 0;
++ class_locale.members.locale = MR_EVT_LOCALE_ALL;
++ class_locale.members.class = MR_EVT_CLASS_DEBUG;
++
++ megasas_register_aen(instance, seq_num, class_locale.word);
++}
++
++/**
++ * Move the internal reset pending commands to a deferred queue.
++ *
++ * We move the commands pending at internal reset time to a
++ * pending queue. This queue would be flushed after successful
++ * completion of the internal reset sequence. if the internal reset
++ * did not complete in time, the kernel reset handler would flush
++ * these commands.
++ **/
++static void
++megasas_internal_reset_defer_cmds(struct megasas_instance *instance)
++{
++ struct megasas_cmd *cmd;
++ int i;
++ u32 max_cmd = instance->max_fw_cmds;
++ u32 defer_index;
++ unsigned long flags;
++
++ defer_index = 0;
++ spin_lock_irqsave(&instance->cmd_pool_lock, flags);
++ for (i = 0; i < max_cmd; i++) {
++ cmd = instance->cmd_list[i];
++ if (cmd->sync_cmd == 1 || cmd->scmd) {
++ printk(KERN_NOTICE "megasas: moving cmd[%d]:%p:%d:%p"
++ "on the defer queue as internal\n",
++ defer_index, cmd, cmd->sync_cmd, cmd->scmd);
++
++ if (!list_empty(&cmd->list)) {
++ printk(KERN_NOTICE "megaraid_sas: ERROR while"
++ " moving this cmd:%p, %d %p, it was"
++ "discovered on some list?\n",
++ cmd, cmd->sync_cmd, cmd->scmd);
++
++ list_del_init(&cmd->list);
++ }
++ defer_index++;
++ list_add_tail(&cmd->list,
++ &instance->internal_reset_pending_q);
++ }
++ }
++ spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
++}
++
++
++static void
++process_fw_state_change_wq(struct work_struct *work)
++{
++ struct megasas_instance *instance =
++ container_of(work, struct megasas_instance, work_init);
++ u32 wait;
++ unsigned long flags;
++
++ if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) {
++ printk(KERN_NOTICE "megaraid_sas: error, recovery st %x \n",
++ instance->adprecovery);
++ return ;
++ }
++
++ if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
++ printk(KERN_NOTICE "megaraid_sas: FW detected to be in fault"
++ "state, restarting it...\n");
++
++ instance->instancet->disable_intr(instance->reg_set);
++ atomic_set(&instance->fw_outstanding, 0);
++
++ atomic_set(&instance->fw_reset_no_pci_access, 1);
++ instance->instancet->adp_reset(instance, instance->reg_set);
++ atomic_set(&instance->fw_reset_no_pci_access, 0 );
++
++ printk(KERN_NOTICE "megaraid_sas: FW restarted successfully,"
++ "initiating next stage...\n");
++
++ printk(KERN_NOTICE "megaraid_sas: HBA recovery state machine,"
++ "state 2 starting...\n");
++
++ /*waitting for about 20 second before start the second init*/
++ for (wait = 0; wait < 30; wait++) {
++ msleep(1000);
++ }
++
++ if (megasas_transition_to_ready(instance)) {
++ printk(KERN_NOTICE "megaraid_sas:adapter not ready\n");
++
++ megaraid_sas_kill_hba(instance);
++ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
++ return ;
++ }
++
++ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
++ (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)
++ ) {
++ *instance->consumer = *instance->producer;
++ } else {
++ *instance->consumer = 0;
++ *instance->producer = 0;
++ }
++
++ megasas_issue_init_mfi(instance);
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ instance->instancet->enable_intr(instance->reg_set);
++
++ megasas_issue_pending_cmds_again(instance);
++ instance->issuepend_done = 1;
++ }
++ return ;
++}
++
++/**
+ * megasas_deplete_reply_queue - Processes all completed commands
+ * @instance: Adapter soft state
+ * @alt_status: Alternate status to be returned to
+ * SCSI mid-layer instead of the status
+ * returned by the FW
++ * Note: this must be called with hba lock held
+ */
+ static int
+-megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
++megasas_deplete_reply_queue(struct megasas_instance *instance,
++ u8 alt_status)
+ {
+- /*
+- * Check if it is our interrupt
+- * Clear the interrupt
+- */
+- if(instance->instancet->clear_intr(instance->reg_set))
++ u32 mfiStatus;
++ u32 fw_state;
++
++ if ((mfiStatus = instance->instancet->check_reset(instance,
++ instance->reg_set)) == 1) {
++ return IRQ_HANDLED;
++ }
++
++ if ((mfiStatus = instance->instancet->clear_intr(
++ instance->reg_set)
++ ) == 0) {
+ return IRQ_NONE;
++ }
++
++ instance->mfiStatus = mfiStatus;
++
++ if ((mfiStatus & MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE)) {
++ fw_state = instance->instancet->read_fw_status_reg(
++ instance->reg_set) & MFI_STATE_MASK;
++
++ if (fw_state != MFI_STATE_FAULT) {
++ printk(KERN_NOTICE "megaraid_sas: fw state:%x\n",
++ fw_state);
++ }
++
++ if ((fw_state == MFI_STATE_FAULT) &&
++ (instance->disableOnlineCtrlReset == 0)) {
++ printk(KERN_NOTICE "megaraid_sas: wait adp restart\n");
++
++ if ((instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS1064R) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_DELL_PERC5) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
++
++ *instance->consumer =
++ MEGASAS_ADPRESET_INPROG_SIGN;
++ }
++
++
++ instance->instancet->disable_intr(instance->reg_set);
++ instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
++ instance->issuepend_done = 0;
++
++ atomic_set(&instance->fw_outstanding, 0);
++ megasas_internal_reset_defer_cmds(instance);
++
++ printk(KERN_NOTICE "megasas: fwState=%x, stage:%d\n",
++ fw_state, instance->adprecovery);
++
++ schedule_work(&instance->work_init);
++ return IRQ_HANDLED;
++
++ } else {
++ printk(KERN_NOTICE "megasas: fwstate:%x, dis_OCR=%x\n",
++ fw_state, instance->disableOnlineCtrlReset);
++ }
++ }
+
+- if (instance->hw_crit_error)
+- goto out_done;
+- /*
+- * Schedule the tasklet for cmd completion
+- */
+ tasklet_schedule(&instance->isr_tasklet);
+-out_done:
+ return IRQ_HANDLED;
+ }
+-
+ /**
+ * megasas_isr - isr entry point
+ */
+ static irqreturn_t megasas_isr(int irq, void *devp)
+ {
+- return megasas_deplete_reply_queue((struct megasas_instance *)devp,
+- DID_OK);
++ struct megasas_instance *instance;
++ unsigned long flags;
++ irqreturn_t rc;
++
++ if (atomic_read(
++ &(((struct megasas_instance *)devp)->fw_reset_no_pci_access)))
++ return IRQ_HANDLED;
++
++ instance = (struct megasas_instance *)devp;
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ rc = megasas_deplete_reply_queue(instance, DID_OK);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ return rc;
+ }
+
+ /**
+@@ -1900,7 +2459,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ "in %d secs\n", fw_state, max_wait);
+ return -ENODEV;
+ }
+- };
++ }
+ printk(KERN_INFO "megasas: FW now in Ready state\n");
+
+ return 0;
+@@ -1982,6 +2541,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
+ */
+ sgl_sz = sge_sz * instance->max_num_sge;
+ frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE;
++ frame_count = 15;
+
+ /*
+ * We need one extra frame for the MFI command
+@@ -2129,6 +2689,7 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
+ cmd = instance->cmd_list[i];
+ memset(cmd, 0, sizeof(struct megasas_cmd));
+ cmd->index = i;
++ cmd->scmd = NULL;
+ cmd->instance = instance;
+
+ list_add_tail(&cmd->list, &instance->cmd_pool);
+@@ -2295,7 +2856,7 @@ megasas_get_ld_list(struct megasas_instance *instance)
+
+ /* the following function will get the instance PD LIST */
+
+- if ((ret == 0) && (ci->ldCount < MAX_LOGICAL_DRIVES)) {
++ if ((ret == 0) && (ci->ldCount <= MAX_LOGICAL_DRIVES)) {
+ memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
+
+ for (ld_index = 0; ld_index < ci->ldCount; ld_index++) {
+@@ -2606,6 +3167,21 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ if (megasas_issue_init_mfi(instance))
+ goto fail_fw_init;
+
++ instance->fw_support_ieee = 0;
++ instance->fw_support_ieee =
++ (instance->instancet->read_fw_status_reg(reg_set) &
++ 0x04000000);
++
++ printk(KERN_NOTICE "megasas_init_mfi: fw_support_ieee=%d",
++ instance->fw_support_ieee);
++
++ if (instance->fw_support_ieee)
++ instance->flag_ieee = 1;
++
++ /** for passthrough
++ * the following function will get the PD LIST.
++ */
++
+ memset(instance->pd_list, 0 ,
+ (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
+ megasas_get_pd_list(instance);
+@@ -2632,6 +3208,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ max_sectors_2 = ctrl_info->max_request_size;
+
+ tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2);
++ instance->disableOnlineCtrlReset =
++ ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
+ }
+
+ instance->max_sectors_per_req = instance->max_num_sge *
+@@ -2849,6 +3427,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_READ;
+ dcmd->timeout = 0;
++ instance->last_seq_num = seq_num;
+ dcmd->data_xfer_len = sizeof(struct megasas_evt_detail);
+ dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
+ dcmd->mbox.w[0] = seq_num;
+@@ -3017,6 +3596,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+
+ instance = (struct megasas_instance *)host->hostdata;
+ memset(instance, 0, sizeof(*instance));
++ atomic_set( &instance->fw_reset_no_pci_access, 0 );
+
+ instance->producer = pci_alloc_consistent(pdev, sizeof(u32),
+ &instance->producer_h);
+@@ -3034,6 +3614,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ megasas_poll_wait_aen = 0;
+ instance->flag_ieee = 0;
+ instance->ev = NULL;
++ instance->issuepend_done = 1;
++ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
++ megasas_poll_wait_aen = 0;
+
+ instance->evt_detail = pci_alloc_consistent(pdev,
+ sizeof(struct
+@@ -3050,6 +3633,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ * Initialize locks and queues
+ */
+ INIT_LIST_HEAD(&instance->cmd_pool);
++ INIT_LIST_HEAD(&instance->internal_reset_pending_q);
+
+ atomic_set(&instance->fw_outstanding,0);
+
+@@ -3057,7 +3641,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ init_waitqueue_head(&instance->abort_cmd_wait_q);
+
+ spin_lock_init(&instance->cmd_pool_lock);
+- spin_lock_init(&instance->fire_lock);
++ spin_lock_init(&instance->hba_lock);
+ spin_lock_init(&instance->completion_lock);
+ spin_lock_init(&poll_aen_lock);
+
+@@ -3082,6 +3666,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ instance->flag = 0;
+ instance->unload = 1;
+ instance->last_time = 0;
++ instance->disableOnlineCtrlReset = 1;
++
++ INIT_WORK(&instance->work_init, process_fw_state_change_wq);
+
+ /*
+ * Initialize MFI Firmware
+@@ -3173,6 +3760,9 @@ static void megasas_flush_cache(struct megasas_instance *instance)
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
++ return;
++
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd)
+@@ -3209,6 +3799,9 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
++ return;
++
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd)
+@@ -3716,6 +4309,9 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
+ struct megasas_iocpacket *ioc;
+ struct megasas_instance *instance;
+ int error;
++ int i;
++ unsigned long flags;
++ u32 wait_time = MEGASAS_RESET_WAIT_TIME;
+
+ ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);
+ if (!ioc)
+@@ -3732,8 +4328,8 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
+ goto out_kfree_ioc;
+ }
+
+- if (instance->hw_crit_error == 1) {
+- printk(KERN_DEBUG "Controller in Crit ERROR\n");
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
++ printk(KERN_ERR "Controller in crit error\n");
+ error = -ENODEV;
+ goto out_kfree_ioc;
+ }
+@@ -3750,6 +4346,35 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
+ error = -ERESTARTSYS;
+ goto out_kfree_ioc;
+ }
++
++ for (i = 0; i < wait_time; i++) {
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ break;
++ }
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
++ printk(KERN_NOTICE "megasas: waiting"
++ "for controller reset to finish\n");
++ }
++
++ msleep(1000);
++ }
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ printk(KERN_ERR "megaraid_sas: timed out while"
++ "waiting for HBA to recover\n");
++ error = -ENODEV;
++ goto out_kfree_ioc;
++ }
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
+ error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc);
+ up(&instance->ioctl_sem);
+
+@@ -3763,6 +4388,9 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
+ struct megasas_instance *instance;
+ struct megasas_aen aen;
+ int error;
++ int i;
++ unsigned long flags;
++ u32 wait_time = MEGASAS_RESET_WAIT_TIME;
+
+ if (file->private_data != file) {
+ printk(KERN_DEBUG "megasas: fasync_helper was not "
+@@ -3778,14 +4406,42 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
+ if (!instance)
+ return -ENODEV;
+
+- if (instance->hw_crit_error == 1) {
+- error = -ENODEV;
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
++ return -ENODEV;
+ }
+
+ if (instance->unload == 1) {
+ return -ENODEV;
+ }
+
++ for (i = 0; i < wait_time; i++) {
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
++ spin_unlock_irqrestore(&instance->hba_lock,
++ flags);
++ break;
++ }
++
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
++ printk(KERN_NOTICE "megasas: waiting for"
++ "controller reset to finish\n");
++ }
++
++ msleep(1000);
++ }
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ printk(KERN_ERR "megaraid_sas: timed out while waiting"
++ "for HBA to recover.\n");
++ return -ENODEV;
++ }
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
+ mutex_lock(&instance->aen_mutex);
+ error = megasas_register_aen(instance, aen.seq_num,
+ aen.class_locale_word);
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index a22d8d48b7dd..a231aa811e56 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -60,6 +60,7 @@
+ #define MFI_STATE_READY 0xB0000000
+ #define MFI_STATE_OPERATIONAL 0xC0000000
+ #define MFI_STATE_FAULT 0xF0000000
++#define MFI_RESET_REQUIRED 0x00000001
+
+ #define MEGAMFI_FRAME_SIZE 64
+
+@@ -73,6 +74,12 @@
+ * HOTPLUG : Resume from Hotplug
+ * MFI_STOP_ADP : Send signal to FW to stop processing
+ */
++#define WRITE_SEQUENCE_OFFSET (0x0000000FC) /* I20 */
++#define HOST_DIAGNOSTIC_OFFSET (0x000000F8) /* I20 */
++#define DIAG_WRITE_ENABLE (0x00000080)
++#define DIAG_RESET_ADAPTER (0x00000004)
++
++#define MFI_ADP_RESET 0x00000040
+ #define MFI_INIT_ABORT 0x00000001
+ #define MFI_INIT_READY 0x00000002
+ #define MFI_INIT_MFIMODE 0x00000004
+@@ -402,8 +409,40 @@ struct megasas_ctrl_prop {
+ u16 ecc_bucket_leak_rate;
+ u8 restore_hotspare_on_insertion;
+ u8 expose_encl_devices;
+- u8 reserved[38];
++ u8 maintainPdFailHistory;
++ u8 disallowHostRequestReordering;
++ u8 abortCCOnError;
++ u8 loadBalanceMode;
++ u8 disableAutoDetectBackplane;
+
++ u8 snapVDSpace;
++
++ /*
++ * Add properties that can be controlled by
++ * a bit in the following structure.
++ */
++
++ struct {
++ u32 copyBackDisabled : 1;
++ u32 SMARTerEnabled : 1;
++ u32 prCorrectUnconfiguredAreas : 1;
++ u32 useFdeOnly : 1;
++ u32 disableNCQ : 1;
++ u32 SSDSMARTerEnabled : 1;
++ u32 SSDPatrolReadEnabled : 1;
++ u32 enableSpinDownUnconfigured : 1;
++ u32 autoEnhancedImport : 1;
++ u32 enableSecretKeyControl : 1;
++ u32 disableOnlineCtrlReset : 1;
++ u32 allowBootWithPinnedCache : 1;
++ u32 disableSpinDownHS : 1;
++ u32 enableJBOD : 1;
++ u32 reserved :18;
++ } OnOffProperties;
++ u8 autoSnapVDSpace;
++ u8 viewSpace;
++ u16 spinDownTime;
++ u8 reserved[24];
+ } __packed;
+
+ /*
+@@ -704,6 +743,12 @@ struct megasas_ctrl_info {
+ */
+ #define IS_DMA64 (sizeof(dma_addr_t) == 8)
+
++#define MFI_XSCALE_OMR0_CHANGE_INTERRUPT 0x00000001
++
++#define MFI_INTR_FLAG_REPLY_MESSAGE 0x00000001
++#define MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE 0x00000002
++#define MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT 0x00000004
++
+ #define MFI_OB_INTR_STATUS_MASK 0x00000002
+ #define MFI_POLL_TIMEOUT_SECS 60
+ #define MEGASAS_COMPLETION_TIMER_INTERVAL (HZ/10)
+@@ -714,6 +759,9 @@ struct megasas_ctrl_info {
+ #define MFI_REPLY_SKINNY_MESSAGE_INTERRUPT 0x40000000
+ #define MFI_SKINNY_ENABLE_INTERRUPT_MASK (0x00000001)
+
++#define MFI_1068_PCSR_OFFSET 0x84
++#define MFI_1068_FW_HANDSHAKE_OFFSET 0x64
++#define MFI_1068_FW_READY 0xDDDD0000
+ /*
+ * register set for both 1068 and 1078 controllers
+ * structure extended for 1078 registers
+@@ -755,8 +803,10 @@ struct megasas_register_set {
+ u32 inbound_high_queue_port ; /*00C4h*/
+
+ u32 reserved_5; /*00C8h*/
+- u32 index_registers[820]; /*00CCh*/
+-
++ u32 res_6[11]; /*CCh*/
++ u32 host_diag;
++ u32 seq_offset;
++ u32 index_registers[807]; /*00CCh*/
+ } __attribute__ ((packed));
+
+ struct megasas_sge32 {
+@@ -1226,11 +1276,12 @@ struct megasas_instance {
+
+ struct megasas_cmd **cmd_list;
+ struct list_head cmd_pool;
++ /* used to sync fire the cmd to fw */
+ spinlock_t cmd_pool_lock;
++ /* used to sync fire the cmd to fw */
++ spinlock_t hba_lock;
+ /* used to synch producer, consumer ptrs in dpc */
+ spinlock_t completion_lock;
+- /* used to sync fire the cmd to fw */
+- spinlock_t fire_lock;
+ struct dma_pool *frame_dma_pool;
+ struct dma_pool *sense_dma_pool;
+
+@@ -1247,19 +1298,36 @@ struct megasas_instance {
+
+ struct pci_dev *pdev;
+ u32 unique_id;
++ u32 fw_support_ieee;
+
+ atomic_t fw_outstanding;
+- u32 hw_crit_error;
++ atomic_t fw_reset_no_pci_access;
+
+ struct megasas_instance_template *instancet;
+ struct tasklet_struct isr_tasklet;
++ struct work_struct work_init;
+
+ u8 flag;
+ u8 unload;
+ u8 flag_ieee;
++ u8 issuepend_done;
++ u8 disableOnlineCtrlReset;
++ u8 adprecovery;
+ unsigned long last_time;
++ u32 mfiStatus;
++ u32 last_seq_num;
+
+ struct timer_list io_completion_timer;
++ struct list_head internal_reset_pending_q;
++};
++
++enum {
++ MEGASAS_HBA_OPERATIONAL = 0,
++ MEGASAS_ADPRESET_SM_INFAULT = 1,
++ MEGASAS_ADPRESET_SM_FW_RESET_SUCCESS = 2,
++ MEGASAS_ADPRESET_SM_OPERATIONAL = 3,
++ MEGASAS_HW_CRITICAL_ERROR = 4,
++ MEGASAS_ADPRESET_INPROG_SIGN = 0xDEADDEAD,
+ };
+
+ struct megasas_instance_template {
+@@ -1272,6 +1340,10 @@ struct megasas_instance_template {
+ int (*clear_intr)(struct megasas_register_set __iomem *);
+
+ u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
++ int (*adp_reset)(struct megasas_instance *, \
++ struct megasas_register_set __iomem *);
++ int (*check_reset)(struct megasas_instance *, \
++ struct megasas_register_set __iomem *);
+ };
+
+ #define MEGASAS_IS_LOGICAL(scp) \
+@@ -1291,7 +1363,9 @@ struct megasas_cmd {
+ u32 index;
+ u8 sync_cmd;
+ u8 cmd_status;
+- u16 abort_aen;
++ u8 abort_aen;
++ u8 retry_for_fw_reset;
++
+
+ struct list_head list;
+ struct scsi_cmnd *scmd;
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0012-megaraid_sas-rename-megaraid_sas.c-to-megaraid_sas_base.c.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0012-megaraid_sas-rename-megaraid_sas.c-to-megaraid_sas_base.c.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,10056 @@
+From cdbbdbaf9a0935163a8ba6c1210f3468dd6c1ae3 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Tue, 14 Dec 2010 19:17:17 -0800
+Subject: [PATCH 12/53] [SCSI] megaraid_sas: Rename megaraid_sas.c to megaraid_sas_base.c
+
+commit 0d49016bbab4fe9164710b1d4bbae116b89b7f7e upstream.
+
+This patch renames megaraid_sas.c to megaraid_sas_base.c to facilitate
+other files in the compile.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/Makefile | 1 +
+ drivers/scsi/megaraid/megaraid_sas.c | 5005 -----------------------------
+ drivers/scsi/megaraid/megaraid_sas_base.c | 5005 +++++++++++++++++++++++++++++
+ 3 files changed, 5006 insertions(+), 5005 deletions(-)
+ delete mode 100644 drivers/scsi/megaraid/megaraid_sas.c
+ create mode 100644 drivers/scsi/megaraid/megaraid_sas_base.c
+
+diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile
+index f469915b97c3..6613a2ceea03 100644
+--- a/drivers/scsi/megaraid/Makefile
++++ b/drivers/scsi/megaraid/Makefile
+@@ -1,3 +1,4 @@
+ obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o
+ obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o
+ obj-$(CONFIG_MEGARAID_SAS) += megaraid_sas.o
++megaraid_sas-objs := megaraid_sas_base.o
+diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
+deleted file mode 100644
+index 72c925d9e0f3..000000000000
+--- a/drivers/scsi/megaraid/megaraid_sas.c
++++ /dev/null
+@@ -1,5005 +0,0 @@
+-/*
+- *
+- * Linux MegaRAID driver for SAS based RAID controllers
+- *
+- * Copyright (c) 2003-2005 LSI Corporation.
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License
+- * as published by the Free Software Foundation; either version
+- * 2 of the License, or (at your option) any later version.
+- *
+- * FILE : megaraid_sas.c
+- * Version : v00.00.04.01-rc1
+- *
+- * Authors:
+- * (email-id : megaraidlinux at lsi.com)
+- * Sreenivas Bagalkote
+- * Sumant Patro
+- * Bo Yang
+- *
+- * List of supported controllers
+- *
+- * OEM Product Name VID DID SSVID SSID
+- * --- ------------ --- --- ---- ----
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/pci.h>
+-#include <linux/list.h>
+-#include <linux/moduleparam.h>
+-#include <linux/module.h>
+-#include <linux/spinlock.h>
+-#include <linux/interrupt.h>
+-#include <linux/delay.h>
+-#include <linux/smp_lock.h>
+-#include <linux/uio.h>
+-#include <asm/uaccess.h>
+-#include <linux/fs.h>
+-#include <linux/compat.h>
+-#include <linux/blkdev.h>
+-#include <linux/mutex.h>
+-#include <linux/poll.h>
+-
+-#include <scsi/scsi.h>
+-#include <scsi/scsi_cmnd.h>
+-#include <scsi/scsi_device.h>
+-#include <scsi/scsi_host.h>
+-#include "megaraid_sas.h"
+-
+-/*
+- * poll_mode_io:1- schedule complete completion from q cmd
+- */
+-static unsigned int poll_mode_io;
+-module_param_named(poll_mode_io, poll_mode_io, int, 0);
+-MODULE_PARM_DESC(poll_mode_io,
+- "Complete cmds from IO path, (default=0)");
+-
+-MODULE_LICENSE("GPL");
+-MODULE_VERSION(MEGASAS_VERSION);
+-MODULE_AUTHOR("megaraidlinux at lsi.com");
+-MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
+-
+-static int megasas_transition_to_ready(struct megasas_instance *instance);
+-static int megasas_get_pd_list(struct megasas_instance *instance);
+-static int megasas_issue_init_mfi(struct megasas_instance *instance);
+-static int megasas_register_aen(struct megasas_instance *instance,
+- u32 seq_num, u32 class_locale_word);
+-/*
+- * PCI ID table for all supported controllers
+- */
+-static struct pci_device_id megasas_pci_table[] = {
+-
+- {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)},
+- /* xscale IOP */
+- {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)},
+- /* ppc IOP */
+- {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078DE)},
+- /* ppc IOP */
+- {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078GEN2)},
+- /* gen2*/
+- {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0079GEN2)},
+- /* gen2*/
+- {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0073SKINNY)},
+- /* skinny*/
+- {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0071SKINNY)},
+- /* skinny*/
+- {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},
+- /* xscale IOP, vega */
+- {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
+- /* xscale IOP */
+- {}
+-};
+-
+-MODULE_DEVICE_TABLE(pci, megasas_pci_table);
+-
+-static int megasas_mgmt_majorno;
+-static struct megasas_mgmt_info megasas_mgmt_info;
+-static struct fasync_struct *megasas_async_queue;
+-static DEFINE_MUTEX(megasas_async_queue_mutex);
+-
+-static int megasas_poll_wait_aen;
+-static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
+-static u32 support_poll_for_event;
+-static u32 megasas_dbg_lvl;
+-
+-/* define lock for aen poll */
+-spinlock_t poll_aen_lock;
+-
+-static void
+-megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+- u8 alt_status);
+-
+-/**
+- * megasas_get_cmd - Get a command from the free pool
+- * @instance: Adapter soft state
+- *
+- * Returns a free command from the pool
+- */
+-static struct megasas_cmd *megasas_get_cmd(struct megasas_instance
+- *instance)
+-{
+- unsigned long flags;
+- struct megasas_cmd *cmd = NULL;
+-
+- spin_lock_irqsave(&instance->cmd_pool_lock, flags);
+-
+- if (!list_empty(&instance->cmd_pool)) {
+- cmd = list_entry((&instance->cmd_pool)->next,
+- struct megasas_cmd, list);
+- list_del_init(&cmd->list);
+- } else {
+- printk(KERN_ERR "megasas: Command pool empty!\n");
+- }
+-
+- spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
+- return cmd;
+-}
+-
+-/**
+- * megasas_return_cmd - Return a cmd to free command pool
+- * @instance: Adapter soft state
+- * @cmd: Command packet to be returned to free command pool
+- */
+-static inline void
+-megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&instance->cmd_pool_lock, flags);
+-
+- cmd->scmd = NULL;
+- list_add_tail(&cmd->list, &instance->cmd_pool);
+-
+- spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
+-}
+-
+-
+-/**
+-* The following functions are defined for xscale
+-* (deviceid : 1064R, PERC5) controllers
+-*/
+-
+-/**
+- * megasas_enable_intr_xscale - Enables interrupts
+- * @regs: MFI register set
+- */
+-static inline void
+-megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
+-{
+- writel(0, &(regs)->outbound_intr_mask);
+-
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_intr_mask);
+-}
+-
+-/**
+- * megasas_disable_intr_xscale -Disables interrupt
+- * @regs: MFI register set
+- */
+-static inline void
+-megasas_disable_intr_xscale(struct megasas_register_set __iomem * regs)
+-{
+- u32 mask = 0x1f;
+- writel(mask, ®s->outbound_intr_mask);
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_intr_mask);
+-}
+-
+-/**
+- * megasas_read_fw_status_reg_xscale - returns the current FW status value
+- * @regs: MFI register set
+- */
+-static u32
+-megasas_read_fw_status_reg_xscale(struct megasas_register_set __iomem * regs)
+-{
+- return readl(&(regs)->outbound_msg_0);
+-}
+-/**
+- * megasas_clear_interrupt_xscale - Check & clear interrupt
+- * @regs: MFI register set
+- */
+-static int
+-megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
+-{
+- u32 status;
+- u32 mfiStatus = 0;
+- /*
+- * Check if it is our interrupt
+- */
+- status = readl(®s->outbound_intr_status);
+-
+- if (status & MFI_OB_INTR_STATUS_MASK)
+- mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
+- if (status & MFI_XSCALE_OMR0_CHANGE_INTERRUPT)
+- mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
+-
+- /*
+- * Clear the interrupt by writing back the same value
+- */
+- if (mfiStatus)
+- writel(status, ®s->outbound_intr_status);
+-
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_intr_status);
+-
+- return mfiStatus;
+-}
+-
+-/**
+- * megasas_fire_cmd_xscale - Sends command to the FW
+- * @frame_phys_addr : Physical address of cmd
+- * @frame_count : Number of frames for the command
+- * @regs : MFI register set
+- */
+-static inline void
+-megasas_fire_cmd_xscale(struct megasas_instance *instance,
+- dma_addr_t frame_phys_addr,
+- u32 frame_count,
+- struct megasas_register_set __iomem *regs)
+-{
+- unsigned long flags;
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- writel((frame_phys_addr >> 3)|(frame_count),
+- &(regs)->inbound_queue_port);
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-}
+-
+-/**
+- * megasas_adp_reset_xscale - For controller reset
+- * @regs: MFI register set
+- */
+-static int
+-megasas_adp_reset_xscale(struct megasas_instance *instance,
+- struct megasas_register_set __iomem *regs)
+-{
+- u32 i;
+- u32 pcidata;
+- writel(MFI_ADP_RESET, ®s->inbound_doorbell);
+-
+- for (i = 0; i < 3; i++)
+- msleep(1000); /* sleep for 3 secs */
+- pcidata = 0;
+- pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata);
+- printk(KERN_NOTICE "pcidata = %x\n", pcidata);
+- if (pcidata & 0x2) {
+- printk(KERN_NOTICE "mfi 1068 offset read=%x\n", pcidata);
+- pcidata &= ~0x2;
+- pci_write_config_dword(instance->pdev,
+- MFI_1068_PCSR_OFFSET, pcidata);
+-
+- for (i = 0; i < 2; i++)
+- msleep(1000); /* need to wait 2 secs again */
+-
+- pcidata = 0;
+- pci_read_config_dword(instance->pdev,
+- MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata);
+- printk(KERN_NOTICE "1068 offset handshake read=%x\n", pcidata);
+- if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) {
+- printk(KERN_NOTICE "1068 offset pcidt=%x\n", pcidata);
+- pcidata = 0;
+- pci_write_config_dword(instance->pdev,
+- MFI_1068_FW_HANDSHAKE_OFFSET, pcidata);
+- }
+- }
+- return 0;
+-}
+-
+-/**
+- * megasas_check_reset_xscale - For controller reset check
+- * @regs: MFI register set
+- */
+-static int
+-megasas_check_reset_xscale(struct megasas_instance *instance,
+- struct megasas_register_set __iomem *regs)
+-{
+- u32 consumer;
+- consumer = *instance->consumer;
+-
+- if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
+- (*instance->consumer == MEGASAS_ADPRESET_INPROG_SIGN)) {
+- return 1;
+- }
+- return 0;
+-}
+-
+-static struct megasas_instance_template megasas_instance_template_xscale = {
+-
+- .fire_cmd = megasas_fire_cmd_xscale,
+- .enable_intr = megasas_enable_intr_xscale,
+- .disable_intr = megasas_disable_intr_xscale,
+- .clear_intr = megasas_clear_intr_xscale,
+- .read_fw_status_reg = megasas_read_fw_status_reg_xscale,
+- .adp_reset = megasas_adp_reset_xscale,
+- .check_reset = megasas_check_reset_xscale,
+-};
+-
+-/**
+-* This is the end of set of functions & definitions specific
+-* to xscale (deviceid : 1064R, PERC5) controllers
+-*/
+-
+-/**
+-* The following functions are defined for ppc (deviceid : 0x60)
+-* controllers
+-*/
+-
+-/**
+- * megasas_enable_intr_ppc - Enables interrupts
+- * @regs: MFI register set
+- */
+-static inline void
+-megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs)
+-{
+- writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
+-
+- writel(~0x80000000, &(regs)->outbound_intr_mask);
+-
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_intr_mask);
+-}
+-
+-/**
+- * megasas_disable_intr_ppc - Disable interrupt
+- * @regs: MFI register set
+- */
+-static inline void
+-megasas_disable_intr_ppc(struct megasas_register_set __iomem * regs)
+-{
+- u32 mask = 0xFFFFFFFF;
+- writel(mask, ®s->outbound_intr_mask);
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_intr_mask);
+-}
+-
+-/**
+- * megasas_read_fw_status_reg_ppc - returns the current FW status value
+- * @regs: MFI register set
+- */
+-static u32
+-megasas_read_fw_status_reg_ppc(struct megasas_register_set __iomem * regs)
+-{
+- return readl(&(regs)->outbound_scratch_pad);
+-}
+-
+-/**
+- * megasas_clear_interrupt_ppc - Check & clear interrupt
+- * @regs: MFI register set
+- */
+-static int
+-megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
+-{
+- u32 status;
+- /*
+- * Check if it is our interrupt
+- */
+- status = readl(®s->outbound_intr_status);
+-
+- if (!(status & MFI_REPLY_1078_MESSAGE_INTERRUPT)) {
+- return 0;
+- }
+-
+- /*
+- * Clear the interrupt by writing back the same value
+- */
+- writel(status, ®s->outbound_doorbell_clear);
+-
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_doorbell_clear);
+-
+- return 1;
+-}
+-/**
+- * megasas_fire_cmd_ppc - Sends command to the FW
+- * @frame_phys_addr : Physical address of cmd
+- * @frame_count : Number of frames for the command
+- * @regs : MFI register set
+- */
+-static inline void
+-megasas_fire_cmd_ppc(struct megasas_instance *instance,
+- dma_addr_t frame_phys_addr,
+- u32 frame_count,
+- struct megasas_register_set __iomem *regs)
+-{
+- unsigned long flags;
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- writel((frame_phys_addr | (frame_count<<1))|1,
+- &(regs)->inbound_queue_port);
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-}
+-
+-/**
+- * megasas_adp_reset_ppc - For controller reset
+- * @regs: MFI register set
+- */
+-static int
+-megasas_adp_reset_ppc(struct megasas_instance *instance,
+- struct megasas_register_set __iomem *regs)
+-{
+- return 0;
+-}
+-
+-/**
+- * megasas_check_reset_ppc - For controller reset check
+- * @regs: MFI register set
+- */
+-static int
+-megasas_check_reset_ppc(struct megasas_instance *instance,
+- struct megasas_register_set __iomem *regs)
+-{
+- return 0;
+-}
+-static struct megasas_instance_template megasas_instance_template_ppc = {
+-
+- .fire_cmd = megasas_fire_cmd_ppc,
+- .enable_intr = megasas_enable_intr_ppc,
+- .disable_intr = megasas_disable_intr_ppc,
+- .clear_intr = megasas_clear_intr_ppc,
+- .read_fw_status_reg = megasas_read_fw_status_reg_ppc,
+- .adp_reset = megasas_adp_reset_ppc,
+- .check_reset = megasas_check_reset_ppc,
+-};
+-
+-/**
+- * megasas_enable_intr_skinny - Enables interrupts
+- * @regs: MFI register set
+- */
+-static inline void
+-megasas_enable_intr_skinny(struct megasas_register_set __iomem *regs)
+-{
+- writel(0xFFFFFFFF, &(regs)->outbound_intr_mask);
+-
+- writel(~MFI_SKINNY_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
+-
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_intr_mask);
+-}
+-
+-/**
+- * megasas_disable_intr_skinny - Disables interrupt
+- * @regs: MFI register set
+- */
+-static inline void
+-megasas_disable_intr_skinny(struct megasas_register_set __iomem *regs)
+-{
+- u32 mask = 0xFFFFFFFF;
+- writel(mask, ®s->outbound_intr_mask);
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_intr_mask);
+-}
+-
+-/**
+- * megasas_read_fw_status_reg_skinny - returns the current FW status value
+- * @regs: MFI register set
+- */
+-static u32
+-megasas_read_fw_status_reg_skinny(struct megasas_register_set __iomem *regs)
+-{
+- return readl(&(regs)->outbound_scratch_pad);
+-}
+-
+-/**
+- * megasas_clear_interrupt_skinny - Check & clear interrupt
+- * @regs: MFI register set
+- */
+-static int
+-megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
+-{
+- u32 status;
+- /*
+- * Check if it is our interrupt
+- */
+- status = readl(®s->outbound_intr_status);
+-
+- if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) {
+- return 0;
+- }
+-
+- /*
+- * Clear the interrupt by writing back the same value
+- */
+- writel(status, ®s->outbound_intr_status);
+-
+- /*
+- * dummy read to flush PCI
+- */
+- readl(®s->outbound_intr_status);
+-
+- return 1;
+-}
+-
+-/**
+- * megasas_fire_cmd_skinny - Sends command to the FW
+- * @frame_phys_addr : Physical address of cmd
+- * @frame_count : Number of frames for the command
+- * @regs : MFI register set
+- */
+-static inline void
+-megasas_fire_cmd_skinny(struct megasas_instance *instance,
+- dma_addr_t frame_phys_addr,
+- u32 frame_count,
+- struct megasas_register_set __iomem *regs)
+-{
+- unsigned long flags;
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- writel(0, &(regs)->inbound_high_queue_port);
+- writel((frame_phys_addr | (frame_count<<1))|1,
+- &(regs)->inbound_low_queue_port);
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-}
+-
+-/**
+- * megasas_adp_reset_skinny - For controller reset
+- * @regs: MFI register set
+- */
+-static int
+-megasas_adp_reset_skinny(struct megasas_instance *instance,
+- struct megasas_register_set __iomem *regs)
+-{
+- return 0;
+-}
+-
+-/**
+- * megasas_check_reset_skinny - For controller reset check
+- * @regs: MFI register set
+- */
+-static int
+-megasas_check_reset_skinny(struct megasas_instance *instance,
+- struct megasas_register_set __iomem *regs)
+-{
+- return 0;
+-}
+-
+-static struct megasas_instance_template megasas_instance_template_skinny = {
+-
+- .fire_cmd = megasas_fire_cmd_skinny,
+- .enable_intr = megasas_enable_intr_skinny,
+- .disable_intr = megasas_disable_intr_skinny,
+- .clear_intr = megasas_clear_intr_skinny,
+- .read_fw_status_reg = megasas_read_fw_status_reg_skinny,
+- .adp_reset = megasas_adp_reset_skinny,
+- .check_reset = megasas_check_reset_skinny,
+-};
+-
+-
+-/**
+-* The following functions are defined for gen2 (deviceid : 0x78 0x79)
+-* controllers
+-*/
+-
+-/**
+- * megasas_enable_intr_gen2 - Enables interrupts
+- * @regs: MFI register set
+- */
+-static inline void
+-megasas_enable_intr_gen2(struct megasas_register_set __iomem *regs)
+-{
+- writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
+-
+- /* write ~0x00000005 (4 & 1) to the intr mask*/
+- writel(~MFI_GEN2_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
+-
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_intr_mask);
+-}
+-
+-/**
+- * megasas_disable_intr_gen2 - Disables interrupt
+- * @regs: MFI register set
+- */
+-static inline void
+-megasas_disable_intr_gen2(struct megasas_register_set __iomem *regs)
+-{
+- u32 mask = 0xFFFFFFFF;
+- writel(mask, ®s->outbound_intr_mask);
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_intr_mask);
+-}
+-
+-/**
+- * megasas_read_fw_status_reg_gen2 - returns the current FW status value
+- * @regs: MFI register set
+- */
+-static u32
+-megasas_read_fw_status_reg_gen2(struct megasas_register_set __iomem *regs)
+-{
+- return readl(&(regs)->outbound_scratch_pad);
+-}
+-
+-/**
+- * megasas_clear_interrupt_gen2 - Check & clear interrupt
+- * @regs: MFI register set
+- */
+-static int
+-megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
+-{
+- u32 status;
+- u32 mfiStatus = 0;
+- /*
+- * Check if it is our interrupt
+- */
+- status = readl(®s->outbound_intr_status);
+-
+- if (status & MFI_GEN2_ENABLE_INTERRUPT_MASK) {
+- mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
+- }
+- if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) {
+- mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
+- }
+-
+- /*
+- * Clear the interrupt by writing back the same value
+- */
+- if (mfiStatus)
+- writel(status, ®s->outbound_doorbell_clear);
+-
+- /* Dummy readl to force pci flush */
+- readl(®s->outbound_intr_status);
+-
+- return mfiStatus;
+-}
+-/**
+- * megasas_fire_cmd_gen2 - Sends command to the FW
+- * @frame_phys_addr : Physical address of cmd
+- * @frame_count : Number of frames for the command
+- * @regs : MFI register set
+- */
+-static inline void
+-megasas_fire_cmd_gen2(struct megasas_instance *instance,
+- dma_addr_t frame_phys_addr,
+- u32 frame_count,
+- struct megasas_register_set __iomem *regs)
+-{
+- unsigned long flags;
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- writel((frame_phys_addr | (frame_count<<1))|1,
+- &(regs)->inbound_queue_port);
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-}
+-
+-/**
+- * megasas_adp_reset_gen2 - For controller reset
+- * @regs: MFI register set
+- */
+-static int
+-megasas_adp_reset_gen2(struct megasas_instance *instance,
+- struct megasas_register_set __iomem *reg_set)
+-{
+- u32 retry = 0 ;
+- u32 HostDiag;
+-
+- writel(0, ®_set->seq_offset);
+- writel(4, ®_set->seq_offset);
+- writel(0xb, ®_set->seq_offset);
+- writel(2, ®_set->seq_offset);
+- writel(7, ®_set->seq_offset);
+- writel(0xd, ®_set->seq_offset);
+- msleep(1000);
+-
+- HostDiag = (u32)readl(®_set->host_diag);
+-
+- while ( !( HostDiag & DIAG_WRITE_ENABLE) ) {
+- msleep(100);
+- HostDiag = (u32)readl(®_set->host_diag);
+- printk(KERN_NOTICE "RESETGEN2: retry=%x, hostdiag=%x\n",
+- retry, HostDiag);
+-
+- if (retry++ >= 100)
+- return 1;
+-
+- }
+-
+- printk(KERN_NOTICE "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag);
+-
+- writel((HostDiag | DIAG_RESET_ADAPTER), ®_set->host_diag);
+-
+- ssleep(10);
+-
+- HostDiag = (u32)readl(®_set->host_diag);
+- while ( ( HostDiag & DIAG_RESET_ADAPTER) ) {
+- msleep(100);
+- HostDiag = (u32)readl(®_set->host_diag);
+- printk(KERN_NOTICE "RESET_GEN2: retry=%x, hostdiag=%x\n",
+- retry, HostDiag);
+-
+- if (retry++ >= 1000)
+- return 1;
+-
+- }
+- return 0;
+-}
+-
+-/**
+- * megasas_check_reset_gen2 - For controller reset check
+- * @regs: MFI register set
+- */
+-static int
+-megasas_check_reset_gen2(struct megasas_instance *instance,
+- struct megasas_register_set __iomem *regs)
+-{
+- return 0;
+-}
+-
+-static struct megasas_instance_template megasas_instance_template_gen2 = {
+-
+- .fire_cmd = megasas_fire_cmd_gen2,
+- .enable_intr = megasas_enable_intr_gen2,
+- .disable_intr = megasas_disable_intr_gen2,
+- .clear_intr = megasas_clear_intr_gen2,
+- .read_fw_status_reg = megasas_read_fw_status_reg_gen2,
+- .adp_reset = megasas_adp_reset_gen2,
+- .check_reset = megasas_check_reset_gen2,
+-};
+-
+-/**
+-* This is the end of set of functions & definitions
+-* specific to gen2 (deviceid : 0x78, 0x79) controllers
+-*/
+-
+-/**
+- * megasas_issue_polled - Issues a polling command
+- * @instance: Adapter soft state
+- * @cmd: Command packet to be issued
+- *
+- * For polling, MFI requires the cmd_status to be set to 0xFF before posting.
+- */
+-static int
+-megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
+-{
+- int i;
+- u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
+-
+- struct megasas_header *frame_hdr = &cmd->frame->hdr;
+-
+- frame_hdr->cmd_status = 0xFF;
+- frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+-
+- /*
+- * Issue the frame using inbound queue port
+- */
+- instance->instancet->fire_cmd(instance,
+- cmd->frame_phys_addr, 0, instance->reg_set);
+-
+- /*
+- * Wait for cmd_status to change
+- */
+- for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i++) {
+- rmb();
+- msleep(1);
+- }
+-
+- if (frame_hdr->cmd_status == 0xff)
+- return -ETIME;
+-
+- return 0;
+-}
+-
+-/**
+- * megasas_issue_blocked_cmd - Synchronous wrapper around regular FW cmds
+- * @instance: Adapter soft state
+- * @cmd: Command to be issued
+- *
+- * This function waits on an event for the command to be returned from ISR.
+- * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
+- * Used to issue ioctl commands.
+- */
+-static int
+-megasas_issue_blocked_cmd(struct megasas_instance *instance,
+- struct megasas_cmd *cmd)
+-{
+- cmd->cmd_status = ENODATA;
+-
+- instance->instancet->fire_cmd(instance,
+- cmd->frame_phys_addr, 0, instance->reg_set);
+-
+- wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA);
+-
+- return 0;
+-}
+-
+-/**
+- * megasas_issue_blocked_abort_cmd - Aborts previously issued cmd
+- * @instance: Adapter soft state
+- * @cmd_to_abort: Previously issued cmd to be aborted
+- *
+- * MFI firmware can abort previously issued AEN comamnd (automatic event
+- * notification). The megasas_issue_blocked_abort_cmd() issues such abort
+- * cmd and waits for return status.
+- * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
+- */
+-static int
+-megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
+- struct megasas_cmd *cmd_to_abort)
+-{
+- struct megasas_cmd *cmd;
+- struct megasas_abort_frame *abort_fr;
+-
+- cmd = megasas_get_cmd(instance);
+-
+- if (!cmd)
+- return -1;
+-
+- abort_fr = &cmd->frame->abort;
+-
+- /*
+- * Prepare and issue the abort frame
+- */
+- abort_fr->cmd = MFI_CMD_ABORT;
+- abort_fr->cmd_status = 0xFF;
+- abort_fr->flags = 0;
+- abort_fr->abort_context = cmd_to_abort->index;
+- abort_fr->abort_mfi_phys_addr_lo = cmd_to_abort->frame_phys_addr;
+- abort_fr->abort_mfi_phys_addr_hi = 0;
+-
+- cmd->sync_cmd = 1;
+- cmd->cmd_status = 0xFF;
+-
+- instance->instancet->fire_cmd(instance,
+- cmd->frame_phys_addr, 0, instance->reg_set);
+-
+- /*
+- * Wait for this cmd to complete
+- */
+- wait_event(instance->abort_cmd_wait_q, cmd->cmd_status != 0xFF);
+- cmd->sync_cmd = 0;
+-
+- megasas_return_cmd(instance, cmd);
+- return 0;
+-}
+-
+-/**
+- * megasas_make_sgl32 - Prepares 32-bit SGL
+- * @instance: Adapter soft state
+- * @scp: SCSI command from the mid-layer
+- * @mfi_sgl: SGL to be filled in
+- *
+- * If successful, this function returns the number of SG elements. Otherwise,
+- * it returnes -1.
+- */
+-static int
+-megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,
+- union megasas_sgl *mfi_sgl)
+-{
+- int i;
+- int sge_count;
+- struct scatterlist *os_sgl;
+-
+- sge_count = scsi_dma_map(scp);
+- BUG_ON(sge_count < 0);
+-
+- if (sge_count) {
+- scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+- mfi_sgl->sge32[i].length = sg_dma_len(os_sgl);
+- mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl);
+- }
+- }
+- return sge_count;
+-}
+-
+-/**
+- * megasas_make_sgl64 - Prepares 64-bit SGL
+- * @instance: Adapter soft state
+- * @scp: SCSI command from the mid-layer
+- * @mfi_sgl: SGL to be filled in
+- *
+- * If successful, this function returns the number of SG elements. Otherwise,
+- * it returnes -1.
+- */
+-static int
+-megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
+- union megasas_sgl *mfi_sgl)
+-{
+- int i;
+- int sge_count;
+- struct scatterlist *os_sgl;
+-
+- sge_count = scsi_dma_map(scp);
+- BUG_ON(sge_count < 0);
+-
+- if (sge_count) {
+- scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+- mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);
+- mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);
+- }
+- }
+- return sge_count;
+-}
+-
+-/**
+- * megasas_make_sgl_skinny - Prepares IEEE SGL
+- * @instance: Adapter soft state
+- * @scp: SCSI command from the mid-layer
+- * @mfi_sgl: SGL to be filled in
+- *
+- * If successful, this function returns the number of SG elements. Otherwise,
+- * it returnes -1.
+- */
+-static int
+-megasas_make_sgl_skinny(struct megasas_instance *instance,
+- struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl)
+-{
+- int i;
+- int sge_count;
+- struct scatterlist *os_sgl;
+-
+- sge_count = scsi_dma_map(scp);
+-
+- if (sge_count) {
+- scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+- mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
+- mfi_sgl->sge_skinny[i].phys_addr =
+- sg_dma_address(os_sgl);
+- }
+- }
+- return sge_count;
+-}
+-
+- /**
+- * megasas_get_frame_count - Computes the number of frames
+- * @frame_type : type of frame- io or pthru frame
+- * @sge_count : number of sg elements
+- *
+- * Returns the number of frames required for numnber of sge's (sge_count)
+- */
+-
+-static u32 megasas_get_frame_count(struct megasas_instance *instance,
+- u8 sge_count, u8 frame_type)
+-{
+- int num_cnt;
+- int sge_bytes;
+- u32 sge_sz;
+- u32 frame_count=0;
+-
+- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+- sizeof(struct megasas_sge32);
+-
+- if (instance->flag_ieee) {
+- sge_sz = sizeof(struct megasas_sge_skinny);
+- }
+-
+- /*
+- * Main frame can contain 2 SGEs for 64-bit SGLs and
+- * 3 SGEs for 32-bit SGLs for ldio &
+- * 1 SGEs for 64-bit SGLs and
+- * 2 SGEs for 32-bit SGLs for pthru frame
+- */
+- if (unlikely(frame_type == PTHRU_FRAME)) {
+- if (instance->flag_ieee == 1) {
+- num_cnt = sge_count - 1;
+- } else if (IS_DMA64)
+- num_cnt = sge_count - 1;
+- else
+- num_cnt = sge_count - 2;
+- } else {
+- if (instance->flag_ieee == 1) {
+- num_cnt = sge_count - 1;
+- } else if (IS_DMA64)
+- num_cnt = sge_count - 2;
+- else
+- num_cnt = sge_count - 3;
+- }
+-
+- if(num_cnt>0){
+- sge_bytes = sge_sz * num_cnt;
+-
+- frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
+- ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;
+- }
+- /* Main frame */
+- frame_count +=1;
+-
+- if (frame_count > 7)
+- frame_count = 8;
+- return frame_count;
+-}
+-
+-/**
+- * megasas_build_dcdb - Prepares a direct cdb (DCDB) command
+- * @instance: Adapter soft state
+- * @scp: SCSI command
+- * @cmd: Command to be prepared in
+- *
+- * This function prepares CDB commands. These are typcially pass-through
+- * commands to the devices.
+- */
+-static int
+-megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
+- struct megasas_cmd *cmd)
+-{
+- u32 is_logical;
+- u32 device_id;
+- u16 flags = 0;
+- struct megasas_pthru_frame *pthru;
+-
+- is_logical = MEGASAS_IS_LOGICAL(scp);
+- device_id = MEGASAS_DEV_INDEX(instance, scp);
+- pthru = (struct megasas_pthru_frame *)cmd->frame;
+-
+- if (scp->sc_data_direction == PCI_DMA_TODEVICE)
+- flags = MFI_FRAME_DIR_WRITE;
+- else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+- flags = MFI_FRAME_DIR_READ;
+- else if (scp->sc_data_direction == PCI_DMA_NONE)
+- flags = MFI_FRAME_DIR_NONE;
+-
+- if (instance->flag_ieee == 1) {
+- flags |= MFI_FRAME_IEEE;
+- }
+-
+- /*
+- * Prepare the DCDB frame
+- */
+- pthru->cmd = (is_logical) ? MFI_CMD_LD_SCSI_IO : MFI_CMD_PD_SCSI_IO;
+- pthru->cmd_status = 0x0;
+- pthru->scsi_status = 0x0;
+- pthru->target_id = device_id;
+- pthru->lun = scp->device->lun;
+- pthru->cdb_len = scp->cmd_len;
+- pthru->timeout = 0;
+- pthru->flags = flags;
+- pthru->data_xfer_len = scsi_bufflen(scp);
+-
+- memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
+-
+- /*
+- * Construct SGL
+- */
+- if (instance->flag_ieee == 1) {
+- pthru->flags |= MFI_FRAME_SGL64;
+- pthru->sge_count = megasas_make_sgl_skinny(instance, scp,
+- &pthru->sgl);
+- } else if (IS_DMA64) {
+- pthru->flags |= MFI_FRAME_SGL64;
+- pthru->sge_count = megasas_make_sgl64(instance, scp,
+- &pthru->sgl);
+- } else
+- pthru->sge_count = megasas_make_sgl32(instance, scp,
+- &pthru->sgl);
+-
+- if (pthru->sge_count > instance->max_num_sge) {
+- printk(KERN_ERR "megasas: DCDB two many SGE NUM=%x\n",
+- pthru->sge_count);
+- return 0;
+- }
+-
+- /*
+- * Sense info specific
+- */
+- pthru->sense_len = SCSI_SENSE_BUFFERSIZE;
+- pthru->sense_buf_phys_addr_hi = 0;
+- pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
+-
+- /*
+- * Compute the total number of frames this command consumes. FW uses
+- * this number to pull sufficient number of frames from host memory.
+- */
+- cmd->frame_count = megasas_get_frame_count(instance, pthru->sge_count,
+- PTHRU_FRAME);
+-
+- return cmd->frame_count;
+-}
+-
+-/**
+- * megasas_build_ldio - Prepares IOs to logical devices
+- * @instance: Adapter soft state
+- * @scp: SCSI command
+- * @cmd: Command to be prepared
+- *
+- * Frames (and accompanying SGLs) for regular SCSI IOs use this function.
+- */
+-static int
+-megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
+- struct megasas_cmd *cmd)
+-{
+- u32 device_id;
+- u8 sc = scp->cmnd[0];
+- u16 flags = 0;
+- struct megasas_io_frame *ldio;
+-
+- device_id = MEGASAS_DEV_INDEX(instance, scp);
+- ldio = (struct megasas_io_frame *)cmd->frame;
+-
+- if (scp->sc_data_direction == PCI_DMA_TODEVICE)
+- flags = MFI_FRAME_DIR_WRITE;
+- else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+- flags = MFI_FRAME_DIR_READ;
+-
+- if (instance->flag_ieee == 1) {
+- flags |= MFI_FRAME_IEEE;
+- }
+-
+- /*
+- * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
+- */
+- ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;
+- ldio->cmd_status = 0x0;
+- ldio->scsi_status = 0x0;
+- ldio->target_id = device_id;
+- ldio->timeout = 0;
+- ldio->reserved_0 = 0;
+- ldio->pad_0 = 0;
+- ldio->flags = flags;
+- ldio->start_lba_hi = 0;
+- ldio->access_byte = (scp->cmd_len != 6) ? scp->cmnd[1] : 0;
+-
+- /*
+- * 6-byte READ(0x08) or WRITE(0x0A) cdb
+- */
+- if (scp->cmd_len == 6) {
+- ldio->lba_count = (u32) scp->cmnd[4];
+- ldio->start_lba_lo = ((u32) scp->cmnd[1] << 16) |
+- ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3];
+-
+- ldio->start_lba_lo &= 0x1FFFFF;
+- }
+-
+- /*
+- * 10-byte READ(0x28) or WRITE(0x2A) cdb
+- */
+- else if (scp->cmd_len == 10) {
+- ldio->lba_count = (u32) scp->cmnd[8] |
+- ((u32) scp->cmnd[7] << 8);
+- ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |
+- ((u32) scp->cmnd[3] << 16) |
+- ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+- }
+-
+- /*
+- * 12-byte READ(0xA8) or WRITE(0xAA) cdb
+- */
+- else if (scp->cmd_len == 12) {
+- ldio->lba_count = ((u32) scp->cmnd[6] << 24) |
+- ((u32) scp->cmnd[7] << 16) |
+- ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
+-
+- ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |
+- ((u32) scp->cmnd[3] << 16) |
+- ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+- }
+-
+- /*
+- * 16-byte READ(0x88) or WRITE(0x8A) cdb
+- */
+- else if (scp->cmd_len == 16) {
+- ldio->lba_count = ((u32) scp->cmnd[10] << 24) |
+- ((u32) scp->cmnd[11] << 16) |
+- ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13];
+-
+- ldio->start_lba_lo = ((u32) scp->cmnd[6] << 24) |
+- ((u32) scp->cmnd[7] << 16) |
+- ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
+-
+- ldio->start_lba_hi = ((u32) scp->cmnd[2] << 24) |
+- ((u32) scp->cmnd[3] << 16) |
+- ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+-
+- }
+-
+- /*
+- * Construct SGL
+- */
+- if (instance->flag_ieee) {
+- ldio->flags |= MFI_FRAME_SGL64;
+- ldio->sge_count = megasas_make_sgl_skinny(instance, scp,
+- &ldio->sgl);
+- } else if (IS_DMA64) {
+- ldio->flags |= MFI_FRAME_SGL64;
+- ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
+- } else
+- ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl);
+-
+- if (ldio->sge_count > instance->max_num_sge) {
+- printk(KERN_ERR "megasas: build_ld_io: sge_count = %x\n",
+- ldio->sge_count);
+- return 0;
+- }
+-
+- /*
+- * Sense info specific
+- */
+- ldio->sense_len = SCSI_SENSE_BUFFERSIZE;
+- ldio->sense_buf_phys_addr_hi = 0;
+- ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
+-
+- /*
+- * Compute the total number of frames this command consumes. FW uses
+- * this number to pull sufficient number of frames from host memory.
+- */
+- cmd->frame_count = megasas_get_frame_count(instance,
+- ldio->sge_count, IO_FRAME);
+-
+- return cmd->frame_count;
+-}
+-
+-/**
+- * megasas_is_ldio - Checks if the cmd is for logical drive
+- * @scmd: SCSI command
+- *
+- * Called by megasas_queue_command to find out if the command to be queued
+- * is a logical drive command
+- */
+-static inline int megasas_is_ldio(struct scsi_cmnd *cmd)
+-{
+- if (!MEGASAS_IS_LOGICAL(cmd))
+- return 0;
+- switch (cmd->cmnd[0]) {
+- case READ_10:
+- case WRITE_10:
+- case READ_12:
+- case WRITE_12:
+- case READ_6:
+- case WRITE_6:
+- case READ_16:
+- case WRITE_16:
+- return 1;
+- default:
+- return 0;
+- }
+-}
+-
+- /**
+- * megasas_dump_pending_frames - Dumps the frame address of all pending cmds
+- * in FW
+- * @instance: Adapter soft state
+- */
+-static inline void
+-megasas_dump_pending_frames(struct megasas_instance *instance)
+-{
+- struct megasas_cmd *cmd;
+- int i,n;
+- union megasas_sgl *mfi_sgl;
+- struct megasas_io_frame *ldio;
+- struct megasas_pthru_frame *pthru;
+- u32 sgcount;
+- u32 max_cmd = instance->max_fw_cmds;
+-
+- printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
+- printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
+- if (IS_DMA64)
+- printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);
+- else
+- printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
+-
+- printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no);
+- for (i = 0; i < max_cmd; i++) {
+- cmd = instance->cmd_list[i];
+- if(!cmd->scmd)
+- continue;
+- printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
+- if (megasas_is_ldio(cmd->scmd)){
+- ldio = (struct megasas_io_frame *)cmd->frame;
+- mfi_sgl = &ldio->sgl;
+- sgcount = ldio->sge_count;
+- printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount);
+- }
+- else {
+- pthru = (struct megasas_pthru_frame *) cmd->frame;
+- mfi_sgl = &pthru->sgl;
+- sgcount = pthru->sge_count;
+- printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount);
+- }
+- if(megasas_dbg_lvl & MEGASAS_DBG_LVL){
+- for (n = 0; n < sgcount; n++){
+- if (IS_DMA64)
+- printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ;
+- else
+- printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ;
+- }
+- }
+- printk(KERN_ERR "\n");
+- } /*for max_cmd*/
+- printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);
+- for (i = 0; i < max_cmd; i++) {
+-
+- cmd = instance->cmd_list[i];
+-
+- if(cmd->sync_cmd == 1){
+- printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);
+- }
+- }
+- printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
+-}
+-
+-/**
+- * megasas_queue_command - Queue entry point
+- * @scmd: SCSI command to be queued
+- * @done: Callback entry point
+- */
+-static int
+-megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
+-{
+- u32 frame_count;
+- struct megasas_cmd *cmd;
+- struct megasas_instance *instance;
+- unsigned long flags;
+-
+- instance = (struct megasas_instance *)
+- scmd->device->host->hostdata;
+-
+- if (instance->issuepend_done == 0)
+- return SCSI_MLQUEUE_HOST_BUSY;
+-
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+- return SCSI_MLQUEUE_HOST_BUSY;
+- }
+-
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-
+- scmd->scsi_done = done;
+- scmd->result = 0;
+-
+- if (MEGASAS_IS_LOGICAL(scmd) &&
+- (scmd->device->id >= MEGASAS_MAX_LD || scmd->device->lun)) {
+- scmd->result = DID_BAD_TARGET << 16;
+- goto out_done;
+- }
+-
+- switch (scmd->cmnd[0]) {
+- case SYNCHRONIZE_CACHE:
+- /*
+- * FW takes care of flush cache on its own
+- * No need to send it down
+- */
+- scmd->result = DID_OK << 16;
+- goto out_done;
+- default:
+- break;
+- }
+-
+- cmd = megasas_get_cmd(instance);
+- if (!cmd)
+- return SCSI_MLQUEUE_HOST_BUSY;
+-
+- /*
+- * Logical drive command
+- */
+- if (megasas_is_ldio(scmd))
+- frame_count = megasas_build_ldio(instance, scmd, cmd);
+- else
+- frame_count = megasas_build_dcdb(instance, scmd, cmd);
+-
+- if (!frame_count)
+- goto out_return_cmd;
+-
+- cmd->scmd = scmd;
+- scmd->SCp.ptr = (char *)cmd;
+-
+- /*
+- * Issue the command to the FW
+- */
+- atomic_inc(&instance->fw_outstanding);
+-
+- instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
+- cmd->frame_count-1, instance->reg_set);
+- /*
+- * Check if we have pend cmds to be completed
+- */
+- if (poll_mode_io && atomic_read(&instance->fw_outstanding))
+- tasklet_schedule(&instance->isr_tasklet);
+-
+-
+- return 0;
+-
+- out_return_cmd:
+- megasas_return_cmd(instance, cmd);
+- out_done:
+- done(scmd);
+- return 0;
+-}
+-
+-static int megasas_slave_configure(struct scsi_device *sdev)
+-{
+- /*
+- * Don't export physical disk devices to the disk driver.
+- *
+- * FIXME: Currently we don't export them to the midlayer at all.
+- * That will be fixed once LSI engineers have audited the
+- * firmware for possible issues.
+- */
+- if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && sdev->type == TYPE_DISK)
+- return -ENXIO;
+-
+- /*
+- * The RAID firmware may require extended timeouts.
+- */
+- if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS)
+- blk_queue_rq_timeout(sdev->request_queue,
+- MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+- return 0;
+-}
+-
+-static void megaraid_sas_kill_hba(struct megasas_instance *instance)
+-{
+- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+- writel(MFI_STOP_ADP,
+- &instance->reg_set->reserved_0[0]);
+- } else {
+- writel(MFI_STOP_ADP,
+- &instance->reg_set->inbound_doorbell);
+- }
+-}
+-
+-/**
+- * megasas_complete_cmd_dpc - Returns FW's controller structure
+- * @instance_addr: Address of adapter soft state
+- *
+- * Tasklet to complete cmds
+- */
+-static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+-{
+- u32 producer;
+- u32 consumer;
+- u32 context;
+- struct megasas_cmd *cmd;
+- struct megasas_instance *instance =
+- (struct megasas_instance *)instance_addr;
+- unsigned long flags;
+-
+- /* If we have already declared adapter dead, donot complete cmds */
+- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR )
+- return;
+-
+- spin_lock_irqsave(&instance->completion_lock, flags);
+-
+- producer = *instance->producer;
+- consumer = *instance->consumer;
+-
+- while (consumer != producer) {
+- context = instance->reply_queue[consumer];
+- if (context >= instance->max_fw_cmds) {
+- printk(KERN_ERR "Unexpected context value %x\n",
+- context);
+- BUG();
+- }
+-
+- cmd = instance->cmd_list[context];
+-
+- megasas_complete_cmd(instance, cmd, DID_OK);
+-
+- consumer++;
+- if (consumer == (instance->max_fw_cmds + 1)) {
+- consumer = 0;
+- }
+- }
+-
+- *instance->consumer = producer;
+-
+- spin_unlock_irqrestore(&instance->completion_lock, flags);
+-
+- /*
+- * Check if we can restore can_queue
+- */
+- if (instance->flag & MEGASAS_FW_BUSY
+- && time_after(jiffies, instance->last_time + 5 * HZ)
+- && atomic_read(&instance->fw_outstanding) < 17) {
+-
+- spin_lock_irqsave(instance->host->host_lock, flags);
+- instance->flag &= ~MEGASAS_FW_BUSY;
+- if ((instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+- instance->host->can_queue =
+- instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
+- } else
+- instance->host->can_queue =
+- instance->max_fw_cmds - MEGASAS_INT_CMDS;
+-
+- spin_unlock_irqrestore(instance->host->host_lock, flags);
+- }
+-}
+-
+-/**
+- * megasas_wait_for_outstanding - Wait for all outstanding cmds
+- * @instance: Adapter soft state
+- *
+- * This function waits for upto MEGASAS_RESET_WAIT_TIME seconds for FW to
+- * complete all its outstanding commands. Returns error if one or more IOs
+- * are pending after this time period. It also marks the controller dead.
+- */
+-static int megasas_wait_for_outstanding(struct megasas_instance *instance)
+-{
+- int i;
+- u32 reset_index;
+- u32 wait_time = MEGASAS_RESET_WAIT_TIME;
+- u8 adprecovery;
+- unsigned long flags;
+- struct list_head clist_local;
+- struct megasas_cmd *reset_cmd;
+-
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- adprecovery = instance->adprecovery;
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-
+- if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+-
+- INIT_LIST_HEAD(&clist_local);
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- list_splice_init(&instance->internal_reset_pending_q,
+- &clist_local);
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-
+- printk(KERN_NOTICE "megasas: HBA reset wait ...\n");
+- for (i = 0; i < wait_time; i++) {
+- msleep(1000);
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- adprecovery = instance->adprecovery;
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+- if (adprecovery == MEGASAS_HBA_OPERATIONAL)
+- break;
+- }
+-
+- if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+- printk(KERN_NOTICE "megasas: reset: Stopping HBA.\n");
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+- return FAILED;
+- }
+-
+- reset_index = 0;
+- while (!list_empty(&clist_local)) {
+- reset_cmd = list_entry((&clist_local)->next,
+- struct megasas_cmd, list);
+- list_del_init(&reset_cmd->list);
+- if (reset_cmd->scmd) {
+- reset_cmd->scmd->result = DID_RESET << 16;
+- printk(KERN_NOTICE "%d:%p reset [%02x], %#lx\n",
+- reset_index, reset_cmd,
+- reset_cmd->scmd->cmnd[0],
+- reset_cmd->scmd->serial_number);
+-
+- reset_cmd->scmd->scsi_done(reset_cmd->scmd);
+- megasas_return_cmd(instance, reset_cmd);
+- } else if (reset_cmd->sync_cmd) {
+- printk(KERN_NOTICE "megasas:%p synch cmds"
+- "reset queue\n",
+- reset_cmd);
+-
+- reset_cmd->cmd_status = ENODATA;
+- instance->instancet->fire_cmd(instance,
+- reset_cmd->frame_phys_addr,
+- 0, instance->reg_set);
+- } else {
+- printk(KERN_NOTICE "megasas: %p unexpected"
+- "cmds lst\n",
+- reset_cmd);
+- }
+- reset_index++;
+- }
+-
+- return SUCCESS;
+- }
+-
+- for (i = 0; i < wait_time; i++) {
+-
+- int outstanding = atomic_read(&instance->fw_outstanding);
+-
+- if (!outstanding)
+- break;
+-
+- if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+- printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
+- "commands to complete\n",i,outstanding);
+- /*
+- * Call cmd completion routine. Cmd to be
+- * be completed directly without depending on isr.
+- */
+- megasas_complete_cmd_dpc((unsigned long)instance);
+- }
+-
+- msleep(1000);
+- }
+-
+- if (atomic_read(&instance->fw_outstanding)) {
+- printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n");
+- /*
+- * Send signal to FW to stop processing any pending cmds.
+- * The controller will be taken offline by the OS now.
+- */
+- if ((instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+- writel(MFI_STOP_ADP,
+- &instance->reg_set->reserved_0[0]);
+- } else {
+- writel(MFI_STOP_ADP,
+- &instance->reg_set->inbound_doorbell);
+- }
+- megasas_dump_pending_frames(instance);
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+- return FAILED;
+- }
+-
+- printk(KERN_NOTICE "megaraid_sas: no pending cmds after reset\n");
+-
+- return SUCCESS;
+-}
+-
+-/**
+- * megasas_generic_reset - Generic reset routine
+- * @scmd: Mid-layer SCSI command
+- *
+- * This routine implements a generic reset handler for device, bus and host
+- * reset requests. Device, bus and host specific reset handlers can use this
+- * function after they do their specific tasks.
+- */
+-static int megasas_generic_reset(struct scsi_cmnd *scmd)
+-{
+- int ret_val;
+- struct megasas_instance *instance;
+-
+- instance = (struct megasas_instance *)scmd->device->host->hostdata;
+-
+- scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n",
+- scmd->serial_number, scmd->cmnd[0], scmd->retries);
+-
+- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+- printk(KERN_ERR "megasas: cannot recover from previous reset "
+- "failures\n");
+- return FAILED;
+- }
+-
+- ret_val = megasas_wait_for_outstanding(instance);
+- if (ret_val == SUCCESS)
+- printk(KERN_NOTICE "megasas: reset successful \n");
+- else
+- printk(KERN_ERR "megasas: failed to do reset\n");
+-
+- return ret_val;
+-}
+-
+-/**
+- * megasas_reset_timer - quiesce the adapter if required
+- * @scmd: scsi cmnd
+- *
+- * Sets the FW busy flag and reduces the host->can_queue if the
+- * cmd has not been completed within the timeout period.
+- */
+-static enum
+-blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+-{
+- struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
+- struct megasas_instance *instance;
+- unsigned long flags;
+-
+- if (time_after(jiffies, scmd->jiffies_at_alloc +
+- (MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
+- return BLK_EH_NOT_HANDLED;
+- }
+-
+- instance = cmd->instance;
+- if (!(instance->flag & MEGASAS_FW_BUSY)) {
+- /* FW is busy, throttle IO */
+- spin_lock_irqsave(instance->host->host_lock, flags);
+-
+- instance->host->can_queue = 16;
+- instance->last_time = jiffies;
+- instance->flag |= MEGASAS_FW_BUSY;
+-
+- spin_unlock_irqrestore(instance->host->host_lock, flags);
+- }
+- return BLK_EH_RESET_TIMER;
+-}
+-
+-/**
+- * megasas_reset_device - Device reset handler entry point
+- */
+-static int megasas_reset_device(struct scsi_cmnd *scmd)
+-{
+- int ret;
+-
+- /*
+- * First wait for all commands to complete
+- */
+- ret = megasas_generic_reset(scmd);
+-
+- return ret;
+-}
+-
+-/**
+- * megasas_reset_bus_host - Bus & host reset handler entry point
+- */
+-static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
+-{
+- int ret;
+-
+- /*
+- * First wait for all commands to complete
+- */
+- ret = megasas_generic_reset(scmd);
+-
+- return ret;
+-}
+-
+-/**
+- * megasas_bios_param - Returns disk geometry for a disk
+- * @sdev: device handle
+- * @bdev: block device
+- * @capacity: drive capacity
+- * @geom: geometry parameters
+- */
+-static int
+-megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+- sector_t capacity, int geom[])
+-{
+- int heads;
+- int sectors;
+- sector_t cylinders;
+- unsigned long tmp;
+- /* Default heads (64) & sectors (32) */
+- heads = 64;
+- sectors = 32;
+-
+- tmp = heads * sectors;
+- cylinders = capacity;
+-
+- sector_div(cylinders, tmp);
+-
+- /*
+- * Handle extended translation size for logical drives > 1Gb
+- */
+-
+- if (capacity >= 0x200000) {
+- heads = 255;
+- sectors = 63;
+- tmp = heads*sectors;
+- cylinders = capacity;
+- sector_div(cylinders, tmp);
+- }
+-
+- geom[0] = heads;
+- geom[1] = sectors;
+- geom[2] = cylinders;
+-
+- return 0;
+-}
+-
+-static void megasas_aen_polling(struct work_struct *work);
+-
+-/**
+- * megasas_service_aen - Processes an event notification
+- * @instance: Adapter soft state
+- * @cmd: AEN command completed by the ISR
+- *
+- * For AEN, driver sends a command down to FW that is held by the FW till an
+- * event occurs. When an event of interest occurs, FW completes the command
+- * that it was previously holding.
+- *
+- * This routines sends SIGIO signal to processes that have registered with the
+- * driver for AEN.
+- */
+-static void
+-megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
+-{
+- unsigned long flags;
+- /*
+- * Don't signal app if it is just an aborted previously registered aen
+- */
+- if ((!cmd->abort_aen) && (instance->unload == 0)) {
+- spin_lock_irqsave(&poll_aen_lock, flags);
+- megasas_poll_wait_aen = 1;
+- spin_unlock_irqrestore(&poll_aen_lock, flags);
+- wake_up(&megasas_poll_wait);
+- kill_fasync(&megasas_async_queue, SIGIO, POLL_IN);
+- }
+- else
+- cmd->abort_aen = 0;
+-
+- instance->aen_cmd = NULL;
+- megasas_return_cmd(instance, cmd);
+-
+- if ((instance->unload == 0) &&
+- ((instance->issuepend_done == 1))) {
+- struct megasas_aen_event *ev;
+- ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+- if (!ev) {
+- printk(KERN_ERR "megasas_service_aen: out of memory\n");
+- } else {
+- ev->instance = instance;
+- instance->ev = ev;
+- INIT_WORK(&ev->hotplug_work, megasas_aen_polling);
+- schedule_delayed_work(
+- (struct delayed_work *)&ev->hotplug_work, 0);
+- }
+- }
+-}
+-
+-/*
+- * Scsi host template for megaraid_sas driver
+- */
+-static struct scsi_host_template megasas_template = {
+-
+- .module = THIS_MODULE,
+- .name = "LSI SAS based MegaRAID driver",
+- .proc_name = "megaraid_sas",
+- .slave_configure = megasas_slave_configure,
+- .queuecommand = megasas_queue_command,
+- .eh_device_reset_handler = megasas_reset_device,
+- .eh_bus_reset_handler = megasas_reset_bus_host,
+- .eh_host_reset_handler = megasas_reset_bus_host,
+- .eh_timed_out = megasas_reset_timer,
+- .bios_param = megasas_bios_param,
+- .use_clustering = ENABLE_CLUSTERING,
+-};
+-
+-/**
+- * megasas_complete_int_cmd - Completes an internal command
+- * @instance: Adapter soft state
+- * @cmd: Command to be completed
+- *
+- * The megasas_issue_blocked_cmd() function waits for a command to complete
+- * after it issues a command. This function wakes up that waiting routine by
+- * calling wake_up() on the wait queue.
+- */
+-static void
+-megasas_complete_int_cmd(struct megasas_instance *instance,
+- struct megasas_cmd *cmd)
+-{
+- cmd->cmd_status = cmd->frame->io.cmd_status;
+-
+- if (cmd->cmd_status == ENODATA) {
+- cmd->cmd_status = 0;
+- }
+- wake_up(&instance->int_cmd_wait_q);
+-}
+-
+-/**
+- * megasas_complete_abort - Completes aborting a command
+- * @instance: Adapter soft state
+- * @cmd: Cmd that was issued to abort another cmd
+- *
+- * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q
+- * after it issues an abort on a previously issued command. This function
+- * wakes up all functions waiting on the same wait queue.
+- */
+-static void
+-megasas_complete_abort(struct megasas_instance *instance,
+- struct megasas_cmd *cmd)
+-{
+- if (cmd->sync_cmd) {
+- cmd->sync_cmd = 0;
+- cmd->cmd_status = 0;
+- wake_up(&instance->abort_cmd_wait_q);
+- }
+-
+- return;
+-}
+-
+-/**
+- * megasas_complete_cmd - Completes a command
+- * @instance: Adapter soft state
+- * @cmd: Command to be completed
+- * @alt_status: If non-zero, use this value as status to
+- * SCSI mid-layer instead of the value returned
+- * by the FW. This should be used if caller wants
+- * an alternate status (as in the case of aborted
+- * commands)
+- */
+-static void
+-megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+- u8 alt_status)
+-{
+- int exception = 0;
+- struct megasas_header *hdr = &cmd->frame->hdr;
+- unsigned long flags;
+-
+- /* flag for the retry reset */
+- cmd->retry_for_fw_reset = 0;
+-
+- if (cmd->scmd)
+- cmd->scmd->SCp.ptr = NULL;
+-
+- switch (hdr->cmd) {
+-
+- case MFI_CMD_PD_SCSI_IO:
+- case MFI_CMD_LD_SCSI_IO:
+-
+- /*
+- * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been
+- * issued either through an IO path or an IOCTL path. If it
+- * was via IOCTL, we will send it to internal completion.
+- */
+- if (cmd->sync_cmd) {
+- cmd->sync_cmd = 0;
+- megasas_complete_int_cmd(instance, cmd);
+- break;
+- }
+-
+- case MFI_CMD_LD_READ:
+- case MFI_CMD_LD_WRITE:
+-
+- if (alt_status) {
+- cmd->scmd->result = alt_status << 16;
+- exception = 1;
+- }
+-
+- if (exception) {
+-
+- atomic_dec(&instance->fw_outstanding);
+-
+- scsi_dma_unmap(cmd->scmd);
+- cmd->scmd->scsi_done(cmd->scmd);
+- megasas_return_cmd(instance, cmd);
+-
+- break;
+- }
+-
+- switch (hdr->cmd_status) {
+-
+- case MFI_STAT_OK:
+- cmd->scmd->result = DID_OK << 16;
+- break;
+-
+- case MFI_STAT_SCSI_IO_FAILED:
+- case MFI_STAT_LD_INIT_IN_PROGRESS:
+- cmd->scmd->result =
+- (DID_ERROR << 16) | hdr->scsi_status;
+- break;
+-
+- case MFI_STAT_SCSI_DONE_WITH_ERROR:
+-
+- cmd->scmd->result = (DID_OK << 16) | hdr->scsi_status;
+-
+- if (hdr->scsi_status == SAM_STAT_CHECK_CONDITION) {
+- memset(cmd->scmd->sense_buffer, 0,
+- SCSI_SENSE_BUFFERSIZE);
+- memcpy(cmd->scmd->sense_buffer, cmd->sense,
+- hdr->sense_len);
+-
+- cmd->scmd->result |= DRIVER_SENSE << 24;
+- }
+-
+- break;
+-
+- case MFI_STAT_LD_OFFLINE:
+- case MFI_STAT_DEVICE_NOT_FOUND:
+- cmd->scmd->result = DID_BAD_TARGET << 16;
+- break;
+-
+- default:
+- printk(KERN_DEBUG "megasas: MFI FW status %#x\n",
+- hdr->cmd_status);
+- cmd->scmd->result = DID_ERROR << 16;
+- break;
+- }
+-
+- atomic_dec(&instance->fw_outstanding);
+-
+- scsi_dma_unmap(cmd->scmd);
+- cmd->scmd->scsi_done(cmd->scmd);
+- megasas_return_cmd(instance, cmd);
+-
+- break;
+-
+- case MFI_CMD_SMP:
+- case MFI_CMD_STP:
+- case MFI_CMD_DCMD:
+- if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
+- cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
+- spin_lock_irqsave(&poll_aen_lock, flags);
+- megasas_poll_wait_aen = 0;
+- spin_unlock_irqrestore(&poll_aen_lock, flags);
+- }
+-
+- /*
+- * See if got an event notification
+- */
+- if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_WAIT)
+- megasas_service_aen(instance, cmd);
+- else
+- megasas_complete_int_cmd(instance, cmd);
+-
+- break;
+-
+- case MFI_CMD_ABORT:
+- /*
+- * Cmd issued to abort another cmd returned
+- */
+- megasas_complete_abort(instance, cmd);
+- break;
+-
+- default:
+- printk("megasas: Unknown command completed! [0x%X]\n",
+- hdr->cmd);
+- break;
+- }
+-}
+-
+-/**
+- * megasas_issue_pending_cmds_again - issue all pending cmds
+- * in FW again because of the fw reset
+- * @instance: Adapter soft state
+- */
+-static inline void
+-megasas_issue_pending_cmds_again(struct megasas_instance *instance)
+-{
+- struct megasas_cmd *cmd;
+- struct list_head clist_local;
+- union megasas_evt_class_locale class_locale;
+- unsigned long flags;
+- u32 seq_num;
+-
+- INIT_LIST_HEAD(&clist_local);
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- list_splice_init(&instance->internal_reset_pending_q, &clist_local);
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-
+- while (!list_empty(&clist_local)) {
+- cmd = list_entry((&clist_local)->next,
+- struct megasas_cmd, list);
+- list_del_init(&cmd->list);
+-
+- if (cmd->sync_cmd || cmd->scmd) {
+- printk(KERN_NOTICE "megaraid_sas: command %p, %p:%d"
+- "detected to be pending while HBA reset.\n",
+- cmd, cmd->scmd, cmd->sync_cmd);
+-
+- cmd->retry_for_fw_reset++;
+-
+- if (cmd->retry_for_fw_reset == 3) {
+- printk(KERN_NOTICE "megaraid_sas: cmd %p, %p:%d"
+- "was tried multiple times during reset."
+- "Shutting down the HBA\n",
+- cmd, cmd->scmd, cmd->sync_cmd);
+- megaraid_sas_kill_hba(instance);
+-
+- instance->adprecovery =
+- MEGASAS_HW_CRITICAL_ERROR;
+- return;
+- }
+- }
+-
+- if (cmd->sync_cmd == 1) {
+- if (cmd->scmd) {
+- printk(KERN_NOTICE "megaraid_sas: unexpected"
+- "cmd attached to internal command!\n");
+- }
+- printk(KERN_NOTICE "megasas: %p synchronous cmd"
+- "on the internal reset queue,"
+- "issue it again.\n", cmd);
+- cmd->cmd_status = ENODATA;
+- instance->instancet->fire_cmd(instance,
+- cmd->frame_phys_addr ,
+- 0, instance->reg_set);
+- } else if (cmd->scmd) {
+- printk(KERN_NOTICE "megasas: %p scsi cmd [%02x],%#lx"
+- "detected on the internal queue, issue again.\n",
+- cmd, cmd->scmd->cmnd[0], cmd->scmd->serial_number);
+-
+- atomic_inc(&instance->fw_outstanding);
+- instance->instancet->fire_cmd(instance,
+- cmd->frame_phys_addr,
+- cmd->frame_count-1, instance->reg_set);
+- } else {
+- printk(KERN_NOTICE "megasas: %p unexpected cmd on the"
+- "internal reset defer list while re-issue!!\n",
+- cmd);
+- }
+- }
+-
+- if (instance->aen_cmd) {
+- printk(KERN_NOTICE "megaraid_sas: aen_cmd in def process\n");
+- megasas_return_cmd(instance, instance->aen_cmd);
+-
+- instance->aen_cmd = NULL;
+- }
+-
+- /*
+- * Initiate AEN (Asynchronous Event Notification)
+- */
+- seq_num = instance->last_seq_num;
+- class_locale.members.reserved = 0;
+- class_locale.members.locale = MR_EVT_LOCALE_ALL;
+- class_locale.members.class = MR_EVT_CLASS_DEBUG;
+-
+- megasas_register_aen(instance, seq_num, class_locale.word);
+-}
+-
+-/**
+- * Move the internal reset pending commands to a deferred queue.
+- *
+- * We move the commands pending at internal reset time to a
+- * pending queue. This queue would be flushed after successful
+- * completion of the internal reset sequence. if the internal reset
+- * did not complete in time, the kernel reset handler would flush
+- * these commands.
+- **/
+-static void
+-megasas_internal_reset_defer_cmds(struct megasas_instance *instance)
+-{
+- struct megasas_cmd *cmd;
+- int i;
+- u32 max_cmd = instance->max_fw_cmds;
+- u32 defer_index;
+- unsigned long flags;
+-
+- defer_index = 0;
+- spin_lock_irqsave(&instance->cmd_pool_lock, flags);
+- for (i = 0; i < max_cmd; i++) {
+- cmd = instance->cmd_list[i];
+- if (cmd->sync_cmd == 1 || cmd->scmd) {
+- printk(KERN_NOTICE "megasas: moving cmd[%d]:%p:%d:%p"
+- "on the defer queue as internal\n",
+- defer_index, cmd, cmd->sync_cmd, cmd->scmd);
+-
+- if (!list_empty(&cmd->list)) {
+- printk(KERN_NOTICE "megaraid_sas: ERROR while"
+- " moving this cmd:%p, %d %p, it was"
+- "discovered on some list?\n",
+- cmd, cmd->sync_cmd, cmd->scmd);
+-
+- list_del_init(&cmd->list);
+- }
+- defer_index++;
+- list_add_tail(&cmd->list,
+- &instance->internal_reset_pending_q);
+- }
+- }
+- spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
+-}
+-
+-
+-static void
+-process_fw_state_change_wq(struct work_struct *work)
+-{
+- struct megasas_instance *instance =
+- container_of(work, struct megasas_instance, work_init);
+- u32 wait;
+- unsigned long flags;
+-
+- if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) {
+- printk(KERN_NOTICE "megaraid_sas: error, recovery st %x \n",
+- instance->adprecovery);
+- return ;
+- }
+-
+- if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+- printk(KERN_NOTICE "megaraid_sas: FW detected to be in fault"
+- "state, restarting it...\n");
+-
+- instance->instancet->disable_intr(instance->reg_set);
+- atomic_set(&instance->fw_outstanding, 0);
+-
+- atomic_set(&instance->fw_reset_no_pci_access, 1);
+- instance->instancet->adp_reset(instance, instance->reg_set);
+- atomic_set(&instance->fw_reset_no_pci_access, 0 );
+-
+- printk(KERN_NOTICE "megaraid_sas: FW restarted successfully,"
+- "initiating next stage...\n");
+-
+- printk(KERN_NOTICE "megaraid_sas: HBA recovery state machine,"
+- "state 2 starting...\n");
+-
+- /*waitting for about 20 second before start the second init*/
+- for (wait = 0; wait < 30; wait++) {
+- msleep(1000);
+- }
+-
+- if (megasas_transition_to_ready(instance)) {
+- printk(KERN_NOTICE "megaraid_sas:adapter not ready\n");
+-
+- megaraid_sas_kill_hba(instance);
+- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
+- return ;
+- }
+-
+- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
+- (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
+- (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)
+- ) {
+- *instance->consumer = *instance->producer;
+- } else {
+- *instance->consumer = 0;
+- *instance->producer = 0;
+- }
+-
+- megasas_issue_init_mfi(instance);
+-
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+- instance->instancet->enable_intr(instance->reg_set);
+-
+- megasas_issue_pending_cmds_again(instance);
+- instance->issuepend_done = 1;
+- }
+- return ;
+-}
+-
+-/**
+- * megasas_deplete_reply_queue - Processes all completed commands
+- * @instance: Adapter soft state
+- * @alt_status: Alternate status to be returned to
+- * SCSI mid-layer instead of the status
+- * returned by the FW
+- * Note: this must be called with hba lock held
+- */
+-static int
+-megasas_deplete_reply_queue(struct megasas_instance *instance,
+- u8 alt_status)
+-{
+- u32 mfiStatus;
+- u32 fw_state;
+-
+- if ((mfiStatus = instance->instancet->check_reset(instance,
+- instance->reg_set)) == 1) {
+- return IRQ_HANDLED;
+- }
+-
+- if ((mfiStatus = instance->instancet->clear_intr(
+- instance->reg_set)
+- ) == 0) {
+- return IRQ_NONE;
+- }
+-
+- instance->mfiStatus = mfiStatus;
+-
+- if ((mfiStatus & MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE)) {
+- fw_state = instance->instancet->read_fw_status_reg(
+- instance->reg_set) & MFI_STATE_MASK;
+-
+- if (fw_state != MFI_STATE_FAULT) {
+- printk(KERN_NOTICE "megaraid_sas: fw state:%x\n",
+- fw_state);
+- }
+-
+- if ((fw_state == MFI_STATE_FAULT) &&
+- (instance->disableOnlineCtrlReset == 0)) {
+- printk(KERN_NOTICE "megaraid_sas: wait adp restart\n");
+-
+- if ((instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS1064R) ||
+- (instance->pdev->device ==
+- PCI_DEVICE_ID_DELL_PERC5) ||
+- (instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
+-
+- *instance->consumer =
+- MEGASAS_ADPRESET_INPROG_SIGN;
+- }
+-
+-
+- instance->instancet->disable_intr(instance->reg_set);
+- instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+- instance->issuepend_done = 0;
+-
+- atomic_set(&instance->fw_outstanding, 0);
+- megasas_internal_reset_defer_cmds(instance);
+-
+- printk(KERN_NOTICE "megasas: fwState=%x, stage:%d\n",
+- fw_state, instance->adprecovery);
+-
+- schedule_work(&instance->work_init);
+- return IRQ_HANDLED;
+-
+- } else {
+- printk(KERN_NOTICE "megasas: fwstate:%x, dis_OCR=%x\n",
+- fw_state, instance->disableOnlineCtrlReset);
+- }
+- }
+-
+- tasklet_schedule(&instance->isr_tasklet);
+- return IRQ_HANDLED;
+-}
+-/**
+- * megasas_isr - isr entry point
+- */
+-static irqreturn_t megasas_isr(int irq, void *devp)
+-{
+- struct megasas_instance *instance;
+- unsigned long flags;
+- irqreturn_t rc;
+-
+- if (atomic_read(
+- &(((struct megasas_instance *)devp)->fw_reset_no_pci_access)))
+- return IRQ_HANDLED;
+-
+- instance = (struct megasas_instance *)devp;
+-
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- rc = megasas_deplete_reply_queue(instance, DID_OK);
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-
+- return rc;
+-}
+-
+-/**
+- * megasas_transition_to_ready - Move the FW to READY state
+- * @instance: Adapter soft state
+- *
+- * During the initialization, FW passes can potentially be in any one of
+- * several possible states. If the FW in operational, waiting-for-handshake
+- * states, driver must take steps to bring it to ready state. Otherwise, it
+- * has to wait for the ready state.
+- */
+-static int
+-megasas_transition_to_ready(struct megasas_instance* instance)
+-{
+- int i;
+- u8 max_wait;
+- u32 fw_state;
+- u32 cur_state;
+-
+- fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+-
+- if (fw_state != MFI_STATE_READY)
+- printk(KERN_INFO "megasas: Waiting for FW to come to ready"
+- " state\n");
+-
+- while (fw_state != MFI_STATE_READY) {
+-
+- switch (fw_state) {
+-
+- case MFI_STATE_FAULT:
+-
+- printk(KERN_DEBUG "megasas: FW in FAULT state!!\n");
+- return -ENODEV;
+-
+- case MFI_STATE_WAIT_HANDSHAKE:
+- /*
+- * Set the CLR bit in inbound doorbell
+- */
+- if ((instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+-
+- writel(
+- MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+- &instance->reg_set->reserved_0[0]);
+- } else {
+- writel(
+- MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+- &instance->reg_set->inbound_doorbell);
+- }
+-
+- max_wait = 2;
+- cur_state = MFI_STATE_WAIT_HANDSHAKE;
+- break;
+-
+- case MFI_STATE_BOOT_MESSAGE_PENDING:
+- if ((instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+- writel(MFI_INIT_HOTPLUG,
+- &instance->reg_set->reserved_0[0]);
+- } else
+- writel(MFI_INIT_HOTPLUG,
+- &instance->reg_set->inbound_doorbell);
+-
+- max_wait = 10;
+- cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
+- break;
+-
+- case MFI_STATE_OPERATIONAL:
+- /*
+- * Bring it to READY state; assuming max wait 10 secs
+- */
+- instance->instancet->disable_intr(instance->reg_set);
+- if ((instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+- writel(MFI_RESET_FLAGS,
+- &instance->reg_set->reserved_0[0]);
+- } else
+- writel(MFI_RESET_FLAGS,
+- &instance->reg_set->inbound_doorbell);
+-
+- max_wait = 60;
+- cur_state = MFI_STATE_OPERATIONAL;
+- break;
+-
+- case MFI_STATE_UNDEFINED:
+- /*
+- * This state should not last for more than 2 seconds
+- */
+- max_wait = 2;
+- cur_state = MFI_STATE_UNDEFINED;
+- break;
+-
+- case MFI_STATE_BB_INIT:
+- max_wait = 2;
+- cur_state = MFI_STATE_BB_INIT;
+- break;
+-
+- case MFI_STATE_FW_INIT:
+- max_wait = 20;
+- cur_state = MFI_STATE_FW_INIT;
+- break;
+-
+- case MFI_STATE_FW_INIT_2:
+- max_wait = 20;
+- cur_state = MFI_STATE_FW_INIT_2;
+- break;
+-
+- case MFI_STATE_DEVICE_SCAN:
+- max_wait = 20;
+- cur_state = MFI_STATE_DEVICE_SCAN;
+- break;
+-
+- case MFI_STATE_FLUSH_CACHE:
+- max_wait = 20;
+- cur_state = MFI_STATE_FLUSH_CACHE;
+- break;
+-
+- default:
+- printk(KERN_DEBUG "megasas: Unknown state 0x%x\n",
+- fw_state);
+- return -ENODEV;
+- }
+-
+- /*
+- * The cur_state should not last for more than max_wait secs
+- */
+- for (i = 0; i < (max_wait * 1000); i++) {
+- fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &
+- MFI_STATE_MASK ;
+-
+- if (fw_state == cur_state) {
+- msleep(1);
+- } else
+- break;
+- }
+-
+- /*
+- * Return error if fw_state hasn't changed after max_wait
+- */
+- if (fw_state == cur_state) {
+- printk(KERN_DEBUG "FW state [%d] hasn't changed "
+- "in %d secs\n", fw_state, max_wait);
+- return -ENODEV;
+- }
+- }
+- printk(KERN_INFO "megasas: FW now in Ready state\n");
+-
+- return 0;
+-}
+-
+-/**
+- * megasas_teardown_frame_pool - Destroy the cmd frame DMA pool
+- * @instance: Adapter soft state
+- */
+-static void megasas_teardown_frame_pool(struct megasas_instance *instance)
+-{
+- int i;
+- u32 max_cmd = instance->max_fw_cmds;
+- struct megasas_cmd *cmd;
+-
+- if (!instance->frame_dma_pool)
+- return;
+-
+- /*
+- * Return all frames to pool
+- */
+- for (i = 0; i < max_cmd; i++) {
+-
+- cmd = instance->cmd_list[i];
+-
+- if (cmd->frame)
+- pci_pool_free(instance->frame_dma_pool, cmd->frame,
+- cmd->frame_phys_addr);
+-
+- if (cmd->sense)
+- pci_pool_free(instance->sense_dma_pool, cmd->sense,
+- cmd->sense_phys_addr);
+- }
+-
+- /*
+- * Now destroy the pool itself
+- */
+- pci_pool_destroy(instance->frame_dma_pool);
+- pci_pool_destroy(instance->sense_dma_pool);
+-
+- instance->frame_dma_pool = NULL;
+- instance->sense_dma_pool = NULL;
+-}
+-
+-/**
+- * megasas_create_frame_pool - Creates DMA pool for cmd frames
+- * @instance: Adapter soft state
+- *
+- * Each command packet has an embedded DMA memory buffer that is used for
+- * filling MFI frame and the SG list that immediately follows the frame. This
+- * function creates those DMA memory buffers for each command packet by using
+- * PCI pool facility.
+- */
+-static int megasas_create_frame_pool(struct megasas_instance *instance)
+-{
+- int i;
+- u32 max_cmd;
+- u32 sge_sz;
+- u32 sgl_sz;
+- u32 total_sz;
+- u32 frame_count;
+- struct megasas_cmd *cmd;
+-
+- max_cmd = instance->max_fw_cmds;
+-
+- /*
+- * Size of our frame is 64 bytes for MFI frame, followed by max SG
+- * elements and finally SCSI_SENSE_BUFFERSIZE bytes for sense buffer
+- */
+- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+- sizeof(struct megasas_sge32);
+-
+- if (instance->flag_ieee) {
+- sge_sz = sizeof(struct megasas_sge_skinny);
+- }
+-
+- /*
+- * Calculated the number of 64byte frames required for SGL
+- */
+- sgl_sz = sge_sz * instance->max_num_sge;
+- frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE;
+- frame_count = 15;
+-
+- /*
+- * We need one extra frame for the MFI command
+- */
+- frame_count++;
+-
+- total_sz = MEGAMFI_FRAME_SIZE * frame_count;
+- /*
+- * Use DMA pool facility provided by PCI layer
+- */
+- instance->frame_dma_pool = pci_pool_create("megasas frame pool",
+- instance->pdev, total_sz, 64,
+- 0);
+-
+- if (!instance->frame_dma_pool) {
+- printk(KERN_DEBUG "megasas: failed to setup frame pool\n");
+- return -ENOMEM;
+- }
+-
+- instance->sense_dma_pool = pci_pool_create("megasas sense pool",
+- instance->pdev, 128, 4, 0);
+-
+- if (!instance->sense_dma_pool) {
+- printk(KERN_DEBUG "megasas: failed to setup sense pool\n");
+-
+- pci_pool_destroy(instance->frame_dma_pool);
+- instance->frame_dma_pool = NULL;
+-
+- return -ENOMEM;
+- }
+-
+- /*
+- * Allocate and attach a frame to each of the commands in cmd_list.
+- * By making cmd->index as the context instead of the &cmd, we can
+- * always use 32bit context regardless of the architecture
+- */
+- for (i = 0; i < max_cmd; i++) {
+-
+- cmd = instance->cmd_list[i];
+-
+- cmd->frame = pci_pool_alloc(instance->frame_dma_pool,
+- GFP_KERNEL, &cmd->frame_phys_addr);
+-
+- cmd->sense = pci_pool_alloc(instance->sense_dma_pool,
+- GFP_KERNEL, &cmd->sense_phys_addr);
+-
+- /*
+- * megasas_teardown_frame_pool() takes care of freeing
+- * whatever has been allocated
+- */
+- if (!cmd->frame || !cmd->sense) {
+- printk(KERN_DEBUG "megasas: pci_pool_alloc failed \n");
+- megasas_teardown_frame_pool(instance);
+- return -ENOMEM;
+- }
+-
+- cmd->frame->io.context = cmd->index;
+- cmd->frame->io.pad_0 = 0;
+- }
+-
+- return 0;
+-}
+-
+-/**
+- * megasas_free_cmds - Free all the cmds in the free cmd pool
+- * @instance: Adapter soft state
+- */
+-static void megasas_free_cmds(struct megasas_instance *instance)
+-{
+- int i;
+- /* First free the MFI frame pool */
+- megasas_teardown_frame_pool(instance);
+-
+- /* Free all the commands in the cmd_list */
+- for (i = 0; i < instance->max_fw_cmds; i++)
+- kfree(instance->cmd_list[i]);
+-
+- /* Free the cmd_list buffer itself */
+- kfree(instance->cmd_list);
+- instance->cmd_list = NULL;
+-
+- INIT_LIST_HEAD(&instance->cmd_pool);
+-}
+-
+-/**
+- * megasas_alloc_cmds - Allocates the command packets
+- * @instance: Adapter soft state
+- *
+- * Each command that is issued to the FW, whether IO commands from the OS or
+- * internal commands like IOCTLs, are wrapped in local data structure called
+- * megasas_cmd. The frame embedded in this megasas_cmd is actually issued to
+- * the FW.
+- *
+- * Each frame has a 32-bit field called context (tag). This context is used
+- * to get back the megasas_cmd from the frame when a frame gets completed in
+- * the ISR. Typically the address of the megasas_cmd itself would be used as
+- * the context. But we wanted to keep the differences between 32 and 64 bit
+- * systems to the mininum. We always use 32 bit integers for the context. In
+- * this driver, the 32 bit values are the indices into an array cmd_list.
+- * This array is used only to look up the megasas_cmd given the context. The
+- * free commands themselves are maintained in a linked list called cmd_pool.
+- */
+-static int megasas_alloc_cmds(struct megasas_instance *instance)
+-{
+- int i;
+- int j;
+- u32 max_cmd;
+- struct megasas_cmd *cmd;
+-
+- max_cmd = instance->max_fw_cmds;
+-
+- /*
+- * instance->cmd_list is an array of struct megasas_cmd pointers.
+- * Allocate the dynamic array first and then allocate individual
+- * commands.
+- */
+- instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL);
+-
+- if (!instance->cmd_list) {
+- printk(KERN_DEBUG "megasas: out of memory\n");
+- return -ENOMEM;
+- }
+-
+-
+- for (i = 0; i < max_cmd; i++) {
+- instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
+- GFP_KERNEL);
+-
+- if (!instance->cmd_list[i]) {
+-
+- for (j = 0; j < i; j++)
+- kfree(instance->cmd_list[j]);
+-
+- kfree(instance->cmd_list);
+- instance->cmd_list = NULL;
+-
+- return -ENOMEM;
+- }
+- }
+-
+- /*
+- * Add all the commands to command pool (instance->cmd_pool)
+- */
+- for (i = 0; i < max_cmd; i++) {
+- cmd = instance->cmd_list[i];
+- memset(cmd, 0, sizeof(struct megasas_cmd));
+- cmd->index = i;
+- cmd->scmd = NULL;
+- cmd->instance = instance;
+-
+- list_add_tail(&cmd->list, &instance->cmd_pool);
+- }
+-
+- /*
+- * Create a frame pool and assign one frame to each cmd
+- */
+- if (megasas_create_frame_pool(instance)) {
+- printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n");
+- megasas_free_cmds(instance);
+- }
+-
+- return 0;
+-}
+-
+-/*
+- * megasas_get_pd_list_info - Returns FW's pd_list structure
+- * @instance: Adapter soft state
+- * @pd_list: pd_list structure
+- *
+- * Issues an internal command (DCMD) to get the FW's controller PD
+- * list structure. This information is mainly used to find out SYSTEM
+- * supported by the FW.
+- */
+-static int
+-megasas_get_pd_list(struct megasas_instance *instance)
+-{
+- int ret = 0, pd_index = 0;
+- struct megasas_cmd *cmd;
+- struct megasas_dcmd_frame *dcmd;
+- struct MR_PD_LIST *ci;
+- struct MR_PD_ADDRESS *pd_addr;
+- dma_addr_t ci_h = 0;
+-
+- cmd = megasas_get_cmd(instance);
+-
+- if (!cmd) {
+- printk(KERN_DEBUG "megasas (get_pd_list): Failed to get cmd\n");
+- return -ENOMEM;
+- }
+-
+- dcmd = &cmd->frame->dcmd;
+-
+- ci = pci_alloc_consistent(instance->pdev,
+- MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), &ci_h);
+-
+- if (!ci) {
+- printk(KERN_DEBUG "Failed to alloc mem for pd_list\n");
+- megasas_return_cmd(instance, cmd);
+- return -ENOMEM;
+- }
+-
+- memset(ci, 0, sizeof(*ci));
+- memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+-
+- dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
+- dcmd->mbox.b[1] = 0;
+- dcmd->cmd = MFI_CMD_DCMD;
+- dcmd->cmd_status = 0xFF;
+- dcmd->sge_count = 1;
+- dcmd->flags = MFI_FRAME_DIR_READ;
+- dcmd->timeout = 0;
+- dcmd->data_xfer_len = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
+- dcmd->opcode = MR_DCMD_PD_LIST_QUERY;
+- dcmd->sgl.sge32[0].phys_addr = ci_h;
+- dcmd->sgl.sge32[0].length = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
+-
+- if (!megasas_issue_polled(instance, cmd)) {
+- ret = 0;
+- } else {
+- ret = -1;
+- }
+-
+- /*
+- * the following function will get the instance PD LIST.
+- */
+-
+- pd_addr = ci->addr;
+-
+- if ( ret == 0 &&
+- (ci->count <
+- (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) {
+-
+- memset(instance->pd_list, 0,
+- MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
+-
+- for (pd_index = 0; pd_index < ci->count; pd_index++) {
+-
+- instance->pd_list[pd_addr->deviceId].tid =
+- pd_addr->deviceId;
+- instance->pd_list[pd_addr->deviceId].driveType =
+- pd_addr->scsiDevType;
+- instance->pd_list[pd_addr->deviceId].driveState =
+- MR_PD_STATE_SYSTEM;
+- pd_addr++;
+- }
+- }
+-
+- pci_free_consistent(instance->pdev,
+- MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
+- ci, ci_h);
+- megasas_return_cmd(instance, cmd);
+-
+- return ret;
+-}
+-
+-/*
+- * megasas_get_ld_list_info - Returns FW's ld_list structure
+- * @instance: Adapter soft state
+- * @ld_list: ld_list structure
+- *
+- * Issues an internal command (DCMD) to get the FW's controller PD
+- * list structure. This information is mainly used to find out SYSTEM
+- * supported by the FW.
+- */
+-static int
+-megasas_get_ld_list(struct megasas_instance *instance)
+-{
+- int ret = 0, ld_index = 0, ids = 0;
+- struct megasas_cmd *cmd;
+- struct megasas_dcmd_frame *dcmd;
+- struct MR_LD_LIST *ci;
+- dma_addr_t ci_h = 0;
+-
+- cmd = megasas_get_cmd(instance);
+-
+- if (!cmd) {
+- printk(KERN_DEBUG "megasas_get_ld_list: Failed to get cmd\n");
+- return -ENOMEM;
+- }
+-
+- dcmd = &cmd->frame->dcmd;
+-
+- ci = pci_alloc_consistent(instance->pdev,
+- sizeof(struct MR_LD_LIST),
+- &ci_h);
+-
+- if (!ci) {
+- printk(KERN_DEBUG "Failed to alloc mem in get_ld_list\n");
+- megasas_return_cmd(instance, cmd);
+- return -ENOMEM;
+- }
+-
+- memset(ci, 0, sizeof(*ci));
+- memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+-
+- dcmd->cmd = MFI_CMD_DCMD;
+- dcmd->cmd_status = 0xFF;
+- dcmd->sge_count = 1;
+- dcmd->flags = MFI_FRAME_DIR_READ;
+- dcmd->timeout = 0;
+- dcmd->data_xfer_len = sizeof(struct MR_LD_LIST);
+- dcmd->opcode = MR_DCMD_LD_GET_LIST;
+- dcmd->sgl.sge32[0].phys_addr = ci_h;
+- dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST);
+- dcmd->pad_0 = 0;
+-
+- if (!megasas_issue_polled(instance, cmd)) {
+- ret = 0;
+- } else {
+- ret = -1;
+- }
+-
+- /* the following function will get the instance PD LIST */
+-
+- if ((ret == 0) && (ci->ldCount <= MAX_LOGICAL_DRIVES)) {
+- memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
+-
+- for (ld_index = 0; ld_index < ci->ldCount; ld_index++) {
+- if (ci->ldList[ld_index].state != 0) {
+- ids = ci->ldList[ld_index].ref.targetId;
+- instance->ld_ids[ids] =
+- ci->ldList[ld_index].ref.targetId;
+- }
+- }
+- }
+-
+- pci_free_consistent(instance->pdev,
+- sizeof(struct MR_LD_LIST),
+- ci,
+- ci_h);
+-
+- megasas_return_cmd(instance, cmd);
+- return ret;
+-}
+-
+-/**
+- * megasas_get_controller_info - Returns FW's controller structure
+- * @instance: Adapter soft state
+- * @ctrl_info: Controller information structure
+- *
+- * Issues an internal command (DCMD) to get the FW's controller structure.
+- * This information is mainly used to find out the maximum IO transfer per
+- * command supported by the FW.
+- */
+-static int
+-megasas_get_ctrl_info(struct megasas_instance *instance,
+- struct megasas_ctrl_info *ctrl_info)
+-{
+- int ret = 0;
+- struct megasas_cmd *cmd;
+- struct megasas_dcmd_frame *dcmd;
+- struct megasas_ctrl_info *ci;
+- dma_addr_t ci_h = 0;
+-
+- cmd = megasas_get_cmd(instance);
+-
+- if (!cmd) {
+- printk(KERN_DEBUG "megasas: Failed to get a free cmd\n");
+- return -ENOMEM;
+- }
+-
+- dcmd = &cmd->frame->dcmd;
+-
+- ci = pci_alloc_consistent(instance->pdev,
+- sizeof(struct megasas_ctrl_info), &ci_h);
+-
+- if (!ci) {
+- printk(KERN_DEBUG "Failed to alloc mem for ctrl info\n");
+- megasas_return_cmd(instance, cmd);
+- return -ENOMEM;
+- }
+-
+- memset(ci, 0, sizeof(*ci));
+- memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+-
+- dcmd->cmd = MFI_CMD_DCMD;
+- dcmd->cmd_status = 0xFF;
+- dcmd->sge_count = 1;
+- dcmd->flags = MFI_FRAME_DIR_READ;
+- dcmd->timeout = 0;
+- dcmd->data_xfer_len = sizeof(struct megasas_ctrl_info);
+- dcmd->opcode = MR_DCMD_CTRL_GET_INFO;
+- dcmd->sgl.sge32[0].phys_addr = ci_h;
+- dcmd->sgl.sge32[0].length = sizeof(struct megasas_ctrl_info);
+-
+- if (!megasas_issue_polled(instance, cmd)) {
+- ret = 0;
+- memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info));
+- } else {
+- ret = -1;
+- }
+-
+- pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),
+- ci, ci_h);
+-
+- megasas_return_cmd(instance, cmd);
+- return ret;
+-}
+-
+-/**
+- * megasas_issue_init_mfi - Initializes the FW
+- * @instance: Adapter soft state
+- *
+- * Issues the INIT MFI cmd
+- */
+-static int
+-megasas_issue_init_mfi(struct megasas_instance *instance)
+-{
+- u32 context;
+-
+- struct megasas_cmd *cmd;
+-
+- struct megasas_init_frame *init_frame;
+- struct megasas_init_queue_info *initq_info;
+- dma_addr_t init_frame_h;
+- dma_addr_t initq_info_h;
+-
+- /*
+- * Prepare a init frame. Note the init frame points to queue info
+- * structure. Each frame has SGL allocated after first 64 bytes. For
+- * this frame - since we don't need any SGL - we use SGL's space as
+- * queue info structure
+- *
+- * We will not get a NULL command below. We just created the pool.
+- */
+- cmd = megasas_get_cmd(instance);
+-
+- init_frame = (struct megasas_init_frame *)cmd->frame;
+- initq_info = (struct megasas_init_queue_info *)
+- ((unsigned long)init_frame + 64);
+-
+- init_frame_h = cmd->frame_phys_addr;
+- initq_info_h = init_frame_h + 64;
+-
+- context = init_frame->context;
+- memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
+- memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
+- init_frame->context = context;
+-
+- initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
+- initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
+-
+- initq_info->producer_index_phys_addr_lo = instance->producer_h;
+- initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
+-
+- init_frame->cmd = MFI_CMD_INIT;
+- init_frame->cmd_status = 0xFF;
+- init_frame->queue_info_new_phys_addr_lo = initq_info_h;
+-
+- init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
+-
+- /*
+- * disable the intr before firing the init frame to FW
+- */
+- instance->instancet->disable_intr(instance->reg_set);
+-
+- /*
+- * Issue the init frame in polled mode
+- */
+-
+- if (megasas_issue_polled(instance, cmd)) {
+- printk(KERN_ERR "megasas: Failed to init firmware\n");
+- megasas_return_cmd(instance, cmd);
+- goto fail_fw_init;
+- }
+-
+- megasas_return_cmd(instance, cmd);
+-
+- return 0;
+-
+-fail_fw_init:
+- return -EINVAL;
+-}
+-
+-/**
+- * megasas_start_timer - Initializes a timer object
+- * @instance: Adapter soft state
+- * @timer: timer object to be initialized
+- * @fn: timer function
+- * @interval: time interval between timer function call
+- */
+-static inline void
+-megasas_start_timer(struct megasas_instance *instance,
+- struct timer_list *timer,
+- void *fn, unsigned long interval)
+-{
+- init_timer(timer);
+- timer->expires = jiffies + interval;
+- timer->data = (unsigned long)instance;
+- timer->function = fn;
+- add_timer(timer);
+-}
+-
+-/**
+- * megasas_io_completion_timer - Timer fn
+- * @instance_addr: Address of adapter soft state
+- *
+- * Schedules tasklet for cmd completion
+- * if poll_mode_io is set
+- */
+-static void
+-megasas_io_completion_timer(unsigned long instance_addr)
+-{
+- struct megasas_instance *instance =
+- (struct megasas_instance *)instance_addr;
+-
+- if (atomic_read(&instance->fw_outstanding))
+- tasklet_schedule(&instance->isr_tasklet);
+-
+- /* Restart timer */
+- if (poll_mode_io)
+- mod_timer(&instance->io_completion_timer,
+- jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
+-}
+-
+-/**
+- * megasas_init_mfi - Initializes the FW
+- * @instance: Adapter soft state
+- *
+- * This is the main function for initializing MFI firmware.
+- */
+-static int megasas_init_mfi(struct megasas_instance *instance)
+-{
+- u32 context_sz;
+- u32 reply_q_sz;
+- u32 max_sectors_1;
+- u32 max_sectors_2;
+- u32 tmp_sectors;
+- struct megasas_register_set __iomem *reg_set;
+- struct megasas_ctrl_info *ctrl_info;
+- /*
+- * Map the message registers
+- */
+- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
+- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0079GEN2)) {
+- instance->base_addr = pci_resource_start(instance->pdev, 1);
+- } else {
+- instance->base_addr = pci_resource_start(instance->pdev, 0);
+- }
+-
+- if (pci_request_regions(instance->pdev, "megasas: LSI")) {
+- printk(KERN_DEBUG "megasas: IO memory region busy!\n");
+- return -EBUSY;
+- }
+-
+- instance->reg_set = ioremap_nocache(instance->base_addr, 8192);
+-
+- if (!instance->reg_set) {
+- printk(KERN_DEBUG "megasas: Failed to map IO mem\n");
+- goto fail_ioremap;
+- }
+-
+- reg_set = instance->reg_set;
+-
+- switch(instance->pdev->device)
+- {
+- case PCI_DEVICE_ID_LSI_SAS1078R:
+- case PCI_DEVICE_ID_LSI_SAS1078DE:
+- instance->instancet = &megasas_instance_template_ppc;
+- break;
+- case PCI_DEVICE_ID_LSI_SAS1078GEN2:
+- case PCI_DEVICE_ID_LSI_SAS0079GEN2:
+- instance->instancet = &megasas_instance_template_gen2;
+- break;
+- case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
+- case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
+- instance->instancet = &megasas_instance_template_skinny;
+- break;
+- case PCI_DEVICE_ID_LSI_SAS1064R:
+- case PCI_DEVICE_ID_DELL_PERC5:
+- default:
+- instance->instancet = &megasas_instance_template_xscale;
+- break;
+- }
+-
+- /*
+- * We expect the FW state to be READY
+- */
+- if (megasas_transition_to_ready(instance))
+- goto fail_ready_state;
+-
+- /*
+- * Get various operational parameters from status register
+- */
+- instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
+- /*
+- * Reduce the max supported cmds by 1. This is to ensure that the
+- * reply_q_sz (1 more than the max cmd that driver may send)
+- * does not exceed max cmds that the FW can support
+- */
+- instance->max_fw_cmds = instance->max_fw_cmds-1;
+- instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
+- 0x10;
+- /*
+- * Create a pool of commands
+- */
+- if (megasas_alloc_cmds(instance))
+- goto fail_alloc_cmds;
+-
+- /*
+- * Allocate memory for reply queue. Length of reply queue should
+- * be _one_ more than the maximum commands handled by the firmware.
+- *
+- * Note: When FW completes commands, it places corresponding contex
+- * values in this circular reply queue. This circular queue is a fairly
+- * typical producer-consumer queue. FW is the producer (of completed
+- * commands) and the driver is the consumer.
+- */
+- context_sz = sizeof(u32);
+- reply_q_sz = context_sz * (instance->max_fw_cmds + 1);
+-
+- instance->reply_queue = pci_alloc_consistent(instance->pdev,
+- reply_q_sz,
+- &instance->reply_queue_h);
+-
+- if (!instance->reply_queue) {
+- printk(KERN_DEBUG "megasas: Out of DMA mem for reply queue\n");
+- goto fail_reply_queue;
+- }
+-
+- if (megasas_issue_init_mfi(instance))
+- goto fail_fw_init;
+-
+- instance->fw_support_ieee = 0;
+- instance->fw_support_ieee =
+- (instance->instancet->read_fw_status_reg(reg_set) &
+- 0x04000000);
+-
+- printk(KERN_NOTICE "megasas_init_mfi: fw_support_ieee=%d",
+- instance->fw_support_ieee);
+-
+- if (instance->fw_support_ieee)
+- instance->flag_ieee = 1;
+-
+- /** for passthrough
+- * the following function will get the PD LIST.
+- */
+-
+- memset(instance->pd_list, 0 ,
+- (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
+- megasas_get_pd_list(instance);
+-
+- memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
+- megasas_get_ld_list(instance);
+-
+- ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
+-
+- /*
+- * Compute the max allowed sectors per IO: The controller info has two
+- * limits on max sectors. Driver should use the minimum of these two.
+- *
+- * 1 << stripe_sz_ops.min = max sectors per strip
+- *
+- * Note that older firmwares ( < FW ver 30) didn't report information
+- * to calculate max_sectors_1. So the number ended up as zero always.
+- */
+- tmp_sectors = 0;
+- if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) {
+-
+- max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
+- ctrl_info->max_strips_per_io;
+- max_sectors_2 = ctrl_info->max_request_size;
+-
+- tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2);
+- instance->disableOnlineCtrlReset =
+- ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
+- }
+-
+- instance->max_sectors_per_req = instance->max_num_sge *
+- PAGE_SIZE / 512;
+- if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
+- instance->max_sectors_per_req = tmp_sectors;
+-
+- kfree(ctrl_info);
+-
+- /*
+- * Setup tasklet for cmd completion
+- */
+-
+- tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+- (unsigned long)instance);
+-
+- /* Initialize the cmd completion timer */
+- if (poll_mode_io)
+- megasas_start_timer(instance, &instance->io_completion_timer,
+- megasas_io_completion_timer,
+- MEGASAS_COMPLETION_TIMER_INTERVAL);
+- return 0;
+-
+- fail_fw_init:
+-
+- pci_free_consistent(instance->pdev, reply_q_sz,
+- instance->reply_queue, instance->reply_queue_h);
+- fail_reply_queue:
+- megasas_free_cmds(instance);
+-
+- fail_alloc_cmds:
+- fail_ready_state:
+- iounmap(instance->reg_set);
+-
+- fail_ioremap:
+- pci_release_regions(instance->pdev);
+-
+- return -EINVAL;
+-}
+-
+-/**
+- * megasas_release_mfi - Reverses the FW initialization
+- * @intance: Adapter soft state
+- */
+-static void megasas_release_mfi(struct megasas_instance *instance)
+-{
+- u32 reply_q_sz = sizeof(u32) * (instance->max_fw_cmds + 1);
+-
+- pci_free_consistent(instance->pdev, reply_q_sz,
+- instance->reply_queue, instance->reply_queue_h);
+-
+- megasas_free_cmds(instance);
+-
+- iounmap(instance->reg_set);
+-
+- pci_release_regions(instance->pdev);
+-}
+-
+-/**
+- * megasas_get_seq_num - Gets latest event sequence numbers
+- * @instance: Adapter soft state
+- * @eli: FW event log sequence numbers information
+- *
+- * FW maintains a log of all events in a non-volatile area. Upper layers would
+- * usually find out the latest sequence number of the events, the seq number at
+- * the boot etc. They would "read" all the events below the latest seq number
+- * by issuing a direct fw cmd (DCMD). For the future events (beyond latest seq
+- * number), they would subsribe to AEN (asynchronous event notification) and
+- * wait for the events to happen.
+- */
+-static int
+-megasas_get_seq_num(struct megasas_instance *instance,
+- struct megasas_evt_log_info *eli)
+-{
+- struct megasas_cmd *cmd;
+- struct megasas_dcmd_frame *dcmd;
+- struct megasas_evt_log_info *el_info;
+- dma_addr_t el_info_h = 0;
+-
+- cmd = megasas_get_cmd(instance);
+-
+- if (!cmd) {
+- return -ENOMEM;
+- }
+-
+- dcmd = &cmd->frame->dcmd;
+- el_info = pci_alloc_consistent(instance->pdev,
+- sizeof(struct megasas_evt_log_info),
+- &el_info_h);
+-
+- if (!el_info) {
+- megasas_return_cmd(instance, cmd);
+- return -ENOMEM;
+- }
+-
+- memset(el_info, 0, sizeof(*el_info));
+- memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+-
+- dcmd->cmd = MFI_CMD_DCMD;
+- dcmd->cmd_status = 0x0;
+- dcmd->sge_count = 1;
+- dcmd->flags = MFI_FRAME_DIR_READ;
+- dcmd->timeout = 0;
+- dcmd->data_xfer_len = sizeof(struct megasas_evt_log_info);
+- dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;
+- dcmd->sgl.sge32[0].phys_addr = el_info_h;
+- dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_log_info);
+-
+- megasas_issue_blocked_cmd(instance, cmd);
+-
+- /*
+- * Copy the data back into callers buffer
+- */
+- memcpy(eli, el_info, sizeof(struct megasas_evt_log_info));
+-
+- pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),
+- el_info, el_info_h);
+-
+- megasas_return_cmd(instance, cmd);
+-
+- return 0;
+-}
+-
+-/**
+- * megasas_register_aen - Registers for asynchronous event notification
+- * @instance: Adapter soft state
+- * @seq_num: The starting sequence number
+- * @class_locale: Class of the event
+- *
+- * This function subscribes for AEN for events beyond the @seq_num. It requests
+- * to be notified if and only if the event is of type @class_locale
+- */
+-static int
+-megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
+- u32 class_locale_word)
+-{
+- int ret_val;
+- struct megasas_cmd *cmd;
+- struct megasas_dcmd_frame *dcmd;
+- union megasas_evt_class_locale curr_aen;
+- union megasas_evt_class_locale prev_aen;
+-
+- /*
+- * If there an AEN pending already (aen_cmd), check if the
+- * class_locale of that pending AEN is inclusive of the new
+- * AEN request we currently have. If it is, then we don't have
+- * to do anything. In other words, whichever events the current
+- * AEN request is subscribing to, have already been subscribed
+- * to.
+- *
+- * If the old_cmd is _not_ inclusive, then we have to abort
+- * that command, form a class_locale that is superset of both
+- * old and current and re-issue to the FW
+- */
+-
+- curr_aen.word = class_locale_word;
+-
+- if (instance->aen_cmd) {
+-
+- prev_aen.word = instance->aen_cmd->frame->dcmd.mbox.w[1];
+-
+- /*
+- * A class whose enum value is smaller is inclusive of all
+- * higher values. If a PROGRESS (= -1) was previously
+- * registered, then a new registration requests for higher
+- * classes need not be sent to FW. They are automatically
+- * included.
+- *
+- * Locale numbers don't have such hierarchy. They are bitmap
+- * values
+- */
+- if ((prev_aen.members.class <= curr_aen.members.class) &&
+- !((prev_aen.members.locale & curr_aen.members.locale) ^
+- curr_aen.members.locale)) {
+- /*
+- * Previously issued event registration includes
+- * current request. Nothing to do.
+- */
+- return 0;
+- } else {
+- curr_aen.members.locale |= prev_aen.members.locale;
+-
+- if (prev_aen.members.class < curr_aen.members.class)
+- curr_aen.members.class = prev_aen.members.class;
+-
+- instance->aen_cmd->abort_aen = 1;
+- ret_val = megasas_issue_blocked_abort_cmd(instance,
+- instance->
+- aen_cmd);
+-
+- if (ret_val) {
+- printk(KERN_DEBUG "megasas: Failed to abort "
+- "previous AEN command\n");
+- return ret_val;
+- }
+- }
+- }
+-
+- cmd = megasas_get_cmd(instance);
+-
+- if (!cmd)
+- return -ENOMEM;
+-
+- dcmd = &cmd->frame->dcmd;
+-
+- memset(instance->evt_detail, 0, sizeof(struct megasas_evt_detail));
+-
+- /*
+- * Prepare DCMD for aen registration
+- */
+- memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+-
+- dcmd->cmd = MFI_CMD_DCMD;
+- dcmd->cmd_status = 0x0;
+- dcmd->sge_count = 1;
+- dcmd->flags = MFI_FRAME_DIR_READ;
+- dcmd->timeout = 0;
+- instance->last_seq_num = seq_num;
+- dcmd->data_xfer_len = sizeof(struct megasas_evt_detail);
+- dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
+- dcmd->mbox.w[0] = seq_num;
+- dcmd->mbox.w[1] = curr_aen.word;
+- dcmd->sgl.sge32[0].phys_addr = (u32) instance->evt_detail_h;
+- dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_detail);
+-
+- if (instance->aen_cmd != NULL) {
+- megasas_return_cmd(instance, cmd);
+- return 0;
+- }
+-
+- /*
+- * Store reference to the cmd used to register for AEN. When an
+- * application wants us to register for AEN, we have to abort this
+- * cmd and re-register with a new EVENT LOCALE supplied by that app
+- */
+- instance->aen_cmd = cmd;
+-
+- /*
+- * Issue the aen registration frame
+- */
+- instance->instancet->fire_cmd(instance,
+- cmd->frame_phys_addr, 0, instance->reg_set);
+-
+- return 0;
+-}
+-
+-/**
+- * megasas_start_aen - Subscribes to AEN during driver load time
+- * @instance: Adapter soft state
+- */
+-static int megasas_start_aen(struct megasas_instance *instance)
+-{
+- struct megasas_evt_log_info eli;
+- union megasas_evt_class_locale class_locale;
+-
+- /*
+- * Get the latest sequence number from FW
+- */
+- memset(&eli, 0, sizeof(eli));
+-
+- if (megasas_get_seq_num(instance, &eli))
+- return -1;
+-
+- /*
+- * Register AEN with FW for latest sequence number plus 1
+- */
+- class_locale.members.reserved = 0;
+- class_locale.members.locale = MR_EVT_LOCALE_ALL;
+- class_locale.members.class = MR_EVT_CLASS_DEBUG;
+-
+- return megasas_register_aen(instance, eli.newest_seq_num + 1,
+- class_locale.word);
+-}
+-
+-/**
+- * megasas_io_attach - Attaches this driver to SCSI mid-layer
+- * @instance: Adapter soft state
+- */
+-static int megasas_io_attach(struct megasas_instance *instance)
+-{
+- struct Scsi_Host *host = instance->host;
+-
+- /*
+- * Export parameters required by SCSI mid-layer
+- */
+- host->irq = instance->pdev->irq;
+- host->unique_id = instance->unique_id;
+- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+- host->can_queue =
+- instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
+- } else
+- host->can_queue =
+- instance->max_fw_cmds - MEGASAS_INT_CMDS;
+- host->this_id = instance->init_id;
+- host->sg_tablesize = instance->max_num_sge;
+- host->max_sectors = instance->max_sectors_per_req;
+- host->cmd_per_lun = 128;
+- host->max_channel = MEGASAS_MAX_CHANNELS - 1;
+- host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL;
+- host->max_lun = MEGASAS_MAX_LUN;
+- host->max_cmd_len = 16;
+-
+- /*
+- * Notify the mid-layer about the new controller
+- */
+- if (scsi_add_host(host, &instance->pdev->dev)) {
+- printk(KERN_DEBUG "megasas: scsi_add_host failed\n");
+- return -ENODEV;
+- }
+-
+- /*
+- * Trigger SCSI to scan our drives
+- */
+- scsi_scan_host(host);
+- return 0;
+-}
+-
+-static int
+-megasas_set_dma_mask(struct pci_dev *pdev)
+-{
+- /*
+- * All our contollers are capable of performing 64-bit DMA
+- */
+- if (IS_DMA64) {
+- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
+-
+- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
+- goto fail_set_dma_mask;
+- }
+- } else {
+- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
+- goto fail_set_dma_mask;
+- }
+- return 0;
+-
+-fail_set_dma_mask:
+- return 1;
+-}
+-
+-/**
+- * megasas_probe_one - PCI hotplug entry point
+- * @pdev: PCI device structure
+- * @id: PCI ids of supported hotplugged adapter
+- */
+-static int __devinit
+-megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+-{
+- int rval;
+- struct Scsi_Host *host;
+- struct megasas_instance *instance;
+-
+- /*
+- * Announce PCI information
+- */
+- printk(KERN_INFO "megasas: %#4.04x:%#4.04x:%#4.04x:%#4.04x: ",
+- pdev->vendor, pdev->device, pdev->subsystem_vendor,
+- pdev->subsystem_device);
+-
+- printk("bus %d:slot %d:func %d\n",
+- pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+-
+- /*
+- * PCI prepping: enable device set bus mastering and dma mask
+- */
+- rval = pci_enable_device(pdev);
+-
+- if (rval) {
+- return rval;
+- }
+-
+- pci_set_master(pdev);
+-
+- if (megasas_set_dma_mask(pdev))
+- goto fail_set_dma_mask;
+-
+- host = scsi_host_alloc(&megasas_template,
+- sizeof(struct megasas_instance));
+-
+- if (!host) {
+- printk(KERN_DEBUG "megasas: scsi_host_alloc failed\n");
+- goto fail_alloc_instance;
+- }
+-
+- instance = (struct megasas_instance *)host->hostdata;
+- memset(instance, 0, sizeof(*instance));
+- atomic_set( &instance->fw_reset_no_pci_access, 0 );
+-
+- instance->producer = pci_alloc_consistent(pdev, sizeof(u32),
+- &instance->producer_h);
+- instance->consumer = pci_alloc_consistent(pdev, sizeof(u32),
+- &instance->consumer_h);
+-
+- if (!instance->producer || !instance->consumer) {
+- printk(KERN_DEBUG "megasas: Failed to allocate memory for "
+- "producer, consumer\n");
+- goto fail_alloc_dma_buf;
+- }
+-
+- *instance->producer = 0;
+- *instance->consumer = 0;
+- megasas_poll_wait_aen = 0;
+- instance->flag_ieee = 0;
+- instance->ev = NULL;
+- instance->issuepend_done = 1;
+- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+- megasas_poll_wait_aen = 0;
+-
+- instance->evt_detail = pci_alloc_consistent(pdev,
+- sizeof(struct
+- megasas_evt_detail),
+- &instance->evt_detail_h);
+-
+- if (!instance->evt_detail) {
+- printk(KERN_DEBUG "megasas: Failed to allocate memory for "
+- "event detail structure\n");
+- goto fail_alloc_dma_buf;
+- }
+-
+- /*
+- * Initialize locks and queues
+- */
+- INIT_LIST_HEAD(&instance->cmd_pool);
+- INIT_LIST_HEAD(&instance->internal_reset_pending_q);
+-
+- atomic_set(&instance->fw_outstanding,0);
+-
+- init_waitqueue_head(&instance->int_cmd_wait_q);
+- init_waitqueue_head(&instance->abort_cmd_wait_q);
+-
+- spin_lock_init(&instance->cmd_pool_lock);
+- spin_lock_init(&instance->hba_lock);
+- spin_lock_init(&instance->completion_lock);
+- spin_lock_init(&poll_aen_lock);
+-
+- mutex_init(&instance->aen_mutex);
+-
+- /*
+- * Initialize PCI related and misc parameters
+- */
+- instance->pdev = pdev;
+- instance->host = host;
+- instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
+- instance->init_id = MEGASAS_DEFAULT_INIT_ID;
+-
+- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+- instance->flag_ieee = 1;
+- sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
+- } else
+- sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
+-
+- megasas_dbg_lvl = 0;
+- instance->flag = 0;
+- instance->unload = 1;
+- instance->last_time = 0;
+- instance->disableOnlineCtrlReset = 1;
+-
+- INIT_WORK(&instance->work_init, process_fw_state_change_wq);
+-
+- /*
+- * Initialize MFI Firmware
+- */
+- if (megasas_init_mfi(instance))
+- goto fail_init_mfi;
+-
+- /*
+- * Register IRQ
+- */
+- if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED, "megasas", instance)) {
+- printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
+- goto fail_irq;
+- }
+-
+- instance->instancet->enable_intr(instance->reg_set);
+-
+- /*
+- * Store instance in PCI softstate
+- */
+- pci_set_drvdata(pdev, instance);
+-
+- /*
+- * Add this controller to megasas_mgmt_info structure so that it
+- * can be exported to management applications
+- */
+- megasas_mgmt_info.count++;
+- megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = instance;
+- megasas_mgmt_info.max_index++;
+-
+- /*
+- * Initiate AEN (Asynchronous Event Notification)
+- */
+- if (megasas_start_aen(instance)) {
+- printk(KERN_DEBUG "megasas: start aen failed\n");
+- goto fail_start_aen;
+- }
+-
+- /*
+- * Register with SCSI mid-layer
+- */
+- if (megasas_io_attach(instance))
+- goto fail_io_attach;
+-
+- instance->unload = 0;
+- return 0;
+-
+- fail_start_aen:
+- fail_io_attach:
+- megasas_mgmt_info.count--;
+- megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL;
+- megasas_mgmt_info.max_index--;
+-
+- pci_set_drvdata(pdev, NULL);
+- instance->instancet->disable_intr(instance->reg_set);
+- free_irq(instance->pdev->irq, instance);
+-
+- megasas_release_mfi(instance);
+-
+- fail_irq:
+- fail_init_mfi:
+- fail_alloc_dma_buf:
+- if (instance->evt_detail)
+- pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
+- instance->evt_detail,
+- instance->evt_detail_h);
+-
+- if (instance->producer)
+- pci_free_consistent(pdev, sizeof(u32), instance->producer,
+- instance->producer_h);
+- if (instance->consumer)
+- pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+- instance->consumer_h);
+- scsi_host_put(host);
+-
+- fail_alloc_instance:
+- fail_set_dma_mask:
+- pci_disable_device(pdev);
+-
+- return -ENODEV;
+-}
+-
+-/**
+- * megasas_flush_cache - Requests FW to flush all its caches
+- * @instance: Adapter soft state
+- */
+-static void megasas_flush_cache(struct megasas_instance *instance)
+-{
+- struct megasas_cmd *cmd;
+- struct megasas_dcmd_frame *dcmd;
+-
+- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+- return;
+-
+- cmd = megasas_get_cmd(instance);
+-
+- if (!cmd)
+- return;
+-
+- dcmd = &cmd->frame->dcmd;
+-
+- memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+-
+- dcmd->cmd = MFI_CMD_DCMD;
+- dcmd->cmd_status = 0x0;
+- dcmd->sge_count = 0;
+- dcmd->flags = MFI_FRAME_DIR_NONE;
+- dcmd->timeout = 0;
+- dcmd->data_xfer_len = 0;
+- dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;
+- dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
+-
+- megasas_issue_blocked_cmd(instance, cmd);
+-
+- megasas_return_cmd(instance, cmd);
+-
+- return;
+-}
+-
+-/**
+- * megasas_shutdown_controller - Instructs FW to shutdown the controller
+- * @instance: Adapter soft state
+- * @opcode: Shutdown/Hibernate
+- */
+-static void megasas_shutdown_controller(struct megasas_instance *instance,
+- u32 opcode)
+-{
+- struct megasas_cmd *cmd;
+- struct megasas_dcmd_frame *dcmd;
+-
+- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+- return;
+-
+- cmd = megasas_get_cmd(instance);
+-
+- if (!cmd)
+- return;
+-
+- if (instance->aen_cmd)
+- megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd);
+-
+- dcmd = &cmd->frame->dcmd;
+-
+- memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+-
+- dcmd->cmd = MFI_CMD_DCMD;
+- dcmd->cmd_status = 0x0;
+- dcmd->sge_count = 0;
+- dcmd->flags = MFI_FRAME_DIR_NONE;
+- dcmd->timeout = 0;
+- dcmd->data_xfer_len = 0;
+- dcmd->opcode = opcode;
+-
+- megasas_issue_blocked_cmd(instance, cmd);
+-
+- megasas_return_cmd(instance, cmd);
+-
+- return;
+-}
+-
+-#ifdef CONFIG_PM
+-/**
+- * megasas_suspend - driver suspend entry point
+- * @pdev: PCI device structure
+- * @state: PCI power state to suspend routine
+- */
+-static int
+-megasas_suspend(struct pci_dev *pdev, pm_message_t state)
+-{
+- struct Scsi_Host *host;
+- struct megasas_instance *instance;
+-
+- instance = pci_get_drvdata(pdev);
+- host = instance->host;
+- instance->unload = 1;
+-
+- if (poll_mode_io)
+- del_timer_sync(&instance->io_completion_timer);
+-
+- megasas_flush_cache(instance);
+- megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
+-
+- /* cancel the delayed work if this work still in queue */
+- if (instance->ev != NULL) {
+- struct megasas_aen_event *ev = instance->ev;
+- cancel_delayed_work(
+- (struct delayed_work *)&ev->hotplug_work);
+- flush_scheduled_work();
+- instance->ev = NULL;
+- }
+-
+- tasklet_kill(&instance->isr_tasklet);
+-
+- pci_set_drvdata(instance->pdev, instance);
+- instance->instancet->disable_intr(instance->reg_set);
+- free_irq(instance->pdev->irq, instance);
+-
+- pci_save_state(pdev);
+- pci_disable_device(pdev);
+-
+- pci_set_power_state(pdev, pci_choose_state(pdev, state));
+-
+- return 0;
+-}
+-
+-/**
+- * megasas_resume- driver resume entry point
+- * @pdev: PCI device structure
+- */
+-static int
+-megasas_resume(struct pci_dev *pdev)
+-{
+- int rval;
+- struct Scsi_Host *host;
+- struct megasas_instance *instance;
+-
+- instance = pci_get_drvdata(pdev);
+- host = instance->host;
+- pci_set_power_state(pdev, PCI_D0);
+- pci_enable_wake(pdev, PCI_D0, 0);
+- pci_restore_state(pdev);
+-
+- /*
+- * PCI prepping: enable device set bus mastering and dma mask
+- */
+- rval = pci_enable_device(pdev);
+-
+- if (rval) {
+- printk(KERN_ERR "megasas: Enable device failed\n");
+- return rval;
+- }
+-
+- pci_set_master(pdev);
+-
+- if (megasas_set_dma_mask(pdev))
+- goto fail_set_dma_mask;
+-
+- /*
+- * Initialize MFI Firmware
+- */
+-
+- *instance->producer = 0;
+- *instance->consumer = 0;
+-
+- atomic_set(&instance->fw_outstanding, 0);
+-
+- /*
+- * We expect the FW state to be READY
+- */
+- if (megasas_transition_to_ready(instance))
+- goto fail_ready_state;
+-
+- if (megasas_issue_init_mfi(instance))
+- goto fail_init_mfi;
+-
+- tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+- (unsigned long)instance);
+-
+- /*
+- * Register IRQ
+- */
+- if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED,
+- "megasas", instance)) {
+- printk(KERN_ERR "megasas: Failed to register IRQ\n");
+- goto fail_irq;
+- }
+-
+- instance->instancet->enable_intr(instance->reg_set);
+-
+- /*
+- * Initiate AEN (Asynchronous Event Notification)
+- */
+- if (megasas_start_aen(instance))
+- printk(KERN_ERR "megasas: Start AEN failed\n");
+-
+- /* Initialize the cmd completion timer */
+- if (poll_mode_io)
+- megasas_start_timer(instance, &instance->io_completion_timer,
+- megasas_io_completion_timer,
+- MEGASAS_COMPLETION_TIMER_INTERVAL);
+- instance->unload = 0;
+-
+- return 0;
+-
+-fail_irq:
+-fail_init_mfi:
+- if (instance->evt_detail)
+- pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
+- instance->evt_detail,
+- instance->evt_detail_h);
+-
+- if (instance->producer)
+- pci_free_consistent(pdev, sizeof(u32), instance->producer,
+- instance->producer_h);
+- if (instance->consumer)
+- pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+- instance->consumer_h);
+- scsi_host_put(host);
+-
+-fail_set_dma_mask:
+-fail_ready_state:
+-
+- pci_disable_device(pdev);
+-
+- return -ENODEV;
+-}
+-#else
+-#define megasas_suspend NULL
+-#define megasas_resume NULL
+-#endif
+-
+-/**
+- * megasas_detach_one - PCI hot"un"plug entry point
+- * @pdev: PCI device structure
+- */
+-static void __devexit megasas_detach_one(struct pci_dev *pdev)
+-{
+- int i;
+- struct Scsi_Host *host;
+- struct megasas_instance *instance;
+-
+- instance = pci_get_drvdata(pdev);
+- instance->unload = 1;
+- host = instance->host;
+-
+- if (poll_mode_io)
+- del_timer_sync(&instance->io_completion_timer);
+-
+- scsi_remove_host(instance->host);
+- megasas_flush_cache(instance);
+- megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
+-
+- /* cancel the delayed work if this work still in queue*/
+- if (instance->ev != NULL) {
+- struct megasas_aen_event *ev = instance->ev;
+- cancel_delayed_work(
+- (struct delayed_work *)&ev->hotplug_work);
+- flush_scheduled_work();
+- instance->ev = NULL;
+- }
+-
+- tasklet_kill(&instance->isr_tasklet);
+-
+- /*
+- * Take the instance off the instance array. Note that we will not
+- * decrement the max_index. We let this array be sparse array
+- */
+- for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+- if (megasas_mgmt_info.instance[i] == instance) {
+- megasas_mgmt_info.count--;
+- megasas_mgmt_info.instance[i] = NULL;
+-
+- break;
+- }
+- }
+-
+- pci_set_drvdata(instance->pdev, NULL);
+-
+- instance->instancet->disable_intr(instance->reg_set);
+-
+- free_irq(instance->pdev->irq, instance);
+-
+- megasas_release_mfi(instance);
+-
+- pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
+- instance->evt_detail, instance->evt_detail_h);
+-
+- pci_free_consistent(pdev, sizeof(u32), instance->producer,
+- instance->producer_h);
+-
+- pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+- instance->consumer_h);
+-
+- scsi_host_put(host);
+-
+- pci_set_drvdata(pdev, NULL);
+-
+- pci_disable_device(pdev);
+-
+- return;
+-}
+-
+-/**
+- * megasas_shutdown - Shutdown entry point
+- * @device: Generic device structure
+- */
+-static void megasas_shutdown(struct pci_dev *pdev)
+-{
+- struct megasas_instance *instance = pci_get_drvdata(pdev);
+- instance->unload = 1;
+- megasas_flush_cache(instance);
+- megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
+-}
+-
+-/**
+- * megasas_mgmt_open - char node "open" entry point
+- */
+-static int megasas_mgmt_open(struct inode *inode, struct file *filep)
+-{
+- cycle_kernel_lock();
+- /*
+- * Allow only those users with admin rights
+- */
+- if (!capable(CAP_SYS_ADMIN))
+- return -EACCES;
+-
+- return 0;
+-}
+-
+-/**
+- * megasas_mgmt_fasync - Async notifier registration from applications
+- *
+- * This function adds the calling process to a driver global queue. When an
+- * event occurs, SIGIO will be sent to all processes in this queue.
+- */
+-static int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
+-{
+- int rc;
+-
+- mutex_lock(&megasas_async_queue_mutex);
+-
+- rc = fasync_helper(fd, filep, mode, &megasas_async_queue);
+-
+- mutex_unlock(&megasas_async_queue_mutex);
+-
+- if (rc >= 0) {
+- /* For sanity check when we get ioctl */
+- filep->private_data = filep;
+- return 0;
+- }
+-
+- printk(KERN_DEBUG "megasas: fasync_helper failed [%d]\n", rc);
+-
+- return rc;
+-}
+-
+-/**
+- * megasas_mgmt_poll - char node "poll" entry point
+- * */
+-static unsigned int megasas_mgmt_poll(struct file *file, poll_table *wait)
+-{
+- unsigned int mask;
+- unsigned long flags;
+- poll_wait(file, &megasas_poll_wait, wait);
+- spin_lock_irqsave(&poll_aen_lock, flags);
+- if (megasas_poll_wait_aen)
+- mask = (POLLIN | POLLRDNORM);
+- else
+- mask = 0;
+- spin_unlock_irqrestore(&poll_aen_lock, flags);
+- return mask;
+-}
+-
+-/**
+- * megasas_mgmt_fw_ioctl - Issues management ioctls to FW
+- * @instance: Adapter soft state
+- * @argp: User's ioctl packet
+- */
+-static int
+-megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
+- struct megasas_iocpacket __user * user_ioc,
+- struct megasas_iocpacket *ioc)
+-{
+- struct megasas_sge32 *kern_sge32;
+- struct megasas_cmd *cmd;
+- void *kbuff_arr[MAX_IOCTL_SGE];
+- dma_addr_t buf_handle = 0;
+- int error = 0, i;
+- void *sense = NULL;
+- dma_addr_t sense_handle;
+- unsigned long *sense_ptr;
+-
+- memset(kbuff_arr, 0, sizeof(kbuff_arr));
+-
+- if (ioc->sge_count > MAX_IOCTL_SGE) {
+- printk(KERN_DEBUG "megasas: SGE count [%d] > max limit [%d]\n",
+- ioc->sge_count, MAX_IOCTL_SGE);
+- return -EINVAL;
+- }
+-
+- cmd = megasas_get_cmd(instance);
+- if (!cmd) {
+- printk(KERN_DEBUG "megasas: Failed to get a cmd packet\n");
+- return -ENOMEM;
+- }
+-
+- /*
+- * User's IOCTL packet has 2 frames (maximum). Copy those two
+- * frames into our cmd's frames. cmd->frame's context will get
+- * overwritten when we copy from user's frames. So set that value
+- * alone separately
+- */
+- memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
+- cmd->frame->hdr.context = cmd->index;
+- cmd->frame->hdr.pad_0 = 0;
+-
+- /*
+- * The management interface between applications and the fw uses
+- * MFI frames. E.g, RAID configuration changes, LD property changes
+- * etc are accomplishes through different kinds of MFI frames. The
+- * driver needs to care only about substituting user buffers with
+- * kernel buffers in SGLs. The location of SGL is embedded in the
+- * struct iocpacket itself.
+- */
+- kern_sge32 = (struct megasas_sge32 *)
+- ((unsigned long)cmd->frame + ioc->sgl_off);
+-
+- /*
+- * For each user buffer, create a mirror buffer and copy in
+- */
+- for (i = 0; i < ioc->sge_count; i++) {
+- if (!ioc->sgl[i].iov_len)
+- continue;
+-
+- kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev,
+- ioc->sgl[i].iov_len,
+- &buf_handle, GFP_KERNEL);
+- if (!kbuff_arr[i]) {
+- printk(KERN_DEBUG "megasas: Failed to alloc "
+- "kernel SGL buffer for IOCTL \n");
+- error = -ENOMEM;
+- goto out;
+- }
+-
+- /*
+- * We don't change the dma_coherent_mask, so
+- * pci_alloc_consistent only returns 32bit addresses
+- */
+- kern_sge32[i].phys_addr = (u32) buf_handle;
+- kern_sge32[i].length = ioc->sgl[i].iov_len;
+-
+- /*
+- * We created a kernel buffer corresponding to the
+- * user buffer. Now copy in from the user buffer
+- */
+- if (copy_from_user(kbuff_arr[i], ioc->sgl[i].iov_base,
+- (u32) (ioc->sgl[i].iov_len))) {
+- error = -EFAULT;
+- goto out;
+- }
+- }
+-
+- if (ioc->sense_len) {
+- sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len,
+- &sense_handle, GFP_KERNEL);
+- if (!sense) {
+- error = -ENOMEM;
+- goto out;
+- }
+-
+- sense_ptr =
+- (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off);
+- *sense_ptr = sense_handle;
+- }
+-
+- /*
+- * Set the sync_cmd flag so that the ISR knows not to complete this
+- * cmd to the SCSI mid-layer
+- */
+- cmd->sync_cmd = 1;
+- megasas_issue_blocked_cmd(instance, cmd);
+- cmd->sync_cmd = 0;
+-
+- /*
+- * copy out the kernel buffers to user buffers
+- */
+- for (i = 0; i < ioc->sge_count; i++) {
+- if (copy_to_user(ioc->sgl[i].iov_base, kbuff_arr[i],
+- ioc->sgl[i].iov_len)) {
+- error = -EFAULT;
+- goto out;
+- }
+- }
+-
+- /*
+- * copy out the sense
+- */
+- if (ioc->sense_len) {
+- /*
+- * sense_ptr points to the location that has the user
+- * sense buffer address
+- */
+- sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw +
+- ioc->sense_off);
+-
+- if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
+- sense, ioc->sense_len)) {
+- printk(KERN_ERR "megasas: Failed to copy out to user "
+- "sense data\n");
+- error = -EFAULT;
+- goto out;
+- }
+- }
+-
+- /*
+- * copy the status codes returned by the fw
+- */
+- if (copy_to_user(&user_ioc->frame.hdr.cmd_status,
+- &cmd->frame->hdr.cmd_status, sizeof(u8))) {
+- printk(KERN_DEBUG "megasas: Error copying out cmd_status\n");
+- error = -EFAULT;
+- }
+-
+- out:
+- if (sense) {
+- dma_free_coherent(&instance->pdev->dev, ioc->sense_len,
+- sense, sense_handle);
+- }
+-
+- for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) {
+- dma_free_coherent(&instance->pdev->dev,
+- kern_sge32[i].length,
+- kbuff_arr[i], kern_sge32[i].phys_addr);
+- }
+-
+- megasas_return_cmd(instance, cmd);
+- return error;
+-}
+-
+-static struct megasas_instance *megasas_lookup_instance(u16 host_no)
+-{
+- int i;
+-
+- for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+-
+- if ((megasas_mgmt_info.instance[i]) &&
+- (megasas_mgmt_info.instance[i]->host->host_no == host_no))
+- return megasas_mgmt_info.instance[i];
+- }
+-
+- return NULL;
+-}
+-
+-static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
+-{
+- struct megasas_iocpacket __user *user_ioc =
+- (struct megasas_iocpacket __user *)arg;
+- struct megasas_iocpacket *ioc;
+- struct megasas_instance *instance;
+- int error;
+- int i;
+- unsigned long flags;
+- u32 wait_time = MEGASAS_RESET_WAIT_TIME;
+-
+- ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);
+- if (!ioc)
+- return -ENOMEM;
+-
+- if (copy_from_user(ioc, user_ioc, sizeof(*ioc))) {
+- error = -EFAULT;
+- goto out_kfree_ioc;
+- }
+-
+- instance = megasas_lookup_instance(ioc->host_no);
+- if (!instance) {
+- error = -ENODEV;
+- goto out_kfree_ioc;
+- }
+-
+- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+- printk(KERN_ERR "Controller in crit error\n");
+- error = -ENODEV;
+- goto out_kfree_ioc;
+- }
+-
+- if (instance->unload == 1) {
+- error = -ENODEV;
+- goto out_kfree_ioc;
+- }
+-
+- /*
+- * We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds
+- */
+- if (down_interruptible(&instance->ioctl_sem)) {
+- error = -ERESTARTSYS;
+- goto out_kfree_ioc;
+- }
+-
+- for (i = 0; i < wait_time; i++) {
+-
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+- break;
+- }
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-
+- if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+- printk(KERN_NOTICE "megasas: waiting"
+- "for controller reset to finish\n");
+- }
+-
+- msleep(1000);
+- }
+-
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-
+- printk(KERN_ERR "megaraid_sas: timed out while"
+- "waiting for HBA to recover\n");
+- error = -ENODEV;
+- goto out_kfree_ioc;
+- }
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-
+- error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc);
+- up(&instance->ioctl_sem);
+-
+- out_kfree_ioc:
+- kfree(ioc);
+- return error;
+-}
+-
+-static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
+-{
+- struct megasas_instance *instance;
+- struct megasas_aen aen;
+- int error;
+- int i;
+- unsigned long flags;
+- u32 wait_time = MEGASAS_RESET_WAIT_TIME;
+-
+- if (file->private_data != file) {
+- printk(KERN_DEBUG "megasas: fasync_helper was not "
+- "called first\n");
+- return -EINVAL;
+- }
+-
+- if (copy_from_user(&aen, (void __user *)arg, sizeof(aen)))
+- return -EFAULT;
+-
+- instance = megasas_lookup_instance(aen.host_no);
+-
+- if (!instance)
+- return -ENODEV;
+-
+- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+- return -ENODEV;
+- }
+-
+- if (instance->unload == 1) {
+- return -ENODEV;
+- }
+-
+- for (i = 0; i < wait_time; i++) {
+-
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+- spin_unlock_irqrestore(&instance->hba_lock,
+- flags);
+- break;
+- }
+-
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-
+- if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+- printk(KERN_NOTICE "megasas: waiting for"
+- "controller reset to finish\n");
+- }
+-
+- msleep(1000);
+- }
+-
+- spin_lock_irqsave(&instance->hba_lock, flags);
+- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+- printk(KERN_ERR "megaraid_sas: timed out while waiting"
+- "for HBA to recover.\n");
+- return -ENODEV;
+- }
+- spin_unlock_irqrestore(&instance->hba_lock, flags);
+-
+- mutex_lock(&instance->aen_mutex);
+- error = megasas_register_aen(instance, aen.seq_num,
+- aen.class_locale_word);
+- mutex_unlock(&instance->aen_mutex);
+- return error;
+-}
+-
+-/**
+- * megasas_mgmt_ioctl - char node ioctl entry point
+- */
+-static long
+-megasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+-{
+- switch (cmd) {
+- case MEGASAS_IOC_FIRMWARE:
+- return megasas_mgmt_ioctl_fw(file, arg);
+-
+- case MEGASAS_IOC_GET_AEN:
+- return megasas_mgmt_ioctl_aen(file, arg);
+- }
+-
+- return -ENOTTY;
+-}
+-
+-#ifdef CONFIG_COMPAT
+-static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
+-{
+- struct compat_megasas_iocpacket __user *cioc =
+- (struct compat_megasas_iocpacket __user *)arg;
+- struct megasas_iocpacket __user *ioc =
+- compat_alloc_user_space(sizeof(struct megasas_iocpacket));
+- int i;
+- int error = 0;
+- compat_uptr_t ptr;
+-
+- if (clear_user(ioc, sizeof(*ioc)))
+- return -EFAULT;
+-
+- if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
+- copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
+- copy_in_user(&ioc->sense_off, &cioc->sense_off, sizeof(u32)) ||
+- copy_in_user(&ioc->sense_len, &cioc->sense_len, sizeof(u32)) ||
+- copy_in_user(ioc->frame.raw, cioc->frame.raw, 128) ||
+- copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32)))
+- return -EFAULT;
+-
+- /*
+- * The sense_ptr is used in megasas_mgmt_fw_ioctl only when
+- * sense_len is not null, so prepare the 64bit value under
+- * the same condition.
+- */
+- if (ioc->sense_len) {
+- void __user **sense_ioc_ptr =
+- (void __user **)(ioc->frame.raw + ioc->sense_off);
+- compat_uptr_t *sense_cioc_ptr =
+- (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off);
+- if (get_user(ptr, sense_cioc_ptr) ||
+- put_user(compat_ptr(ptr), sense_ioc_ptr))
+- return -EFAULT;
+- }
+-
+- for (i = 0; i < MAX_IOCTL_SGE; i++) {
+- if (get_user(ptr, &cioc->sgl[i].iov_base) ||
+- put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) ||
+- copy_in_user(&ioc->sgl[i].iov_len,
+- &cioc->sgl[i].iov_len, sizeof(compat_size_t)))
+- return -EFAULT;
+- }
+-
+- error = megasas_mgmt_ioctl_fw(file, (unsigned long)ioc);
+-
+- if (copy_in_user(&cioc->frame.hdr.cmd_status,
+- &ioc->frame.hdr.cmd_status, sizeof(u8))) {
+- printk(KERN_DEBUG "megasas: error copy_in_user cmd_status\n");
+- return -EFAULT;
+- }
+- return error;
+-}
+-
+-static long
+-megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
+- unsigned long arg)
+-{
+- switch (cmd) {
+- case MEGASAS_IOC_FIRMWARE32:
+- return megasas_mgmt_compat_ioctl_fw(file, arg);
+- case MEGASAS_IOC_GET_AEN:
+- return megasas_mgmt_ioctl_aen(file, arg);
+- }
+-
+- return -ENOTTY;
+-}
+-#endif
+-
+-/*
+- * File operations structure for management interface
+- */
+-static const struct file_operations megasas_mgmt_fops = {
+- .owner = THIS_MODULE,
+- .open = megasas_mgmt_open,
+- .fasync = megasas_mgmt_fasync,
+- .unlocked_ioctl = megasas_mgmt_ioctl,
+- .poll = megasas_mgmt_poll,
+-#ifdef CONFIG_COMPAT
+- .compat_ioctl = megasas_mgmt_compat_ioctl,
+-#endif
+-};
+-
+-/*
+- * PCI hotplug support registration structure
+- */
+-static struct pci_driver megasas_pci_driver = {
+-
+- .name = "megaraid_sas",
+- .id_table = megasas_pci_table,
+- .probe = megasas_probe_one,
+- .remove = __devexit_p(megasas_detach_one),
+- .suspend = megasas_suspend,
+- .resume = megasas_resume,
+- .shutdown = megasas_shutdown,
+-};
+-
+-/*
+- * Sysfs driver attributes
+- */
+-static ssize_t megasas_sysfs_show_version(struct device_driver *dd, char *buf)
+-{
+- return snprintf(buf, strlen(MEGASAS_VERSION) + 2, "%s\n",
+- MEGASAS_VERSION);
+-}
+-
+-static DRIVER_ATTR(version, S_IRUGO, megasas_sysfs_show_version, NULL);
+-
+-static ssize_t
+-megasas_sysfs_show_release_date(struct device_driver *dd, char *buf)
+-{
+- return snprintf(buf, strlen(MEGASAS_RELDATE) + 2, "%s\n",
+- MEGASAS_RELDATE);
+-}
+-
+-static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
+- NULL);
+-
+-static ssize_t
+-megasas_sysfs_show_support_poll_for_event(struct device_driver *dd, char *buf)
+-{
+- return sprintf(buf, "%u\n", support_poll_for_event);
+-}
+-
+-static DRIVER_ATTR(support_poll_for_event, S_IRUGO,
+- megasas_sysfs_show_support_poll_for_event, NULL);
+-
+-static ssize_t
+-megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
+-{
+- return sprintf(buf, "%u\n", megasas_dbg_lvl);
+-}
+-
+-static ssize_t
+-megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count)
+-{
+- int retval = count;
+- if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){
+- printk(KERN_ERR "megasas: could not set dbg_lvl\n");
+- retval = -EINVAL;
+- }
+- return retval;
+-}
+-
+-static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUSR, megasas_sysfs_show_dbg_lvl,
+- megasas_sysfs_set_dbg_lvl);
+-
+-static ssize_t
+-megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf)
+-{
+- return sprintf(buf, "%u\n", poll_mode_io);
+-}
+-
+-static ssize_t
+-megasas_sysfs_set_poll_mode_io(struct device_driver *dd,
+- const char *buf, size_t count)
+-{
+- int retval = count;
+- int tmp = poll_mode_io;
+- int i;
+- struct megasas_instance *instance;
+-
+- if (sscanf(buf, "%u", &poll_mode_io) < 1) {
+- printk(KERN_ERR "megasas: could not set poll_mode_io\n");
+- retval = -EINVAL;
+- }
+-
+- /*
+- * Check if poll_mode_io is already set or is same as previous value
+- */
+- if ((tmp && poll_mode_io) || (tmp == poll_mode_io))
+- goto out;
+-
+- if (poll_mode_io) {
+- /*
+- * Start timers for all adapters
+- */
+- for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+- instance = megasas_mgmt_info.instance[i];
+- if (instance) {
+- megasas_start_timer(instance,
+- &instance->io_completion_timer,
+- megasas_io_completion_timer,
+- MEGASAS_COMPLETION_TIMER_INTERVAL);
+- }
+- }
+- } else {
+- /*
+- * Delete timers for all adapters
+- */
+- for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+- instance = megasas_mgmt_info.instance[i];
+- if (instance)
+- del_timer_sync(&instance->io_completion_timer);
+- }
+- }
+-
+-out:
+- return retval;
+-}
+-
+-static void
+-megasas_aen_polling(struct work_struct *work)
+-{
+- struct megasas_aen_event *ev =
+- container_of(work, struct megasas_aen_event, hotplug_work);
+- struct megasas_instance *instance = ev->instance;
+- union megasas_evt_class_locale class_locale;
+- struct Scsi_Host *host;
+- struct scsi_device *sdev1;
+- u16 pd_index = 0;
+- u16 ld_index = 0;
+- int i, j, doscan = 0;
+- u32 seq_num;
+- int error;
+-
+- if (!instance) {
+- printk(KERN_ERR "invalid instance!\n");
+- kfree(ev);
+- return;
+- }
+- instance->ev = NULL;
+- host = instance->host;
+- if (instance->evt_detail) {
+-
+- switch (instance->evt_detail->code) {
+- case MR_EVT_PD_INSERTED:
+- if (megasas_get_pd_list(instance) == 0) {
+- for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+- for (j = 0;
+- j < MEGASAS_MAX_DEV_PER_CHANNEL;
+- j++) {
+-
+- pd_index =
+- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+-
+- sdev1 =
+- scsi_device_lookup(host, i, j, 0);
+-
+- if (instance->pd_list[pd_index].driveState
+- == MR_PD_STATE_SYSTEM) {
+- if (!sdev1) {
+- scsi_add_device(host, i, j, 0);
+- }
+-
+- if (sdev1)
+- scsi_device_put(sdev1);
+- }
+- }
+- }
+- }
+- doscan = 0;
+- break;
+-
+- case MR_EVT_PD_REMOVED:
+- if (megasas_get_pd_list(instance) == 0) {
+- megasas_get_pd_list(instance);
+- for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+- for (j = 0;
+- j < MEGASAS_MAX_DEV_PER_CHANNEL;
+- j++) {
+-
+- pd_index =
+- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+-
+- sdev1 =
+- scsi_device_lookup(host, i, j, 0);
+-
+- if (instance->pd_list[pd_index].driveState
+- == MR_PD_STATE_SYSTEM) {
+- if (sdev1) {
+- scsi_device_put(sdev1);
+- }
+- } else {
+- if (sdev1) {
+- scsi_remove_device(sdev1);
+- scsi_device_put(sdev1);
+- }
+- }
+- }
+- }
+- }
+- doscan = 0;
+- break;
+-
+- case MR_EVT_LD_OFFLINE:
+- case MR_EVT_LD_DELETED:
+- megasas_get_ld_list(instance);
+- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+- for (j = 0;
+- j < MEGASAS_MAX_DEV_PER_CHANNEL;
+- j++) {
+-
+- ld_index =
+- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+-
+- sdev1 = scsi_device_lookup(host,
+- i + MEGASAS_MAX_LD_CHANNELS,
+- j,
+- 0);
+-
+- if (instance->ld_ids[ld_index] != 0xff) {
+- if (sdev1) {
+- scsi_device_put(sdev1);
+- }
+- } else {
+- if (sdev1) {
+- scsi_remove_device(sdev1);
+- scsi_device_put(sdev1);
+- }
+- }
+- }
+- }
+- doscan = 0;
+- break;
+- case MR_EVT_LD_CREATED:
+- megasas_get_ld_list(instance);
+- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+- for (j = 0;
+- j < MEGASAS_MAX_DEV_PER_CHANNEL;
+- j++) {
+- ld_index =
+- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+-
+- sdev1 = scsi_device_lookup(host,
+- i+MEGASAS_MAX_LD_CHANNELS,
+- j, 0);
+-
+- if (instance->ld_ids[ld_index] !=
+- 0xff) {
+- if (!sdev1) {
+- scsi_add_device(host,
+- i + 2,
+- j, 0);
+- }
+- }
+- if (sdev1) {
+- scsi_device_put(sdev1);
+- }
+- }
+- }
+- doscan = 0;
+- break;
+- case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
+- case MR_EVT_FOREIGN_CFG_IMPORTED:
+- doscan = 1;
+- break;
+- default:
+- doscan = 0;
+- break;
+- }
+- } else {
+- printk(KERN_ERR "invalid evt_detail!\n");
+- kfree(ev);
+- return;
+- }
+-
+- if (doscan) {
+- printk(KERN_INFO "scanning ...\n");
+- megasas_get_pd_list(instance);
+- for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+- for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+- pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
+- sdev1 = scsi_device_lookup(host, i, j, 0);
+- if (instance->pd_list[pd_index].driveState ==
+- MR_PD_STATE_SYSTEM) {
+- if (!sdev1) {
+- scsi_add_device(host, i, j, 0);
+- }
+- if (sdev1)
+- scsi_device_put(sdev1);
+- } else {
+- if (sdev1) {
+- scsi_remove_device(sdev1);
+- scsi_device_put(sdev1);
+- }
+- }
+- }
+- }
+-
+- megasas_get_ld_list(instance);
+- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+- for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+- ld_index =
+- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+-
+- sdev1 = scsi_device_lookup(host,
+- i+MEGASAS_MAX_LD_CHANNELS, j, 0);
+- if (instance->ld_ids[ld_index] != 0xff) {
+- if (!sdev1) {
+- scsi_add_device(host,
+- i+2,
+- j, 0);
+- } else {
+- scsi_device_put(sdev1);
+- }
+- } else {
+- if (sdev1) {
+- scsi_remove_device(sdev1);
+- scsi_device_put(sdev1);
+- }
+- }
+- }
+- }
+- }
+-
+- if ( instance->aen_cmd != NULL ) {
+- kfree(ev);
+- return ;
+- }
+-
+- seq_num = instance->evt_detail->seq_num + 1;
+-
+- /* Register AEN with FW for latest sequence number plus 1 */
+- class_locale.members.reserved = 0;
+- class_locale.members.locale = MR_EVT_LOCALE_ALL;
+- class_locale.members.class = MR_EVT_CLASS_DEBUG;
+- mutex_lock(&instance->aen_mutex);
+- error = megasas_register_aen(instance, seq_num,
+- class_locale.word);
+- mutex_unlock(&instance->aen_mutex);
+-
+- if (error)
+- printk(KERN_ERR "register aen failed error %x\n", error);
+-
+- kfree(ev);
+-}
+-
+-
+-static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUSR,
+- megasas_sysfs_show_poll_mode_io,
+- megasas_sysfs_set_poll_mode_io);
+-
+-/**
+- * megasas_init - Driver load entry point
+- */
+-static int __init megasas_init(void)
+-{
+- int rval;
+-
+- /*
+- * Announce driver version and other information
+- */
+- printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION,
+- MEGASAS_EXT_VERSION);
+-
+- support_poll_for_event = 2;
+-
+- memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
+-
+- /*
+- * Register character device node
+- */
+- rval = register_chrdev(0, "megaraid_sas_ioctl", &megasas_mgmt_fops);
+-
+- if (rval < 0) {
+- printk(KERN_DEBUG "megasas: failed to open device node\n");
+- return rval;
+- }
+-
+- megasas_mgmt_majorno = rval;
+-
+- /*
+- * Register ourselves as PCI hotplug module
+- */
+- rval = pci_register_driver(&megasas_pci_driver);
+-
+- if (rval) {
+- printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
+- goto err_pcidrv;
+- }
+-
+- rval = driver_create_file(&megasas_pci_driver.driver,
+- &driver_attr_version);
+- if (rval)
+- goto err_dcf_attr_ver;
+- rval = driver_create_file(&megasas_pci_driver.driver,
+- &driver_attr_release_date);
+- if (rval)
+- goto err_dcf_rel_date;
+-
+- rval = driver_create_file(&megasas_pci_driver.driver,
+- &driver_attr_support_poll_for_event);
+- if (rval)
+- goto err_dcf_support_poll_for_event;
+-
+- rval = driver_create_file(&megasas_pci_driver.driver,
+- &driver_attr_dbg_lvl);
+- if (rval)
+- goto err_dcf_dbg_lvl;
+- rval = driver_create_file(&megasas_pci_driver.driver,
+- &driver_attr_poll_mode_io);
+- if (rval)
+- goto err_dcf_poll_mode_io;
+-
+- return rval;
+-
+-err_dcf_poll_mode_io:
+- driver_remove_file(&megasas_pci_driver.driver,
+- &driver_attr_dbg_lvl);
+-err_dcf_dbg_lvl:
+- driver_remove_file(&megasas_pci_driver.driver,
+- &driver_attr_support_poll_for_event);
+-
+-err_dcf_support_poll_for_event:
+- driver_remove_file(&megasas_pci_driver.driver,
+- &driver_attr_release_date);
+-
+-err_dcf_rel_date:
+- driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+-err_dcf_attr_ver:
+- pci_unregister_driver(&megasas_pci_driver);
+-err_pcidrv:
+- unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+- return rval;
+-}
+-
+-/**
+- * megasas_exit - Driver unload entry point
+- */
+-static void __exit megasas_exit(void)
+-{
+- driver_remove_file(&megasas_pci_driver.driver,
+- &driver_attr_poll_mode_io);
+- driver_remove_file(&megasas_pci_driver.driver,
+- &driver_attr_dbg_lvl);
+- driver_remove_file(&megasas_pci_driver.driver,
+- &driver_attr_release_date);
+- driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+-
+- pci_unregister_driver(&megasas_pci_driver);
+- unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+-}
+-
+-module_init(megasas_init);
+-module_exit(megasas_exit);
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+new file mode 100644
+index 000000000000..a18ae3cba87e
+--- /dev/null
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -0,0 +1,5005 @@
++/*
++ *
++ * Linux MegaRAID driver for SAS based RAID controllers
++ *
++ * Copyright (c) 2003-2005 LSI Corporation.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * FILE : megaraid_sas.c
++ * Version : v00.00.04.01-rc1
++ *
++ * Authors:
++ * (email-id : megaraidlinux at lsi.com)
++ * Sreenivas Bagalkote
++ * Sumant Patro
++ * Bo Yang
++ *
++ * List of supported controllers
++ *
++ * OEM Product Name VID DID SSVID SSID
++ * --- ------------ --- --- ---- ----
++ */
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/list.h>
++#include <linux/moduleparam.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/smp_lock.h>
++#include <linux/uio.h>
++#include <asm/uaccess.h>
++#include <linux/fs.h>
++#include <linux/compat.h>
++#include <linux/blkdev.h>
++#include <linux/mutex.h>
++#include <linux/poll.h>
++
++#include <scsi/scsi.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_host.h>
++#include "megaraid_sas.h"
++
++/*
++ * poll_mode_io:1- schedule complete completion from q cmd
++ */
++static unsigned int poll_mode_io;
++module_param_named(poll_mode_io, poll_mode_io, int, 0);
++MODULE_PARM_DESC(poll_mode_io,
++ "Complete cmds from IO path, (default=0)");
++
++MODULE_LICENSE("GPL");
++MODULE_VERSION(MEGASAS_VERSION);
++MODULE_AUTHOR("megaraidlinux at lsi.com");
++MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
++
++static int megasas_transition_to_ready(struct megasas_instance *instance);
++static int megasas_get_pd_list(struct megasas_instance *instance);
++static int megasas_issue_init_mfi(struct megasas_instance *instance);
++static int megasas_register_aen(struct megasas_instance *instance,
++ u32 seq_num, u32 class_locale_word);
++/*
++ * PCI ID table for all supported controllers
++ */
++static struct pci_device_id megasas_pci_table[] = {
++
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)},
++ /* xscale IOP */
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)},
++ /* ppc IOP */
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078DE)},
++ /* ppc IOP */
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078GEN2)},
++ /* gen2*/
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0079GEN2)},
++ /* gen2*/
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0073SKINNY)},
++ /* skinny*/
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0071SKINNY)},
++ /* skinny*/
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},
++ /* xscale IOP, vega */
++ {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
++ /* xscale IOP */
++ {}
++};
++
++MODULE_DEVICE_TABLE(pci, megasas_pci_table);
++
++static int megasas_mgmt_majorno;
++static struct megasas_mgmt_info megasas_mgmt_info;
++static struct fasync_struct *megasas_async_queue;
++static DEFINE_MUTEX(megasas_async_queue_mutex);
++
++static int megasas_poll_wait_aen;
++static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
++static u32 support_poll_for_event;
++static u32 megasas_dbg_lvl;
++
++/* define lock for aen poll */
++spinlock_t poll_aen_lock;
++
++static void
++megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
++ u8 alt_status);
++
++/**
++ * megasas_get_cmd - Get a command from the free pool
++ * @instance: Adapter soft state
++ *
++ * Returns a free command from the pool
++ */
++static struct megasas_cmd *megasas_get_cmd(struct megasas_instance
++ *instance)
++{
++ unsigned long flags;
++ struct megasas_cmd *cmd = NULL;
++
++ spin_lock_irqsave(&instance->cmd_pool_lock, flags);
++
++ if (!list_empty(&instance->cmd_pool)) {
++ cmd = list_entry((&instance->cmd_pool)->next,
++ struct megasas_cmd, list);
++ list_del_init(&cmd->list);
++ } else {
++ printk(KERN_ERR "megasas: Command pool empty!\n");
++ }
++
++ spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
++ return cmd;
++}
++
++/**
++ * megasas_return_cmd - Return a cmd to free command pool
++ * @instance: Adapter soft state
++ * @cmd: Command packet to be returned to free command pool
++ */
++static inline void
++megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&instance->cmd_pool_lock, flags);
++
++ cmd->scmd = NULL;
++ list_add_tail(&cmd->list, &instance->cmd_pool);
++
++ spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
++}
++
++
++/**
++* The following functions are defined for xscale
++* (deviceid : 1064R, PERC5) controllers
++*/
++
++/**
++ * megasas_enable_intr_xscale - Enables interrupts
++ * @regs: MFI register set
++ */
++static inline void
++megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
++{
++ writel(0, &(regs)->outbound_intr_mask);
++
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_mask);
++}
++
++/**
++ * megasas_disable_intr_xscale -Disables interrupt
++ * @regs: MFI register set
++ */
++static inline void
++megasas_disable_intr_xscale(struct megasas_register_set __iomem * regs)
++{
++ u32 mask = 0x1f;
++ writel(mask, ®s->outbound_intr_mask);
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_mask);
++}
++
++/**
++ * megasas_read_fw_status_reg_xscale - returns the current FW status value
++ * @regs: MFI register set
++ */
++static u32
++megasas_read_fw_status_reg_xscale(struct megasas_register_set __iomem * regs)
++{
++ return readl(&(regs)->outbound_msg_0);
++}
++/**
++ * megasas_clear_interrupt_xscale - Check & clear interrupt
++ * @regs: MFI register set
++ */
++static int
++megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
++{
++ u32 status;
++ u32 mfiStatus = 0;
++ /*
++ * Check if it is our interrupt
++ */
++ status = readl(®s->outbound_intr_status);
++
++ if (status & MFI_OB_INTR_STATUS_MASK)
++ mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
++ if (status & MFI_XSCALE_OMR0_CHANGE_INTERRUPT)
++ mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
++
++ /*
++ * Clear the interrupt by writing back the same value
++ */
++ if (mfiStatus)
++ writel(status, ®s->outbound_intr_status);
++
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_status);
++
++ return mfiStatus;
++}
++
++/**
++ * megasas_fire_cmd_xscale - Sends command to the FW
++ * @frame_phys_addr : Physical address of cmd
++ * @frame_count : Number of frames for the command
++ * @regs : MFI register set
++ */
++static inline void
++megasas_fire_cmd_xscale(struct megasas_instance *instance,
++ dma_addr_t frame_phys_addr,
++ u32 frame_count,
++ struct megasas_register_set __iomem *regs)
++{
++ unsigned long flags;
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ writel((frame_phys_addr >> 3)|(frame_count),
++ &(regs)->inbound_queue_port);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++}
++
++/**
++ * megasas_adp_reset_xscale - For controller reset
++ * @regs: MFI register set
++ */
++static int
++megasas_adp_reset_xscale(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ u32 i;
++ u32 pcidata;
++ writel(MFI_ADP_RESET, ®s->inbound_doorbell);
++
++ for (i = 0; i < 3; i++)
++ msleep(1000); /* sleep for 3 secs */
++ pcidata = 0;
++ pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata);
++ printk(KERN_NOTICE "pcidata = %x\n", pcidata);
++ if (pcidata & 0x2) {
++ printk(KERN_NOTICE "mfi 1068 offset read=%x\n", pcidata);
++ pcidata &= ~0x2;
++ pci_write_config_dword(instance->pdev,
++ MFI_1068_PCSR_OFFSET, pcidata);
++
++ for (i = 0; i < 2; i++)
++ msleep(1000); /* need to wait 2 secs again */
++
++ pcidata = 0;
++ pci_read_config_dword(instance->pdev,
++ MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata);
++ printk(KERN_NOTICE "1068 offset handshake read=%x\n", pcidata);
++ if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) {
++ printk(KERN_NOTICE "1068 offset pcidt=%x\n", pcidata);
++ pcidata = 0;
++ pci_write_config_dword(instance->pdev,
++ MFI_1068_FW_HANDSHAKE_OFFSET, pcidata);
++ }
++ }
++ return 0;
++}
++
++/**
++ * megasas_check_reset_xscale - For controller reset check
++ * @regs: MFI register set
++ */
++static int
++megasas_check_reset_xscale(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ u32 consumer;
++ consumer = *instance->consumer;
++
++ if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
++ (*instance->consumer == MEGASAS_ADPRESET_INPROG_SIGN)) {
++ return 1;
++ }
++ return 0;
++}
++
++static struct megasas_instance_template megasas_instance_template_xscale = {
++
++ .fire_cmd = megasas_fire_cmd_xscale,
++ .enable_intr = megasas_enable_intr_xscale,
++ .disable_intr = megasas_disable_intr_xscale,
++ .clear_intr = megasas_clear_intr_xscale,
++ .read_fw_status_reg = megasas_read_fw_status_reg_xscale,
++ .adp_reset = megasas_adp_reset_xscale,
++ .check_reset = megasas_check_reset_xscale,
++};
++
++/**
++* This is the end of set of functions & definitions specific
++* to xscale (deviceid : 1064R, PERC5) controllers
++*/
++
++/**
++* The following functions are defined for ppc (deviceid : 0x60)
++* controllers
++*/
++
++/**
++ * megasas_enable_intr_ppc - Enables interrupts
++ * @regs: MFI register set
++ */
++static inline void
++megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs)
++{
++ writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
++
++ writel(~0x80000000, &(regs)->outbound_intr_mask);
++
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_mask);
++}
++
++/**
++ * megasas_disable_intr_ppc - Disable interrupt
++ * @regs: MFI register set
++ */
++static inline void
++megasas_disable_intr_ppc(struct megasas_register_set __iomem * regs)
++{
++ u32 mask = 0xFFFFFFFF;
++ writel(mask, ®s->outbound_intr_mask);
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_mask);
++}
++
++/**
++ * megasas_read_fw_status_reg_ppc - returns the current FW status value
++ * @regs: MFI register set
++ */
++static u32
++megasas_read_fw_status_reg_ppc(struct megasas_register_set __iomem * regs)
++{
++ return readl(&(regs)->outbound_scratch_pad);
++}
++
++/**
++ * megasas_clear_interrupt_ppc - Check & clear interrupt
++ * @regs: MFI register set
++ */
++static int
++megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
++{
++ u32 status;
++ /*
++ * Check if it is our interrupt
++ */
++ status = readl(®s->outbound_intr_status);
++
++ if (!(status & MFI_REPLY_1078_MESSAGE_INTERRUPT)) {
++ return 0;
++ }
++
++ /*
++ * Clear the interrupt by writing back the same value
++ */
++ writel(status, ®s->outbound_doorbell_clear);
++
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_doorbell_clear);
++
++ return 1;
++}
++/**
++ * megasas_fire_cmd_ppc - Sends command to the FW
++ * @frame_phys_addr : Physical address of cmd
++ * @frame_count : Number of frames for the command
++ * @regs : MFI register set
++ */
++static inline void
++megasas_fire_cmd_ppc(struct megasas_instance *instance,
++ dma_addr_t frame_phys_addr,
++ u32 frame_count,
++ struct megasas_register_set __iomem *regs)
++{
++ unsigned long flags;
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ writel((frame_phys_addr | (frame_count<<1))|1,
++ &(regs)->inbound_queue_port);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++}
++
++/**
++ * megasas_adp_reset_ppc - For controller reset
++ * @regs: MFI register set
++ */
++static int
++megasas_adp_reset_ppc(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
++}
++
++/**
++ * megasas_check_reset_ppc - For controller reset check
++ * @regs: MFI register set
++ */
++static int
++megasas_check_reset_ppc(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
++}
++static struct megasas_instance_template megasas_instance_template_ppc = {
++
++ .fire_cmd = megasas_fire_cmd_ppc,
++ .enable_intr = megasas_enable_intr_ppc,
++ .disable_intr = megasas_disable_intr_ppc,
++ .clear_intr = megasas_clear_intr_ppc,
++ .read_fw_status_reg = megasas_read_fw_status_reg_ppc,
++ .adp_reset = megasas_adp_reset_ppc,
++ .check_reset = megasas_check_reset_ppc,
++};
++
++/**
++ * megasas_enable_intr_skinny - Enables interrupts
++ * @regs: MFI register set
++ */
++static inline void
++megasas_enable_intr_skinny(struct megasas_register_set __iomem *regs)
++{
++ writel(0xFFFFFFFF, &(regs)->outbound_intr_mask);
++
++ writel(~MFI_SKINNY_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
++
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_mask);
++}
++
++/**
++ * megasas_disable_intr_skinny - Disables interrupt
++ * @regs: MFI register set
++ */
++static inline void
++megasas_disable_intr_skinny(struct megasas_register_set __iomem *regs)
++{
++ u32 mask = 0xFFFFFFFF;
++ writel(mask, ®s->outbound_intr_mask);
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_mask);
++}
++
++/**
++ * megasas_read_fw_status_reg_skinny - returns the current FW status value
++ * @regs: MFI register set
++ */
++static u32
++megasas_read_fw_status_reg_skinny(struct megasas_register_set __iomem *regs)
++{
++ return readl(&(regs)->outbound_scratch_pad);
++}
++
++/**
++ * megasas_clear_interrupt_skinny - Check & clear interrupt
++ * @regs: MFI register set
++ */
++static int
++megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
++{
++ u32 status;
++ /*
++ * Check if it is our interrupt
++ */
++ status = readl(®s->outbound_intr_status);
++
++ if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) {
++ return 0;
++ }
++
++ /*
++ * Clear the interrupt by writing back the same value
++ */
++ writel(status, ®s->outbound_intr_status);
++
++ /*
++ * dummy read to flush PCI
++ */
++ readl(®s->outbound_intr_status);
++
++ return 1;
++}
++
++/**
++ * megasas_fire_cmd_skinny - Sends command to the FW
++ * @frame_phys_addr : Physical address of cmd
++ * @frame_count : Number of frames for the command
++ * @regs : MFI register set
++ */
++static inline void
++megasas_fire_cmd_skinny(struct megasas_instance *instance,
++ dma_addr_t frame_phys_addr,
++ u32 frame_count,
++ struct megasas_register_set __iomem *regs)
++{
++ unsigned long flags;
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ writel(0, &(regs)->inbound_high_queue_port);
++ writel((frame_phys_addr | (frame_count<<1))|1,
++ &(regs)->inbound_low_queue_port);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++}
++
++/**
++ * megasas_adp_reset_skinny - For controller reset
++ * @regs: MFI register set
++ */
++static int
++megasas_adp_reset_skinny(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
++}
++
++/**
++ * megasas_check_reset_skinny - For controller reset check
++ * @regs: MFI register set
++ */
++static int
++megasas_check_reset_skinny(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
++}
++
++static struct megasas_instance_template megasas_instance_template_skinny = {
++
++ .fire_cmd = megasas_fire_cmd_skinny,
++ .enable_intr = megasas_enable_intr_skinny,
++ .disable_intr = megasas_disable_intr_skinny,
++ .clear_intr = megasas_clear_intr_skinny,
++ .read_fw_status_reg = megasas_read_fw_status_reg_skinny,
++ .adp_reset = megasas_adp_reset_skinny,
++ .check_reset = megasas_check_reset_skinny,
++};
++
++
++/**
++* The following functions are defined for gen2 (deviceid : 0x78 0x79)
++* controllers
++*/
++
++/**
++ * megasas_enable_intr_gen2 - Enables interrupts
++ * @regs: MFI register set
++ */
++static inline void
++megasas_enable_intr_gen2(struct megasas_register_set __iomem *regs)
++{
++ writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
++
++ /* write ~0x00000005 (4 & 1) to the intr mask*/
++ writel(~MFI_GEN2_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
++
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_mask);
++}
++
++/**
++ * megasas_disable_intr_gen2 - Disables interrupt
++ * @regs: MFI register set
++ */
++static inline void
++megasas_disable_intr_gen2(struct megasas_register_set __iomem *regs)
++{
++ u32 mask = 0xFFFFFFFF;
++ writel(mask, ®s->outbound_intr_mask);
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_mask);
++}
++
++/**
++ * megasas_read_fw_status_reg_gen2 - returns the current FW status value
++ * @regs: MFI register set
++ */
++static u32
++megasas_read_fw_status_reg_gen2(struct megasas_register_set __iomem *regs)
++{
++ return readl(&(regs)->outbound_scratch_pad);
++}
++
++/**
++ * megasas_clear_interrupt_gen2 - Check & clear interrupt
++ * @regs: MFI register set
++ */
++static int
++megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
++{
++ u32 status;
++ u32 mfiStatus = 0;
++ /*
++ * Check if it is our interrupt
++ */
++ status = readl(®s->outbound_intr_status);
++
++ if (status & MFI_GEN2_ENABLE_INTERRUPT_MASK) {
++ mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
++ }
++ if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) {
++ mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
++ }
++
++ /*
++ * Clear the interrupt by writing back the same value
++ */
++ if (mfiStatus)
++ writel(status, ®s->outbound_doorbell_clear);
++
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_status);
++
++ return mfiStatus;
++}
++/**
++ * megasas_fire_cmd_gen2 - Sends command to the FW
++ * @frame_phys_addr : Physical address of cmd
++ * @frame_count : Number of frames for the command
++ * @regs : MFI register set
++ */
++static inline void
++megasas_fire_cmd_gen2(struct megasas_instance *instance,
++ dma_addr_t frame_phys_addr,
++ u32 frame_count,
++ struct megasas_register_set __iomem *regs)
++{
++ unsigned long flags;
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ writel((frame_phys_addr | (frame_count<<1))|1,
++ &(regs)->inbound_queue_port);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++}
++
++/**
++ * megasas_adp_reset_gen2 - For controller reset
++ * @regs: MFI register set
++ */
++static int
++megasas_adp_reset_gen2(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *reg_set)
++{
++ u32 retry = 0 ;
++ u32 HostDiag;
++
++ writel(0, ®_set->seq_offset);
++ writel(4, ®_set->seq_offset);
++ writel(0xb, ®_set->seq_offset);
++ writel(2, ®_set->seq_offset);
++ writel(7, ®_set->seq_offset);
++ writel(0xd, ®_set->seq_offset);
++ msleep(1000);
++
++ HostDiag = (u32)readl(®_set->host_diag);
++
++ while ( !( HostDiag & DIAG_WRITE_ENABLE) ) {
++ msleep(100);
++ HostDiag = (u32)readl(®_set->host_diag);
++ printk(KERN_NOTICE "RESETGEN2: retry=%x, hostdiag=%x\n",
++ retry, HostDiag);
++
++ if (retry++ >= 100)
++ return 1;
++
++ }
++
++ printk(KERN_NOTICE "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag);
++
++ writel((HostDiag | DIAG_RESET_ADAPTER), ®_set->host_diag);
++
++ ssleep(10);
++
++ HostDiag = (u32)readl(®_set->host_diag);
++ while ( ( HostDiag & DIAG_RESET_ADAPTER) ) {
++ msleep(100);
++ HostDiag = (u32)readl(®_set->host_diag);
++ printk(KERN_NOTICE "RESET_GEN2: retry=%x, hostdiag=%x\n",
++ retry, HostDiag);
++
++ if (retry++ >= 1000)
++ return 1;
++
++ }
++ return 0;
++}
++
++/**
++ * megasas_check_reset_gen2 - For controller reset check
++ * @regs: MFI register set
++ */
++static int
++megasas_check_reset_gen2(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
++}
++
++static struct megasas_instance_template megasas_instance_template_gen2 = {
++
++ .fire_cmd = megasas_fire_cmd_gen2,
++ .enable_intr = megasas_enable_intr_gen2,
++ .disable_intr = megasas_disable_intr_gen2,
++ .clear_intr = megasas_clear_intr_gen2,
++ .read_fw_status_reg = megasas_read_fw_status_reg_gen2,
++ .adp_reset = megasas_adp_reset_gen2,
++ .check_reset = megasas_check_reset_gen2,
++};
++
++/**
++* This is the end of set of functions & definitions
++* specific to gen2 (deviceid : 0x78, 0x79) controllers
++*/
++
++/**
++ * megasas_issue_polled - Issues a polling command
++ * @instance: Adapter soft state
++ * @cmd: Command packet to be issued
++ *
++ * For polling, MFI requires the cmd_status to be set to 0xFF before posting.
++ */
++static int
++megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
++{
++ int i;
++ u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
++
++ struct megasas_header *frame_hdr = &cmd->frame->hdr;
++
++ frame_hdr->cmd_status = 0xFF;
++ frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
++
++ /*
++ * Issue the frame using inbound queue port
++ */
++ instance->instancet->fire_cmd(instance,
++ cmd->frame_phys_addr, 0, instance->reg_set);
++
++ /*
++ * Wait for cmd_status to change
++ */
++ for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i++) {
++ rmb();
++ msleep(1);
++ }
++
++ if (frame_hdr->cmd_status == 0xff)
++ return -ETIME;
++
++ return 0;
++}
++
++/**
++ * megasas_issue_blocked_cmd - Synchronous wrapper around regular FW cmds
++ * @instance: Adapter soft state
++ * @cmd: Command to be issued
++ *
++ * This function waits on an event for the command to be returned from ISR.
++ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
++ * Used to issue ioctl commands.
++ */
++static int
++megasas_issue_blocked_cmd(struct megasas_instance *instance,
++ struct megasas_cmd *cmd)
++{
++ cmd->cmd_status = ENODATA;
++
++ instance->instancet->fire_cmd(instance,
++ cmd->frame_phys_addr, 0, instance->reg_set);
++
++ wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA);
++
++ return 0;
++}
++
++/**
++ * megasas_issue_blocked_abort_cmd - Aborts previously issued cmd
++ * @instance: Adapter soft state
++ * @cmd_to_abort: Previously issued cmd to be aborted
++ *
++ * MFI firmware can abort previously issued AEN comamnd (automatic event
++ * notification). The megasas_issue_blocked_abort_cmd() issues such abort
++ * cmd and waits for return status.
++ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
++ */
++static int
++megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
++ struct megasas_cmd *cmd_to_abort)
++{
++ struct megasas_cmd *cmd;
++ struct megasas_abort_frame *abort_fr;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd)
++ return -1;
++
++ abort_fr = &cmd->frame->abort;
++
++ /*
++ * Prepare and issue the abort frame
++ */
++ abort_fr->cmd = MFI_CMD_ABORT;
++ abort_fr->cmd_status = 0xFF;
++ abort_fr->flags = 0;
++ abort_fr->abort_context = cmd_to_abort->index;
++ abort_fr->abort_mfi_phys_addr_lo = cmd_to_abort->frame_phys_addr;
++ abort_fr->abort_mfi_phys_addr_hi = 0;
++
++ cmd->sync_cmd = 1;
++ cmd->cmd_status = 0xFF;
++
++ instance->instancet->fire_cmd(instance,
++ cmd->frame_phys_addr, 0, instance->reg_set);
++
++ /*
++ * Wait for this cmd to complete
++ */
++ wait_event(instance->abort_cmd_wait_q, cmd->cmd_status != 0xFF);
++ cmd->sync_cmd = 0;
++
++ megasas_return_cmd(instance, cmd);
++ return 0;
++}
++
++/**
++ * megasas_make_sgl32 - Prepares 32-bit SGL
++ * @instance: Adapter soft state
++ * @scp: SCSI command from the mid-layer
++ * @mfi_sgl: SGL to be filled in
++ *
++ * If successful, this function returns the number of SG elements. Otherwise,
++ * it returnes -1.
++ */
++static int
++megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,
++ union megasas_sgl *mfi_sgl)
++{
++ int i;
++ int sge_count;
++ struct scatterlist *os_sgl;
++
++ sge_count = scsi_dma_map(scp);
++ BUG_ON(sge_count < 0);
++
++ if (sge_count) {
++ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
++ mfi_sgl->sge32[i].length = sg_dma_len(os_sgl);
++ mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl);
++ }
++ }
++ return sge_count;
++}
++
++/**
++ * megasas_make_sgl64 - Prepares 64-bit SGL
++ * @instance: Adapter soft state
++ * @scp: SCSI command from the mid-layer
++ * @mfi_sgl: SGL to be filled in
++ *
++ * If successful, this function returns the number of SG elements. Otherwise,
++ * it returnes -1.
++ */
++static int
++megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
++ union megasas_sgl *mfi_sgl)
++{
++ int i;
++ int sge_count;
++ struct scatterlist *os_sgl;
++
++ sge_count = scsi_dma_map(scp);
++ BUG_ON(sge_count < 0);
++
++ if (sge_count) {
++ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
++ mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);
++ mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);
++ }
++ }
++ return sge_count;
++}
++
++/**
++ * megasas_make_sgl_skinny - Prepares IEEE SGL
++ * @instance: Adapter soft state
++ * @scp: SCSI command from the mid-layer
++ * @mfi_sgl: SGL to be filled in
++ *
++ * If successful, this function returns the number of SG elements. Otherwise,
++ * it returnes -1.
++ */
++static int
++megasas_make_sgl_skinny(struct megasas_instance *instance,
++ struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl)
++{
++ int i;
++ int sge_count;
++ struct scatterlist *os_sgl;
++
++ sge_count = scsi_dma_map(scp);
++
++ if (sge_count) {
++ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
++ mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
++ mfi_sgl->sge_skinny[i].phys_addr =
++ sg_dma_address(os_sgl);
++ }
++ }
++ return sge_count;
++}
++
++ /**
++ * megasas_get_frame_count - Computes the number of frames
++ * @frame_type : type of frame- io or pthru frame
++ * @sge_count : number of sg elements
++ *
++ * Returns the number of frames required for numnber of sge's (sge_count)
++ */
++
++static u32 megasas_get_frame_count(struct megasas_instance *instance,
++ u8 sge_count, u8 frame_type)
++{
++ int num_cnt;
++ int sge_bytes;
++ u32 sge_sz;
++ u32 frame_count=0;
++
++ sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
++ sizeof(struct megasas_sge32);
++
++ if (instance->flag_ieee) {
++ sge_sz = sizeof(struct megasas_sge_skinny);
++ }
++
++ /*
++ * Main frame can contain 2 SGEs for 64-bit SGLs and
++ * 3 SGEs for 32-bit SGLs for ldio &
++ * 1 SGEs for 64-bit SGLs and
++ * 2 SGEs for 32-bit SGLs for pthru frame
++ */
++ if (unlikely(frame_type == PTHRU_FRAME)) {
++ if (instance->flag_ieee == 1) {
++ num_cnt = sge_count - 1;
++ } else if (IS_DMA64)
++ num_cnt = sge_count - 1;
++ else
++ num_cnt = sge_count - 2;
++ } else {
++ if (instance->flag_ieee == 1) {
++ num_cnt = sge_count - 1;
++ } else if (IS_DMA64)
++ num_cnt = sge_count - 2;
++ else
++ num_cnt = sge_count - 3;
++ }
++
++ if(num_cnt>0){
++ sge_bytes = sge_sz * num_cnt;
++
++ frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
++ ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;
++ }
++ /* Main frame */
++ frame_count +=1;
++
++ if (frame_count > 7)
++ frame_count = 8;
++ return frame_count;
++}
++
++/**
++ * megasas_build_dcdb - Prepares a direct cdb (DCDB) command
++ * @instance: Adapter soft state
++ * @scp: SCSI command
++ * @cmd: Command to be prepared in
++ *
++ * This function prepares CDB commands. These are typcially pass-through
++ * commands to the devices.
++ */
++static int
++megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
++ struct megasas_cmd *cmd)
++{
++ u32 is_logical;
++ u32 device_id;
++ u16 flags = 0;
++ struct megasas_pthru_frame *pthru;
++
++ is_logical = MEGASAS_IS_LOGICAL(scp);
++ device_id = MEGASAS_DEV_INDEX(instance, scp);
++ pthru = (struct megasas_pthru_frame *)cmd->frame;
++
++ if (scp->sc_data_direction == PCI_DMA_TODEVICE)
++ flags = MFI_FRAME_DIR_WRITE;
++ else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
++ flags = MFI_FRAME_DIR_READ;
++ else if (scp->sc_data_direction == PCI_DMA_NONE)
++ flags = MFI_FRAME_DIR_NONE;
++
++ if (instance->flag_ieee == 1) {
++ flags |= MFI_FRAME_IEEE;
++ }
++
++ /*
++ * Prepare the DCDB frame
++ */
++ pthru->cmd = (is_logical) ? MFI_CMD_LD_SCSI_IO : MFI_CMD_PD_SCSI_IO;
++ pthru->cmd_status = 0x0;
++ pthru->scsi_status = 0x0;
++ pthru->target_id = device_id;
++ pthru->lun = scp->device->lun;
++ pthru->cdb_len = scp->cmd_len;
++ pthru->timeout = 0;
++ pthru->flags = flags;
++ pthru->data_xfer_len = scsi_bufflen(scp);
++
++ memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
++
++ /*
++ * Construct SGL
++ */
++ if (instance->flag_ieee == 1) {
++ pthru->flags |= MFI_FRAME_SGL64;
++ pthru->sge_count = megasas_make_sgl_skinny(instance, scp,
++ &pthru->sgl);
++ } else if (IS_DMA64) {
++ pthru->flags |= MFI_FRAME_SGL64;
++ pthru->sge_count = megasas_make_sgl64(instance, scp,
++ &pthru->sgl);
++ } else
++ pthru->sge_count = megasas_make_sgl32(instance, scp,
++ &pthru->sgl);
++
++ if (pthru->sge_count > instance->max_num_sge) {
++ printk(KERN_ERR "megasas: DCDB two many SGE NUM=%x\n",
++ pthru->sge_count);
++ return 0;
++ }
++
++ /*
++ * Sense info specific
++ */
++ pthru->sense_len = SCSI_SENSE_BUFFERSIZE;
++ pthru->sense_buf_phys_addr_hi = 0;
++ pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
++
++ /*
++ * Compute the total number of frames this command consumes. FW uses
++ * this number to pull sufficient number of frames from host memory.
++ */
++ cmd->frame_count = megasas_get_frame_count(instance, pthru->sge_count,
++ PTHRU_FRAME);
++
++ return cmd->frame_count;
++}
++
++/**
++ * megasas_build_ldio - Prepares IOs to logical devices
++ * @instance: Adapter soft state
++ * @scp: SCSI command
++ * @cmd: Command to be prepared
++ *
++ * Frames (and accompanying SGLs) for regular SCSI IOs use this function.
++ */
++static int
++megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
++ struct megasas_cmd *cmd)
++{
++ u32 device_id;
++ u8 sc = scp->cmnd[0];
++ u16 flags = 0;
++ struct megasas_io_frame *ldio;
++
++ device_id = MEGASAS_DEV_INDEX(instance, scp);
++ ldio = (struct megasas_io_frame *)cmd->frame;
++
++ if (scp->sc_data_direction == PCI_DMA_TODEVICE)
++ flags = MFI_FRAME_DIR_WRITE;
++ else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
++ flags = MFI_FRAME_DIR_READ;
++
++ if (instance->flag_ieee == 1) {
++ flags |= MFI_FRAME_IEEE;
++ }
++
++ /*
++ * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
++ */
++ ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;
++ ldio->cmd_status = 0x0;
++ ldio->scsi_status = 0x0;
++ ldio->target_id = device_id;
++ ldio->timeout = 0;
++ ldio->reserved_0 = 0;
++ ldio->pad_0 = 0;
++ ldio->flags = flags;
++ ldio->start_lba_hi = 0;
++ ldio->access_byte = (scp->cmd_len != 6) ? scp->cmnd[1] : 0;
++
++ /*
++ * 6-byte READ(0x08) or WRITE(0x0A) cdb
++ */
++ if (scp->cmd_len == 6) {
++ ldio->lba_count = (u32) scp->cmnd[4];
++ ldio->start_lba_lo = ((u32) scp->cmnd[1] << 16) |
++ ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3];
++
++ ldio->start_lba_lo &= 0x1FFFFF;
++ }
++
++ /*
++ * 10-byte READ(0x28) or WRITE(0x2A) cdb
++ */
++ else if (scp->cmd_len == 10) {
++ ldio->lba_count = (u32) scp->cmnd[8] |
++ ((u32) scp->cmnd[7] << 8);
++ ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |
++ ((u32) scp->cmnd[3] << 16) |
++ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
++ }
++
++ /*
++ * 12-byte READ(0xA8) or WRITE(0xAA) cdb
++ */
++ else if (scp->cmd_len == 12) {
++ ldio->lba_count = ((u32) scp->cmnd[6] << 24) |
++ ((u32) scp->cmnd[7] << 16) |
++ ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
++
++ ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |
++ ((u32) scp->cmnd[3] << 16) |
++ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
++ }
++
++ /*
++ * 16-byte READ(0x88) or WRITE(0x8A) cdb
++ */
++ else if (scp->cmd_len == 16) {
++ ldio->lba_count = ((u32) scp->cmnd[10] << 24) |
++ ((u32) scp->cmnd[11] << 16) |
++ ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13];
++
++ ldio->start_lba_lo = ((u32) scp->cmnd[6] << 24) |
++ ((u32) scp->cmnd[7] << 16) |
++ ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
++
++ ldio->start_lba_hi = ((u32) scp->cmnd[2] << 24) |
++ ((u32) scp->cmnd[3] << 16) |
++ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
++
++ }
++
++ /*
++ * Construct SGL
++ */
++ if (instance->flag_ieee) {
++ ldio->flags |= MFI_FRAME_SGL64;
++ ldio->sge_count = megasas_make_sgl_skinny(instance, scp,
++ &ldio->sgl);
++ } else if (IS_DMA64) {
++ ldio->flags |= MFI_FRAME_SGL64;
++ ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
++ } else
++ ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl);
++
++ if (ldio->sge_count > instance->max_num_sge) {
++ printk(KERN_ERR "megasas: build_ld_io: sge_count = %x\n",
++ ldio->sge_count);
++ return 0;
++ }
++
++ /*
++ * Sense info specific
++ */
++ ldio->sense_len = SCSI_SENSE_BUFFERSIZE;
++ ldio->sense_buf_phys_addr_hi = 0;
++ ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
++
++ /*
++ * Compute the total number of frames this command consumes. FW uses
++ * this number to pull sufficient number of frames from host memory.
++ */
++ cmd->frame_count = megasas_get_frame_count(instance,
++ ldio->sge_count, IO_FRAME);
++
++ return cmd->frame_count;
++}
++
++/**
++ * megasas_is_ldio - Checks if the cmd is for logical drive
++ * @scmd: SCSI command
++ *
++ * Called by megasas_queue_command to find out if the command to be queued
++ * is a logical drive command
++ */
++static inline int megasas_is_ldio(struct scsi_cmnd *cmd)
++{
++ if (!MEGASAS_IS_LOGICAL(cmd))
++ return 0;
++ switch (cmd->cmnd[0]) {
++ case READ_10:
++ case WRITE_10:
++ case READ_12:
++ case WRITE_12:
++ case READ_6:
++ case WRITE_6:
++ case READ_16:
++ case WRITE_16:
++ return 1;
++ default:
++ return 0;
++ }
++}
++
++ /**
++ * megasas_dump_pending_frames - Dumps the frame address of all pending cmds
++ * in FW
++ * @instance: Adapter soft state
++ */
++static inline void
++megasas_dump_pending_frames(struct megasas_instance *instance)
++{
++ struct megasas_cmd *cmd;
++ int i,n;
++ union megasas_sgl *mfi_sgl;
++ struct megasas_io_frame *ldio;
++ struct megasas_pthru_frame *pthru;
++ u32 sgcount;
++ u32 max_cmd = instance->max_fw_cmds;
++
++ printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
++ printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
++ if (IS_DMA64)
++ printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);
++ else
++ printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
++
++ printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no);
++ for (i = 0; i < max_cmd; i++) {
++ cmd = instance->cmd_list[i];
++ if(!cmd->scmd)
++ continue;
++ printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
++ if (megasas_is_ldio(cmd->scmd)){
++ ldio = (struct megasas_io_frame *)cmd->frame;
++ mfi_sgl = &ldio->sgl;
++ sgcount = ldio->sge_count;
++ printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount);
++ }
++ else {
++ pthru = (struct megasas_pthru_frame *) cmd->frame;
++ mfi_sgl = &pthru->sgl;
++ sgcount = pthru->sge_count;
++ printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount);
++ }
++ if(megasas_dbg_lvl & MEGASAS_DBG_LVL){
++ for (n = 0; n < sgcount; n++){
++ if (IS_DMA64)
++ printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ;
++ else
++ printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ;
++ }
++ }
++ printk(KERN_ERR "\n");
++ } /*for max_cmd*/
++ printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);
++ for (i = 0; i < max_cmd; i++) {
++
++ cmd = instance->cmd_list[i];
++
++ if(cmd->sync_cmd == 1){
++ printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);
++ }
++ }
++ printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
++}
++
++/**
++ * megasas_queue_command - Queue entry point
++ * @scmd: SCSI command to be queued
++ * @done: Callback entry point
++ */
++static int
++megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
++{
++ u32 frame_count;
++ struct megasas_cmd *cmd;
++ struct megasas_instance *instance;
++ unsigned long flags;
++
++ instance = (struct megasas_instance *)
++ scmd->device->host->hostdata;
++
++ if (instance->issuepend_done == 0)
++ return SCSI_MLQUEUE_HOST_BUSY;
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ return SCSI_MLQUEUE_HOST_BUSY;
++ }
++
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ scmd->scsi_done = done;
++ scmd->result = 0;
++
++ if (MEGASAS_IS_LOGICAL(scmd) &&
++ (scmd->device->id >= MEGASAS_MAX_LD || scmd->device->lun)) {
++ scmd->result = DID_BAD_TARGET << 16;
++ goto out_done;
++ }
++
++ switch (scmd->cmnd[0]) {
++ case SYNCHRONIZE_CACHE:
++ /*
++ * FW takes care of flush cache on its own
++ * No need to send it down
++ */
++ scmd->result = DID_OK << 16;
++ goto out_done;
++ default:
++ break;
++ }
++
++ cmd = megasas_get_cmd(instance);
++ if (!cmd)
++ return SCSI_MLQUEUE_HOST_BUSY;
++
++ /*
++ * Logical drive command
++ */
++ if (megasas_is_ldio(scmd))
++ frame_count = megasas_build_ldio(instance, scmd, cmd);
++ else
++ frame_count = megasas_build_dcdb(instance, scmd, cmd);
++
++ if (!frame_count)
++ goto out_return_cmd;
++
++ cmd->scmd = scmd;
++ scmd->SCp.ptr = (char *)cmd;
++
++ /*
++ * Issue the command to the FW
++ */
++ atomic_inc(&instance->fw_outstanding);
++
++ instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
++ cmd->frame_count-1, instance->reg_set);
++ /*
++ * Check if we have pend cmds to be completed
++ */
++ if (poll_mode_io && atomic_read(&instance->fw_outstanding))
++ tasklet_schedule(&instance->isr_tasklet);
++
++
++ return 0;
++
++ out_return_cmd:
++ megasas_return_cmd(instance, cmd);
++ out_done:
++ done(scmd);
++ return 0;
++}
++
++static int megasas_slave_configure(struct scsi_device *sdev)
++{
++ /*
++ * Don't export physical disk devices to the disk driver.
++ *
++ * FIXME: Currently we don't export them to the midlayer at all.
++ * That will be fixed once LSI engineers have audited the
++ * firmware for possible issues.
++ */
++ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && sdev->type == TYPE_DISK)
++ return -ENXIO;
++
++ /*
++ * The RAID firmware may require extended timeouts.
++ */
++ if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS)
++ blk_queue_rq_timeout(sdev->request_queue,
++ MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
++ return 0;
++}
++
++static void megaraid_sas_kill_hba(struct megasas_instance *instance)
++{
++ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ writel(MFI_STOP_ADP,
++ &instance->reg_set->reserved_0[0]);
++ } else {
++ writel(MFI_STOP_ADP,
++ &instance->reg_set->inbound_doorbell);
++ }
++}
++
++/**
++ * megasas_complete_cmd_dpc - Returns FW's controller structure
++ * @instance_addr: Address of adapter soft state
++ *
++ * Tasklet to complete cmds
++ */
++static void megasas_complete_cmd_dpc(unsigned long instance_addr)
++{
++ u32 producer;
++ u32 consumer;
++ u32 context;
++ struct megasas_cmd *cmd;
++ struct megasas_instance *instance =
++ (struct megasas_instance *)instance_addr;
++ unsigned long flags;
++
++ /* If we have already declared adapter dead, donot complete cmds */
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR )
++ return;
++
++ spin_lock_irqsave(&instance->completion_lock, flags);
++
++ producer = *instance->producer;
++ consumer = *instance->consumer;
++
++ while (consumer != producer) {
++ context = instance->reply_queue[consumer];
++ if (context >= instance->max_fw_cmds) {
++ printk(KERN_ERR "Unexpected context value %x\n",
++ context);
++ BUG();
++ }
++
++ cmd = instance->cmd_list[context];
++
++ megasas_complete_cmd(instance, cmd, DID_OK);
++
++ consumer++;
++ if (consumer == (instance->max_fw_cmds + 1)) {
++ consumer = 0;
++ }
++ }
++
++ *instance->consumer = producer;
++
++ spin_unlock_irqrestore(&instance->completion_lock, flags);
++
++ /*
++ * Check if we can restore can_queue
++ */
++ if (instance->flag & MEGASAS_FW_BUSY
++ && time_after(jiffies, instance->last_time + 5 * HZ)
++ && atomic_read(&instance->fw_outstanding) < 17) {
++
++ spin_lock_irqsave(instance->host->host_lock, flags);
++ instance->flag &= ~MEGASAS_FW_BUSY;
++ if ((instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ instance->host->can_queue =
++ instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
++ } else
++ instance->host->can_queue =
++ instance->max_fw_cmds - MEGASAS_INT_CMDS;
++
++ spin_unlock_irqrestore(instance->host->host_lock, flags);
++ }
++}
++
++/**
++ * megasas_wait_for_outstanding - Wait for all outstanding cmds
++ * @instance: Adapter soft state
++ *
++ * This function waits for upto MEGASAS_RESET_WAIT_TIME seconds for FW to
++ * complete all its outstanding commands. Returns error if one or more IOs
++ * are pending after this time period. It also marks the controller dead.
++ */
++static int megasas_wait_for_outstanding(struct megasas_instance *instance)
++{
++ int i;
++ u32 reset_index;
++ u32 wait_time = MEGASAS_RESET_WAIT_TIME;
++ u8 adprecovery;
++ unsigned long flags;
++ struct list_head clist_local;
++ struct megasas_cmd *reset_cmd;
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ adprecovery = instance->adprecovery;
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
++
++ INIT_LIST_HEAD(&clist_local);
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ list_splice_init(&instance->internal_reset_pending_q,
++ &clist_local);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ printk(KERN_NOTICE "megasas: HBA reset wait ...\n");
++ for (i = 0; i < wait_time; i++) {
++ msleep(1000);
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ adprecovery = instance->adprecovery;
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ if (adprecovery == MEGASAS_HBA_OPERATIONAL)
++ break;
++ }
++
++ if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
++ printk(KERN_NOTICE "megasas: reset: Stopping HBA.\n");
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ return FAILED;
++ }
++
++ reset_index = 0;
++ while (!list_empty(&clist_local)) {
++ reset_cmd = list_entry((&clist_local)->next,
++ struct megasas_cmd, list);
++ list_del_init(&reset_cmd->list);
++ if (reset_cmd->scmd) {
++ reset_cmd->scmd->result = DID_RESET << 16;
++ printk(KERN_NOTICE "%d:%p reset [%02x], %#lx\n",
++ reset_index, reset_cmd,
++ reset_cmd->scmd->cmnd[0],
++ reset_cmd->scmd->serial_number);
++
++ reset_cmd->scmd->scsi_done(reset_cmd->scmd);
++ megasas_return_cmd(instance, reset_cmd);
++ } else if (reset_cmd->sync_cmd) {
++ printk(KERN_NOTICE "megasas:%p synch cmds"
++ "reset queue\n",
++ reset_cmd);
++
++ reset_cmd->cmd_status = ENODATA;
++ instance->instancet->fire_cmd(instance,
++ reset_cmd->frame_phys_addr,
++ 0, instance->reg_set);
++ } else {
++ printk(KERN_NOTICE "megasas: %p unexpected"
++ "cmds lst\n",
++ reset_cmd);
++ }
++ reset_index++;
++ }
++
++ return SUCCESS;
++ }
++
++ for (i = 0; i < wait_time; i++) {
++
++ int outstanding = atomic_read(&instance->fw_outstanding);
++
++ if (!outstanding)
++ break;
++
++ if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
++ printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
++ "commands to complete\n",i,outstanding);
++ /*
++ * Call cmd completion routine. Cmd to be
++ * be completed directly without depending on isr.
++ */
++ megasas_complete_cmd_dpc((unsigned long)instance);
++ }
++
++ msleep(1000);
++ }
++
++ if (atomic_read(&instance->fw_outstanding)) {
++ printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n");
++ /*
++ * Send signal to FW to stop processing any pending cmds.
++ * The controller will be taken offline by the OS now.
++ */
++ if ((instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ writel(MFI_STOP_ADP,
++ &instance->reg_set->reserved_0[0]);
++ } else {
++ writel(MFI_STOP_ADP,
++ &instance->reg_set->inbound_doorbell);
++ }
++ megasas_dump_pending_frames(instance);
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ return FAILED;
++ }
++
++ printk(KERN_NOTICE "megaraid_sas: no pending cmds after reset\n");
++
++ return SUCCESS;
++}
++
++/**
++ * megasas_generic_reset - Generic reset routine
++ * @scmd: Mid-layer SCSI command
++ *
++ * This routine implements a generic reset handler for device, bus and host
++ * reset requests. Device, bus and host specific reset handlers can use this
++ * function after they do their specific tasks.
++ */
++static int megasas_generic_reset(struct scsi_cmnd *scmd)
++{
++ int ret_val;
++ struct megasas_instance *instance;
++
++ instance = (struct megasas_instance *)scmd->device->host->hostdata;
++
++ scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n",
++ scmd->serial_number, scmd->cmnd[0], scmd->retries);
++
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
++ printk(KERN_ERR "megasas: cannot recover from previous reset "
++ "failures\n");
++ return FAILED;
++ }
++
++ ret_val = megasas_wait_for_outstanding(instance);
++ if (ret_val == SUCCESS)
++ printk(KERN_NOTICE "megasas: reset successful \n");
++ else
++ printk(KERN_ERR "megasas: failed to do reset\n");
++
++ return ret_val;
++}
++
++/**
++ * megasas_reset_timer - quiesce the adapter if required
++ * @scmd: scsi cmnd
++ *
++ * Sets the FW busy flag and reduces the host->can_queue if the
++ * cmd has not been completed within the timeout period.
++ */
++static enum
++blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
++{
++ struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
++ struct megasas_instance *instance;
++ unsigned long flags;
++
++ if (time_after(jiffies, scmd->jiffies_at_alloc +
++ (MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
++ return BLK_EH_NOT_HANDLED;
++ }
++
++ instance = cmd->instance;
++ if (!(instance->flag & MEGASAS_FW_BUSY)) {
++ /* FW is busy, throttle IO */
++ spin_lock_irqsave(instance->host->host_lock, flags);
++
++ instance->host->can_queue = 16;
++ instance->last_time = jiffies;
++ instance->flag |= MEGASAS_FW_BUSY;
++
++ spin_unlock_irqrestore(instance->host->host_lock, flags);
++ }
++ return BLK_EH_RESET_TIMER;
++}
++
++/**
++ * megasas_reset_device - Device reset handler entry point
++ */
++static int megasas_reset_device(struct scsi_cmnd *scmd)
++{
++ int ret;
++
++ /*
++ * First wait for all commands to complete
++ */
++ ret = megasas_generic_reset(scmd);
++
++ return ret;
++}
++
++/**
++ * megasas_reset_bus_host - Bus & host reset handler entry point
++ */
++static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
++{
++ int ret;
++
++ /*
++ * First wait for all commands to complete
++ */
++ ret = megasas_generic_reset(scmd);
++
++ return ret;
++}
++
++/**
++ * megasas_bios_param - Returns disk geometry for a disk
++ * @sdev: device handle
++ * @bdev: block device
++ * @capacity: drive capacity
++ * @geom: geometry parameters
++ */
++static int
++megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
++ sector_t capacity, int geom[])
++{
++ int heads;
++ int sectors;
++ sector_t cylinders;
++ unsigned long tmp;
++ /* Default heads (64) & sectors (32) */
++ heads = 64;
++ sectors = 32;
++
++ tmp = heads * sectors;
++ cylinders = capacity;
++
++ sector_div(cylinders, tmp);
++
++ /*
++ * Handle extended translation size for logical drives > 1Gb
++ */
++
++ if (capacity >= 0x200000) {
++ heads = 255;
++ sectors = 63;
++ tmp = heads*sectors;
++ cylinders = capacity;
++ sector_div(cylinders, tmp);
++ }
++
++ geom[0] = heads;
++ geom[1] = sectors;
++ geom[2] = cylinders;
++
++ return 0;
++}
++
++static void megasas_aen_polling(struct work_struct *work);
++
++/**
++ * megasas_service_aen - Processes an event notification
++ * @instance: Adapter soft state
++ * @cmd: AEN command completed by the ISR
++ *
++ * For AEN, driver sends a command down to FW that is held by the FW till an
++ * event occurs. When an event of interest occurs, FW completes the command
++ * that it was previously holding.
++ *
++ * This routines sends SIGIO signal to processes that have registered with the
++ * driver for AEN.
++ */
++static void
++megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
++{
++ unsigned long flags;
++ /*
++ * Don't signal app if it is just an aborted previously registered aen
++ */
++ if ((!cmd->abort_aen) && (instance->unload == 0)) {
++ spin_lock_irqsave(&poll_aen_lock, flags);
++ megasas_poll_wait_aen = 1;
++ spin_unlock_irqrestore(&poll_aen_lock, flags);
++ wake_up(&megasas_poll_wait);
++ kill_fasync(&megasas_async_queue, SIGIO, POLL_IN);
++ }
++ else
++ cmd->abort_aen = 0;
++
++ instance->aen_cmd = NULL;
++ megasas_return_cmd(instance, cmd);
++
++ if ((instance->unload == 0) &&
++ ((instance->issuepend_done == 1))) {
++ struct megasas_aen_event *ev;
++ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
++ if (!ev) {
++ printk(KERN_ERR "megasas_service_aen: out of memory\n");
++ } else {
++ ev->instance = instance;
++ instance->ev = ev;
++ INIT_WORK(&ev->hotplug_work, megasas_aen_polling);
++ schedule_delayed_work(
++ (struct delayed_work *)&ev->hotplug_work, 0);
++ }
++ }
++}
++
++/*
++ * Scsi host template for megaraid_sas driver
++ */
++static struct scsi_host_template megasas_template = {
++
++ .module = THIS_MODULE,
++ .name = "LSI SAS based MegaRAID driver",
++ .proc_name = "megaraid_sas",
++ .slave_configure = megasas_slave_configure,
++ .queuecommand = megasas_queue_command,
++ .eh_device_reset_handler = megasas_reset_device,
++ .eh_bus_reset_handler = megasas_reset_bus_host,
++ .eh_host_reset_handler = megasas_reset_bus_host,
++ .eh_timed_out = megasas_reset_timer,
++ .bios_param = megasas_bios_param,
++ .use_clustering = ENABLE_CLUSTERING,
++};
++
++/**
++ * megasas_complete_int_cmd - Completes an internal command
++ * @instance: Adapter soft state
++ * @cmd: Command to be completed
++ *
++ * The megasas_issue_blocked_cmd() function waits for a command to complete
++ * after it issues a command. This function wakes up that waiting routine by
++ * calling wake_up() on the wait queue.
++ */
++static void
++megasas_complete_int_cmd(struct megasas_instance *instance,
++ struct megasas_cmd *cmd)
++{
++ cmd->cmd_status = cmd->frame->io.cmd_status;
++
++ if (cmd->cmd_status == ENODATA) {
++ cmd->cmd_status = 0;
++ }
++ wake_up(&instance->int_cmd_wait_q);
++}
++
++/**
++ * megasas_complete_abort - Completes aborting a command
++ * @instance: Adapter soft state
++ * @cmd: Cmd that was issued to abort another cmd
++ *
++ * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q
++ * after it issues an abort on a previously issued command. This function
++ * wakes up all functions waiting on the same wait queue.
++ */
++static void
++megasas_complete_abort(struct megasas_instance *instance,
++ struct megasas_cmd *cmd)
++{
++ if (cmd->sync_cmd) {
++ cmd->sync_cmd = 0;
++ cmd->cmd_status = 0;
++ wake_up(&instance->abort_cmd_wait_q);
++ }
++
++ return;
++}
++
++/**
++ * megasas_complete_cmd - Completes a command
++ * @instance: Adapter soft state
++ * @cmd: Command to be completed
++ * @alt_status: If non-zero, use this value as status to
++ * SCSI mid-layer instead of the value returned
++ * by the FW. This should be used if caller wants
++ * an alternate status (as in the case of aborted
++ * commands)
++ */
++static void
++megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
++ u8 alt_status)
++{
++ int exception = 0;
++ struct megasas_header *hdr = &cmd->frame->hdr;
++ unsigned long flags;
++
++ /* flag for the retry reset */
++ cmd->retry_for_fw_reset = 0;
++
++ if (cmd->scmd)
++ cmd->scmd->SCp.ptr = NULL;
++
++ switch (hdr->cmd) {
++
++ case MFI_CMD_PD_SCSI_IO:
++ case MFI_CMD_LD_SCSI_IO:
++
++ /*
++ * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been
++ * issued either through an IO path or an IOCTL path. If it
++ * was via IOCTL, we will send it to internal completion.
++ */
++ if (cmd->sync_cmd) {
++ cmd->sync_cmd = 0;
++ megasas_complete_int_cmd(instance, cmd);
++ break;
++ }
++
++ case MFI_CMD_LD_READ:
++ case MFI_CMD_LD_WRITE:
++
++ if (alt_status) {
++ cmd->scmd->result = alt_status << 16;
++ exception = 1;
++ }
++
++ if (exception) {
++
++ atomic_dec(&instance->fw_outstanding);
++
++ scsi_dma_unmap(cmd->scmd);
++ cmd->scmd->scsi_done(cmd->scmd);
++ megasas_return_cmd(instance, cmd);
++
++ break;
++ }
++
++ switch (hdr->cmd_status) {
++
++ case MFI_STAT_OK:
++ cmd->scmd->result = DID_OK << 16;
++ break;
++
++ case MFI_STAT_SCSI_IO_FAILED:
++ case MFI_STAT_LD_INIT_IN_PROGRESS:
++ cmd->scmd->result =
++ (DID_ERROR << 16) | hdr->scsi_status;
++ break;
++
++ case MFI_STAT_SCSI_DONE_WITH_ERROR:
++
++ cmd->scmd->result = (DID_OK << 16) | hdr->scsi_status;
++
++ if (hdr->scsi_status == SAM_STAT_CHECK_CONDITION) {
++ memset(cmd->scmd->sense_buffer, 0,
++ SCSI_SENSE_BUFFERSIZE);
++ memcpy(cmd->scmd->sense_buffer, cmd->sense,
++ hdr->sense_len);
++
++ cmd->scmd->result |= DRIVER_SENSE << 24;
++ }
++
++ break;
++
++ case MFI_STAT_LD_OFFLINE:
++ case MFI_STAT_DEVICE_NOT_FOUND:
++ cmd->scmd->result = DID_BAD_TARGET << 16;
++ break;
++
++ default:
++ printk(KERN_DEBUG "megasas: MFI FW status %#x\n",
++ hdr->cmd_status);
++ cmd->scmd->result = DID_ERROR << 16;
++ break;
++ }
++
++ atomic_dec(&instance->fw_outstanding);
++
++ scsi_dma_unmap(cmd->scmd);
++ cmd->scmd->scsi_done(cmd->scmd);
++ megasas_return_cmd(instance, cmd);
++
++ break;
++
++ case MFI_CMD_SMP:
++ case MFI_CMD_STP:
++ case MFI_CMD_DCMD:
++ if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
++ cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
++ spin_lock_irqsave(&poll_aen_lock, flags);
++ megasas_poll_wait_aen = 0;
++ spin_unlock_irqrestore(&poll_aen_lock, flags);
++ }
++
++ /*
++ * See if got an event notification
++ */
++ if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_WAIT)
++ megasas_service_aen(instance, cmd);
++ else
++ megasas_complete_int_cmd(instance, cmd);
++
++ break;
++
++ case MFI_CMD_ABORT:
++ /*
++ * Cmd issued to abort another cmd returned
++ */
++ megasas_complete_abort(instance, cmd);
++ break;
++
++ default:
++ printk("megasas: Unknown command completed! [0x%X]\n",
++ hdr->cmd);
++ break;
++ }
++}
++
++/**
++ * megasas_issue_pending_cmds_again - issue all pending cmds
++ * in FW again because of the fw reset
++ * @instance: Adapter soft state
++ */
++static inline void
++megasas_issue_pending_cmds_again(struct megasas_instance *instance)
++{
++ struct megasas_cmd *cmd;
++ struct list_head clist_local;
++ union megasas_evt_class_locale class_locale;
++ unsigned long flags;
++ u32 seq_num;
++
++ INIT_LIST_HEAD(&clist_local);
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ list_splice_init(&instance->internal_reset_pending_q, &clist_local);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ while (!list_empty(&clist_local)) {
++ cmd = list_entry((&clist_local)->next,
++ struct megasas_cmd, list);
++ list_del_init(&cmd->list);
++
++ if (cmd->sync_cmd || cmd->scmd) {
++ printk(KERN_NOTICE "megaraid_sas: command %p, %p:%d"
++ "detected to be pending while HBA reset.\n",
++ cmd, cmd->scmd, cmd->sync_cmd);
++
++ cmd->retry_for_fw_reset++;
++
++ if (cmd->retry_for_fw_reset == 3) {
++ printk(KERN_NOTICE "megaraid_sas: cmd %p, %p:%d"
++ "was tried multiple times during reset."
++ "Shutting down the HBA\n",
++ cmd, cmd->scmd, cmd->sync_cmd);
++ megaraid_sas_kill_hba(instance);
++
++ instance->adprecovery =
++ MEGASAS_HW_CRITICAL_ERROR;
++ return;
++ }
++ }
++
++ if (cmd->sync_cmd == 1) {
++ if (cmd->scmd) {
++ printk(KERN_NOTICE "megaraid_sas: unexpected"
++ "cmd attached to internal command!\n");
++ }
++ printk(KERN_NOTICE "megasas: %p synchronous cmd"
++ "on the internal reset queue,"
++ "issue it again.\n", cmd);
++ cmd->cmd_status = ENODATA;
++ instance->instancet->fire_cmd(instance,
++ cmd->frame_phys_addr ,
++ 0, instance->reg_set);
++ } else if (cmd->scmd) {
++ printk(KERN_NOTICE "megasas: %p scsi cmd [%02x],%#lx"
++ "detected on the internal queue, issue again.\n",
++ cmd, cmd->scmd->cmnd[0], cmd->scmd->serial_number);
++
++ atomic_inc(&instance->fw_outstanding);
++ instance->instancet->fire_cmd(instance,
++ cmd->frame_phys_addr,
++ cmd->frame_count-1, instance->reg_set);
++ } else {
++ printk(KERN_NOTICE "megasas: %p unexpected cmd on the"
++ "internal reset defer list while re-issue!!\n",
++ cmd);
++ }
++ }
++
++ if (instance->aen_cmd) {
++ printk(KERN_NOTICE "megaraid_sas: aen_cmd in def process\n");
++ megasas_return_cmd(instance, instance->aen_cmd);
++
++ instance->aen_cmd = NULL;
++ }
++
++ /*
++ * Initiate AEN (Asynchronous Event Notification)
++ */
++ seq_num = instance->last_seq_num;
++ class_locale.members.reserved = 0;
++ class_locale.members.locale = MR_EVT_LOCALE_ALL;
++ class_locale.members.class = MR_EVT_CLASS_DEBUG;
++
++ megasas_register_aen(instance, seq_num, class_locale.word);
++}
++
++/**
++ * Move the internal reset pending commands to a deferred queue.
++ *
++ * We move the commands pending at internal reset time to a
++ * pending queue. This queue would be flushed after successful
++ * completion of the internal reset sequence. if the internal reset
++ * did not complete in time, the kernel reset handler would flush
++ * these commands.
++ **/
++static void
++megasas_internal_reset_defer_cmds(struct megasas_instance *instance)
++{
++ struct megasas_cmd *cmd;
++ int i;
++ u32 max_cmd = instance->max_fw_cmds;
++ u32 defer_index;
++ unsigned long flags;
++
++ defer_index = 0;
++ spin_lock_irqsave(&instance->cmd_pool_lock, flags);
++ for (i = 0; i < max_cmd; i++) {
++ cmd = instance->cmd_list[i];
++ if (cmd->sync_cmd == 1 || cmd->scmd) {
++ printk(KERN_NOTICE "megasas: moving cmd[%d]:%p:%d:%p"
++ "on the defer queue as internal\n",
++ defer_index, cmd, cmd->sync_cmd, cmd->scmd);
++
++ if (!list_empty(&cmd->list)) {
++ printk(KERN_NOTICE "megaraid_sas: ERROR while"
++ " moving this cmd:%p, %d %p, it was"
++ "discovered on some list?\n",
++ cmd, cmd->sync_cmd, cmd->scmd);
++
++ list_del_init(&cmd->list);
++ }
++ defer_index++;
++ list_add_tail(&cmd->list,
++ &instance->internal_reset_pending_q);
++ }
++ }
++ spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
++}
++
++
++static void
++process_fw_state_change_wq(struct work_struct *work)
++{
++ struct megasas_instance *instance =
++ container_of(work, struct megasas_instance, work_init);
++ u32 wait;
++ unsigned long flags;
++
++ if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) {
++ printk(KERN_NOTICE "megaraid_sas: error, recovery st %x \n",
++ instance->adprecovery);
++ return ;
++ }
++
++ if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
++ printk(KERN_NOTICE "megaraid_sas: FW detected to be in fault"
++ "state, restarting it...\n");
++
++ instance->instancet->disable_intr(instance->reg_set);
++ atomic_set(&instance->fw_outstanding, 0);
++
++ atomic_set(&instance->fw_reset_no_pci_access, 1);
++ instance->instancet->adp_reset(instance, instance->reg_set);
++ atomic_set(&instance->fw_reset_no_pci_access, 0 );
++
++ printk(KERN_NOTICE "megaraid_sas: FW restarted successfully,"
++ "initiating next stage...\n");
++
++ printk(KERN_NOTICE "megaraid_sas: HBA recovery state machine,"
++ "state 2 starting...\n");
++
++ /*waitting for about 20 second before start the second init*/
++ for (wait = 0; wait < 30; wait++) {
++ msleep(1000);
++ }
++
++ if (megasas_transition_to_ready(instance)) {
++ printk(KERN_NOTICE "megaraid_sas:adapter not ready\n");
++
++ megaraid_sas_kill_hba(instance);
++ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
++ return ;
++ }
++
++ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
++ (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)
++ ) {
++ *instance->consumer = *instance->producer;
++ } else {
++ *instance->consumer = 0;
++ *instance->producer = 0;
++ }
++
++ megasas_issue_init_mfi(instance);
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ instance->instancet->enable_intr(instance->reg_set);
++
++ megasas_issue_pending_cmds_again(instance);
++ instance->issuepend_done = 1;
++ }
++ return ;
++}
++
++/**
++ * megasas_deplete_reply_queue - Processes all completed commands
++ * @instance: Adapter soft state
++ * @alt_status: Alternate status to be returned to
++ * SCSI mid-layer instead of the status
++ * returned by the FW
++ * Note: this must be called with hba lock held
++ */
++static int
++megasas_deplete_reply_queue(struct megasas_instance *instance,
++ u8 alt_status)
++{
++ u32 mfiStatus;
++ u32 fw_state;
++
++ if ((mfiStatus = instance->instancet->check_reset(instance,
++ instance->reg_set)) == 1) {
++ return IRQ_HANDLED;
++ }
++
++ if ((mfiStatus = instance->instancet->clear_intr(
++ instance->reg_set)
++ ) == 0) {
++ return IRQ_NONE;
++ }
++
++ instance->mfiStatus = mfiStatus;
++
++ if ((mfiStatus & MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE)) {
++ fw_state = instance->instancet->read_fw_status_reg(
++ instance->reg_set) & MFI_STATE_MASK;
++
++ if (fw_state != MFI_STATE_FAULT) {
++ printk(KERN_NOTICE "megaraid_sas: fw state:%x\n",
++ fw_state);
++ }
++
++ if ((fw_state == MFI_STATE_FAULT) &&
++ (instance->disableOnlineCtrlReset == 0)) {
++ printk(KERN_NOTICE "megaraid_sas: wait adp restart\n");
++
++ if ((instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS1064R) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_DELL_PERC5) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
++
++ *instance->consumer =
++ MEGASAS_ADPRESET_INPROG_SIGN;
++ }
++
++
++ instance->instancet->disable_intr(instance->reg_set);
++ instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
++ instance->issuepend_done = 0;
++
++ atomic_set(&instance->fw_outstanding, 0);
++ megasas_internal_reset_defer_cmds(instance);
++
++ printk(KERN_NOTICE "megasas: fwState=%x, stage:%d\n",
++ fw_state, instance->adprecovery);
++
++ schedule_work(&instance->work_init);
++ return IRQ_HANDLED;
++
++ } else {
++ printk(KERN_NOTICE "megasas: fwstate:%x, dis_OCR=%x\n",
++ fw_state, instance->disableOnlineCtrlReset);
++ }
++ }
++
++ tasklet_schedule(&instance->isr_tasklet);
++ return IRQ_HANDLED;
++}
++/**
++ * megasas_isr - isr entry point
++ */
++static irqreturn_t megasas_isr(int irq, void *devp)
++{
++ struct megasas_instance *instance;
++ unsigned long flags;
++ irqreturn_t rc;
++
++ if (atomic_read(
++ &(((struct megasas_instance *)devp)->fw_reset_no_pci_access)))
++ return IRQ_HANDLED;
++
++ instance = (struct megasas_instance *)devp;
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ rc = megasas_deplete_reply_queue(instance, DID_OK);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ return rc;
++}
++
++/**
++ * megasas_transition_to_ready - Move the FW to READY state
++ * @instance: Adapter soft state
++ *
++ * During the initialization, FW passes can potentially be in any one of
++ * several possible states. If the FW in operational, waiting-for-handshake
++ * states, driver must take steps to bring it to ready state. Otherwise, it
++ * has to wait for the ready state.
++ */
++static int
++megasas_transition_to_ready(struct megasas_instance* instance)
++{
++ int i;
++ u8 max_wait;
++ u32 fw_state;
++ u32 cur_state;
++
++ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
++
++ if (fw_state != MFI_STATE_READY)
++ printk(KERN_INFO "megasas: Waiting for FW to come to ready"
++ " state\n");
++
++ while (fw_state != MFI_STATE_READY) {
++
++ switch (fw_state) {
++
++ case MFI_STATE_FAULT:
++
++ printk(KERN_DEBUG "megasas: FW in FAULT state!!\n");
++ return -ENODEV;
++
++ case MFI_STATE_WAIT_HANDSHAKE:
++ /*
++ * Set the CLR bit in inbound doorbell
++ */
++ if ((instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++
++ writel(
++ MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
++ &instance->reg_set->reserved_0[0]);
++ } else {
++ writel(
++ MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
++ &instance->reg_set->inbound_doorbell);
++ }
++
++ max_wait = 2;
++ cur_state = MFI_STATE_WAIT_HANDSHAKE;
++ break;
++
++ case MFI_STATE_BOOT_MESSAGE_PENDING:
++ if ((instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ writel(MFI_INIT_HOTPLUG,
++ &instance->reg_set->reserved_0[0]);
++ } else
++ writel(MFI_INIT_HOTPLUG,
++ &instance->reg_set->inbound_doorbell);
++
++ max_wait = 10;
++ cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
++ break;
++
++ case MFI_STATE_OPERATIONAL:
++ /*
++ * Bring it to READY state; assuming max wait 10 secs
++ */
++ instance->instancet->disable_intr(instance->reg_set);
++ if ((instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ writel(MFI_RESET_FLAGS,
++ &instance->reg_set->reserved_0[0]);
++ } else
++ writel(MFI_RESET_FLAGS,
++ &instance->reg_set->inbound_doorbell);
++
++ max_wait = 60;
++ cur_state = MFI_STATE_OPERATIONAL;
++ break;
++
++ case MFI_STATE_UNDEFINED:
++ /*
++ * This state should not last for more than 2 seconds
++ */
++ max_wait = 2;
++ cur_state = MFI_STATE_UNDEFINED;
++ break;
++
++ case MFI_STATE_BB_INIT:
++ max_wait = 2;
++ cur_state = MFI_STATE_BB_INIT;
++ break;
++
++ case MFI_STATE_FW_INIT:
++ max_wait = 20;
++ cur_state = MFI_STATE_FW_INIT;
++ break;
++
++ case MFI_STATE_FW_INIT_2:
++ max_wait = 20;
++ cur_state = MFI_STATE_FW_INIT_2;
++ break;
++
++ case MFI_STATE_DEVICE_SCAN:
++ max_wait = 20;
++ cur_state = MFI_STATE_DEVICE_SCAN;
++ break;
++
++ case MFI_STATE_FLUSH_CACHE:
++ max_wait = 20;
++ cur_state = MFI_STATE_FLUSH_CACHE;
++ break;
++
++ default:
++ printk(KERN_DEBUG "megasas: Unknown state 0x%x\n",
++ fw_state);
++ return -ENODEV;
++ }
++
++ /*
++ * The cur_state should not last for more than max_wait secs
++ */
++ for (i = 0; i < (max_wait * 1000); i++) {
++ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &
++ MFI_STATE_MASK ;
++
++ if (fw_state == cur_state) {
++ msleep(1);
++ } else
++ break;
++ }
++
++ /*
++ * Return error if fw_state hasn't changed after max_wait
++ */
++ if (fw_state == cur_state) {
++ printk(KERN_DEBUG "FW state [%d] hasn't changed "
++ "in %d secs\n", fw_state, max_wait);
++ return -ENODEV;
++ }
++ }
++ printk(KERN_INFO "megasas: FW now in Ready state\n");
++
++ return 0;
++}
++
++/**
++ * megasas_teardown_frame_pool - Destroy the cmd frame DMA pool
++ * @instance: Adapter soft state
++ */
++static void megasas_teardown_frame_pool(struct megasas_instance *instance)
++{
++ int i;
++ u32 max_cmd = instance->max_fw_cmds;
++ struct megasas_cmd *cmd;
++
++ if (!instance->frame_dma_pool)
++ return;
++
++ /*
++ * Return all frames to pool
++ */
++ for (i = 0; i < max_cmd; i++) {
++
++ cmd = instance->cmd_list[i];
++
++ if (cmd->frame)
++ pci_pool_free(instance->frame_dma_pool, cmd->frame,
++ cmd->frame_phys_addr);
++
++ if (cmd->sense)
++ pci_pool_free(instance->sense_dma_pool, cmd->sense,
++ cmd->sense_phys_addr);
++ }
++
++ /*
++ * Now destroy the pool itself
++ */
++ pci_pool_destroy(instance->frame_dma_pool);
++ pci_pool_destroy(instance->sense_dma_pool);
++
++ instance->frame_dma_pool = NULL;
++ instance->sense_dma_pool = NULL;
++}
++
++/**
++ * megasas_create_frame_pool - Creates DMA pool for cmd frames
++ * @instance: Adapter soft state
++ *
++ * Each command packet has an embedded DMA memory buffer that is used for
++ * filling MFI frame and the SG list that immediately follows the frame. This
++ * function creates those DMA memory buffers for each command packet by using
++ * PCI pool facility.
++ */
++static int megasas_create_frame_pool(struct megasas_instance *instance)
++{
++ int i;
++ u32 max_cmd;
++ u32 sge_sz;
++ u32 sgl_sz;
++ u32 total_sz;
++ u32 frame_count;
++ struct megasas_cmd *cmd;
++
++ max_cmd = instance->max_fw_cmds;
++
++ /*
++ * Size of our frame is 64 bytes for MFI frame, followed by max SG
++ * elements and finally SCSI_SENSE_BUFFERSIZE bytes for sense buffer
++ */
++ sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
++ sizeof(struct megasas_sge32);
++
++ if (instance->flag_ieee) {
++ sge_sz = sizeof(struct megasas_sge_skinny);
++ }
++
++ /*
++ * Calculated the number of 64byte frames required for SGL
++ */
++ sgl_sz = sge_sz * instance->max_num_sge;
++ frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE;
++ frame_count = 15;
++
++ /*
++ * We need one extra frame for the MFI command
++ */
++ frame_count++;
++
++ total_sz = MEGAMFI_FRAME_SIZE * frame_count;
++ /*
++ * Use DMA pool facility provided by PCI layer
++ */
++ instance->frame_dma_pool = pci_pool_create("megasas frame pool",
++ instance->pdev, total_sz, 64,
++ 0);
++
++ if (!instance->frame_dma_pool) {
++ printk(KERN_DEBUG "megasas: failed to setup frame pool\n");
++ return -ENOMEM;
++ }
++
++ instance->sense_dma_pool = pci_pool_create("megasas sense pool",
++ instance->pdev, 128, 4, 0);
++
++ if (!instance->sense_dma_pool) {
++ printk(KERN_DEBUG "megasas: failed to setup sense pool\n");
++
++ pci_pool_destroy(instance->frame_dma_pool);
++ instance->frame_dma_pool = NULL;
++
++ return -ENOMEM;
++ }
++
++ /*
++ * Allocate and attach a frame to each of the commands in cmd_list.
++ * By making cmd->index as the context instead of the &cmd, we can
++ * always use 32bit context regardless of the architecture
++ */
++ for (i = 0; i < max_cmd; i++) {
++
++ cmd = instance->cmd_list[i];
++
++ cmd->frame = pci_pool_alloc(instance->frame_dma_pool,
++ GFP_KERNEL, &cmd->frame_phys_addr);
++
++ cmd->sense = pci_pool_alloc(instance->sense_dma_pool,
++ GFP_KERNEL, &cmd->sense_phys_addr);
++
++ /*
++ * megasas_teardown_frame_pool() takes care of freeing
++ * whatever has been allocated
++ */
++ if (!cmd->frame || !cmd->sense) {
++ printk(KERN_DEBUG "megasas: pci_pool_alloc failed \n");
++ megasas_teardown_frame_pool(instance);
++ return -ENOMEM;
++ }
++
++ cmd->frame->io.context = cmd->index;
++ cmd->frame->io.pad_0 = 0;
++ }
++
++ return 0;
++}
++
++/**
++ * megasas_free_cmds - Free all the cmds in the free cmd pool
++ * @instance: Adapter soft state
++ */
++static void megasas_free_cmds(struct megasas_instance *instance)
++{
++ int i;
++ /* First free the MFI frame pool */
++ megasas_teardown_frame_pool(instance);
++
++ /* Free all the commands in the cmd_list */
++ for (i = 0; i < instance->max_fw_cmds; i++)
++ kfree(instance->cmd_list[i]);
++
++ /* Free the cmd_list buffer itself */
++ kfree(instance->cmd_list);
++ instance->cmd_list = NULL;
++
++ INIT_LIST_HEAD(&instance->cmd_pool);
++}
++
++/**
++ * megasas_alloc_cmds - Allocates the command packets
++ * @instance: Adapter soft state
++ *
++ * Each command that is issued to the FW, whether IO commands from the OS or
++ * internal commands like IOCTLs, are wrapped in local data structure called
++ * megasas_cmd. The frame embedded in this megasas_cmd is actually issued to
++ * the FW.
++ *
++ * Each frame has a 32-bit field called context (tag). This context is used
++ * to get back the megasas_cmd from the frame when a frame gets completed in
++ * the ISR. Typically the address of the megasas_cmd itself would be used as
++ * the context. But we wanted to keep the differences between 32 and 64 bit
++ * systems to the mininum. We always use 32 bit integers for the context. In
++ * this driver, the 32 bit values are the indices into an array cmd_list.
++ * This array is used only to look up the megasas_cmd given the context. The
++ * free commands themselves are maintained in a linked list called cmd_pool.
++ */
++static int megasas_alloc_cmds(struct megasas_instance *instance)
++{
++ int i;
++ int j;
++ u32 max_cmd;
++ struct megasas_cmd *cmd;
++
++ max_cmd = instance->max_fw_cmds;
++
++ /*
++ * instance->cmd_list is an array of struct megasas_cmd pointers.
++ * Allocate the dynamic array first and then allocate individual
++ * commands.
++ */
++ instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL);
++
++ if (!instance->cmd_list) {
++ printk(KERN_DEBUG "megasas: out of memory\n");
++ return -ENOMEM;
++ }
++
++
++ for (i = 0; i < max_cmd; i++) {
++ instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
++ GFP_KERNEL);
++
++ if (!instance->cmd_list[i]) {
++
++ for (j = 0; j < i; j++)
++ kfree(instance->cmd_list[j]);
++
++ kfree(instance->cmd_list);
++ instance->cmd_list = NULL;
++
++ return -ENOMEM;
++ }
++ }
++
++ /*
++ * Add all the commands to command pool (instance->cmd_pool)
++ */
++ for (i = 0; i < max_cmd; i++) {
++ cmd = instance->cmd_list[i];
++ memset(cmd, 0, sizeof(struct megasas_cmd));
++ cmd->index = i;
++ cmd->scmd = NULL;
++ cmd->instance = instance;
++
++ list_add_tail(&cmd->list, &instance->cmd_pool);
++ }
++
++ /*
++ * Create a frame pool and assign one frame to each cmd
++ */
++ if (megasas_create_frame_pool(instance)) {
++ printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n");
++ megasas_free_cmds(instance);
++ }
++
++ return 0;
++}
++
++/*
++ * megasas_get_pd_list_info - Returns FW's pd_list structure
++ * @instance: Adapter soft state
++ * @pd_list: pd_list structure
++ *
++ * Issues an internal command (DCMD) to get the FW's controller PD
++ * list structure. This information is mainly used to find out SYSTEM
++ * supported by the FW.
++ */
++static int
++megasas_get_pd_list(struct megasas_instance *instance)
++{
++ int ret = 0, pd_index = 0;
++ struct megasas_cmd *cmd;
++ struct megasas_dcmd_frame *dcmd;
++ struct MR_PD_LIST *ci;
++ struct MR_PD_ADDRESS *pd_addr;
++ dma_addr_t ci_h = 0;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd) {
++ printk(KERN_DEBUG "megasas (get_pd_list): Failed to get cmd\n");
++ return -ENOMEM;
++ }
++
++ dcmd = &cmd->frame->dcmd;
++
++ ci = pci_alloc_consistent(instance->pdev,
++ MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), &ci_h);
++
++ if (!ci) {
++ printk(KERN_DEBUG "Failed to alloc mem for pd_list\n");
++ megasas_return_cmd(instance, cmd);
++ return -ENOMEM;
++ }
++
++ memset(ci, 0, sizeof(*ci));
++ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
++
++ dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
++ dcmd->mbox.b[1] = 0;
++ dcmd->cmd = MFI_CMD_DCMD;
++ dcmd->cmd_status = 0xFF;
++ dcmd->sge_count = 1;
++ dcmd->flags = MFI_FRAME_DIR_READ;
++ dcmd->timeout = 0;
++ dcmd->data_xfer_len = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
++ dcmd->opcode = MR_DCMD_PD_LIST_QUERY;
++ dcmd->sgl.sge32[0].phys_addr = ci_h;
++ dcmd->sgl.sge32[0].length = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
++
++ if (!megasas_issue_polled(instance, cmd)) {
++ ret = 0;
++ } else {
++ ret = -1;
++ }
++
++ /*
++ * the following function will get the instance PD LIST.
++ */
++
++ pd_addr = ci->addr;
++
++ if ( ret == 0 &&
++ (ci->count <
++ (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) {
++
++ memset(instance->pd_list, 0,
++ MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
++
++ for (pd_index = 0; pd_index < ci->count; pd_index++) {
++
++ instance->pd_list[pd_addr->deviceId].tid =
++ pd_addr->deviceId;
++ instance->pd_list[pd_addr->deviceId].driveType =
++ pd_addr->scsiDevType;
++ instance->pd_list[pd_addr->deviceId].driveState =
++ MR_PD_STATE_SYSTEM;
++ pd_addr++;
++ }
++ }
++
++ pci_free_consistent(instance->pdev,
++ MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
++ ci, ci_h);
++ megasas_return_cmd(instance, cmd);
++
++ return ret;
++}
++
++/*
++ * megasas_get_ld_list_info - Returns FW's ld_list structure
++ * @instance: Adapter soft state
++ * @ld_list: ld_list structure
++ *
++ * Issues an internal command (DCMD) to get the FW's controller PD
++ * list structure. This information is mainly used to find out SYSTEM
++ * supported by the FW.
++ */
++static int
++megasas_get_ld_list(struct megasas_instance *instance)
++{
++ int ret = 0, ld_index = 0, ids = 0;
++ struct megasas_cmd *cmd;
++ struct megasas_dcmd_frame *dcmd;
++ struct MR_LD_LIST *ci;
++ dma_addr_t ci_h = 0;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd) {
++ printk(KERN_DEBUG "megasas_get_ld_list: Failed to get cmd\n");
++ return -ENOMEM;
++ }
++
++ dcmd = &cmd->frame->dcmd;
++
++ ci = pci_alloc_consistent(instance->pdev,
++ sizeof(struct MR_LD_LIST),
++ &ci_h);
++
++ if (!ci) {
++ printk(KERN_DEBUG "Failed to alloc mem in get_ld_list\n");
++ megasas_return_cmd(instance, cmd);
++ return -ENOMEM;
++ }
++
++ memset(ci, 0, sizeof(*ci));
++ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
++
++ dcmd->cmd = MFI_CMD_DCMD;
++ dcmd->cmd_status = 0xFF;
++ dcmd->sge_count = 1;
++ dcmd->flags = MFI_FRAME_DIR_READ;
++ dcmd->timeout = 0;
++ dcmd->data_xfer_len = sizeof(struct MR_LD_LIST);
++ dcmd->opcode = MR_DCMD_LD_GET_LIST;
++ dcmd->sgl.sge32[0].phys_addr = ci_h;
++ dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST);
++ dcmd->pad_0 = 0;
++
++ if (!megasas_issue_polled(instance, cmd)) {
++ ret = 0;
++ } else {
++ ret = -1;
++ }
++
++ /* the following function will get the instance PD LIST */
++
++ if ((ret == 0) && (ci->ldCount <= MAX_LOGICAL_DRIVES)) {
++ memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
++
++ for (ld_index = 0; ld_index < ci->ldCount; ld_index++) {
++ if (ci->ldList[ld_index].state != 0) {
++ ids = ci->ldList[ld_index].ref.targetId;
++ instance->ld_ids[ids] =
++ ci->ldList[ld_index].ref.targetId;
++ }
++ }
++ }
++
++ pci_free_consistent(instance->pdev,
++ sizeof(struct MR_LD_LIST),
++ ci,
++ ci_h);
++
++ megasas_return_cmd(instance, cmd);
++ return ret;
++}
++
++/**
++ * megasas_get_controller_info - Returns FW's controller structure
++ * @instance: Adapter soft state
++ * @ctrl_info: Controller information structure
++ *
++ * Issues an internal command (DCMD) to get the FW's controller structure.
++ * This information is mainly used to find out the maximum IO transfer per
++ * command supported by the FW.
++ */
++static int
++megasas_get_ctrl_info(struct megasas_instance *instance,
++ struct megasas_ctrl_info *ctrl_info)
++{
++ int ret = 0;
++ struct megasas_cmd *cmd;
++ struct megasas_dcmd_frame *dcmd;
++ struct megasas_ctrl_info *ci;
++ dma_addr_t ci_h = 0;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd) {
++ printk(KERN_DEBUG "megasas: Failed to get a free cmd\n");
++ return -ENOMEM;
++ }
++
++ dcmd = &cmd->frame->dcmd;
++
++ ci = pci_alloc_consistent(instance->pdev,
++ sizeof(struct megasas_ctrl_info), &ci_h);
++
++ if (!ci) {
++ printk(KERN_DEBUG "Failed to alloc mem for ctrl info\n");
++ megasas_return_cmd(instance, cmd);
++ return -ENOMEM;
++ }
++
++ memset(ci, 0, sizeof(*ci));
++ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
++
++ dcmd->cmd = MFI_CMD_DCMD;
++ dcmd->cmd_status = 0xFF;
++ dcmd->sge_count = 1;
++ dcmd->flags = MFI_FRAME_DIR_READ;
++ dcmd->timeout = 0;
++ dcmd->data_xfer_len = sizeof(struct megasas_ctrl_info);
++ dcmd->opcode = MR_DCMD_CTRL_GET_INFO;
++ dcmd->sgl.sge32[0].phys_addr = ci_h;
++ dcmd->sgl.sge32[0].length = sizeof(struct megasas_ctrl_info);
++
++ if (!megasas_issue_polled(instance, cmd)) {
++ ret = 0;
++ memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info));
++ } else {
++ ret = -1;
++ }
++
++ pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),
++ ci, ci_h);
++
++ megasas_return_cmd(instance, cmd);
++ return ret;
++}
++
++/**
++ * megasas_issue_init_mfi - Initializes the FW
++ * @instance: Adapter soft state
++ *
++ * Issues the INIT MFI cmd
++ */
++static int
++megasas_issue_init_mfi(struct megasas_instance *instance)
++{
++ u32 context;
++
++ struct megasas_cmd *cmd;
++
++ struct megasas_init_frame *init_frame;
++ struct megasas_init_queue_info *initq_info;
++ dma_addr_t init_frame_h;
++ dma_addr_t initq_info_h;
++
++ /*
++ * Prepare a init frame. Note the init frame points to queue info
++ * structure. Each frame has SGL allocated after first 64 bytes. For
++ * this frame - since we don't need any SGL - we use SGL's space as
++ * queue info structure
++ *
++ * We will not get a NULL command below. We just created the pool.
++ */
++ cmd = megasas_get_cmd(instance);
++
++ init_frame = (struct megasas_init_frame *)cmd->frame;
++ initq_info = (struct megasas_init_queue_info *)
++ ((unsigned long)init_frame + 64);
++
++ init_frame_h = cmd->frame_phys_addr;
++ initq_info_h = init_frame_h + 64;
++
++ context = init_frame->context;
++ memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
++ memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
++ init_frame->context = context;
++
++ initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
++ initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
++
++ initq_info->producer_index_phys_addr_lo = instance->producer_h;
++ initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
++
++ init_frame->cmd = MFI_CMD_INIT;
++ init_frame->cmd_status = 0xFF;
++ init_frame->queue_info_new_phys_addr_lo = initq_info_h;
++
++ init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
++
++ /*
++ * disable the intr before firing the init frame to FW
++ */
++ instance->instancet->disable_intr(instance->reg_set);
++
++ /*
++ * Issue the init frame in polled mode
++ */
++
++ if (megasas_issue_polled(instance, cmd)) {
++ printk(KERN_ERR "megasas: Failed to init firmware\n");
++ megasas_return_cmd(instance, cmd);
++ goto fail_fw_init;
++ }
++
++ megasas_return_cmd(instance, cmd);
++
++ return 0;
++
++fail_fw_init:
++ return -EINVAL;
++}
++
++/**
++ * megasas_start_timer - Initializes a timer object
++ * @instance: Adapter soft state
++ * @timer: timer object to be initialized
++ * @fn: timer function
++ * @interval: time interval between timer function call
++ */
++static inline void
++megasas_start_timer(struct megasas_instance *instance,
++ struct timer_list *timer,
++ void *fn, unsigned long interval)
++{
++ init_timer(timer);
++ timer->expires = jiffies + interval;
++ timer->data = (unsigned long)instance;
++ timer->function = fn;
++ add_timer(timer);
++}
++
++/**
++ * megasas_io_completion_timer - Timer fn
++ * @instance_addr: Address of adapter soft state
++ *
++ * Schedules tasklet for cmd completion
++ * if poll_mode_io is set
++ */
++static void
++megasas_io_completion_timer(unsigned long instance_addr)
++{
++ struct megasas_instance *instance =
++ (struct megasas_instance *)instance_addr;
++
++ if (atomic_read(&instance->fw_outstanding))
++ tasklet_schedule(&instance->isr_tasklet);
++
++ /* Restart timer */
++ if (poll_mode_io)
++ mod_timer(&instance->io_completion_timer,
++ jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
++}
++
++/**
++ * megasas_init_mfi - Initializes the FW
++ * @instance: Adapter soft state
++ *
++ * This is the main function for initializing MFI firmware.
++ */
++static int megasas_init_mfi(struct megasas_instance *instance)
++{
++ u32 context_sz;
++ u32 reply_q_sz;
++ u32 max_sectors_1;
++ u32 max_sectors_2;
++ u32 tmp_sectors;
++ struct megasas_register_set __iomem *reg_set;
++ struct megasas_ctrl_info *ctrl_info;
++ /*
++ * Map the message registers
++ */
++ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0079GEN2)) {
++ instance->base_addr = pci_resource_start(instance->pdev, 1);
++ } else {
++ instance->base_addr = pci_resource_start(instance->pdev, 0);
++ }
++
++ if (pci_request_regions(instance->pdev, "megasas: LSI")) {
++ printk(KERN_DEBUG "megasas: IO memory region busy!\n");
++ return -EBUSY;
++ }
++
++ instance->reg_set = ioremap_nocache(instance->base_addr, 8192);
++
++ if (!instance->reg_set) {
++ printk(KERN_DEBUG "megasas: Failed to map IO mem\n");
++ goto fail_ioremap;
++ }
++
++ reg_set = instance->reg_set;
++
++ switch(instance->pdev->device)
++ {
++ case PCI_DEVICE_ID_LSI_SAS1078R:
++ case PCI_DEVICE_ID_LSI_SAS1078DE:
++ instance->instancet = &megasas_instance_template_ppc;
++ break;
++ case PCI_DEVICE_ID_LSI_SAS1078GEN2:
++ case PCI_DEVICE_ID_LSI_SAS0079GEN2:
++ instance->instancet = &megasas_instance_template_gen2;
++ break;
++ case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
++ case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
++ instance->instancet = &megasas_instance_template_skinny;
++ break;
++ case PCI_DEVICE_ID_LSI_SAS1064R:
++ case PCI_DEVICE_ID_DELL_PERC5:
++ default:
++ instance->instancet = &megasas_instance_template_xscale;
++ break;
++ }
++
++ /*
++ * We expect the FW state to be READY
++ */
++ if (megasas_transition_to_ready(instance))
++ goto fail_ready_state;
++
++ /*
++ * Get various operational parameters from status register
++ */
++ instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
++ /*
++ * Reduce the max supported cmds by 1. This is to ensure that the
++ * reply_q_sz (1 more than the max cmd that driver may send)
++ * does not exceed max cmds that the FW can support
++ */
++ instance->max_fw_cmds = instance->max_fw_cmds-1;
++ instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
++ 0x10;
++ /*
++ * Create a pool of commands
++ */
++ if (megasas_alloc_cmds(instance))
++ goto fail_alloc_cmds;
++
++ /*
++ * Allocate memory for reply queue. Length of reply queue should
++ * be _one_ more than the maximum commands handled by the firmware.
++ *
++ * Note: When FW completes commands, it places corresponding contex
++ * values in this circular reply queue. This circular queue is a fairly
++ * typical producer-consumer queue. FW is the producer (of completed
++ * commands) and the driver is the consumer.
++ */
++ context_sz = sizeof(u32);
++ reply_q_sz = context_sz * (instance->max_fw_cmds + 1);
++
++ instance->reply_queue = pci_alloc_consistent(instance->pdev,
++ reply_q_sz,
++ &instance->reply_queue_h);
++
++ if (!instance->reply_queue) {
++ printk(KERN_DEBUG "megasas: Out of DMA mem for reply queue\n");
++ goto fail_reply_queue;
++ }
++
++ if (megasas_issue_init_mfi(instance))
++ goto fail_fw_init;
++
++ instance->fw_support_ieee = 0;
++ instance->fw_support_ieee =
++ (instance->instancet->read_fw_status_reg(reg_set) &
++ 0x04000000);
++
++ printk(KERN_NOTICE "megasas_init_mfi: fw_support_ieee=%d",
++ instance->fw_support_ieee);
++
++ if (instance->fw_support_ieee)
++ instance->flag_ieee = 1;
++
++ /** for passthrough
++ * the following function will get the PD LIST.
++ */
++
++ memset(instance->pd_list, 0 ,
++ (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
++ megasas_get_pd_list(instance);
++
++ memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
++ megasas_get_ld_list(instance);
++
++ ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
++
++ /*
++ * Compute the max allowed sectors per IO: The controller info has two
++ * limits on max sectors. Driver should use the minimum of these two.
++ *
++ * 1 << stripe_sz_ops.min = max sectors per strip
++ *
++ * Note that older firmwares ( < FW ver 30) didn't report information
++ * to calculate max_sectors_1. So the number ended up as zero always.
++ */
++ tmp_sectors = 0;
++ if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) {
++
++ max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
++ ctrl_info->max_strips_per_io;
++ max_sectors_2 = ctrl_info->max_request_size;
++
++ tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2);
++ instance->disableOnlineCtrlReset =
++ ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
++ }
++
++ instance->max_sectors_per_req = instance->max_num_sge *
++ PAGE_SIZE / 512;
++ if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
++ instance->max_sectors_per_req = tmp_sectors;
++
++ kfree(ctrl_info);
++
++ /*
++ * Setup tasklet for cmd completion
++ */
++
++ tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
++ (unsigned long)instance);
++
++ /* Initialize the cmd completion timer */
++ if (poll_mode_io)
++ megasas_start_timer(instance, &instance->io_completion_timer,
++ megasas_io_completion_timer,
++ MEGASAS_COMPLETION_TIMER_INTERVAL);
++ return 0;
++
++ fail_fw_init:
++
++ pci_free_consistent(instance->pdev, reply_q_sz,
++ instance->reply_queue, instance->reply_queue_h);
++ fail_reply_queue:
++ megasas_free_cmds(instance);
++
++ fail_alloc_cmds:
++ fail_ready_state:
++ iounmap(instance->reg_set);
++
++ fail_ioremap:
++ pci_release_regions(instance->pdev);
++
++ return -EINVAL;
++}
++
++/**
++ * megasas_release_mfi - Reverses the FW initialization
++ * @intance: Adapter soft state
++ */
++static void megasas_release_mfi(struct megasas_instance *instance)
++{
++ u32 reply_q_sz = sizeof(u32) * (instance->max_fw_cmds + 1);
++
++ pci_free_consistent(instance->pdev, reply_q_sz,
++ instance->reply_queue, instance->reply_queue_h);
++
++ megasas_free_cmds(instance);
++
++ iounmap(instance->reg_set);
++
++ pci_release_regions(instance->pdev);
++}
++
++/**
++ * megasas_get_seq_num - Gets latest event sequence numbers
++ * @instance: Adapter soft state
++ * @eli: FW event log sequence numbers information
++ *
++ * FW maintains a log of all events in a non-volatile area. Upper layers would
++ * usually find out the latest sequence number of the events, the seq number at
++ * the boot etc. They would "read" all the events below the latest seq number
++ * by issuing a direct fw cmd (DCMD). For the future events (beyond latest seq
++ * number), they would subsribe to AEN (asynchronous event notification) and
++ * wait for the events to happen.
++ */
++static int
++megasas_get_seq_num(struct megasas_instance *instance,
++ struct megasas_evt_log_info *eli)
++{
++ struct megasas_cmd *cmd;
++ struct megasas_dcmd_frame *dcmd;
++ struct megasas_evt_log_info *el_info;
++ dma_addr_t el_info_h = 0;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd) {
++ return -ENOMEM;
++ }
++
++ dcmd = &cmd->frame->dcmd;
++ el_info = pci_alloc_consistent(instance->pdev,
++ sizeof(struct megasas_evt_log_info),
++ &el_info_h);
++
++ if (!el_info) {
++ megasas_return_cmd(instance, cmd);
++ return -ENOMEM;
++ }
++
++ memset(el_info, 0, sizeof(*el_info));
++ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
++
++ dcmd->cmd = MFI_CMD_DCMD;
++ dcmd->cmd_status = 0x0;
++ dcmd->sge_count = 1;
++ dcmd->flags = MFI_FRAME_DIR_READ;
++ dcmd->timeout = 0;
++ dcmd->data_xfer_len = sizeof(struct megasas_evt_log_info);
++ dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;
++ dcmd->sgl.sge32[0].phys_addr = el_info_h;
++ dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_log_info);
++
++ megasas_issue_blocked_cmd(instance, cmd);
++
++ /*
++ * Copy the data back into callers buffer
++ */
++ memcpy(eli, el_info, sizeof(struct megasas_evt_log_info));
++
++ pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),
++ el_info, el_info_h);
++
++ megasas_return_cmd(instance, cmd);
++
++ return 0;
++}
++
++/**
++ * megasas_register_aen - Registers for asynchronous event notification
++ * @instance: Adapter soft state
++ * @seq_num: The starting sequence number
++ * @class_locale: Class of the event
++ *
++ * This function subscribes for AEN for events beyond the @seq_num. It requests
++ * to be notified if and only if the event is of type @class_locale
++ */
++static int
++megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
++ u32 class_locale_word)
++{
++ int ret_val;
++ struct megasas_cmd *cmd;
++ struct megasas_dcmd_frame *dcmd;
++ union megasas_evt_class_locale curr_aen;
++ union megasas_evt_class_locale prev_aen;
++
++ /*
++ * If there an AEN pending already (aen_cmd), check if the
++ * class_locale of that pending AEN is inclusive of the new
++ * AEN request we currently have. If it is, then we don't have
++ * to do anything. In other words, whichever events the current
++ * AEN request is subscribing to, have already been subscribed
++ * to.
++ *
++ * If the old_cmd is _not_ inclusive, then we have to abort
++ * that command, form a class_locale that is superset of both
++ * old and current and re-issue to the FW
++ */
++
++ curr_aen.word = class_locale_word;
++
++ if (instance->aen_cmd) {
++
++ prev_aen.word = instance->aen_cmd->frame->dcmd.mbox.w[1];
++
++ /*
++ * A class whose enum value is smaller is inclusive of all
++ * higher values. If a PROGRESS (= -1) was previously
++ * registered, then a new registration requests for higher
++ * classes need not be sent to FW. They are automatically
++ * included.
++ *
++ * Locale numbers don't have such hierarchy. They are bitmap
++ * values
++ */
++ if ((prev_aen.members.class <= curr_aen.members.class) &&
++ !((prev_aen.members.locale & curr_aen.members.locale) ^
++ curr_aen.members.locale)) {
++ /*
++ * Previously issued event registration includes
++ * current request. Nothing to do.
++ */
++ return 0;
++ } else {
++ curr_aen.members.locale |= prev_aen.members.locale;
++
++ if (prev_aen.members.class < curr_aen.members.class)
++ curr_aen.members.class = prev_aen.members.class;
++
++ instance->aen_cmd->abort_aen = 1;
++ ret_val = megasas_issue_blocked_abort_cmd(instance,
++ instance->
++ aen_cmd);
++
++ if (ret_val) {
++ printk(KERN_DEBUG "megasas: Failed to abort "
++ "previous AEN command\n");
++ return ret_val;
++ }
++ }
++ }
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd)
++ return -ENOMEM;
++
++ dcmd = &cmd->frame->dcmd;
++
++ memset(instance->evt_detail, 0, sizeof(struct megasas_evt_detail));
++
++ /*
++ * Prepare DCMD for aen registration
++ */
++ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
++
++ dcmd->cmd = MFI_CMD_DCMD;
++ dcmd->cmd_status = 0x0;
++ dcmd->sge_count = 1;
++ dcmd->flags = MFI_FRAME_DIR_READ;
++ dcmd->timeout = 0;
++ instance->last_seq_num = seq_num;
++ dcmd->data_xfer_len = sizeof(struct megasas_evt_detail);
++ dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
++ dcmd->mbox.w[0] = seq_num;
++ dcmd->mbox.w[1] = curr_aen.word;
++ dcmd->sgl.sge32[0].phys_addr = (u32) instance->evt_detail_h;
++ dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_detail);
++
++ if (instance->aen_cmd != NULL) {
++ megasas_return_cmd(instance, cmd);
++ return 0;
++ }
++
++ /*
++ * Store reference to the cmd used to register for AEN. When an
++ * application wants us to register for AEN, we have to abort this
++ * cmd and re-register with a new EVENT LOCALE supplied by that app
++ */
++ instance->aen_cmd = cmd;
++
++ /*
++ * Issue the aen registration frame
++ */
++ instance->instancet->fire_cmd(instance,
++ cmd->frame_phys_addr, 0, instance->reg_set);
++
++ return 0;
++}
++
++/**
++ * megasas_start_aen - Subscribes to AEN during driver load time
++ * @instance: Adapter soft state
++ */
++static int megasas_start_aen(struct megasas_instance *instance)
++{
++ struct megasas_evt_log_info eli;
++ union megasas_evt_class_locale class_locale;
++
++ /*
++ * Get the latest sequence number from FW
++ */
++ memset(&eli, 0, sizeof(eli));
++
++ if (megasas_get_seq_num(instance, &eli))
++ return -1;
++
++ /*
++ * Register AEN with FW for latest sequence number plus 1
++ */
++ class_locale.members.reserved = 0;
++ class_locale.members.locale = MR_EVT_LOCALE_ALL;
++ class_locale.members.class = MR_EVT_CLASS_DEBUG;
++
++ return megasas_register_aen(instance, eli.newest_seq_num + 1,
++ class_locale.word);
++}
++
++/**
++ * megasas_io_attach - Attaches this driver to SCSI mid-layer
++ * @instance: Adapter soft state
++ */
++static int megasas_io_attach(struct megasas_instance *instance)
++{
++ struct Scsi_Host *host = instance->host;
++
++ /*
++ * Export parameters required by SCSI mid-layer
++ */
++ host->irq = instance->pdev->irq;
++ host->unique_id = instance->unique_id;
++ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ host->can_queue =
++ instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
++ } else
++ host->can_queue =
++ instance->max_fw_cmds - MEGASAS_INT_CMDS;
++ host->this_id = instance->init_id;
++ host->sg_tablesize = instance->max_num_sge;
++ host->max_sectors = instance->max_sectors_per_req;
++ host->cmd_per_lun = 128;
++ host->max_channel = MEGASAS_MAX_CHANNELS - 1;
++ host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL;
++ host->max_lun = MEGASAS_MAX_LUN;
++ host->max_cmd_len = 16;
++
++ /*
++ * Notify the mid-layer about the new controller
++ */
++ if (scsi_add_host(host, &instance->pdev->dev)) {
++ printk(KERN_DEBUG "megasas: scsi_add_host failed\n");
++ return -ENODEV;
++ }
++
++ /*
++ * Trigger SCSI to scan our drives
++ */
++ scsi_scan_host(host);
++ return 0;
++}
++
++static int
++megasas_set_dma_mask(struct pci_dev *pdev)
++{
++ /*
++ * All our contollers are capable of performing 64-bit DMA
++ */
++ if (IS_DMA64) {
++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
++
++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
++ goto fail_set_dma_mask;
++ }
++ } else {
++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
++ goto fail_set_dma_mask;
++ }
++ return 0;
++
++fail_set_dma_mask:
++ return 1;
++}
++
++/**
++ * megasas_probe_one - PCI hotplug entry point
++ * @pdev: PCI device structure
++ * @id: PCI ids of supported hotplugged adapter
++ */
++static int __devinit
++megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ int rval;
++ struct Scsi_Host *host;
++ struct megasas_instance *instance;
++
++ /*
++ * Announce PCI information
++ */
++ printk(KERN_INFO "megasas: %#4.04x:%#4.04x:%#4.04x:%#4.04x: ",
++ pdev->vendor, pdev->device, pdev->subsystem_vendor,
++ pdev->subsystem_device);
++
++ printk("bus %d:slot %d:func %d\n",
++ pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
++
++ /*
++ * PCI prepping: enable device set bus mastering and dma mask
++ */
++ rval = pci_enable_device(pdev);
++
++ if (rval) {
++ return rval;
++ }
++
++ pci_set_master(pdev);
++
++ if (megasas_set_dma_mask(pdev))
++ goto fail_set_dma_mask;
++
++ host = scsi_host_alloc(&megasas_template,
++ sizeof(struct megasas_instance));
++
++ if (!host) {
++ printk(KERN_DEBUG "megasas: scsi_host_alloc failed\n");
++ goto fail_alloc_instance;
++ }
++
++ instance = (struct megasas_instance *)host->hostdata;
++ memset(instance, 0, sizeof(*instance));
++ atomic_set( &instance->fw_reset_no_pci_access, 0 );
++
++ instance->producer = pci_alloc_consistent(pdev, sizeof(u32),
++ &instance->producer_h);
++ instance->consumer = pci_alloc_consistent(pdev, sizeof(u32),
++ &instance->consumer_h);
++
++ if (!instance->producer || !instance->consumer) {
++ printk(KERN_DEBUG "megasas: Failed to allocate memory for "
++ "producer, consumer\n");
++ goto fail_alloc_dma_buf;
++ }
++
++ *instance->producer = 0;
++ *instance->consumer = 0;
++ megasas_poll_wait_aen = 0;
++ instance->flag_ieee = 0;
++ instance->ev = NULL;
++ instance->issuepend_done = 1;
++ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
++ megasas_poll_wait_aen = 0;
++
++ instance->evt_detail = pci_alloc_consistent(pdev,
++ sizeof(struct
++ megasas_evt_detail),
++ &instance->evt_detail_h);
++
++ if (!instance->evt_detail) {
++ printk(KERN_DEBUG "megasas: Failed to allocate memory for "
++ "event detail structure\n");
++ goto fail_alloc_dma_buf;
++ }
++
++ /*
++ * Initialize locks and queues
++ */
++ INIT_LIST_HEAD(&instance->cmd_pool);
++ INIT_LIST_HEAD(&instance->internal_reset_pending_q);
++
++ atomic_set(&instance->fw_outstanding,0);
++
++ init_waitqueue_head(&instance->int_cmd_wait_q);
++ init_waitqueue_head(&instance->abort_cmd_wait_q);
++
++ spin_lock_init(&instance->cmd_pool_lock);
++ spin_lock_init(&instance->hba_lock);
++ spin_lock_init(&instance->completion_lock);
++ spin_lock_init(&poll_aen_lock);
++
++ mutex_init(&instance->aen_mutex);
++
++ /*
++ * Initialize PCI related and misc parameters
++ */
++ instance->pdev = pdev;
++ instance->host = host;
++ instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
++ instance->init_id = MEGASAS_DEFAULT_INIT_ID;
++
++ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ instance->flag_ieee = 1;
++ sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
++ } else
++ sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
++
++ megasas_dbg_lvl = 0;
++ instance->flag = 0;
++ instance->unload = 1;
++ instance->last_time = 0;
++ instance->disableOnlineCtrlReset = 1;
++
++ INIT_WORK(&instance->work_init, process_fw_state_change_wq);
++
++ /*
++ * Initialize MFI Firmware
++ */
++ if (megasas_init_mfi(instance))
++ goto fail_init_mfi;
++
++ /*
++ * Register IRQ
++ */
++ if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED, "megasas", instance)) {
++ printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
++ goto fail_irq;
++ }
++
++ instance->instancet->enable_intr(instance->reg_set);
++
++ /*
++ * Store instance in PCI softstate
++ */
++ pci_set_drvdata(pdev, instance);
++
++ /*
++ * Add this controller to megasas_mgmt_info structure so that it
++ * can be exported to management applications
++ */
++ megasas_mgmt_info.count++;
++ megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = instance;
++ megasas_mgmt_info.max_index++;
++
++ /*
++ * Initiate AEN (Asynchronous Event Notification)
++ */
++ if (megasas_start_aen(instance)) {
++ printk(KERN_DEBUG "megasas: start aen failed\n");
++ goto fail_start_aen;
++ }
++
++ /*
++ * Register with SCSI mid-layer
++ */
++ if (megasas_io_attach(instance))
++ goto fail_io_attach;
++
++ instance->unload = 0;
++ return 0;
++
++ fail_start_aen:
++ fail_io_attach:
++ megasas_mgmt_info.count--;
++ megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL;
++ megasas_mgmt_info.max_index--;
++
++ pci_set_drvdata(pdev, NULL);
++ instance->instancet->disable_intr(instance->reg_set);
++ free_irq(instance->pdev->irq, instance);
++
++ megasas_release_mfi(instance);
++
++ fail_irq:
++ fail_init_mfi:
++ fail_alloc_dma_buf:
++ if (instance->evt_detail)
++ pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
++ instance->evt_detail,
++ instance->evt_detail_h);
++
++ if (instance->producer)
++ pci_free_consistent(pdev, sizeof(u32), instance->producer,
++ instance->producer_h);
++ if (instance->consumer)
++ pci_free_consistent(pdev, sizeof(u32), instance->consumer,
++ instance->consumer_h);
++ scsi_host_put(host);
++
++ fail_alloc_instance:
++ fail_set_dma_mask:
++ pci_disable_device(pdev);
++
++ return -ENODEV;
++}
++
++/**
++ * megasas_flush_cache - Requests FW to flush all its caches
++ * @instance: Adapter soft state
++ */
++static void megasas_flush_cache(struct megasas_instance *instance)
++{
++ struct megasas_cmd *cmd;
++ struct megasas_dcmd_frame *dcmd;
++
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
++ return;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd)
++ return;
++
++ dcmd = &cmd->frame->dcmd;
++
++ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
++
++ dcmd->cmd = MFI_CMD_DCMD;
++ dcmd->cmd_status = 0x0;
++ dcmd->sge_count = 0;
++ dcmd->flags = MFI_FRAME_DIR_NONE;
++ dcmd->timeout = 0;
++ dcmd->data_xfer_len = 0;
++ dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;
++ dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
++
++ megasas_issue_blocked_cmd(instance, cmd);
++
++ megasas_return_cmd(instance, cmd);
++
++ return;
++}
++
++/**
++ * megasas_shutdown_controller - Instructs FW to shutdown the controller
++ * @instance: Adapter soft state
++ * @opcode: Shutdown/Hibernate
++ */
++static void megasas_shutdown_controller(struct megasas_instance *instance,
++ u32 opcode)
++{
++ struct megasas_cmd *cmd;
++ struct megasas_dcmd_frame *dcmd;
++
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
++ return;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd)
++ return;
++
++ if (instance->aen_cmd)
++ megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd);
++
++ dcmd = &cmd->frame->dcmd;
++
++ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
++
++ dcmd->cmd = MFI_CMD_DCMD;
++ dcmd->cmd_status = 0x0;
++ dcmd->sge_count = 0;
++ dcmd->flags = MFI_FRAME_DIR_NONE;
++ dcmd->timeout = 0;
++ dcmd->data_xfer_len = 0;
++ dcmd->opcode = opcode;
++
++ megasas_issue_blocked_cmd(instance, cmd);
++
++ megasas_return_cmd(instance, cmd);
++
++ return;
++}
++
++#ifdef CONFIG_PM
++/**
++ * megasas_suspend - driver suspend entry point
++ * @pdev: PCI device structure
++ * @state: PCI power state to suspend routine
++ */
++static int
++megasas_suspend(struct pci_dev *pdev, pm_message_t state)
++{
++ struct Scsi_Host *host;
++ struct megasas_instance *instance;
++
++ instance = pci_get_drvdata(pdev);
++ host = instance->host;
++ instance->unload = 1;
++
++ if (poll_mode_io)
++ del_timer_sync(&instance->io_completion_timer);
++
++ megasas_flush_cache(instance);
++ megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
++
++ /* cancel the delayed work if this work still in queue */
++ if (instance->ev != NULL) {
++ struct megasas_aen_event *ev = instance->ev;
++ cancel_delayed_work(
++ (struct delayed_work *)&ev->hotplug_work);
++ flush_scheduled_work();
++ instance->ev = NULL;
++ }
++
++ tasklet_kill(&instance->isr_tasklet);
++
++ pci_set_drvdata(instance->pdev, instance);
++ instance->instancet->disable_intr(instance->reg_set);
++ free_irq(instance->pdev->irq, instance);
++
++ pci_save_state(pdev);
++ pci_disable_device(pdev);
++
++ pci_set_power_state(pdev, pci_choose_state(pdev, state));
++
++ return 0;
++}
++
++/**
++ * megasas_resume- driver resume entry point
++ * @pdev: PCI device structure
++ */
++static int
++megasas_resume(struct pci_dev *pdev)
++{
++ int rval;
++ struct Scsi_Host *host;
++ struct megasas_instance *instance;
++
++ instance = pci_get_drvdata(pdev);
++ host = instance->host;
++ pci_set_power_state(pdev, PCI_D0);
++ pci_enable_wake(pdev, PCI_D0, 0);
++ pci_restore_state(pdev);
++
++ /*
++ * PCI prepping: enable device set bus mastering and dma mask
++ */
++ rval = pci_enable_device(pdev);
++
++ if (rval) {
++ printk(KERN_ERR "megasas: Enable device failed\n");
++ return rval;
++ }
++
++ pci_set_master(pdev);
++
++ if (megasas_set_dma_mask(pdev))
++ goto fail_set_dma_mask;
++
++ /*
++ * Initialize MFI Firmware
++ */
++
++ *instance->producer = 0;
++ *instance->consumer = 0;
++
++ atomic_set(&instance->fw_outstanding, 0);
++
++ /*
++ * We expect the FW state to be READY
++ */
++ if (megasas_transition_to_ready(instance))
++ goto fail_ready_state;
++
++ if (megasas_issue_init_mfi(instance))
++ goto fail_init_mfi;
++
++ tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
++ (unsigned long)instance);
++
++ /*
++ * Register IRQ
++ */
++ if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED,
++ "megasas", instance)) {
++ printk(KERN_ERR "megasas: Failed to register IRQ\n");
++ goto fail_irq;
++ }
++
++ instance->instancet->enable_intr(instance->reg_set);
++
++ /*
++ * Initiate AEN (Asynchronous Event Notification)
++ */
++ if (megasas_start_aen(instance))
++ printk(KERN_ERR "megasas: Start AEN failed\n");
++
++ /* Initialize the cmd completion timer */
++ if (poll_mode_io)
++ megasas_start_timer(instance, &instance->io_completion_timer,
++ megasas_io_completion_timer,
++ MEGASAS_COMPLETION_TIMER_INTERVAL);
++ instance->unload = 0;
++
++ return 0;
++
++fail_irq:
++fail_init_mfi:
++ if (instance->evt_detail)
++ pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
++ instance->evt_detail,
++ instance->evt_detail_h);
++
++ if (instance->producer)
++ pci_free_consistent(pdev, sizeof(u32), instance->producer,
++ instance->producer_h);
++ if (instance->consumer)
++ pci_free_consistent(pdev, sizeof(u32), instance->consumer,
++ instance->consumer_h);
++ scsi_host_put(host);
++
++fail_set_dma_mask:
++fail_ready_state:
++
++ pci_disable_device(pdev);
++
++ return -ENODEV;
++}
++#else
++#define megasas_suspend NULL
++#define megasas_resume NULL
++#endif
++
++/**
++ * megasas_detach_one - PCI hot"un"plug entry point
++ * @pdev: PCI device structure
++ */
++static void __devexit megasas_detach_one(struct pci_dev *pdev)
++{
++ int i;
++ struct Scsi_Host *host;
++ struct megasas_instance *instance;
++
++ instance = pci_get_drvdata(pdev);
++ instance->unload = 1;
++ host = instance->host;
++
++ if (poll_mode_io)
++ del_timer_sync(&instance->io_completion_timer);
++
++ scsi_remove_host(instance->host);
++ megasas_flush_cache(instance);
++ megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
++
++ /* cancel the delayed work if this work still in queue*/
++ if (instance->ev != NULL) {
++ struct megasas_aen_event *ev = instance->ev;
++ cancel_delayed_work(
++ (struct delayed_work *)&ev->hotplug_work);
++ flush_scheduled_work();
++ instance->ev = NULL;
++ }
++
++ tasklet_kill(&instance->isr_tasklet);
++
++ /*
++ * Take the instance off the instance array. Note that we will not
++ * decrement the max_index. We let this array be sparse array
++ */
++ for (i = 0; i < megasas_mgmt_info.max_index; i++) {
++ if (megasas_mgmt_info.instance[i] == instance) {
++ megasas_mgmt_info.count--;
++ megasas_mgmt_info.instance[i] = NULL;
++
++ break;
++ }
++ }
++
++ pci_set_drvdata(instance->pdev, NULL);
++
++ instance->instancet->disable_intr(instance->reg_set);
++
++ free_irq(instance->pdev->irq, instance);
++
++ megasas_release_mfi(instance);
++
++ pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
++ instance->evt_detail, instance->evt_detail_h);
++
++ pci_free_consistent(pdev, sizeof(u32), instance->producer,
++ instance->producer_h);
++
++ pci_free_consistent(pdev, sizeof(u32), instance->consumer,
++ instance->consumer_h);
++
++ scsi_host_put(host);
++
++ pci_set_drvdata(pdev, NULL);
++
++ pci_disable_device(pdev);
++
++ return;
++}
++
++/**
++ * megasas_shutdown - Shutdown entry point
++ * @device: Generic device structure
++ */
++static void megasas_shutdown(struct pci_dev *pdev)
++{
++ struct megasas_instance *instance = pci_get_drvdata(pdev);
++ instance->unload = 1;
++ megasas_flush_cache(instance);
++ megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
++}
++
++/**
++ * megasas_mgmt_open - char node "open" entry point
++ */
++static int megasas_mgmt_open(struct inode *inode, struct file *filep)
++{
++ cycle_kernel_lock();
++ /*
++ * Allow only those users with admin rights
++ */
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ return 0;
++}
++
++/**
++ * megasas_mgmt_fasync - Async notifier registration from applications
++ *
++ * This function adds the calling process to a driver global queue. When an
++ * event occurs, SIGIO will be sent to all processes in this queue.
++ */
++static int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
++{
++ int rc;
++
++ mutex_lock(&megasas_async_queue_mutex);
++
++ rc = fasync_helper(fd, filep, mode, &megasas_async_queue);
++
++ mutex_unlock(&megasas_async_queue_mutex);
++
++ if (rc >= 0) {
++ /* For sanity check when we get ioctl */
++ filep->private_data = filep;
++ return 0;
++ }
++
++ printk(KERN_DEBUG "megasas: fasync_helper failed [%d]\n", rc);
++
++ return rc;
++}
++
++/**
++ * megasas_mgmt_poll - char node "poll" entry point
++ * */
++static unsigned int megasas_mgmt_poll(struct file *file, poll_table *wait)
++{
++ unsigned int mask;
++ unsigned long flags;
++ poll_wait(file, &megasas_poll_wait, wait);
++ spin_lock_irqsave(&poll_aen_lock, flags);
++ if (megasas_poll_wait_aen)
++ mask = (POLLIN | POLLRDNORM);
++ else
++ mask = 0;
++ spin_unlock_irqrestore(&poll_aen_lock, flags);
++ return mask;
++}
++
++/**
++ * megasas_mgmt_fw_ioctl - Issues management ioctls to FW
++ * @instance: Adapter soft state
++ * @argp: User's ioctl packet
++ */
++static int
++megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
++ struct megasas_iocpacket __user * user_ioc,
++ struct megasas_iocpacket *ioc)
++{
++ struct megasas_sge32 *kern_sge32;
++ struct megasas_cmd *cmd;
++ void *kbuff_arr[MAX_IOCTL_SGE];
++ dma_addr_t buf_handle = 0;
++ int error = 0, i;
++ void *sense = NULL;
++ dma_addr_t sense_handle;
++ unsigned long *sense_ptr;
++
++ memset(kbuff_arr, 0, sizeof(kbuff_arr));
++
++ if (ioc->sge_count > MAX_IOCTL_SGE) {
++ printk(KERN_DEBUG "megasas: SGE count [%d] > max limit [%d]\n",
++ ioc->sge_count, MAX_IOCTL_SGE);
++ return -EINVAL;
++ }
++
++ cmd = megasas_get_cmd(instance);
++ if (!cmd) {
++ printk(KERN_DEBUG "megasas: Failed to get a cmd packet\n");
++ return -ENOMEM;
++ }
++
++ /*
++ * User's IOCTL packet has 2 frames (maximum). Copy those two
++ * frames into our cmd's frames. cmd->frame's context will get
++ * overwritten when we copy from user's frames. So set that value
++ * alone separately
++ */
++ memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
++ cmd->frame->hdr.context = cmd->index;
++ cmd->frame->hdr.pad_0 = 0;
++
++ /*
++ * The management interface between applications and the fw uses
++ * MFI frames. E.g, RAID configuration changes, LD property changes
++ * etc are accomplishes through different kinds of MFI frames. The
++ * driver needs to care only about substituting user buffers with
++ * kernel buffers in SGLs. The location of SGL is embedded in the
++ * struct iocpacket itself.
++ */
++ kern_sge32 = (struct megasas_sge32 *)
++ ((unsigned long)cmd->frame + ioc->sgl_off);
++
++ /*
++ * For each user buffer, create a mirror buffer and copy in
++ */
++ for (i = 0; i < ioc->sge_count; i++) {
++ if (!ioc->sgl[i].iov_len)
++ continue;
++
++ kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev,
++ ioc->sgl[i].iov_len,
++ &buf_handle, GFP_KERNEL);
++ if (!kbuff_arr[i]) {
++ printk(KERN_DEBUG "megasas: Failed to alloc "
++ "kernel SGL buffer for IOCTL \n");
++ error = -ENOMEM;
++ goto out;
++ }
++
++ /*
++ * We don't change the dma_coherent_mask, so
++ * pci_alloc_consistent only returns 32bit addresses
++ */
++ kern_sge32[i].phys_addr = (u32) buf_handle;
++ kern_sge32[i].length = ioc->sgl[i].iov_len;
++
++ /*
++ * We created a kernel buffer corresponding to the
++ * user buffer. Now copy in from the user buffer
++ */
++ if (copy_from_user(kbuff_arr[i], ioc->sgl[i].iov_base,
++ (u32) (ioc->sgl[i].iov_len))) {
++ error = -EFAULT;
++ goto out;
++ }
++ }
++
++ if (ioc->sense_len) {
++ sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len,
++ &sense_handle, GFP_KERNEL);
++ if (!sense) {
++ error = -ENOMEM;
++ goto out;
++ }
++
++ sense_ptr =
++ (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off);
++ *sense_ptr = sense_handle;
++ }
++
++ /*
++ * Set the sync_cmd flag so that the ISR knows not to complete this
++ * cmd to the SCSI mid-layer
++ */
++ cmd->sync_cmd = 1;
++ megasas_issue_blocked_cmd(instance, cmd);
++ cmd->sync_cmd = 0;
++
++ /*
++ * copy out the kernel buffers to user buffers
++ */
++ for (i = 0; i < ioc->sge_count; i++) {
++ if (copy_to_user(ioc->sgl[i].iov_base, kbuff_arr[i],
++ ioc->sgl[i].iov_len)) {
++ error = -EFAULT;
++ goto out;
++ }
++ }
++
++ /*
++ * copy out the sense
++ */
++ if (ioc->sense_len) {
++ /*
++ * sense_ptr points to the location that has the user
++ * sense buffer address
++ */
++ sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw +
++ ioc->sense_off);
++
++ if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
++ sense, ioc->sense_len)) {
++ printk(KERN_ERR "megasas: Failed to copy out to user "
++ "sense data\n");
++ error = -EFAULT;
++ goto out;
++ }
++ }
++
++ /*
++ * copy the status codes returned by the fw
++ */
++ if (copy_to_user(&user_ioc->frame.hdr.cmd_status,
++ &cmd->frame->hdr.cmd_status, sizeof(u8))) {
++ printk(KERN_DEBUG "megasas: Error copying out cmd_status\n");
++ error = -EFAULT;
++ }
++
++ out:
++ if (sense) {
++ dma_free_coherent(&instance->pdev->dev, ioc->sense_len,
++ sense, sense_handle);
++ }
++
++ for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) {
++ dma_free_coherent(&instance->pdev->dev,
++ kern_sge32[i].length,
++ kbuff_arr[i], kern_sge32[i].phys_addr);
++ }
++
++ megasas_return_cmd(instance, cmd);
++ return error;
++}
++
++static struct megasas_instance *megasas_lookup_instance(u16 host_no)
++{
++ int i;
++
++ for (i = 0; i < megasas_mgmt_info.max_index; i++) {
++
++ if ((megasas_mgmt_info.instance[i]) &&
++ (megasas_mgmt_info.instance[i]->host->host_no == host_no))
++ return megasas_mgmt_info.instance[i];
++ }
++
++ return NULL;
++}
++
++static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
++{
++ struct megasas_iocpacket __user *user_ioc =
++ (struct megasas_iocpacket __user *)arg;
++ struct megasas_iocpacket *ioc;
++ struct megasas_instance *instance;
++ int error;
++ int i;
++ unsigned long flags;
++ u32 wait_time = MEGASAS_RESET_WAIT_TIME;
++
++ ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);
++ if (!ioc)
++ return -ENOMEM;
++
++ if (copy_from_user(ioc, user_ioc, sizeof(*ioc))) {
++ error = -EFAULT;
++ goto out_kfree_ioc;
++ }
++
++ instance = megasas_lookup_instance(ioc->host_no);
++ if (!instance) {
++ error = -ENODEV;
++ goto out_kfree_ioc;
++ }
++
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
++ printk(KERN_ERR "Controller in crit error\n");
++ error = -ENODEV;
++ goto out_kfree_ioc;
++ }
++
++ if (instance->unload == 1) {
++ error = -ENODEV;
++ goto out_kfree_ioc;
++ }
++
++ /*
++ * We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds
++ */
++ if (down_interruptible(&instance->ioctl_sem)) {
++ error = -ERESTARTSYS;
++ goto out_kfree_ioc;
++ }
++
++ for (i = 0; i < wait_time; i++) {
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ break;
++ }
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
++ printk(KERN_NOTICE "megasas: waiting"
++ "for controller reset to finish\n");
++ }
++
++ msleep(1000);
++ }
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ printk(KERN_ERR "megaraid_sas: timed out while"
++ "waiting for HBA to recover\n");
++ error = -ENODEV;
++ goto out_kfree_ioc;
++ }
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc);
++ up(&instance->ioctl_sem);
++
++ out_kfree_ioc:
++ kfree(ioc);
++ return error;
++}
++
++static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
++{
++ struct megasas_instance *instance;
++ struct megasas_aen aen;
++ int error;
++ int i;
++ unsigned long flags;
++ u32 wait_time = MEGASAS_RESET_WAIT_TIME;
++
++ if (file->private_data != file) {
++ printk(KERN_DEBUG "megasas: fasync_helper was not "
++ "called first\n");
++ return -EINVAL;
++ }
++
++ if (copy_from_user(&aen, (void __user *)arg, sizeof(aen)))
++ return -EFAULT;
++
++ instance = megasas_lookup_instance(aen.host_no);
++
++ if (!instance)
++ return -ENODEV;
++
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
++ return -ENODEV;
++ }
++
++ if (instance->unload == 1) {
++ return -ENODEV;
++ }
++
++ for (i = 0; i < wait_time; i++) {
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
++ spin_unlock_irqrestore(&instance->hba_lock,
++ flags);
++ break;
++ }
++
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
++ printk(KERN_NOTICE "megasas: waiting for"
++ "controller reset to finish\n");
++ }
++
++ msleep(1000);
++ }
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ printk(KERN_ERR "megaraid_sas: timed out while waiting"
++ "for HBA to recover.\n");
++ return -ENODEV;
++ }
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ mutex_lock(&instance->aen_mutex);
++ error = megasas_register_aen(instance, aen.seq_num,
++ aen.class_locale_word);
++ mutex_unlock(&instance->aen_mutex);
++ return error;
++}
++
++/**
++ * megasas_mgmt_ioctl - char node ioctl entry point
++ */
++static long
++megasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ switch (cmd) {
++ case MEGASAS_IOC_FIRMWARE:
++ return megasas_mgmt_ioctl_fw(file, arg);
++
++ case MEGASAS_IOC_GET_AEN:
++ return megasas_mgmt_ioctl_aen(file, arg);
++ }
++
++ return -ENOTTY;
++}
++
++#ifdef CONFIG_COMPAT
++static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
++{
++ struct compat_megasas_iocpacket __user *cioc =
++ (struct compat_megasas_iocpacket __user *)arg;
++ struct megasas_iocpacket __user *ioc =
++ compat_alloc_user_space(sizeof(struct megasas_iocpacket));
++ int i;
++ int error = 0;
++ compat_uptr_t ptr;
++
++ if (clear_user(ioc, sizeof(*ioc)))
++ return -EFAULT;
++
++ if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
++ copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
++ copy_in_user(&ioc->sense_off, &cioc->sense_off, sizeof(u32)) ||
++ copy_in_user(&ioc->sense_len, &cioc->sense_len, sizeof(u32)) ||
++ copy_in_user(ioc->frame.raw, cioc->frame.raw, 128) ||
++ copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32)))
++ return -EFAULT;
++
++ /*
++ * The sense_ptr is used in megasas_mgmt_fw_ioctl only when
++ * sense_len is not null, so prepare the 64bit value under
++ * the same condition.
++ */
++ if (ioc->sense_len) {
++ void __user **sense_ioc_ptr =
++ (void __user **)(ioc->frame.raw + ioc->sense_off);
++ compat_uptr_t *sense_cioc_ptr =
++ (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off);
++ if (get_user(ptr, sense_cioc_ptr) ||
++ put_user(compat_ptr(ptr), sense_ioc_ptr))
++ return -EFAULT;
++ }
++
++ for (i = 0; i < MAX_IOCTL_SGE; i++) {
++ if (get_user(ptr, &cioc->sgl[i].iov_base) ||
++ put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) ||
++ copy_in_user(&ioc->sgl[i].iov_len,
++ &cioc->sgl[i].iov_len, sizeof(compat_size_t)))
++ return -EFAULT;
++ }
++
++ error = megasas_mgmt_ioctl_fw(file, (unsigned long)ioc);
++
++ if (copy_in_user(&cioc->frame.hdr.cmd_status,
++ &ioc->frame.hdr.cmd_status, sizeof(u8))) {
++ printk(KERN_DEBUG "megasas: error copy_in_user cmd_status\n");
++ return -EFAULT;
++ }
++ return error;
++}
++
++static long
++megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ switch (cmd) {
++ case MEGASAS_IOC_FIRMWARE32:
++ return megasas_mgmt_compat_ioctl_fw(file, arg);
++ case MEGASAS_IOC_GET_AEN:
++ return megasas_mgmt_ioctl_aen(file, arg);
++ }
++
++ return -ENOTTY;
++}
++#endif
++
++/*
++ * File operations structure for management interface
++ */
++static const struct file_operations megasas_mgmt_fops = {
++ .owner = THIS_MODULE,
++ .open = megasas_mgmt_open,
++ .fasync = megasas_mgmt_fasync,
++ .unlocked_ioctl = megasas_mgmt_ioctl,
++ .poll = megasas_mgmt_poll,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = megasas_mgmt_compat_ioctl,
++#endif
++};
++
++/*
++ * PCI hotplug support registration structure
++ */
++static struct pci_driver megasas_pci_driver = {
++
++ .name = "megaraid_sas",
++ .id_table = megasas_pci_table,
++ .probe = megasas_probe_one,
++ .remove = __devexit_p(megasas_detach_one),
++ .suspend = megasas_suspend,
++ .resume = megasas_resume,
++ .shutdown = megasas_shutdown,
++};
++
++/*
++ * Sysfs driver attributes
++ */
++static ssize_t megasas_sysfs_show_version(struct device_driver *dd, char *buf)
++{
++ return snprintf(buf, strlen(MEGASAS_VERSION) + 2, "%s\n",
++ MEGASAS_VERSION);
++}
++
++static DRIVER_ATTR(version, S_IRUGO, megasas_sysfs_show_version, NULL);
++
++static ssize_t
++megasas_sysfs_show_release_date(struct device_driver *dd, char *buf)
++{
++ return snprintf(buf, strlen(MEGASAS_RELDATE) + 2, "%s\n",
++ MEGASAS_RELDATE);
++}
++
++static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
++ NULL);
++
++static ssize_t
++megasas_sysfs_show_support_poll_for_event(struct device_driver *dd, char *buf)
++{
++ return sprintf(buf, "%u\n", support_poll_for_event);
++}
++
++static DRIVER_ATTR(support_poll_for_event, S_IRUGO,
++ megasas_sysfs_show_support_poll_for_event, NULL);
++
++static ssize_t
++megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
++{
++ return sprintf(buf, "%u\n", megasas_dbg_lvl);
++}
++
++static ssize_t
++megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count)
++{
++ int retval = count;
++ if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){
++ printk(KERN_ERR "megasas: could not set dbg_lvl\n");
++ retval = -EINVAL;
++ }
++ return retval;
++}
++
++static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUSR, megasas_sysfs_show_dbg_lvl,
++ megasas_sysfs_set_dbg_lvl);
++
++static ssize_t
++megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf)
++{
++ return sprintf(buf, "%u\n", poll_mode_io);
++}
++
++static ssize_t
++megasas_sysfs_set_poll_mode_io(struct device_driver *dd,
++ const char *buf, size_t count)
++{
++ int retval = count;
++ int tmp = poll_mode_io;
++ int i;
++ struct megasas_instance *instance;
++
++ if (sscanf(buf, "%u", &poll_mode_io) < 1) {
++ printk(KERN_ERR "megasas: could not set poll_mode_io\n");
++ retval = -EINVAL;
++ }
++
++ /*
++ * Check if poll_mode_io is already set or is same as previous value
++ */
++ if ((tmp && poll_mode_io) || (tmp == poll_mode_io))
++ goto out;
++
++ if (poll_mode_io) {
++ /*
++ * Start timers for all adapters
++ */
++ for (i = 0; i < megasas_mgmt_info.max_index; i++) {
++ instance = megasas_mgmt_info.instance[i];
++ if (instance) {
++ megasas_start_timer(instance,
++ &instance->io_completion_timer,
++ megasas_io_completion_timer,
++ MEGASAS_COMPLETION_TIMER_INTERVAL);
++ }
++ }
++ } else {
++ /*
++ * Delete timers for all adapters
++ */
++ for (i = 0; i < megasas_mgmt_info.max_index; i++) {
++ instance = megasas_mgmt_info.instance[i];
++ if (instance)
++ del_timer_sync(&instance->io_completion_timer);
++ }
++ }
++
++out:
++ return retval;
++}
++
++static void
++megasas_aen_polling(struct work_struct *work)
++{
++ struct megasas_aen_event *ev =
++ container_of(work, struct megasas_aen_event, hotplug_work);
++ struct megasas_instance *instance = ev->instance;
++ union megasas_evt_class_locale class_locale;
++ struct Scsi_Host *host;
++ struct scsi_device *sdev1;
++ u16 pd_index = 0;
++ u16 ld_index = 0;
++ int i, j, doscan = 0;
++ u32 seq_num;
++ int error;
++
++ if (!instance) {
++ printk(KERN_ERR "invalid instance!\n");
++ kfree(ev);
++ return;
++ }
++ instance->ev = NULL;
++ host = instance->host;
++ if (instance->evt_detail) {
++
++ switch (instance->evt_detail->code) {
++ case MR_EVT_PD_INSERTED:
++ if (megasas_get_pd_list(instance) == 0) {
++ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
++ for (j = 0;
++ j < MEGASAS_MAX_DEV_PER_CHANNEL;
++ j++) {
++
++ pd_index =
++ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
++
++ sdev1 =
++ scsi_device_lookup(host, i, j, 0);
++
++ if (instance->pd_list[pd_index].driveState
++ == MR_PD_STATE_SYSTEM) {
++ if (!sdev1) {
++ scsi_add_device(host, i, j, 0);
++ }
++
++ if (sdev1)
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ }
++ doscan = 0;
++ break;
++
++ case MR_EVT_PD_REMOVED:
++ if (megasas_get_pd_list(instance) == 0) {
++ megasas_get_pd_list(instance);
++ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
++ for (j = 0;
++ j < MEGASAS_MAX_DEV_PER_CHANNEL;
++ j++) {
++
++ pd_index =
++ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
++
++ sdev1 =
++ scsi_device_lookup(host, i, j, 0);
++
++ if (instance->pd_list[pd_index].driveState
++ == MR_PD_STATE_SYSTEM) {
++ if (sdev1) {
++ scsi_device_put(sdev1);
++ }
++ } else {
++ if (sdev1) {
++ scsi_remove_device(sdev1);
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ }
++ }
++ doscan = 0;
++ break;
++
++ case MR_EVT_LD_OFFLINE:
++ case MR_EVT_LD_DELETED:
++ megasas_get_ld_list(instance);
++ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
++ for (j = 0;
++ j < MEGASAS_MAX_DEV_PER_CHANNEL;
++ j++) {
++
++ ld_index =
++ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
++
++ sdev1 = scsi_device_lookup(host,
++ i + MEGASAS_MAX_LD_CHANNELS,
++ j,
++ 0);
++
++ if (instance->ld_ids[ld_index] != 0xff) {
++ if (sdev1) {
++ scsi_device_put(sdev1);
++ }
++ } else {
++ if (sdev1) {
++ scsi_remove_device(sdev1);
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ }
++ doscan = 0;
++ break;
++ case MR_EVT_LD_CREATED:
++ megasas_get_ld_list(instance);
++ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
++ for (j = 0;
++ j < MEGASAS_MAX_DEV_PER_CHANNEL;
++ j++) {
++ ld_index =
++ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
++
++ sdev1 = scsi_device_lookup(host,
++ i+MEGASAS_MAX_LD_CHANNELS,
++ j, 0);
++
++ if (instance->ld_ids[ld_index] !=
++ 0xff) {
++ if (!sdev1) {
++ scsi_add_device(host,
++ i + 2,
++ j, 0);
++ }
++ }
++ if (sdev1) {
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ doscan = 0;
++ break;
++ case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
++ case MR_EVT_FOREIGN_CFG_IMPORTED:
++ doscan = 1;
++ break;
++ default:
++ doscan = 0;
++ break;
++ }
++ } else {
++ printk(KERN_ERR "invalid evt_detail!\n");
++ kfree(ev);
++ return;
++ }
++
++ if (doscan) {
++ printk(KERN_INFO "scanning ...\n");
++ megasas_get_pd_list(instance);
++ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
++ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
++ pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
++ sdev1 = scsi_device_lookup(host, i, j, 0);
++ if (instance->pd_list[pd_index].driveState ==
++ MR_PD_STATE_SYSTEM) {
++ if (!sdev1) {
++ scsi_add_device(host, i, j, 0);
++ }
++ if (sdev1)
++ scsi_device_put(sdev1);
++ } else {
++ if (sdev1) {
++ scsi_remove_device(sdev1);
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ }
++
++ megasas_get_ld_list(instance);
++ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
++ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
++ ld_index =
++ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
++
++ sdev1 = scsi_device_lookup(host,
++ i+MEGASAS_MAX_LD_CHANNELS, j, 0);
++ if (instance->ld_ids[ld_index] != 0xff) {
++ if (!sdev1) {
++ scsi_add_device(host,
++ i+2,
++ j, 0);
++ } else {
++ scsi_device_put(sdev1);
++ }
++ } else {
++ if (sdev1) {
++ scsi_remove_device(sdev1);
++ scsi_device_put(sdev1);
++ }
++ }
++ }
++ }
++ }
++
++ if ( instance->aen_cmd != NULL ) {
++ kfree(ev);
++ return ;
++ }
++
++ seq_num = instance->evt_detail->seq_num + 1;
++
++ /* Register AEN with FW for latest sequence number plus 1 */
++ class_locale.members.reserved = 0;
++ class_locale.members.locale = MR_EVT_LOCALE_ALL;
++ class_locale.members.class = MR_EVT_CLASS_DEBUG;
++ mutex_lock(&instance->aen_mutex);
++ error = megasas_register_aen(instance, seq_num,
++ class_locale.word);
++ mutex_unlock(&instance->aen_mutex);
++
++ if (error)
++ printk(KERN_ERR "register aen failed error %x\n", error);
++
++ kfree(ev);
++}
++
++
++static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUSR,
++ megasas_sysfs_show_poll_mode_io,
++ megasas_sysfs_set_poll_mode_io);
++
++/**
++ * megasas_init - Driver load entry point
++ */
++static int __init megasas_init(void)
++{
++ int rval;
++
++ /*
++ * Announce driver version and other information
++ */
++ printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION,
++ MEGASAS_EXT_VERSION);
++
++ support_poll_for_event = 2;
++
++ memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
++
++ /*
++ * Register character device node
++ */
++ rval = register_chrdev(0, "megaraid_sas_ioctl", &megasas_mgmt_fops);
++
++ if (rval < 0) {
++ printk(KERN_DEBUG "megasas: failed to open device node\n");
++ return rval;
++ }
++
++ megasas_mgmt_majorno = rval;
++
++ /*
++ * Register ourselves as PCI hotplug module
++ */
++ rval = pci_register_driver(&megasas_pci_driver);
++
++ if (rval) {
++ printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
++ goto err_pcidrv;
++ }
++
++ rval = driver_create_file(&megasas_pci_driver.driver,
++ &driver_attr_version);
++ if (rval)
++ goto err_dcf_attr_ver;
++ rval = driver_create_file(&megasas_pci_driver.driver,
++ &driver_attr_release_date);
++ if (rval)
++ goto err_dcf_rel_date;
++
++ rval = driver_create_file(&megasas_pci_driver.driver,
++ &driver_attr_support_poll_for_event);
++ if (rval)
++ goto err_dcf_support_poll_for_event;
++
++ rval = driver_create_file(&megasas_pci_driver.driver,
++ &driver_attr_dbg_lvl);
++ if (rval)
++ goto err_dcf_dbg_lvl;
++ rval = driver_create_file(&megasas_pci_driver.driver,
++ &driver_attr_poll_mode_io);
++ if (rval)
++ goto err_dcf_poll_mode_io;
++
++ return rval;
++
++err_dcf_poll_mode_io:
++ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_dbg_lvl);
++err_dcf_dbg_lvl:
++ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_support_poll_for_event);
++
++err_dcf_support_poll_for_event:
++ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_release_date);
++
++err_dcf_rel_date:
++ driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
++err_dcf_attr_ver:
++ pci_unregister_driver(&megasas_pci_driver);
++err_pcidrv:
++ unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
++ return rval;
++}
++
++/**
++ * megasas_exit - Driver unload entry point
++ */
++static void __exit megasas_exit(void)
++{
++ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_poll_mode_io);
++ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_dbg_lvl);
++ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_release_date);
++ driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
++
++ pci_unregister_driver(&megasas_pci_driver);
++ unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
++}
++
++module_init(megasas_init);
++module_exit(megasas_exit);
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0013-megaraid_sas-add-msi-x-support-and-msix_disable-module-parameter.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0013-megaraid_sas-add-msi-x-support-and-msix_disable-module-parameter.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,129 @@
+From cd97f4f1a3c388667115057585c95c16c17321cd Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Tue, 21 Dec 2010 10:17:40 -0800
+Subject: [PATCH 13/53] [SCSI] megaraid_sas: Add MSI-X support and msix_disable module parameter
+
+commit 80d9da98b4034edd31f6bacdb96c7489c4460173 upstream.
+
+This patch adds MSI-X support and 'msix_disable' module parameter to
+the megaraid_sas driver.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.h | 3 +++
+ drivers/scsi/megaraid/megaraid_sas_base.c | 41 +++++++++++++++++++++++++------
+ 2 files changed, 37 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index a231aa811e56..4a6253d92b7e 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -1319,6 +1319,9 @@ struct megasas_instance {
+
+ struct timer_list io_completion_timer;
+ struct list_head internal_reset_pending_q;
++
++ u8 msi_flag;
++ struct msix_entry msixentry;
+ };
+
+ enum {
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index a18ae3cba87e..e5738869272c 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -56,6 +56,10 @@ module_param_named(poll_mode_io, poll_mode_io, int, 0);
+ MODULE_PARM_DESC(poll_mode_io,
+ "Complete cmds from IO path, (default=0)");
+
++static int msix_disable;
++module_param(msix_disable, int, S_IRUGO);
++MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
++
+ MODULE_LICENSE("GPL");
+ MODULE_VERSION(MEGASAS_VERSION);
+ MODULE_AUTHOR("megaraidlinux at lsi.com");
+@@ -3676,10 +3680,20 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ if (megasas_init_mfi(instance))
+ goto fail_init_mfi;
+
++ /* Try to enable MSI-X */
++ if ((instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078R) &&
++ (instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078DE) &&
++ (instance->pdev->device != PCI_DEVICE_ID_LSI_VERDE_ZCR) &&
++ !msix_disable && !pci_enable_msix(instance->pdev,
++ &instance->msixentry, 1))
++ instance->msi_flag = 1;
++
+ /*
+ * Register IRQ
+ */
+- if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED, "megasas", instance)) {
++ if (request_irq(instance->msi_flag ? instance->msixentry.vector :
++ pdev->irq, megasas_isr,
++ IRQF_SHARED, "megasas", instance)) {
+ printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
+ goto fail_irq;
+ }
+@@ -3724,8 +3738,10 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+
+ pci_set_drvdata(pdev, NULL);
+ instance->instancet->disable_intr(instance->reg_set);
+- free_irq(instance->pdev->irq, instance);
+-
++ free_irq(instance->msi_flag ? instance->msixentry.vector :
++ instance->pdev->irq, instance);
++ if (instance->msi_flag)
++ pci_disable_msix(instance->pdev);
+ megasas_release_mfi(instance);
+
+ fail_irq:
+@@ -3864,7 +3880,10 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
+
+ pci_set_drvdata(instance->pdev, instance);
+ instance->instancet->disable_intr(instance->reg_set);
+- free_irq(instance->pdev->irq, instance);
++ free_irq(instance->msi_flag ? instance->msixentry.vector :
++ instance->pdev->irq, instance);
++ if (instance->msi_flag)
++ pci_disable_msix(instance->pdev);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+@@ -3927,11 +3946,16 @@ megasas_resume(struct pci_dev *pdev)
+ tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+ (unsigned long)instance);
+
++ /* Now re-enable MSI-X */
++ if (instance->msi_flag)
++ pci_enable_msix(instance->pdev, &instance->msixentry, 1);
++
+ /*
+ * Register IRQ
+ */
+- if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED,
+- "megasas", instance)) {
++ if (request_irq(instance->msi_flag ? instance->msixentry.vector :
++ pdev->irq, megasas_isr,
++ IRQF_SHARED, "megasas", instance)) {
+ printk(KERN_ERR "megasas: Failed to register IRQ\n");
+ goto fail_irq;
+ }
+@@ -4029,7 +4053,10 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
+
+ instance->instancet->disable_intr(instance->reg_set);
+
+- free_irq(instance->pdev->irq, instance);
++ free_irq(instance->msi_flag ? instance->msixentry.vector :
++ instance->pdev->irq, instance);
++ if (instance->msi_flag)
++ pci_disable_msix(instance->pdev);
+
+ megasas_release_mfi(instance);
+
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0014-megaraid_sas-make-driver-pci-legacy-i-o-port-free-driver.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0014-megaraid_sas-make-driver-pci-legacy-i-o-port-free-driver.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,94 @@
+From 473ac59f82dc5fdf24c06fee2b4b0be1c89fb958 Mon Sep 17 00:00:00 2001
+From: Noriyuki Fujii <n-fujii at np.css.fujitsu.com>
+Date: Fri, 20 Nov 2009 16:27:20 +0900
+Subject: [PATCH 14/53] [SCSI] megaraid_sas: make driver PCI legacy I/O port free driver
+
+commit aeab3fd7b865bc4086a80a83cfdd67dded3b41a0 upstream.
+
+On the large servers, I/O port resource may not be assigned to all
+the PCI devices since it is limited (to 64KB on Intel Architecture[1])
+and it may also be fragmented (I/O base register of PCI-to-PCI bridge
+will usually be aligned to a 4KB boundary[2]).
+If no I/O port resource is assigned to devices, those devices do not
+work.
+
+[1] Some machines support 64KB I/O port space per PCI segment.
+[2] Some P2P bridges support optional 1KB aligned I/O base.
+
+Therefore, I made a patch for MegaRAID SAS driver to make PCI legacy
+I/O port free. I have also tested the patch and it had no problem.
+
+The way to make PCI legacy I/O port free is the same as Fusion-MPT
+driver's and it has been merged into 2.6.30.4.
+
+This has already been fixed in e1000 and lpfc.
+
+As a result of the above, the driver can handle its device even when
+there are a huge number of PCI devices being used on the system and no
+I/O port region assigned to the device.
+
+Signed-off-by: Noriyuki Fujii <n-fujii at np.css.fujitsu.com>
+Acked-by: "Yang, Bo" <Bo.Yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index e5738869272c..58442f4b3ae1 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -3088,7 +3088,9 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ instance->base_addr = pci_resource_start(instance->pdev, 0);
+ }
+
+- if (pci_request_regions(instance->pdev, "megasas: LSI")) {
++ if (pci_request_selected_regions(instance->pdev,
++ pci_select_bars(instance->pdev, IORESOURCE_MEM),
++ "megasas: LSI")) {
+ printk(KERN_DEBUG "megasas: IO memory region busy!\n");
+ return -EBUSY;
+ }
+@@ -3249,7 +3251,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ iounmap(instance->reg_set);
+
+ fail_ioremap:
+- pci_release_regions(instance->pdev);
++ pci_release_selected_regions(instance->pdev,
++ pci_select_bars(instance->pdev, IORESOURCE_MEM));
+
+ return -EINVAL;
+ }
+@@ -3269,7 +3272,8 @@ static void megasas_release_mfi(struct megasas_instance *instance)
+
+ iounmap(instance->reg_set);
+
+- pci_release_regions(instance->pdev);
++ pci_release_selected_regions(instance->pdev,
++ pci_select_bars(instance->pdev, IORESOURCE_MEM));
+ }
+
+ /**
+@@ -3579,7 +3583,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ /*
+ * PCI prepping: enable device set bus mastering and dma mask
+ */
+- rval = pci_enable_device(pdev);
++ rval = pci_enable_device_mem(pdev);
+
+ if (rval) {
+ return rval;
+@@ -3913,7 +3917,7 @@ megasas_resume(struct pci_dev *pdev)
+ /*
+ * PCI prepping: enable device set bus mastering and dma mask
+ */
+- rval = pci_enable_device(pdev);
++ rval = pci_enable_device_mem(pdev);
+
+ if (rval) {
+ printk(KERN_ERR "megasas: Enable device failed\n");
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0015-megaraid_sas-use-lowest-memory-bar-for-sr-iov-vf-support.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0015-megaraid_sas-use-lowest-memory-bar-for-sr-iov-vf-support.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,88 @@
+From a80b25ee54c8660c6e2486d34726a721c32be57c Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Tue, 14 Dec 2010 18:56:07 -0800
+Subject: [PATCH 15/53] [SCSI] megaraid_sas: Use lowest memory bar for SR-IOV VF support
+
+commit b6d5d8808b4c563a56414a4c4c6d652b5f87c088 upstream.
+
+The following patch modifies the megaraid_sas driver to select the
+lowest memory bar available so the driver will work in SR-IOV VF
+environments where the memory bar mapping changes.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.h | 1 +
+ drivers/scsi/megaraid/megaraid_sas_base.c | 27 +++++++++------------------
+ 2 files changed, 10 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 4a6253d92b7e..83c6e3aa6f43 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -1322,6 +1322,7 @@ struct megasas_instance {
+
+ u8 msi_flag;
+ struct msix_entry msixentry;
++ unsigned long bar;
+ };
+
+ enum {
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 58442f4b3ae1..e019480cd64b 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -3076,21 +3076,14 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ u32 tmp_sectors;
+ struct megasas_register_set __iomem *reg_set;
+ struct megasas_ctrl_info *ctrl_info;
+- /*
+- * Map the message registers
+- */
+- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
+- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0079GEN2)) {
+- instance->base_addr = pci_resource_start(instance->pdev, 1);
+- } else {
+- instance->base_addr = pci_resource_start(instance->pdev, 0);
+- }
++ unsigned long bar_list;
+
+- if (pci_request_selected_regions(instance->pdev,
+- pci_select_bars(instance->pdev, IORESOURCE_MEM),
+- "megasas: LSI")) {
++ /* Find first memory bar */
++ bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
++ instance->bar = find_first_bit(&bar_list, sizeof(unsigned long));
++ instance->base_addr = pci_resource_start(instance->pdev, instance->bar);
++ if (pci_request_selected_regions(instance->pdev, instance->bar,
++ "megasas: LSI")) {
+ printk(KERN_DEBUG "megasas: IO memory region busy!\n");
+ return -EBUSY;
+ }
+@@ -3251,8 +3244,7 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ iounmap(instance->reg_set);
+
+ fail_ioremap:
+- pci_release_selected_regions(instance->pdev,
+- pci_select_bars(instance->pdev, IORESOURCE_MEM));
++ pci_release_selected_regions(instance->pdev, instance->bar);
+
+ return -EINVAL;
+ }
+@@ -3272,8 +3264,7 @@ static void megasas_release_mfi(struct megasas_instance *instance)
+
+ iounmap(instance->reg_set);
+
+- pci_release_selected_regions(instance->pdev,
+- pci_select_bars(instance->pdev, IORESOURCE_MEM));
++ pci_release_selected_regions(instance->pdev, instance->bar);
+ }
+
+ /**
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0016-megaraid_sas-add-struct-megasas_instance_template-changes.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0016-megaraid_sas-add-struct-megasas_instance_template-changes.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,454 @@
+From b6c1cb051e831fe75110c9e6055b46b45e57f058 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Tue, 21 Dec 2010 10:23:23 -0800
+Subject: [PATCH 16/53] [SCSI] megaraid_sas: Add struct megasas_instance_template changes
+
+commit cd50ba8ede5cd3c4606a8e5d163913da5ff36ad7 upstream.
+
+The following patch adds struct megasas_instance_template changes to
+the megaraid_sas driver, and changes all code to use the new instance
+entries:
+
+ irqreturn_t (*service_isr )(int irq, void *devp);
+ void (*tasklet)(unsigned long);
+ u32 (*init_adapter)(struct megasas_instance *);
+ u32 (*build_and_issue_cmd) (struct megasas_instance *, struct scsi_cmnd *);
+ void (*issue_dcmd) (struct megasas_instance *instance,
+ struct megasas_cmd *cmd);
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.h | 7 +
+ drivers/scsi/megaraid/megaraid_sas_base.c | 278 +++++++++++++++++++-----------
+ 2 files changed, 180 insertions(+), 105 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 83c6e3aa6f43..0663f2efda12 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -1348,6 +1348,13 @@ struct megasas_instance_template {
+ struct megasas_register_set __iomem *);
+ int (*check_reset)(struct megasas_instance *, \
+ struct megasas_register_set __iomem *);
++ irqreturn_t (*service_isr)(int irq, void *devp);
++ void (*tasklet)(unsigned long);
++ u32 (*init_adapter)(struct megasas_instance *);
++ u32 (*build_and_issue_cmd) (struct megasas_instance *,
++ struct scsi_cmnd *);
++ void (*issue_dcmd) (struct megasas_instance *instance,
++ struct megasas_cmd *cmd);
+ };
+
+ #define MEGASAS_IS_LOGICAL(scp) \
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index e019480cd64b..7f2b199b82c2 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -114,6 +114,20 @@ spinlock_t poll_aen_lock;
+ static void
+ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ u8 alt_status);
++static irqreturn_t megasas_isr(int irq, void *devp);
++static u32
++megasas_init_adapter_mfi(struct megasas_instance *instance);
++u32
++megasas_build_and_issue_cmd(struct megasas_instance *instance,
++ struct scsi_cmnd *scmd);
++static void megasas_complete_cmd_dpc(unsigned long instance_addr);
++
++void
++megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
++{
++ instance->instancet->fire_cmd(instance,
++ cmd->frame_phys_addr, 0, instance->reg_set);
++}
+
+ /**
+ * megasas_get_cmd - Get a command from the free pool
+@@ -317,6 +331,11 @@ static struct megasas_instance_template megasas_instance_template_xscale = {
+ .read_fw_status_reg = megasas_read_fw_status_reg_xscale,
+ .adp_reset = megasas_adp_reset_xscale,
+ .check_reset = megasas_check_reset_xscale,
++ .service_isr = megasas_isr,
++ .tasklet = megasas_complete_cmd_dpc,
++ .init_adapter = megasas_init_adapter_mfi,
++ .build_and_issue_cmd = megasas_build_and_issue_cmd,
++ .issue_dcmd = megasas_issue_dcmd,
+ };
+
+ /**
+@@ -443,6 +462,11 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
+ .read_fw_status_reg = megasas_read_fw_status_reg_ppc,
+ .adp_reset = megasas_adp_reset_ppc,
+ .check_reset = megasas_check_reset_ppc,
++ .service_isr = megasas_isr,
++ .tasklet = megasas_complete_cmd_dpc,
++ .init_adapter = megasas_init_adapter_mfi,
++ .build_and_issue_cmd = megasas_build_and_issue_cmd,
++ .issue_dcmd = megasas_issue_dcmd,
+ };
+
+ /**
+@@ -564,6 +588,11 @@ static struct megasas_instance_template megasas_instance_template_skinny = {
+ .read_fw_status_reg = megasas_read_fw_status_reg_skinny,
+ .adp_reset = megasas_adp_reset_skinny,
+ .check_reset = megasas_check_reset_skinny,
++ .service_isr = megasas_isr,
++ .tasklet = megasas_complete_cmd_dpc,
++ .init_adapter = megasas_init_adapter_mfi,
++ .build_and_issue_cmd = megasas_build_and_issue_cmd,
++ .issue_dcmd = megasas_issue_dcmd,
+ };
+
+
+@@ -734,6 +763,11 @@ static struct megasas_instance_template megasas_instance_template_gen2 = {
+ .read_fw_status_reg = megasas_read_fw_status_reg_gen2,
+ .adp_reset = megasas_adp_reset_gen2,
+ .check_reset = megasas_check_reset_gen2,
++ .service_isr = megasas_isr,
++ .tasklet = megasas_complete_cmd_dpc,
++ .init_adapter = megasas_init_adapter_mfi,
++ .build_and_issue_cmd = megasas_build_and_issue_cmd,
++ .issue_dcmd = megasas_issue_dcmd,
+ };
+
+ /**
+@@ -1305,6 +1339,51 @@ megasas_dump_pending_frames(struct megasas_instance *instance)
+ printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
+ }
+
++u32
++megasas_build_and_issue_cmd(struct megasas_instance *instance,
++ struct scsi_cmnd *scmd)
++{
++ struct megasas_cmd *cmd;
++ u32 frame_count;
++
++ cmd = megasas_get_cmd(instance);
++ if (!cmd)
++ return SCSI_MLQUEUE_HOST_BUSY;
++
++ /*
++ * Logical drive command
++ */
++ if (megasas_is_ldio(scmd))
++ frame_count = megasas_build_ldio(instance, scmd, cmd);
++ else
++ frame_count = megasas_build_dcdb(instance, scmd, cmd);
++
++ if (!frame_count)
++ goto out_return_cmd;
++
++ cmd->scmd = scmd;
++ scmd->SCp.ptr = (char *)cmd;
++
++ /*
++ * Issue the command to the FW
++ */
++ atomic_inc(&instance->fw_outstanding);
++
++ instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
++ cmd->frame_count-1, instance->reg_set);
++ /*
++ * Check if we have pend cmds to be completed
++ */
++ if (poll_mode_io && atomic_read(&instance->fw_outstanding))
++ tasklet_schedule(&instance->isr_tasklet);
++
++ return 0;
++out_return_cmd:
++ megasas_return_cmd(instance, cmd);
++ return 1;
++}
++
++
+ /**
+ * megasas_queue_command - Queue entry point
+ * @scmd: SCSI command to be queued
+@@ -1313,8 +1392,6 @@ megasas_dump_pending_frames(struct megasas_instance *instance)
+ static int
+ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
+ {
+- u32 frame_count;
+- struct megasas_cmd *cmd;
+ struct megasas_instance *instance;
+ unsigned long flags;
+
+@@ -1353,42 +1430,13 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
+ break;
+ }
+
+- cmd = megasas_get_cmd(instance);
+- if (!cmd)
++ if (instance->instancet->build_and_issue_cmd(instance, scmd)) {
++ printk(KERN_ERR "megasas: Err returned from build_and_issue_cmd\n");
+ return SCSI_MLQUEUE_HOST_BUSY;
+-
+- /*
+- * Logical drive command
+- */
+- if (megasas_is_ldio(scmd))
+- frame_count = megasas_build_ldio(instance, scmd, cmd);
+- else
+- frame_count = megasas_build_dcdb(instance, scmd, cmd);
+-
+- if (!frame_count)
+- goto out_return_cmd;
+-
+- cmd->scmd = scmd;
+- scmd->SCp.ptr = (char *)cmd;
+-
+- /*
+- * Issue the command to the FW
+- */
+- atomic_inc(&instance->fw_outstanding);
+-
+- instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
+- cmd->frame_count-1, instance->reg_set);
+- /*
+- * Check if we have pend cmds to be completed
+- */
+- if (poll_mode_io && atomic_read(&instance->fw_outstanding))
+- tasklet_schedule(&instance->isr_tasklet);
+-
++ }
+
+ return 0;
+
+- out_return_cmd:
+- megasas_return_cmd(instance, cmd);
+ out_done:
+ done(scmd);
+ return 0;
+@@ -3061,69 +3109,15 @@ megasas_io_completion_timer(unsigned long instance_addr)
+ jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
+ }
+
+-/**
+- * megasas_init_mfi - Initializes the FW
+- * @instance: Adapter soft state
+- *
+- * This is the main function for initializing MFI firmware.
+- */
+-static int megasas_init_mfi(struct megasas_instance *instance)
++static u32
++megasas_init_adapter_mfi(struct megasas_instance *instance)
+ {
++ struct megasas_register_set __iomem *reg_set;
+ u32 context_sz;
+ u32 reply_q_sz;
+- u32 max_sectors_1;
+- u32 max_sectors_2;
+- u32 tmp_sectors;
+- struct megasas_register_set __iomem *reg_set;
+- struct megasas_ctrl_info *ctrl_info;
+- unsigned long bar_list;
+-
+- /* Find first memory bar */
+- bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
+- instance->bar = find_first_bit(&bar_list, sizeof(unsigned long));
+- instance->base_addr = pci_resource_start(instance->pdev, instance->bar);
+- if (pci_request_selected_regions(instance->pdev, instance->bar,
+- "megasas: LSI")) {
+- printk(KERN_DEBUG "megasas: IO memory region busy!\n");
+- return -EBUSY;
+- }
+-
+- instance->reg_set = ioremap_nocache(instance->base_addr, 8192);
+-
+- if (!instance->reg_set) {
+- printk(KERN_DEBUG "megasas: Failed to map IO mem\n");
+- goto fail_ioremap;
+- }
+
+ reg_set = instance->reg_set;
+
+- switch(instance->pdev->device)
+- {
+- case PCI_DEVICE_ID_LSI_SAS1078R:
+- case PCI_DEVICE_ID_LSI_SAS1078DE:
+- instance->instancet = &megasas_instance_template_ppc;
+- break;
+- case PCI_DEVICE_ID_LSI_SAS1078GEN2:
+- case PCI_DEVICE_ID_LSI_SAS0079GEN2:
+- instance->instancet = &megasas_instance_template_gen2;
+- break;
+- case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
+- case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
+- instance->instancet = &megasas_instance_template_skinny;
+- break;
+- case PCI_DEVICE_ID_LSI_SAS1064R:
+- case PCI_DEVICE_ID_DELL_PERC5:
+- default:
+- instance->instancet = &megasas_instance_template_xscale;
+- break;
+- }
+-
+- /*
+- * We expect the FW state to be READY
+- */
+- if (megasas_transition_to_ready(instance))
+- goto fail_ready_state;
+-
+ /*
+ * Get various operational parameters from status register
+ */
+@@ -3177,6 +3171,87 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ if (instance->fw_support_ieee)
+ instance->flag_ieee = 1;
+
++ return 0;
++
++fail_fw_init:
++
++ pci_free_consistent(instance->pdev, reply_q_sz,
++ instance->reply_queue, instance->reply_queue_h);
++fail_reply_queue:
++ megasas_free_cmds(instance);
++
++fail_alloc_cmds:
++ iounmap(instance->reg_set);
++ return 1;
++}
++
++/**
++ * megasas_init_fw - Initializes the FW
++ * @instance: Adapter soft state
++ *
++ * This is the main function for initializing firmware
++ */
++
++static int megasas_init_fw(struct megasas_instance *instance)
++{
++ u32 max_sectors_1;
++ u32 max_sectors_2;
++ u32 tmp_sectors;
++ struct megasas_register_set __iomem *reg_set;
++ struct megasas_ctrl_info *ctrl_info;
++ unsigned long bar_list;
++
++ /* Find first memory bar */
++ bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
++ instance->bar = find_first_bit(&bar_list, sizeof(unsigned long));
++ instance->base_addr = pci_resource_start(instance->pdev, instance->bar);
++ if (pci_request_selected_regions(instance->pdev, instance->bar,
++ "megasas: LSI")) {
++ printk(KERN_DEBUG "megasas: IO memory region busy!\n");
++ return -EBUSY;
++ }
++
++ instance->reg_set = ioremap_nocache(instance->base_addr, 8192);
++
++ if (!instance->reg_set) {
++ printk(KERN_DEBUG "megasas: Failed to map IO mem\n");
++ goto fail_ioremap;
++ }
++
++ reg_set = instance->reg_set;
++
++ switch (instance->pdev->device) {
++ case PCI_DEVICE_ID_LSI_SAS1078R:
++ case PCI_DEVICE_ID_LSI_SAS1078DE:
++ instance->instancet = &megasas_instance_template_ppc;
++ break;
++ case PCI_DEVICE_ID_LSI_SAS1078GEN2:
++ case PCI_DEVICE_ID_LSI_SAS0079GEN2:
++ instance->instancet = &megasas_instance_template_gen2;
++ break;
++ case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
++ case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
++ instance->instancet = &megasas_instance_template_skinny;
++ break;
++ case PCI_DEVICE_ID_LSI_SAS1064R:
++ case PCI_DEVICE_ID_DELL_PERC5:
++ default:
++ instance->instancet = &megasas_instance_template_xscale;
++ break;
++ }
++
++ /*
++ * We expect the FW state to be READY
++ */
++ if (megasas_transition_to_ready(instance))
++ goto fail_ready_state;
++
++ /* Get operational params, sge flags, send init cmd to controller */
++ if (instance->instancet->init_adapter(instance))
++ return -ENODEV;
++
++ printk(KERN_ERR "megasas: INIT adapter done\n");
++
+ /** for passthrough
+ * the following function will get the PD LIST.
+ */
+@@ -3232,15 +3307,7 @@ static int megasas_init_mfi(struct megasas_instance *instance)
+ MEGASAS_COMPLETION_TIMER_INTERVAL);
+ return 0;
+
+- fail_fw_init:
+-
+- pci_free_consistent(instance->pdev, reply_q_sz,
+- instance->reply_queue, instance->reply_queue_h);
+- fail_reply_queue:
+- megasas_free_cmds(instance);
+-
+- fail_alloc_cmds:
+- fail_ready_state:
++fail_ready_state:
+ iounmap(instance->reg_set);
+
+ fail_ioremap:
+@@ -3672,7 +3739,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ /*
+ * Initialize MFI Firmware
+ */
+- if (megasas_init_mfi(instance))
++ if (megasas_init_fw(instance))
+ goto fail_init_mfi;
+
+ /* Try to enable MSI-X */
+@@ -3687,7 +3754,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ * Register IRQ
+ */
+ if (request_irq(instance->msi_flag ? instance->msixentry.vector :
+- pdev->irq, megasas_isr,
++ pdev->irq, instance->instancet->service_isr,
+ IRQF_SHARED, "megasas", instance)) {
+ printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
+ goto fail_irq;
+@@ -3737,7 +3804,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ instance->pdev->irq, instance);
+ if (instance->msi_flag)
+ pci_disable_msix(instance->pdev);
+- megasas_release_mfi(instance);
+
+ fail_irq:
+ fail_init_mfi:
+@@ -3747,9 +3813,11 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ instance->evt_detail,
+ instance->evt_detail_h);
+
+- if (instance->producer)
++ if (instance->producer) {
+ pci_free_consistent(pdev, sizeof(u32), instance->producer,
+ instance->producer_h);
++ megasas_release_mfi(instance);
++ }
+ if (instance->consumer)
+ pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+ instance->consumer_h);
+@@ -3949,7 +4017,7 @@ megasas_resume(struct pci_dev *pdev)
+ * Register IRQ
+ */
+ if (request_irq(instance->msi_flag ? instance->msixentry.vector :
+- pdev->irq, megasas_isr,
++ pdev->irq, instance->instancet->service_isr,
+ IRQF_SHARED, "megasas", instance)) {
+ printk(KERN_ERR "megasas: Failed to register IRQ\n");
+ goto fail_irq;
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0017-megaraid_sas-add-9565-9285-specific-code.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0017-megaraid_sas-add-9565-9285-specific-code.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,4352 @@
+From 8638045828d99252418c6dc7972a89fc5185242c Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Tue, 21 Dec 2010 13:34:31 -0800
+Subject: [PATCH 17/53] [SCSI] megaraid_sas: Add 9565/9285 specific code
+
+commit 9c915a8c99bce637226aa09cb05fc18486b229cb upstream.
+
+This patch adds MegaRAID 9265/9285 (Device id 0x5b) specific code
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/Makefile | 3 +-
+ drivers/scsi/megaraid/megaraid_sas.h | 32 +-
+ drivers/scsi/megaraid/megaraid_sas_base.c | 362 +++--
+ drivers/scsi/megaraid/megaraid_sas_fp.c | 516 ++++++
+ drivers/scsi/megaraid/megaraid_sas_fusion.c | 2248 +++++++++++++++++++++++++++
+ drivers/scsi/megaraid/megaraid_sas_fusion.h | 695 +++++++++
+ 6 files changed, 3748 insertions(+), 108 deletions(-)
+ create mode 100644 drivers/scsi/megaraid/megaraid_sas_fp.c
+ create mode 100644 drivers/scsi/megaraid/megaraid_sas_fusion.c
+ create mode 100644 drivers/scsi/megaraid/megaraid_sas_fusion.h
+
+diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile
+index 6613a2ceea03..5826ed509e3e 100644
+--- a/drivers/scsi/megaraid/Makefile
++++ b/drivers/scsi/megaraid/Makefile
+@@ -1,4 +1,5 @@
+ obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o
+ obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o
+ obj-$(CONFIG_MEGARAID_SAS) += megaraid_sas.o
+-megaraid_sas-objs := megaraid_sas_base.o
++megaraid_sas-objs := megaraid_sas_base.o megaraid_sas_fusion.o \
++ megaraid_sas_fp.o
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 0663f2efda12..887f33ebcf21 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -32,6 +32,7 @@
+ #define PCI_DEVICE_ID_LSI_SAS0079GEN2 0x0079
+ #define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073
+ #define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071
++#define PCI_DEVICE_ID_LSI_FUSION 0x005b
+
+ /*
+ * =====================================
+@@ -421,7 +422,6 @@ struct megasas_ctrl_prop {
+ * Add properties that can be controlled by
+ * a bit in the following structure.
+ */
+-
+ struct {
+ u32 copyBackDisabled : 1;
+ u32 SMARTerEnabled : 1;
+@@ -701,6 +701,7 @@ struct megasas_ctrl_info {
+ #define MEGASAS_DEFAULT_INIT_ID -1
+ #define MEGASAS_MAX_LUN 8
+ #define MEGASAS_MAX_LD 64
++#define MEGASAS_DEFAULT_CMD_PER_LUN 128
+ #define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \
+ MEGASAS_MAX_DEV_PER_CHANNEL)
+ #define MEGASAS_MAX_LD_IDS (MEGASAS_MAX_LD_CHANNELS * \
+@@ -768,7 +769,10 @@ struct megasas_ctrl_info {
+ */
+
+ struct megasas_register_set {
+- u32 reserved_0[4]; /*0000h*/
++ u32 doorbell; /*0000h*/
++ u32 fusion_seq_offset; /*0004h*/
++ u32 fusion_host_diag; /*0008h*/
++ u32 reserved_01; /*000Ch*/
+
+ u32 inbound_msg_0; /*0010h*/
+ u32 inbound_msg_1; /*0014h*/
+@@ -788,15 +792,18 @@ struct megasas_register_set {
+ u32 inbound_queue_port; /*0040h*/
+ u32 outbound_queue_port; /*0044h*/
+
+- u32 reserved_2[22]; /*0048h*/
++ u32 reserved_2[9]; /*0048h*/
++ u32 reply_post_host_index; /*006Ch*/
++ u32 reserved_2_2[12]; /*0070h*/
+
+ u32 outbound_doorbell_clear; /*00A0h*/
+
+ u32 reserved_3[3]; /*00A4h*/
+
+ u32 outbound_scratch_pad ; /*00B0h*/
++ u32 outbound_scratch_pad_2; /*00B4h*/
+
+- u32 reserved_4[3]; /*00B4h*/
++ u32 reserved_4[2]; /*00B8h*/
+
+ u32 inbound_low_queue_port ; /*00C0h*/
+
+@@ -1271,6 +1278,9 @@ struct megasas_instance {
+
+ u16 max_num_sge;
+ u16 max_fw_cmds;
++ /* For Fusion its num IOCTL cmds, for others MFI based its
++ max_fw_cmds */
++ u16 max_mfi_cmds;
+ u32 max_sectors_per_req;
+ struct megasas_aen_event *ev;
+
+@@ -1320,9 +1330,15 @@ struct megasas_instance {
+ struct timer_list io_completion_timer;
+ struct list_head internal_reset_pending_q;
+
++ /* Ptr to hba specfic information */
++ void *ctrl_context;
+ u8 msi_flag;
+ struct msix_entry msixentry;
++ u64 map_id;
++ struct megasas_cmd *map_update_cmd;
+ unsigned long bar;
++ long reset_flags;
++ struct mutex reset_mutex;
+ };
+
+ enum {
+@@ -1381,7 +1397,13 @@ struct megasas_cmd {
+ struct list_head list;
+ struct scsi_cmnd *scmd;
+ struct megasas_instance *instance;
+- u32 frame_count;
++ union {
++ struct {
++ u16 smid;
++ u16 resvd;
++ } context;
++ u32 frame_count;
++ };
+ };
+
+ #define MAX_MGMT_ADAPTERS 1024
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 7f2b199b82c2..d532b330e03f 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -46,6 +46,7 @@
+ #include <scsi/scsi_cmnd.h>
+ #include <scsi/scsi_device.h>
+ #include <scsi/scsi_host.h>
++#include "megaraid_sas_fusion.h"
+ #include "megaraid_sas.h"
+
+ /*
+@@ -65,7 +66,7 @@ MODULE_VERSION(MEGASAS_VERSION);
+ MODULE_AUTHOR("megaraidlinux at lsi.com");
+ MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
+
+-static int megasas_transition_to_ready(struct megasas_instance *instance);
++int megasas_transition_to_ready(struct megasas_instance *instance);
+ static int megasas_get_pd_list(struct megasas_instance *instance);
+ static int megasas_issue_init_mfi(struct megasas_instance *instance);
+ static int megasas_register_aen(struct megasas_instance *instance,
+@@ -93,6 +94,8 @@ static struct pci_device_id megasas_pci_table[] = {
+ /* xscale IOP, vega */
+ {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
+ /* xscale IOP */
++ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)},
++ /* Fusion */
+ {}
+ };
+
+@@ -106,14 +109,15 @@ static DEFINE_MUTEX(megasas_async_queue_mutex);
+ static int megasas_poll_wait_aen;
+ static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
+ static u32 support_poll_for_event;
+-static u32 megasas_dbg_lvl;
++u32 megasas_dbg_lvl;
+
+ /* define lock for aen poll */
+ spinlock_t poll_aen_lock;
+
+-static void
++void
+ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ u8 alt_status);
++
+ static irqreturn_t megasas_isr(int irq, void *devp);
+ static u32
+ megasas_init_adapter_mfi(struct megasas_instance *instance);
+@@ -121,6 +125,23 @@ u32
+ megasas_build_and_issue_cmd(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd);
+ static void megasas_complete_cmd_dpc(unsigned long instance_addr);
++void
++megasas_release_fusion(struct megasas_instance *instance);
++int
++megasas_ioc_init_fusion(struct megasas_instance *instance);
++void
++megasas_free_cmds_fusion(struct megasas_instance *instance);
++u8
++megasas_get_map_info(struct megasas_instance *instance);
++int
++megasas_sync_map_info(struct megasas_instance *instance);
++int
++wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd);
++void megasas_reset_reply_desc(struct megasas_instance *instance);
++u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
++ struct LD_LOAD_BALANCE_INFO *lbInfo);
++int megasas_reset_fusion(struct Scsi_Host *shost);
++void megasas_fusion_ocr_wq(struct work_struct *work);
+
+ void
+ megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
+@@ -135,7 +156,7 @@ megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
+ *
+ * Returns a free command from the pool
+ */
+-static struct megasas_cmd *megasas_get_cmd(struct megasas_instance
++struct megasas_cmd *megasas_get_cmd(struct megasas_instance
+ *instance)
+ {
+ unsigned long flags;
+@@ -160,7 +181,7 @@ static struct megasas_cmd *megasas_get_cmd(struct megasas_instance
+ * @instance: Adapter soft state
+ * @cmd: Command packet to be returned to free command pool
+ */
+-static inline void
++inline void
+ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
+ {
+ unsigned long flags;
+@@ -168,6 +189,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
+ spin_lock_irqsave(&instance->cmd_pool_lock, flags);
+
+ cmd->scmd = NULL;
++ cmd->frame_count = 0;
+ list_add_tail(&cmd->list, &instance->cmd_pool);
+
+ spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
+@@ -775,6 +797,11 @@ static struct megasas_instance_template megasas_instance_template_gen2 = {
+ * specific to gen2 (deviceid : 0x78, 0x79) controllers
+ */
+
++/*
++ * Template added for TB (Fusion)
++ */
++extern struct megasas_instance_template megasas_instance_template_fusion;
++
+ /**
+ * megasas_issue_polled - Issues a polling command
+ * @instance: Adapter soft state
+@@ -782,11 +809,9 @@ static struct megasas_instance_template megasas_instance_template_gen2 = {
+ *
+ * For polling, MFI requires the cmd_status to be set to 0xFF before posting.
+ */
+-static int
++int
+ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
+ {
+- int i;
+- u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
+
+ struct megasas_header *frame_hdr = &cmd->frame->hdr;
+
+@@ -796,21 +821,12 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
+ /*
+ * Issue the frame using inbound queue port
+ */
+- instance->instancet->fire_cmd(instance,
+- cmd->frame_phys_addr, 0, instance->reg_set);
++ instance->instancet->issue_dcmd(instance, cmd);
+
+ /*
+ * Wait for cmd_status to change
+ */
+- for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i++) {
+- rmb();
+- msleep(1);
+- }
+-
+- if (frame_hdr->cmd_status == 0xff)
+- return -ETIME;
+-
+- return 0;
++ return wait_and_poll(instance, cmd);
+ }
+
+ /**
+@@ -828,8 +844,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
+ {
+ cmd->cmd_status = ENODATA;
+
+- instance->instancet->fire_cmd(instance,
+- cmd->frame_phys_addr, 0, instance->reg_set);
++ instance->instancet->issue_dcmd(instance, cmd);
+
+ wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA);
+
+@@ -873,8 +888,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
+ cmd->sync_cmd = 1;
+ cmd->cmd_status = 0xFF;
+
+- instance->instancet->fire_cmd(instance,
+- cmd->frame_phys_addr, 0, instance->reg_set);
++ instance->instancet->issue_dcmd(instance, cmd);
+
+ /*
+ * Wait for this cmd to complete
+@@ -1257,7 +1271,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ * Called by megasas_queue_command to find out if the command to be queued
+ * is a logical drive command
+ */
+-static inline int megasas_is_ldio(struct scsi_cmnd *cmd)
++inline int megasas_is_ldio(struct scsi_cmnd *cmd)
+ {
+ if (!MEGASAS_IS_LOGICAL(cmd))
+ return 0;
+@@ -1463,15 +1477,44 @@ static int megasas_slave_configure(struct scsi_device *sdev)
+ return 0;
+ }
+
+-static void megaraid_sas_kill_hba(struct megasas_instance *instance)
++void megaraid_sas_kill_hba(struct megasas_instance *instance)
+ {
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+- writel(MFI_STOP_ADP,
+- &instance->reg_set->reserved_0[0]);
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)) {
++ writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
+ } else {
+- writel(MFI_STOP_ADP,
+- &instance->reg_set->inbound_doorbell);
++ writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell);
++ }
++}
++
++ /**
++ * megasas_check_and_restore_queue_depth - Check if queue depth needs to be
++ * restored to max value
++ * @instance: Adapter soft state
++ *
++ */
++void
++megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
++{
++ unsigned long flags;
++ if (instance->flag & MEGASAS_FW_BUSY
++ && time_after(jiffies, instance->last_time + 5 * HZ)
++ && atomic_read(&instance->fw_outstanding) < 17) {
++
++ spin_lock_irqsave(instance->host->host_lock, flags);
++ instance->flag &= ~MEGASAS_FW_BUSY;
++ if ((instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ instance->host->can_queue =
++ instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
++ } else
++ instance->host->can_queue =
++ instance->max_fw_cmds - MEGASAS_INT_CMDS;
++
++ spin_unlock_irqrestore(instance->host->host_lock, flags);
+ }
+ }
+
+@@ -1525,24 +1568,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+ /*
+ * Check if we can restore can_queue
+ */
+- if (instance->flag & MEGASAS_FW_BUSY
+- && time_after(jiffies, instance->last_time + 5 * HZ)
+- && atomic_read(&instance->fw_outstanding) < 17) {
+-
+- spin_lock_irqsave(instance->host->host_lock, flags);
+- instance->flag &= ~MEGASAS_FW_BUSY;
+- if ((instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+- instance->host->can_queue =
+- instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
+- } else
+- instance->host->can_queue =
+- instance->max_fw_cmds - MEGASAS_INT_CMDS;
+-
+- spin_unlock_irqrestore(instance->host->host_lock, flags);
+- }
++ megasas_check_and_restore_queue_depth(instance);
+ }
+
+ /**
+@@ -1658,7 +1684,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ writel(MFI_STOP_ADP,
+- &instance->reg_set->reserved_0[0]);
++ &instance->reg_set->doorbell);
+ } else {
+ writel(MFI_STOP_ADP,
+ &instance->reg_set->inbound_doorbell);
+@@ -1762,11 +1788,16 @@ static int megasas_reset_device(struct scsi_cmnd *scmd)
+ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
+ {
+ int ret;
++ struct megasas_instance *instance;
++ instance = (struct megasas_instance *)scmd->device->host->hostdata;
+
+ /*
+ * First wait for all commands to complete
+ */
+- ret = megasas_generic_reset(scmd);
++ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
++ ret = megasas_reset_fusion(scmd->device->host);
++ else
++ ret = megasas_generic_reset(scmd);
+
+ return ret;
+ }
+@@ -1935,13 +1966,14 @@ megasas_complete_abort(struct megasas_instance *instance,
+ * an alternate status (as in the case of aborted
+ * commands)
+ */
+-static void
++void
+ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ u8 alt_status)
+ {
+ int exception = 0;
+ struct megasas_header *hdr = &cmd->frame->hdr;
+ unsigned long flags;
++ struct fusion_context *fusion = instance->ctrl_context;
+
+ /* flag for the retry reset */
+ cmd->retry_for_fw_reset = 0;
+@@ -2034,6 +2066,37 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ case MFI_CMD_SMP:
+ case MFI_CMD_STP:
+ case MFI_CMD_DCMD:
++ /* Check for LD map update */
++ if ((cmd->frame->dcmd.opcode == MR_DCMD_LD_MAP_GET_INFO) &&
++ (cmd->frame->dcmd.mbox.b[1] == 1)) {
++ spin_lock_irqsave(instance->host->host_lock, flags);
++ if (cmd->frame->hdr.cmd_status != 0) {
++ if (cmd->frame->hdr.cmd_status !=
++ MFI_STAT_NOT_FOUND)
++ printk(KERN_WARNING "megasas: map sync"
++ "failed, status = 0x%x.\n",
++ cmd->frame->hdr.cmd_status);
++ else {
++ megasas_return_cmd(instance, cmd);
++ spin_unlock_irqrestore(
++ instance->host->host_lock,
++ flags);
++ break;
++ }
++ } else
++ instance->map_id++;
++ megasas_return_cmd(instance, cmd);
++ if (MR_ValidateMapInfo(
++ fusion->ld_map[(instance->map_id & 1)],
++ fusion->load_balance_info))
++ fusion->fast_path_io = 1;
++ else
++ fusion->fast_path_io = 0;
++ megasas_sync_map_info(instance);
++ spin_unlock_irqrestore(instance->host->host_lock,
++ flags);
++ break;
++ }
+ if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
+ cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
+ spin_lock_irqsave(&poll_aen_lock, flags);
+@@ -2372,7 +2435,7 @@ static irqreturn_t megasas_isr(int irq, void *devp)
+ * states, driver must take steps to bring it to ready state. Otherwise, it
+ * has to wait for the ready state.
+ */
+-static int
++int
+ megasas_transition_to_ready(struct megasas_instance* instance)
+ {
+ int i;
+@@ -2402,11 +2465,12 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+-
++ PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_FUSION)) {
+ writel(
+ MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+- &instance->reg_set->reserved_0[0]);
++ &instance->reg_set->doorbell);
+ } else {
+ writel(
+ MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+@@ -2419,11 +2483,13 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+
+ case MFI_STATE_BOOT_MESSAGE_PENDING:
+ if ((instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+- (instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_FUSION)) {
+ writel(MFI_INIT_HOTPLUG,
+- &instance->reg_set->reserved_0[0]);
++ &instance->reg_set->doorbell);
+ } else
+ writel(MFI_INIT_HOTPLUG,
+ &instance->reg_set->inbound_doorbell);
+@@ -2440,9 +2506,23 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
++ PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
++ (instance->pdev->device
++ == PCI_DEVICE_ID_LSI_FUSION)) {
+ writel(MFI_RESET_FLAGS,
+- &instance->reg_set->reserved_0[0]);
++ &instance->reg_set->doorbell);
++ if (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_FUSION) {
++ for (i = 0; i < (10 * 1000); i += 20) {
++ if (readl(
++ &instance->
++ reg_set->
++ doorbell) & 1)
++ msleep(20);
++ else
++ break;
++ }
++ }
+ } else
+ writel(MFI_RESET_FLAGS,
+ &instance->reg_set->inbound_doorbell);
+@@ -2524,7 +2604,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ static void megasas_teardown_frame_pool(struct megasas_instance *instance)
+ {
+ int i;
+- u32 max_cmd = instance->max_fw_cmds;
++ u32 max_cmd = instance->max_mfi_cmds;
+ struct megasas_cmd *cmd;
+
+ if (!instance->frame_dma_pool)
+@@ -2575,7 +2655,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
+ u32 frame_count;
+ struct megasas_cmd *cmd;
+
+- max_cmd = instance->max_fw_cmds;
++ max_cmd = instance->max_mfi_cmds;
+
+ /*
+ * Size of our frame is 64 bytes for MFI frame, followed by max SG
+@@ -2661,14 +2741,15 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
+ * megasas_free_cmds - Free all the cmds in the free cmd pool
+ * @instance: Adapter soft state
+ */
+-static void megasas_free_cmds(struct megasas_instance *instance)
++void megasas_free_cmds(struct megasas_instance *instance)
+ {
+ int i;
+ /* First free the MFI frame pool */
+ megasas_teardown_frame_pool(instance);
+
+ /* Free all the commands in the cmd_list */
+- for (i = 0; i < instance->max_fw_cmds; i++)
++ for (i = 0; i < instance->max_mfi_cmds; i++)
++
+ kfree(instance->cmd_list[i]);
+
+ /* Free the cmd_list buffer itself */
+@@ -2696,14 +2777,14 @@ static void megasas_free_cmds(struct megasas_instance *instance)
+ * This array is used only to look up the megasas_cmd given the context. The
+ * free commands themselves are maintained in a linked list called cmd_pool.
+ */
+-static int megasas_alloc_cmds(struct megasas_instance *instance)
++int megasas_alloc_cmds(struct megasas_instance *instance)
+ {
+ int i;
+ int j;
+ u32 max_cmd;
+ struct megasas_cmd *cmd;
+
+- max_cmd = instance->max_fw_cmds;
++ max_cmd = instance->max_mfi_cmds;
+
+ /*
+ * instance->cmd_list is an array of struct megasas_cmd pointers.
+@@ -2717,6 +2798,7 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
+ return -ENOMEM;
+ }
+
++ memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) *max_cmd);
+
+ for (i = 0; i < max_cmd; i++) {
+ instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
+@@ -3128,6 +3210,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance)
+ * does not exceed max cmds that the FW can support
+ */
+ instance->max_fw_cmds = instance->max_fw_cmds-1;
++ instance->max_mfi_cmds = instance->max_fw_cmds;
+ instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
+ 0x10;
+ /*
+@@ -3221,6 +3304,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
+ reg_set = instance->reg_set;
+
+ switch (instance->pdev->device) {
++ case PCI_DEVICE_ID_LSI_FUSION:
++ instance->instancet = &megasas_instance_template_fusion;
++ break;
+ case PCI_DEVICE_ID_LSI_SAS1078R:
+ case PCI_DEVICE_ID_LSI_SAS1078DE:
+ instance->instancet = &megasas_instance_template_ppc;
+@@ -3322,9 +3408,10 @@ fail_ready_state:
+ */
+ static void megasas_release_mfi(struct megasas_instance *instance)
+ {
+- u32 reply_q_sz = sizeof(u32) * (instance->max_fw_cmds + 1);
++ u32 reply_q_sz = sizeof(u32) *(instance->max_mfi_cmds + 1);
+
+- pci_free_consistent(instance->pdev, reply_q_sz,
++ if (instance->reply_queue)
++ pci_free_consistent(instance->pdev, reply_q_sz,
+ instance->reply_queue, instance->reply_queue_h);
+
+ megasas_free_cmds(instance);
+@@ -3516,8 +3603,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
+ /*
+ * Issue the aen registration frame
+ */
+- instance->instancet->fire_cmd(instance,
+- cmd->frame_phys_addr, 0, instance->reg_set);
++ instance->instancet->issue_dcmd(instance, cmd);
+
+ return 0;
+ }
+@@ -3573,12 +3659,18 @@ static int megasas_io_attach(struct megasas_instance *instance)
+ host->this_id = instance->init_id;
+ host->sg_tablesize = instance->max_num_sge;
+ host->max_sectors = instance->max_sectors_per_req;
+- host->cmd_per_lun = 128;
++ host->cmd_per_lun = MEGASAS_DEFAULT_CMD_PER_LUN;
+ host->max_channel = MEGASAS_MAX_CHANNELS - 1;
+ host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL;
+ host->max_lun = MEGASAS_MAX_LUN;
+ host->max_cmd_len = 16;
+
++ /* Fusion only supports host reset */
++ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) {
++ host->hostt->eh_device_reset_handler = NULL;
++ host->hostt->eh_bus_reset_handler = NULL;
++ }
++
+ /*
+ * Notify the mid-layer about the new controller
+ */
+@@ -3663,20 +3755,45 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ instance = (struct megasas_instance *)host->hostdata;
+ memset(instance, 0, sizeof(*instance));
+ atomic_set( &instance->fw_reset_no_pci_access, 0 );
++ instance->pdev = pdev;
+
+- instance->producer = pci_alloc_consistent(pdev, sizeof(u32),
+- &instance->producer_h);
+- instance->consumer = pci_alloc_consistent(pdev, sizeof(u32),
+- &instance->consumer_h);
++ switch (instance->pdev->device) {
++ case PCI_DEVICE_ID_LSI_FUSION:
++ {
++ struct fusion_context *fusion;
+
+- if (!instance->producer || !instance->consumer) {
+- printk(KERN_DEBUG "megasas: Failed to allocate memory for "
+- "producer, consumer\n");
+- goto fail_alloc_dma_buf;
++ instance->ctrl_context =
++ kzalloc(sizeof(struct fusion_context), GFP_KERNEL);
++ if (!instance->ctrl_context) {
++ printk(KERN_DEBUG "megasas: Failed to allocate "
++ "memory for Fusion context info\n");
++ goto fail_alloc_dma_buf;
++ }
++ fusion = instance->ctrl_context;
++ INIT_LIST_HEAD(&fusion->cmd_pool);
++ spin_lock_init(&fusion->cmd_pool_lock);
++ }
++ break;
++ default: /* For all other supported controllers */
++
++ instance->producer =
++ pci_alloc_consistent(pdev, sizeof(u32),
++ &instance->producer_h);
++ instance->consumer =
++ pci_alloc_consistent(pdev, sizeof(u32),
++ &instance->consumer_h);
++
++ if (!instance->producer || !instance->consumer) {
++ printk(KERN_DEBUG "megasas: Failed to allocate"
++ "memory for producer, consumer\n");
++ goto fail_alloc_dma_buf;
++ }
++
++ *instance->producer = 0;
++ *instance->consumer = 0;
++ break;
+ }
+
+- *instance->producer = 0;
+- *instance->consumer = 0;
+ megasas_poll_wait_aen = 0;
+ instance->flag_ieee = 0;
+ instance->ev = NULL;
+@@ -3712,11 +3829,11 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ spin_lock_init(&poll_aen_lock);
+
+ mutex_init(&instance->aen_mutex);
++ mutex_init(&instance->reset_mutex);
+
+ /*
+ * Initialize PCI related and misc parameters
+ */
+- instance->pdev = pdev;
+ instance->host = host;
+ instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
+ instance->init_id = MEGASAS_DEFAULT_INIT_ID;
+@@ -3734,7 +3851,10 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ instance->last_time = 0;
+ instance->disableOnlineCtrlReset = 1;
+
+- INIT_WORK(&instance->work_init, process_fw_state_change_wq);
++ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
++ INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
++ else
++ INIT_WORK(&instance->work_init, process_fw_state_change_wq);
+
+ /*
+ * Initialize MFI Firmware
+@@ -3817,6 +3937,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ pci_free_consistent(pdev, sizeof(u32), instance->producer,
+ instance->producer_h);
+ megasas_release_mfi(instance);
++ } else {
++ megasas_release_fusion(instance);
+ }
+ if (instance->consumer)
+ pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+@@ -3888,7 +4010,9 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
+
+ if (instance->aen_cmd)
+ megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd);
+-
++ if (instance->map_update_cmd)
++ megasas_issue_blocked_abort_cmd(instance,
++ instance->map_update_cmd);
+ dcmd = &cmd->frame->dcmd;
+
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+@@ -3992,9 +4116,6 @@ megasas_resume(struct pci_dev *pdev)
+ * Initialize MFI Firmware
+ */
+
+- *instance->producer = 0;
+- *instance->consumer = 0;
+-
+ atomic_set(&instance->fw_outstanding, 0);
+
+ /*
+@@ -4003,11 +4124,29 @@ megasas_resume(struct pci_dev *pdev)
+ if (megasas_transition_to_ready(instance))
+ goto fail_ready_state;
+
+- if (megasas_issue_init_mfi(instance))
+- goto fail_init_mfi;
++ switch (instance->pdev->device) {
++ case PCI_DEVICE_ID_LSI_FUSION:
++ {
++ megasas_reset_reply_desc(instance);
++ if (megasas_ioc_init_fusion(instance)) {
++ megasas_free_cmds(instance);
++ megasas_free_cmds_fusion(instance);
++ goto fail_init_mfi;
++ }
++ if (!megasas_get_map_info(instance))
++ megasas_sync_map_info(instance);
++ }
++ break;
++ default:
++ *instance->producer = 0;
++ *instance->consumer = 0;
++ if (megasas_issue_init_mfi(instance))
++ goto fail_init_mfi;
++ break;
++ }
+
+- tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+- (unsigned long)instance);
++ tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
++ (unsigned long)instance);
+
+ /* Now re-enable MSI-X */
+ if (instance->msi_flag)
+@@ -4076,10 +4215,12 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
+ int i;
+ struct Scsi_Host *host;
+ struct megasas_instance *instance;
++ struct fusion_context *fusion;
+
+ instance = pci_get_drvdata(pdev);
+ instance->unload = 1;
+ host = instance->host;
++ fusion = instance->ctrl_context;
+
+ if (poll_mode_io)
+ del_timer_sync(&instance->io_completion_timer);
+@@ -4121,16 +4262,32 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
+ if (instance->msi_flag)
+ pci_disable_msix(instance->pdev);
+
+- megasas_release_mfi(instance);
+-
+- pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
+- instance->evt_detail, instance->evt_detail_h);
+-
+- pci_free_consistent(pdev, sizeof(u32), instance->producer,
+- instance->producer_h);
+-
+- pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+- instance->consumer_h);
++ switch (instance->pdev->device) {
++ case PCI_DEVICE_ID_LSI_FUSION:
++ megasas_release_fusion(instance);
++ for (i = 0; i < 2 ; i++)
++ if (fusion->ld_map[i])
++ dma_free_coherent(&instance->pdev->dev,
++ fusion->map_sz,
++ fusion->ld_map[i],
++ fusion->
++ ld_map_phys[i]);
++ kfree(instance->ctrl_context);
++ break;
++ default:
++ megasas_release_mfi(instance);
++ pci_free_consistent(pdev,
++ sizeof(struct megasas_evt_detail),
++ instance->evt_detail,
++ instance->evt_detail_h);
++ pci_free_consistent(pdev, sizeof(u32),
++ instance->producer,
++ instance->producer_h);
++ pci_free_consistent(pdev, sizeof(u32),
++ instance->consumer,
++ instance->consumer_h);
++ break;
++ }
+
+ scsi_host_put(host);
+
+@@ -4902,6 +5059,7 @@ megasas_aen_polling(struct work_struct *work)
+ break;
+ case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
+ case MR_EVT_FOREIGN_CFG_IMPORTED:
++ case MR_EVT_LD_STATE_CHANGE:
+ doscan = 1;
+ break;
+ default:
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
+new file mode 100644
+index 000000000000..53fa96ae2b3e
+--- /dev/null
++++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
+@@ -0,0 +1,516 @@
++/*
++ * Linux MegaRAID driver for SAS based RAID controllers
++ *
++ * Copyright (c) 2009-2011 LSI Corporation.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * FILE: megaraid_sas_fp.c
++ *
++ * Authors: LSI Corporation
++ * Sumant Patro
++ * Varad Talamacki
++ * Manoj Jose
++ *
++ * Send feedback to: <megaraidlinux at lsi.com>
++ *
++ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
++ * ATTN: Linuxraid
++ */
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/list.h>
++#include <linux/moduleparam.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/smp_lock.h>
++#include <linux/uio.h>
++#include <linux/uaccess.h>
++#include <linux/fs.h>
++#include <linux/compat.h>
++#include <linux/blkdev.h>
++#include <linux/poll.h>
++
++#include <scsi/scsi.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_host.h>
++
++#include "megaraid_sas_fusion.h"
++#include <asm/div64.h>
++
++#define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
++#define MR_LD_STATE_OPTIMAL 3
++#define FALSE 0
++#define TRUE 1
++
++/* Prototypes */
++void
++mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map,
++ struct LD_LOAD_BALANCE_INFO *lbInfo);
++
++u32 mega_mod64(u64 dividend, u32 divisor)
++{
++ u64 d;
++ u32 remainder;
++
++ if (!divisor)
++ printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n");
++ d = dividend;
++ remainder = do_div(d, divisor);
++ return remainder;
++}
++
++/**
++ * @param dividend : Dividend
++ * @param divisor : Divisor
++ *
++ * @return quotient
++ **/
++u64 mega_div64_32(uint64_t dividend, uint32_t divisor)
++{
++ u32 remainder;
++ u64 d;
++
++ if (!divisor)
++ printk(KERN_ERR "megasas : DIVISOR is zero in mod fn\n");
++
++ d = dividend;
++ remainder = do_div(d, divisor);
++
++ return d;
++}
++
++struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
++{
++ return &map->raidMap.ldSpanMap[ld].ldRaid;
++}
++
++static struct MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u32 ld,
++ struct MR_FW_RAID_MAP_ALL
++ *map)
++{
++ return &map->raidMap.ldSpanMap[ld].spanBlock[0];
++}
++
++static u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_FW_RAID_MAP_ALL *map)
++{
++ return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
++}
++
++static u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map)
++{
++ return map->raidMap.arMapInfo[ar].pd[arm];
++}
++
++static u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map)
++{
++ return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef;
++}
++
++static u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map)
++{
++ return map->raidMap.devHndlInfo[pd].curDevHdl;
++}
++
++u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
++{
++ return map->raidMap.ldSpanMap[ld].ldRaid.targetId;
++}
++
++u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map)
++{
++ return map->raidMap.ldTgtIdToLd[ldTgtId];
++}
++
++static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span,
++ struct MR_FW_RAID_MAP_ALL *map)
++{
++ return &map->raidMap.ldSpanMap[ld].spanBlock[span].span;
++}
++
++/*
++ * This function will validate Map info data provided by FW
++ */
++u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
++ struct LD_LOAD_BALANCE_INFO *lbInfo)
++{
++ struct MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap;
++
++ if (pFwRaidMap->totalSize !=
++ (sizeof(struct MR_FW_RAID_MAP) -sizeof(struct MR_LD_SPAN_MAP) +
++ (sizeof(struct MR_LD_SPAN_MAP) *pFwRaidMap->ldCount))) {
++ printk(KERN_ERR "megasas: map info structure size 0x%x is not matching with ld count\n",
++ (unsigned int)((sizeof(struct MR_FW_RAID_MAP) -
++ sizeof(struct MR_LD_SPAN_MAP)) +
++ (sizeof(struct MR_LD_SPAN_MAP) *
++ pFwRaidMap->ldCount)));
++ printk(KERN_ERR "megasas: span map %x, pFwRaidMap->totalSize "
++ ": %x\n", (unsigned int)sizeof(struct MR_LD_SPAN_MAP),
++ pFwRaidMap->totalSize);
++ return 0;
++ }
++
++ mr_update_load_balance_params(map, lbInfo);
++
++ return 1;
++}
++
++u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk,
++ struct MR_FW_RAID_MAP_ALL *map, int *div_error)
++{
++ struct MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map);
++ struct MR_QUAD_ELEMENT *quad;
++ struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
++ u32 span, j;
++
++ for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) {
++
++ for (j = 0; j < pSpanBlock->block_span_info.noElements; j++) {
++ quad = &pSpanBlock->block_span_info.quad[j];
++
++ if (quad->diff == 0) {
++ *div_error = 1;
++ return span;
++ }
++ if (quad->logStart <= row && row <= quad->logEnd &&
++ (mega_mod64(row-quad->logStart, quad->diff)) == 0) {
++ if (span_blk != NULL) {
++ u64 blk, debugBlk;
++ blk =
++ mega_div64_32(
++ (row-quad->logStart),
++ quad->diff);
++ debugBlk = blk;
++
++ blk = (blk + quad->offsetInSpan) <<
++ raid->stripeShift;
++ *span_blk = blk;
++ }
++ return span;
++ }
++ }
++ }
++ return span;
++}
++
++/*
++******************************************************************************
++*
++* This routine calculates the arm, span and block for the specified stripe and
++* reference in stripe.
++*
++* Inputs :
++*
++* ld - Logical drive number
++* stripRow - Stripe number
++* stripRef - Reference in stripe
++*
++* Outputs :
++*
++* span - Span number
++* block - Absolute Block number in the physical disk
++*/
++u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock,
++ u16 *pDevHandle, struct RAID_CONTEXT *pRAID_Context,
++ struct MR_FW_RAID_MAP_ALL *map)
++{
++ struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
++ u32 pd, arRef;
++ u8 physArm, span;
++ u64 row;
++ u8 retval = TRUE;
++ int error_code = 0;
++
++ row = mega_div64_32(stripRow, raid->rowDataSize);
++
++ if (raid->level == 6) {
++ /* logical arm within row */
++ u32 logArm = mega_mod64(stripRow, raid->rowDataSize);
++ u32 rowMod, armQ, arm;
++
++ if (raid->rowSize == 0)
++ return FALSE;
++ /* get logical row mod */
++ rowMod = mega_mod64(row, raid->rowSize);
++ armQ = raid->rowSize-1-rowMod; /* index of Q drive */
++ arm = armQ+1+logArm; /* data always logically follows Q */
++ if (arm >= raid->rowSize) /* handle wrap condition */
++ arm -= raid->rowSize;
++ physArm = (u8)arm;
++ } else {
++ if (raid->modFactor == 0)
++ return FALSE;
++ physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow,
++ raid->modFactor),
++ map);
++ }
++
++ if (raid->spanDepth == 1) {
++ span = 0;
++ *pdBlock = row << raid->stripeShift;
++ } else {
++ span = (u8)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code);
++ if (error_code == 1)
++ return FALSE;
++ }
++
++ /* Get the array on which this span is present */
++ arRef = MR_LdSpanArrayGet(ld, span, map);
++ pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */
++
++ if (pd != MR_PD_INVALID)
++ /* Get dev handle from Pd. */
++ *pDevHandle = MR_PdDevHandleGet(pd, map);
++ else {
++ *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */
++ if (raid->level >= 5)
++ pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
++ else if (raid->level == 1) {
++ /* Get alternate Pd. */
++ pd = MR_ArPdGet(arRef, physArm + 1, map);
++ if (pd != MR_PD_INVALID)
++ /* Get dev handle from Pd */
++ *pDevHandle = MR_PdDevHandleGet(pd, map);
++ }
++ retval = FALSE;
++ }
++
++ *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
++ pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) |
++ physArm;
++ return retval;
++}
++
++/*
++******************************************************************************
++*
++* MR_BuildRaidContext function
++*
++* This function will initiate command processing. The start/end row and strip
++* information is calculated then the lock is acquired.
++* This function will return 0 if region lock was acquired OR return num strips
++*/
++u8
++MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
++ struct RAID_CONTEXT *pRAID_Context,
++ struct MR_FW_RAID_MAP_ALL *map)
++{
++ struct MR_LD_RAID *raid;
++ u32 ld, stripSize, stripe_mask;
++ u64 endLba, endStrip, endRow, start_row, start_strip;
++ u64 regStart;
++ u32 regSize;
++ u8 num_strips, numRows;
++ u16 ref_in_start_stripe, ref_in_end_stripe;
++ u64 ldStartBlock;
++ u32 numBlocks, ldTgtId;
++ u8 isRead;
++ u8 retval = 0;
++
++ ldStartBlock = io_info->ldStartBlock;
++ numBlocks = io_info->numBlocks;
++ ldTgtId = io_info->ldTgtId;
++ isRead = io_info->isRead;
++
++ ld = MR_TargetIdToLdGet(ldTgtId, map);
++ raid = MR_LdRaidGet(ld, map);
++
++ stripSize = 1 << raid->stripeShift;
++ stripe_mask = stripSize-1;
++ /*
++ * calculate starting row and stripe, and number of strips and rows
++ */
++ start_strip = ldStartBlock >> raid->stripeShift;
++ ref_in_start_stripe = (u16)(ldStartBlock & stripe_mask);
++ endLba = ldStartBlock + numBlocks - 1;
++ ref_in_end_stripe = (u16)(endLba & stripe_mask);
++ endStrip = endLba >> raid->stripeShift;
++ num_strips = (u8)(endStrip - start_strip + 1); /* End strip */
++ if (raid->rowDataSize == 0)
++ return FALSE;
++ start_row = mega_div64_32(start_strip, raid->rowDataSize);
++ endRow = mega_div64_32(endStrip, raid->rowDataSize);
++ numRows = (u8)(endRow - start_row + 1);
++
++ /*
++ * calculate region info.
++ */
++
++ /* assume region is at the start of the first row */
++ regStart = start_row << raid->stripeShift;
++ /* assume this IO needs the full row - we'll adjust if not true */
++ regSize = stripSize;
++
++ /* If IO spans more than 1 strip, fp is not possible
++ FP is not possible for writes on non-0 raid levels
++ FP is not possible if LD is not capable */
++ if (num_strips > 1 || (!isRead && raid->level != 0) ||
++ !raid->capability.fpCapable) {
++ io_info->fpOkForIo = FALSE;
++ } else {
++ io_info->fpOkForIo = TRUE;
++ }
++
++ if (numRows == 1) {
++ /* single-strip IOs can always lock only the data needed */
++ if (num_strips == 1) {
++ regStart += ref_in_start_stripe;
++ regSize = numBlocks;
++ }
++ /* multi-strip IOs always need to full stripe locked */
++ } else {
++ if (start_strip == (start_row + 1) * raid->rowDataSize - 1) {
++ /* If the start strip is the last in the start row */
++ regStart += ref_in_start_stripe;
++ regSize = stripSize - ref_in_start_stripe;
++ /* initialize count to sectors from startref to end
++ of strip */
++ }
++
++ if (numRows > 2)
++ /* Add complete rows in the middle of the transfer */
++ regSize += (numRows-2) << raid->stripeShift;
++
++ /* if IO ends within first strip of last row */
++ if (endStrip == endRow*raid->rowDataSize)
++ regSize += ref_in_end_stripe+1;
++ else
++ regSize += stripSize;
++ }
++
++ pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec;
++ pRAID_Context->regLockFlags = (isRead) ? REGION_TYPE_SHARED_READ :
++ raid->regTypeReqOnWrite;
++ pRAID_Context->VirtualDiskTgtId = raid->targetId;
++ pRAID_Context->regLockRowLBA = regStart;
++ pRAID_Context->regLockLength = regSize;
++ pRAID_Context->configSeqNum = raid->seqNum;
++
++ /*Get Phy Params only if FP capable, or else leave it to MR firmware
++ to do the calculation.*/
++ if (io_info->fpOkForIo) {
++ retval = MR_GetPhyParams(ld, start_strip, ref_in_start_stripe,
++ &io_info->pdBlock,
++ &io_info->devHandle, pRAID_Context,
++ map);
++ /* If IO on an invalid Pd, then FP i snot possible */
++ if (io_info->devHandle == MR_PD_INVALID)
++ io_info->fpOkForIo = FALSE;
++ return retval;
++ } else if (isRead) {
++ uint stripIdx;
++ for (stripIdx = 0; stripIdx < num_strips; stripIdx++) {
++ if (!MR_GetPhyParams(ld, start_strip + stripIdx,
++ ref_in_start_stripe,
++ &io_info->pdBlock,
++ &io_info->devHandle,
++ pRAID_Context, map))
++ return TRUE;
++ }
++ }
++ return TRUE;
++}
++
++void
++mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map,
++ struct LD_LOAD_BALANCE_INFO *lbInfo)
++{
++ int ldCount;
++ u16 ld;
++ struct MR_LD_RAID *raid;
++
++ for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
++ ld = MR_TargetIdToLdGet(ldCount, map);
++ if (ld >= MAX_LOGICAL_DRIVES) {
++ lbInfo[ldCount].loadBalanceFlag = 0;
++ continue;
++ }
++
++ raid = MR_LdRaidGet(ld, map);
++
++ /* Two drive Optimal RAID 1 */
++ if ((raid->level == 1) && (raid->rowSize == 2) &&
++ (raid->spanDepth == 1) && raid->ldState ==
++ MR_LD_STATE_OPTIMAL) {
++ u32 pd, arRef;
++
++ lbInfo[ldCount].loadBalanceFlag = 1;
++
++ /* Get the array on which this span is present */
++ arRef = MR_LdSpanArrayGet(ld, 0, map);
++
++ /* Get the Pd */
++ pd = MR_ArPdGet(arRef, 0, map);
++ /* Get dev handle from Pd */
++ lbInfo[ldCount].raid1DevHandle[0] =
++ MR_PdDevHandleGet(pd, map);
++ /* Get the Pd */
++ pd = MR_ArPdGet(arRef, 1, map);
++
++ /* Get the dev handle from Pd */
++ lbInfo[ldCount].raid1DevHandle[1] =
++ MR_PdDevHandleGet(pd, map);
++ } else
++ lbInfo[ldCount].loadBalanceFlag = 0;
++ }
++}
++
++u8 megasas_get_best_arm(struct LD_LOAD_BALANCE_INFO *lbInfo, u8 arm, u64 block,
++ u32 count)
++{
++ u16 pend0, pend1;
++ u64 diff0, diff1;
++ u8 bestArm;
++
++ /* get the pending cmds for the data and mirror arms */
++ pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]);
++ pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]);
++
++ /* Determine the disk whose head is nearer to the req. block */
++ diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]);
++ diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]);
++ bestArm = (diff0 <= diff1 ? 0 : 1);
++
++ if ((bestArm == arm && pend0 > pend1 + 16) ||
++ (bestArm != arm && pend1 > pend0 + 16))
++ bestArm ^= 1;
++
++ /* Update the last accessed block on the correct pd */
++ lbInfo->last_accessed_block[bestArm] = block + count - 1;
++
++ return bestArm;
++}
++
++u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo,
++ struct IO_REQUEST_INFO *io_info)
++{
++ u8 arm, old_arm;
++ u16 devHandle;
++
++ old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1;
++
++ /* get best new arm */
++ arm = megasas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock,
++ io_info->numBlocks);
++ devHandle = lbInfo->raid1DevHandle[arm];
++ atomic_inc(&lbInfo->scsi_pending_cmds[arm]);
++
++ return devHandle;
++}
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+new file mode 100644
+index 000000000000..c1e09d5a6196
+--- /dev/null
++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+@@ -0,0 +1,2248 @@
++/*
++ * Linux MegaRAID driver for SAS based RAID controllers
++ *
++ * Copyright (c) 2009-2011 LSI Corporation.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * FILE: megaraid_sas_fusion.c
++ *
++ * Authors: LSI Corporation
++ * Sumant Patro
++ * Adam Radford <linuxraid at lsi.com>
++ *
++ * Send feedback to: <megaraidlinux at lsi.com>
++ *
++ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
++ * ATTN: Linuxraid
++ */
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/list.h>
++#include <linux/moduleparam.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/smp_lock.h>
++#include <linux/uio.h>
++#include <linux/uaccess.h>
++#include <linux/fs.h>
++#include <linux/compat.h>
++#include <linux/blkdev.h>
++#include <linux/mutex.h>
++#include <linux/poll.h>
++
++#include <scsi/scsi.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_host.h>
++
++#include "megaraid_sas_fusion.h"
++#include "megaraid_sas.h"
++
++extern void megasas_free_cmds(struct megasas_instance *instance);
++extern struct megasas_cmd *megasas_get_cmd(struct megasas_instance
++ *instance);
++extern void
++megasas_complete_cmd(struct megasas_instance *instance,
++ struct megasas_cmd *cmd, u8 alt_status);
++int megasas_is_ldio(struct scsi_cmnd *cmd);
++int
++wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd);
++
++void
++megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd);
++int megasas_alloc_cmds(struct megasas_instance *instance);
++int
++megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs);
++int
++megasas_issue_polled(struct megasas_instance *instance,
++ struct megasas_cmd *cmd);
++
++u8
++MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
++ struct RAID_CONTEXT *pRAID_Context,
++ struct MR_FW_RAID_MAP_ALL *map);
++u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
++struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
++
++u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
++u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
++ struct LD_LOAD_BALANCE_INFO *lbInfo);
++u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo,
++ struct IO_REQUEST_INFO *in_info);
++int megasas_transition_to_ready(struct megasas_instance *instance);
++void megaraid_sas_kill_hba(struct megasas_instance *instance);
++
++extern u32 megasas_dbg_lvl;
++
++/**
++ * megasas_enable_intr_fusion - Enables interrupts
++ * @regs: MFI register set
++ */
++void
++megasas_enable_intr_fusion(struct megasas_register_set __iomem *regs)
++{
++ writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
++
++ /* Dummy readl to force pci flush */
++ readl(®s->outbound_intr_mask);
++}
++
++/**
++ * megasas_disable_intr_fusion - Disables interrupt
++ * @regs: MFI register set
++ */
++void
++megasas_disable_intr_fusion(struct megasas_register_set __iomem *regs)
++{
++ u32 mask = 0xFFFFFFFF;
++ u32 status;
++
++ writel(mask, ®s->outbound_intr_mask);
++ /* Dummy readl to force pci flush */
++ status = readl(®s->outbound_intr_mask);
++}
++
++int
++megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs)
++{
++ u32 status;
++ /*
++ * Check if it is our interrupt
++ */
++ status = readl(®s->outbound_intr_status);
++
++ if (status & 1) {
++ writel(status, ®s->outbound_intr_status);
++ readl(®s->outbound_intr_status);
++ return 1;
++ }
++ if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
++ return 0;
++
++ /*
++ * dummy read to flush PCI
++ */
++ readl(®s->outbound_intr_status);
++
++ return 1;
++}
++
++/**
++ * megasas_get_cmd_fusion - Get a command from the free pool
++ * @instance: Adapter soft state
++ *
++ * Returns a free command from the pool
++ */
++struct megasas_cmd_fusion *megasas_get_cmd_fusion(struct megasas_instance
++ *instance)
++{
++ unsigned long flags;
++ struct fusion_context *fusion =
++ (struct fusion_context *)instance->ctrl_context;
++ struct megasas_cmd_fusion *cmd = NULL;
++
++ spin_lock_irqsave(&fusion->cmd_pool_lock, flags);
++
++ if (!list_empty(&fusion->cmd_pool)) {
++ cmd = list_entry((&fusion->cmd_pool)->next,
++ struct megasas_cmd_fusion, list);
++ list_del_init(&cmd->list);
++ } else {
++ printk(KERN_ERR "megasas: Command pool (fusion) empty!\n");
++ }
++
++ spin_unlock_irqrestore(&fusion->cmd_pool_lock, flags);
++ return cmd;
++}
++
++/**
++ * megasas_return_cmd_fusion - Return a cmd to free command pool
++ * @instance: Adapter soft state
++ * @cmd: Command packet to be returned to free command pool
++ */
++static inline void
++megasas_return_cmd_fusion(struct megasas_instance *instance,
++ struct megasas_cmd_fusion *cmd)
++{
++ unsigned long flags;
++ struct fusion_context *fusion =
++ (struct fusion_context *)instance->ctrl_context;
++
++ spin_lock_irqsave(&fusion->cmd_pool_lock, flags);
++
++ cmd->scmd = NULL;
++ cmd->sync_cmd_idx = (u32)ULONG_MAX;
++ list_add_tail(&cmd->list, &fusion->cmd_pool);
++
++ spin_unlock_irqrestore(&fusion->cmd_pool_lock, flags);
++}
++
++/**
++ * megasas_teardown_frame_pool_fusion - Destroy the cmd frame DMA pool
++ * @instance: Adapter soft state
++ */
++static void megasas_teardown_frame_pool_fusion(
++ struct megasas_instance *instance)
++{
++ int i;
++ struct fusion_context *fusion = instance->ctrl_context;
++
++ u16 max_cmd = instance->max_fw_cmds;
++
++ struct megasas_cmd_fusion *cmd;
++
++ if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
++ printk(KERN_ERR "megasas: dma pool is null. SG Pool %p, "
++ "sense pool : %p\n", fusion->sg_dma_pool,
++ fusion->sense_dma_pool);
++ return;
++ }
++
++ /*
++ * Return all frames to pool
++ */
++ for (i = 0; i < max_cmd; i++) {
++
++ cmd = fusion->cmd_list[i];
++
++ if (cmd->sg_frame)
++ pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
++ cmd->sg_frame_phys_addr);
++
++ if (cmd->sense)
++ pci_pool_free(fusion->sense_dma_pool, cmd->sense,
++ cmd->sense_phys_addr);
++ }
++
++ /*
++ * Now destroy the pool itself
++ */
++ pci_pool_destroy(fusion->sg_dma_pool);
++ pci_pool_destroy(fusion->sense_dma_pool);
++
++ fusion->sg_dma_pool = NULL;
++ fusion->sense_dma_pool = NULL;
++}
++
++/**
++ * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool
++ * @instance: Adapter soft state
++ */
++void
++megasas_free_cmds_fusion(struct megasas_instance *instance)
++{
++ int i;
++ struct fusion_context *fusion = instance->ctrl_context;
++
++ u32 max_cmds, req_sz, reply_sz, io_frames_sz;
++
++
++ req_sz = fusion->request_alloc_sz;
++ reply_sz = fusion->reply_alloc_sz;
++ io_frames_sz = fusion->io_frames_alloc_sz;
++
++ max_cmds = instance->max_fw_cmds;
++
++ /* Free descriptors and request Frames memory */
++ if (fusion->req_frames_desc)
++ dma_free_coherent(&instance->pdev->dev, req_sz,
++ fusion->req_frames_desc,
++ fusion->req_frames_desc_phys);
++
++ if (fusion->reply_frames_desc) {
++ pci_pool_free(fusion->reply_frames_desc_pool,
++ fusion->reply_frames_desc,
++ fusion->reply_frames_desc_phys);
++ pci_pool_destroy(fusion->reply_frames_desc_pool);
++ }
++
++ if (fusion->io_request_frames) {
++ pci_pool_free(fusion->io_request_frames_pool,
++ fusion->io_request_frames,
++ fusion->io_request_frames_phys);
++ pci_pool_destroy(fusion->io_request_frames_pool);
++ }
++
++ /* Free the Fusion frame pool */
++ megasas_teardown_frame_pool_fusion(instance);
++
++ /* Free all the commands in the cmd_list */
++ for (i = 0; i < max_cmds; i++)
++ kfree(fusion->cmd_list[i]);
++
++ /* Free the cmd_list buffer itself */
++ kfree(fusion->cmd_list);
++ fusion->cmd_list = NULL;
++
++ INIT_LIST_HEAD(&fusion->cmd_pool);
++}
++
++/**
++ * megasas_create_frame_pool_fusion - Creates DMA pool for cmd frames
++ * @instance: Adapter soft state
++ *
++ */
++static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
++{
++ int i;
++ u32 max_cmd;
++ struct fusion_context *fusion;
++ struct megasas_cmd_fusion *cmd;
++ u32 total_sz_chain_frame;
++
++ fusion = instance->ctrl_context;
++ max_cmd = instance->max_fw_cmds;
++
++ total_sz_chain_frame = MEGASAS_MAX_SZ_CHAIN_FRAME;
++
++ /*
++ * Use DMA pool facility provided by PCI layer
++ */
++
++ fusion->sg_dma_pool = pci_pool_create("megasas sg pool fusion",
++ instance->pdev,
++ total_sz_chain_frame, 4,
++ 0);
++ if (!fusion->sg_dma_pool) {
++ printk(KERN_DEBUG "megasas: failed to setup request pool "
++ "fusion\n");
++ return -ENOMEM;
++ }
++ fusion->sense_dma_pool = pci_pool_create("megasas sense pool fusion",
++ instance->pdev,
++ SCSI_SENSE_BUFFERSIZE, 64, 0);
++
++ if (!fusion->sense_dma_pool) {
++ printk(KERN_DEBUG "megasas: failed to setup sense pool "
++ "fusion\n");
++ pci_pool_destroy(fusion->sg_dma_pool);
++ fusion->sg_dma_pool = NULL;
++ return -ENOMEM;
++ }
++
++ /*
++ * Allocate and attach a frame to each of the commands in cmd_list
++ */
++ for (i = 0; i < max_cmd; i++) {
++
++ cmd = fusion->cmd_list[i];
++
++ cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
++ GFP_KERNEL,
++ &cmd->sg_frame_phys_addr);
++
++ cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
++ GFP_KERNEL, &cmd->sense_phys_addr);
++ /*
++ * megasas_teardown_frame_pool_fusion() takes care of freeing
++ * whatever has been allocated
++ */
++ if (!cmd->sg_frame || !cmd->sense) {
++ printk(KERN_DEBUG "megasas: pci_pool_alloc failed\n");
++ megasas_teardown_frame_pool_fusion(instance);
++ return -ENOMEM;
++ }
++ }
++ return 0;
++}
++
++/**
++ * megasas_alloc_cmds_fusion - Allocates the command packets
++ * @instance: Adapter soft state
++ *
++ *
++ * Each frame has a 32-bit field called context. This context is used to get
++ * back the megasas_cmd_fusion from the frame when a frame gets completed
++ * In this driver, the 32 bit values are the indices into an array cmd_list.
++ * This array is used only to look up the megasas_cmd_fusion given the context.
++ * The free commands themselves are maintained in a linked list called cmd_pool.
++ *
++ * cmds are formed in the io_request and sg_frame members of the
++ * megasas_cmd_fusion. The context field is used to get a request descriptor
++ * and is used as SMID of the cmd.
++ * SMID value range is from 1 to max_fw_cmds.
++ */
++int
++megasas_alloc_cmds_fusion(struct megasas_instance *instance)
++{
++ int i, j;
++ u32 max_cmd, io_frames_sz;
++ struct fusion_context *fusion;
++ struct megasas_cmd_fusion *cmd;
++ union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
++ u32 offset;
++ dma_addr_t io_req_base_phys;
++ u8 *io_req_base;
++
++ fusion = instance->ctrl_context;
++
++ max_cmd = instance->max_fw_cmds;
++
++ fusion->req_frames_desc =
++ dma_alloc_coherent(&instance->pdev->dev,
++ fusion->request_alloc_sz,
++ &fusion->req_frames_desc_phys, GFP_KERNEL);
++
++ if (!fusion->req_frames_desc) {
++ printk(KERN_ERR "megasas; Could not allocate memory for "
++ "request_frames\n");
++ goto fail_req_desc;
++ }
++
++ fusion->reply_frames_desc_pool =
++ pci_pool_create("reply_frames pool", instance->pdev,
++ fusion->reply_alloc_sz, 16, 0);
++
++ if (!fusion->reply_frames_desc_pool) {
++ printk(KERN_ERR "megasas; Could not allocate memory for "
++ "reply_frame pool\n");
++ goto fail_reply_desc;
++ }
++
++ fusion->reply_frames_desc =
++ pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
++ &fusion->reply_frames_desc_phys);
++ if (!fusion->reply_frames_desc) {
++ printk(KERN_ERR "megasas; Could not allocate memory for "
++ "reply_frame pool\n");
++ pci_pool_destroy(fusion->reply_frames_desc_pool);
++ goto fail_reply_desc;
++ }
++
++ reply_desc = fusion->reply_frames_desc;
++ for (i = 0; i < fusion->reply_q_depth; i++, reply_desc++)
++ reply_desc->Words = ULLONG_MAX;
++
++ io_frames_sz = fusion->io_frames_alloc_sz;
++
++ fusion->io_request_frames_pool =
++ pci_pool_create("io_request_frames pool", instance->pdev,
++ fusion->io_frames_alloc_sz, 16, 0);
++
++ if (!fusion->io_request_frames_pool) {
++ printk(KERN_ERR "megasas: Could not allocate memory for "
++ "io_request_frame pool\n");
++ goto fail_io_frames;
++ }
++
++ fusion->io_request_frames =
++ pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
++ &fusion->io_request_frames_phys);
++ if (!fusion->io_request_frames) {
++ printk(KERN_ERR "megasas: Could not allocate memory for "
++ "io_request_frames frames\n");
++ pci_pool_destroy(fusion->io_request_frames_pool);
++ goto fail_io_frames;
++ }
++
++ /*
++ * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
++ * Allocate the dynamic array first and then allocate individual
++ * commands.
++ */
++ fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *)
++ *max_cmd, GFP_KERNEL);
++
++ if (!fusion->cmd_list) {
++ printk(KERN_DEBUG "megasas: out of memory. Could not alloc "
++ "memory for cmd_list_fusion\n");
++ goto fail_cmd_list;
++ }
++
++ memset(fusion->cmd_list, 0, sizeof(struct megasas_cmd_fusion *)
++ *max_cmd);
++
++ max_cmd = instance->max_fw_cmds;
++ for (i = 0; i < max_cmd; i++) {
++ fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
++ GFP_KERNEL);
++ if (!fusion->cmd_list[i]) {
++ printk(KERN_ERR "Could not alloc cmd list fusion\n");
++
++ for (j = 0; j < i; j++)
++ kfree(fusion->cmd_list[j]);
++
++ kfree(fusion->cmd_list);
++ fusion->cmd_list = NULL;
++ goto fail_cmd_list;
++ }
++ }
++
++ /* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */
++ io_req_base = fusion->io_request_frames +
++ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
++ io_req_base_phys = fusion->io_request_frames_phys +
++ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
++
++ /*
++ * Add all the commands to command pool (fusion->cmd_pool)
++ */
++
++ /* SMID 0 is reserved. Set SMID/index from 1 */
++ for (i = 0; i < max_cmd; i++) {
++ cmd = fusion->cmd_list[i];
++ offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
++ memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
++ cmd->index = i + 1;
++ cmd->scmd = NULL;
++ cmd->sync_cmd_idx = (u32)ULONG_MAX; /* Set to Invalid */
++ cmd->instance = instance;
++ cmd->io_request =
++ (struct MPI2_RAID_SCSI_IO_REQUEST *)
++ (io_req_base + offset);
++ memset(cmd->io_request, 0,
++ sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
++ cmd->io_request_phys_addr = io_req_base_phys + offset;
++
++ list_add_tail(&cmd->list, &fusion->cmd_pool);
++ }
++
++ /*
++ * Create a frame pool and assign one frame to each cmd
++ */
++ if (megasas_create_frame_pool_fusion(instance)) {
++ printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n");
++ megasas_free_cmds_fusion(instance);
++ goto fail_req_desc;
++ }
++
++ return 0;
++
++fail_cmd_list:
++ pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames,
++ fusion->io_request_frames_phys);
++ pci_pool_destroy(fusion->io_request_frames_pool);
++fail_io_frames:
++ dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
++ fusion->reply_frames_desc,
++ fusion->reply_frames_desc_phys);
++ pci_pool_free(fusion->reply_frames_desc_pool,
++ fusion->reply_frames_desc,
++ fusion->reply_frames_desc_phys);
++ pci_pool_destroy(fusion->reply_frames_desc_pool);
++
++fail_reply_desc:
++ dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
++ fusion->req_frames_desc,
++ fusion->req_frames_desc_phys);
++fail_req_desc:
++ return -ENOMEM;
++}
++
++/**
++ * wait_and_poll - Issues a polling command
++ * @instance: Adapter soft state
++ * @cmd: Command packet to be issued
++ *
++ * For polling, MFI requires the cmd_status to be set to 0xFF before posting.
++ */
++int
++wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd)
++{
++ int i;
++ struct megasas_header *frame_hdr = &cmd->frame->hdr;
++
++ u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
++
++ /*
++ * Wait for cmd_status to change
++ */
++ for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) {
++ rmb();
++ msleep(20);
++ }
++
++ if (frame_hdr->cmd_status == 0xff)
++ return -ETIME;
++
++ return 0;
++}
++
++/**
++ * megasas_ioc_init_fusion - Initializes the FW
++ * @instance: Adapter soft state
++ *
++ * Issues the IOC Init cmd
++ */
++int
++megasas_ioc_init_fusion(struct megasas_instance *instance)
++{
++ struct megasas_init_frame *init_frame;
++ struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
++ dma_addr_t ioc_init_handle;
++ u32 context;
++ struct megasas_cmd *cmd;
++ u8 ret;
++ struct fusion_context *fusion;
++ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
++ int i;
++ struct megasas_header *frame_hdr;
++
++ fusion = instance->ctrl_context;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd) {
++ printk(KERN_ERR "Could not allocate cmd for INIT Frame\n");
++ ret = 1;
++ goto fail_get_cmd;
++ }
++
++ IOCInitMessage =
++ dma_alloc_coherent(&instance->pdev->dev,
++ sizeof(struct MPI2_IOC_INIT_REQUEST),
++ &ioc_init_handle, GFP_KERNEL);
++
++ if (!IOCInitMessage) {
++ printk(KERN_ERR "Could not allocate memory for "
++ "IOCInitMessage\n");
++ ret = 1;
++ goto fail_fw_init;
++ }
++
++ memset(IOCInitMessage, 0, sizeof(struct MPI2_IOC_INIT_REQUEST));
++
++ IOCInitMessage->Function = MPI2_FUNCTION_IOC_INIT;
++ IOCInitMessage->WhoInit = MPI2_WHOINIT_HOST_DRIVER;
++ IOCInitMessage->MsgVersion = MPI2_VERSION;
++ IOCInitMessage->HeaderVersion = MPI2_HEADER_VERSION;
++ IOCInitMessage->SystemRequestFrameSize =
++ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4;
++
++ IOCInitMessage->ReplyDescriptorPostQueueDepth = fusion->reply_q_depth;
++ IOCInitMessage->ReplyDescriptorPostQueueAddress =
++ fusion->reply_frames_desc_phys;
++ IOCInitMessage->SystemRequestFrameBaseAddress =
++ fusion->io_request_frames_phys;
++
++ init_frame = (struct megasas_init_frame *)cmd->frame;
++ memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
++
++ frame_hdr = &cmd->frame->hdr;
++ context = init_frame->context;
++ init_frame->context = context;
++
++ frame_hdr->cmd_status = 0xFF;
++ frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
++
++ init_frame->cmd = MFI_CMD_INIT;
++ init_frame->cmd_status = 0xFF;
++
++ init_frame->queue_info_new_phys_addr_lo = ioc_init_handle;
++ init_frame->data_xfer_len = sizeof(struct MPI2_IOC_INIT_REQUEST);
++
++ req_desc =
++ (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)fusion->req_frames_desc;
++
++ req_desc->Words = cmd->frame_phys_addr;
++ req_desc->MFAIo.RequestFlags =
++ (MEGASAS_REQ_DESCRIPT_FLAGS_MFA <<
++ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
++
++ /*
++ * disable the intr before firing the init frame
++ */
++ instance->instancet->disable_intr(instance->reg_set);
++
++ for (i = 0; i < (10 * 1000); i += 20) {
++ if (readl(&instance->reg_set->doorbell) & 1)
++ msleep(20);
++ else
++ break;
++ }
++
++ instance->instancet->fire_cmd(instance, req_desc->u.low,
++ req_desc->u.high, instance->reg_set);
++
++ wait_and_poll(instance, cmd);
++
++ frame_hdr = &cmd->frame->hdr;
++ if (frame_hdr->cmd_status != 0) {
++ ret = 1;
++ goto fail_fw_init;
++ }
++ printk(KERN_ERR "megasas:IOC Init cmd success\n");
++
++ ret = 0;
++
++fail_fw_init:
++ megasas_return_cmd(instance, cmd);
++ if (IOCInitMessage)
++ dma_free_coherent(&instance->pdev->dev,
++ sizeof(struct MPI2_IOC_INIT_REQUEST),
++ IOCInitMessage, ioc_init_handle);
++fail_get_cmd:
++ return ret;
++}
++
++/*
++ * megasas_return_cmd_for_smid - Returns a cmd_fusion for a SMID
++ * @instance: Adapter soft state
++ *
++ */
++void
++megasas_return_cmd_for_smid(struct megasas_instance *instance, u16 smid)
++{
++ struct fusion_context *fusion;
++ struct megasas_cmd_fusion *cmd;
++
++ fusion = instance->ctrl_context;
++ cmd = fusion->cmd_list[smid - 1];
++ megasas_return_cmd_fusion(instance, cmd);
++}
++
++/*
++ * megasas_get_ld_map_info - Returns FW's ld_map structure
++ * @instance: Adapter soft state
++ * @pend: Pend the command or not
++ * Issues an internal command (DCMD) to get the FW's controller PD
++ * list structure. This information is mainly used to find out SYSTEM
++ * supported by the FW.
++ */
++static int
++megasas_get_ld_map_info(struct megasas_instance *instance)
++{
++ int ret = 0;
++ struct megasas_cmd *cmd;
++ struct megasas_dcmd_frame *dcmd;
++ struct MR_FW_RAID_MAP_ALL *ci;
++ dma_addr_t ci_h = 0;
++ u32 size_map_info;
++ struct fusion_context *fusion;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd) {
++ printk(KERN_DEBUG "megasas: Failed to get cmd for map info.\n");
++ return -ENOMEM;
++ }
++
++ fusion = instance->ctrl_context;
++
++ if (!fusion) {
++ megasas_return_cmd(instance, cmd);
++ return 1;
++ }
++
++ dcmd = &cmd->frame->dcmd;
++
++ size_map_info = sizeof(struct MR_FW_RAID_MAP) +
++ (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1));
++
++ ci = fusion->ld_map[(instance->map_id & 1)];
++ ci_h = fusion->ld_map_phys[(instance->map_id & 1)];
++
++ if (!ci) {
++ printk(KERN_DEBUG "Failed to alloc mem for ld_map_info\n");
++ megasas_return_cmd(instance, cmd);
++ return -ENOMEM;
++ }
++
++ memset(ci, 0, sizeof(*ci));
++ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
++
++ dcmd->cmd = MFI_CMD_DCMD;
++ dcmd->cmd_status = 0xFF;
++ dcmd->sge_count = 1;
++ dcmd->flags = MFI_FRAME_DIR_READ;
++ dcmd->timeout = 0;
++ dcmd->pad_0 = 0;
++ dcmd->data_xfer_len = size_map_info;
++ dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
++ dcmd->sgl.sge32[0].phys_addr = ci_h;
++ dcmd->sgl.sge32[0].length = size_map_info;
++
++ if (!megasas_issue_polled(instance, cmd))
++ ret = 0;
++ else {
++ printk(KERN_ERR "megasas: Get LD Map Info Failed\n");
++ ret = -1;
++ }
++
++ megasas_return_cmd(instance, cmd);
++
++ return ret;
++}
++
++u8
++megasas_get_map_info(struct megasas_instance *instance)
++{
++ struct fusion_context *fusion = instance->ctrl_context;
++
++ fusion->fast_path_io = 0;
++ if (!megasas_get_ld_map_info(instance)) {
++ if (MR_ValidateMapInfo(fusion->ld_map[(instance->map_id & 1)],
++ fusion->load_balance_info)) {
++ fusion->fast_path_io = 1;
++ return 0;
++ }
++ }
++ return 1;
++}
++
++/*
++ * megasas_sync_map_info - Returns FW's ld_map structure
++ * @instance: Adapter soft state
++ *
++ * Issues an internal command (DCMD) to get the FW's controller PD
++ * list structure. This information is mainly used to find out SYSTEM
++ * supported by the FW.
++ */
++int
++megasas_sync_map_info(struct megasas_instance *instance)
++{
++ int ret = 0, i;
++ struct megasas_cmd *cmd;
++ struct megasas_dcmd_frame *dcmd;
++ u32 size_sync_info, num_lds;
++ struct fusion_context *fusion;
++ struct MR_LD_TARGET_SYNC *ci = NULL;
++ struct MR_FW_RAID_MAP_ALL *map;
++ struct MR_LD_RAID *raid;
++ struct MR_LD_TARGET_SYNC *ld_sync;
++ dma_addr_t ci_h = 0;
++ u32 size_map_info;
++
++ cmd = megasas_get_cmd(instance);
++
++ if (!cmd) {
++ printk(KERN_DEBUG "megasas: Failed to get cmd for sync"
++ "info.\n");
++ return -ENOMEM;
++ }
++
++ fusion = instance->ctrl_context;
++
++ if (!fusion) {
++ megasas_return_cmd(instance, cmd);
++ return 1;
++ }
++
++ map = fusion->ld_map[instance->map_id & 1];
++
++ num_lds = map->raidMap.ldCount;
++
++ dcmd = &cmd->frame->dcmd;
++
++ size_sync_info = sizeof(struct MR_LD_TARGET_SYNC) *num_lds;
++
++ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
++
++ ci = (struct MR_LD_TARGET_SYNC *)
++ fusion->ld_map[(instance->map_id - 1) & 1];
++ memset(ci, 0, sizeof(struct MR_FW_RAID_MAP_ALL));
++
++ ci_h = fusion->ld_map_phys[(instance->map_id - 1) & 1];
++
++ ld_sync = (struct MR_LD_TARGET_SYNC *)ci;
++
++ for (i = 0; i < num_lds; i++, ld_sync++) {
++ raid = MR_LdRaidGet(i, map);
++ ld_sync->targetId = MR_GetLDTgtId(i, map);
++ ld_sync->seqNum = raid->seqNum;
++ }
++
++ size_map_info = sizeof(struct MR_FW_RAID_MAP) +
++ (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1));
++
++ dcmd->cmd = MFI_CMD_DCMD;
++ dcmd->cmd_status = 0xFF;
++ dcmd->sge_count = 1;
++ dcmd->flags = MFI_FRAME_DIR_WRITE;
++ dcmd->timeout = 0;
++ dcmd->pad_0 = 0;
++ dcmd->data_xfer_len = size_map_info;
++ dcmd->mbox.b[0] = num_lds;
++ dcmd->mbox.b[1] = MEGASAS_DCMD_MBOX_PEND_FLAG;
++ dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
++ dcmd->sgl.sge32[0].phys_addr = ci_h;
++ dcmd->sgl.sge32[0].length = size_map_info;
++
++ instance->map_update_cmd = cmd;
++
++ instance->instancet->issue_dcmd(instance, cmd);
++
++ return ret;
++}
++
++/**
++ * megasas_init_adapter_fusion - Initializes the FW
++ * @instance: Adapter soft state
++ *
++ * This is the main function for initializing firmware.
++ */
++u32
++megasas_init_adapter_fusion(struct megasas_instance *instance)
++{
++ struct megasas_register_set __iomem *reg_set;
++ struct fusion_context *fusion;
++ u32 max_cmd;
++ int i = 0;
++
++ fusion = instance->ctrl_context;
++
++ reg_set = instance->reg_set;
++
++ /*
++ * Get various operational parameters from status register
++ */
++ instance->max_fw_cmds =
++ instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
++ instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
++
++ /*
++ * Reduce the max supported cmds by 1. This is to ensure that the
++ * reply_q_sz (1 more than the max cmd that driver may send)
++ * does not exceed max cmds that the FW can support
++ */
++ instance->max_fw_cmds = instance->max_fw_cmds-1;
++ /* Only internal cmds (DCMD) need to have MFI frames */
++ instance->max_mfi_cmds = MEGASAS_INT_CMDS;
++
++ max_cmd = instance->max_fw_cmds;
++
++ fusion->reply_q_depth = ((max_cmd + 1 + 15)/16)*16;
++
++ fusion->request_alloc_sz =
++ sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *max_cmd;
++ fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)
++ *(fusion->reply_q_depth);
++ fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE +
++ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE *
++ (max_cmd + 1)); /* Extra 1 for SMID 0 */
++
++ fusion->max_sge_in_main_msg =
++ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
++ offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16;
++
++ fusion->max_sge_in_chain =
++ MEGASAS_MAX_SZ_CHAIN_FRAME / sizeof(union MPI2_SGE_IO_UNION);
++
++ instance->max_num_sge = fusion->max_sge_in_main_msg +
++ fusion->max_sge_in_chain - 2;
++
++ /* Used for pass thru MFI frame (DCMD) */
++ fusion->chain_offset_mfi_pthru =
++ offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL)/16;
++
++ fusion->chain_offset_io_request =
++ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
++ sizeof(union MPI2_SGE_IO_UNION))/16;
++
++ fusion->last_reply_idx = 0;
++
++ /*
++ * Allocate memory for descriptors
++ * Create a pool of commands
++ */
++ if (megasas_alloc_cmds(instance))
++ goto fail_alloc_mfi_cmds;
++ if (megasas_alloc_cmds_fusion(instance))
++ goto fail_alloc_cmds;
++
++ if (megasas_ioc_init_fusion(instance))
++ goto fail_ioc_init;
++
++ instance->flag_ieee = 1;
++
++ fusion->map_sz = sizeof(struct MR_FW_RAID_MAP) +
++ (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1));
++
++ fusion->fast_path_io = 0;
++
++ for (i = 0; i < 2; i++) {
++ fusion->ld_map[i] = dma_alloc_coherent(&instance->pdev->dev,
++ fusion->map_sz,
++ &fusion->ld_map_phys[i],
++ GFP_KERNEL);
++ if (!fusion->ld_map[i]) {
++ printk(KERN_ERR "megasas: Could not allocate memory "
++ "for map info\n");
++ goto fail_map_info;
++ }
++ }
++
++ if (!megasas_get_map_info(instance))
++ megasas_sync_map_info(instance);
++
++ return 0;
++
++fail_alloc_cmds:
++fail_alloc_mfi_cmds:
++fail_map_info:
++ if (i == 1)
++ dma_free_coherent(&instance->pdev->dev, fusion->map_sz,
++ fusion->ld_map[0], fusion->ld_map_phys[0]);
++fail_ioc_init:
++ return 1;
++}
++
++/**
++ * megasas_fire_cmd_fusion - Sends command to the FW
++ * @frame_phys_addr : Physical address of cmd
++ * @frame_count : Number of frames for the command
++ * @regs : MFI register set
++ */
++void
++megasas_fire_cmd_fusion(struct megasas_instance *instance,
++ dma_addr_t req_desc_lo,
++ u32 req_desc_hi,
++ struct megasas_register_set __iomem *regs)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&instance->hba_lock, flags);
++
++ writel(req_desc_lo,
++ &(regs)->inbound_low_queue_port);
++ writel(req_desc_hi, &(regs)->inbound_high_queue_port);
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++}
++
++/**
++ * map_cmd_status - Maps FW cmd status to OS cmd status
++ * @cmd : Pointer to cmd
++ * @status : status of cmd returned by FW
++ * @ext_status : ext status of cmd returned by FW
++ */
++
++void
++map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status)
++{
++
++ switch (status) {
++
++ case MFI_STAT_OK:
++ cmd->scmd->result = DID_OK << 16;
++ break;
++
++ case MFI_STAT_SCSI_IO_FAILED:
++ case MFI_STAT_LD_INIT_IN_PROGRESS:
++ cmd->scmd->result = (DID_ERROR << 16) | ext_status;
++ break;
++
++ case MFI_STAT_SCSI_DONE_WITH_ERROR:
++
++ cmd->scmd->result = (DID_OK << 16) | ext_status;
++ if (ext_status == SAM_STAT_CHECK_CONDITION) {
++ memset(cmd->scmd->sense_buffer, 0,
++ SCSI_SENSE_BUFFERSIZE);
++ memcpy(cmd->scmd->sense_buffer, cmd->sense,
++ SCSI_SENSE_BUFFERSIZE);
++ cmd->scmd->result |= DRIVER_SENSE << 24;
++ }
++ break;
++
++ case MFI_STAT_LD_OFFLINE:
++ case MFI_STAT_DEVICE_NOT_FOUND:
++ cmd->scmd->result = DID_BAD_TARGET << 16;
++ break;
++
++ default:
++ printk(KERN_DEBUG "megasas: FW status %#x\n", status);
++ cmd->scmd->result = DID_ERROR << 16;
++ break;
++ }
++}
++
++/**
++ * megasas_make_sgl_fusion - Prepares 32-bit SGL
++ * @instance: Adapter soft state
++ * @scp: SCSI command from the mid-layer
++ * @sgl_ptr: SGL to be filled in
++ * @cmd: cmd we are working on
++ *
++ * If successful, this function returns the number of SG elements.
++ */
++static int
++megasas_make_sgl_fusion(struct megasas_instance *instance,
++ struct scsi_cmnd *scp,
++ struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr,
++ struct megasas_cmd_fusion *cmd)
++{
++ int i, sg_processed;
++ int sge_count, sge_idx;
++ struct scatterlist *os_sgl;
++ struct fusion_context *fusion;
++
++ fusion = instance->ctrl_context;
++
++ cmd->io_request->ChainOffset = 0;
++
++ sge_count = scsi_dma_map(scp);
++
++ BUG_ON(sge_count < 0);
++
++ if (sge_count > instance->max_num_sge || !sge_count)
++ return sge_count;
++
++ if (sge_count > fusion->max_sge_in_main_msg) {
++ /* One element to store the chain info */
++ sge_idx = fusion->max_sge_in_main_msg - 1;
++ } else
++ sge_idx = sge_count;
++
++ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
++ sgl_ptr->Length = sg_dma_len(os_sgl);
++ sgl_ptr->Address = sg_dma_address(os_sgl);
++ sgl_ptr->Flags = 0;
++ sgl_ptr++;
++
++ sg_processed = i + 1;
++
++ if ((sg_processed == (fusion->max_sge_in_main_msg - 1)) &&
++ (sge_count > fusion->max_sge_in_main_msg)) {
++
++ struct MPI25_IEEE_SGE_CHAIN64 *sg_chain;
++ cmd->io_request->ChainOffset =
++ fusion->chain_offset_io_request;
++ sg_chain = sgl_ptr;
++ /* Prepare chain element */
++ sg_chain->NextChainOffset = 0;
++ sg_chain->Flags = (IEEE_SGE_FLAGS_CHAIN_ELEMENT |
++ MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
++ sg_chain->Length = (sizeof(union MPI2_SGE_IO_UNION)
++ *(sge_count - sg_processed));
++ sg_chain->Address = cmd->sg_frame_phys_addr;
++
++ sgl_ptr =
++ (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame;
++ }
++ }
++
++ return sge_count;
++}
++
++/**
++ * megasas_set_pd_lba - Sets PD LBA
++ * @cdb: CDB
++ * @cdb_len: cdb length
++ * @start_blk: Start block of IO
++ *
++ * Used to set the PD LBA in CDB for FP IOs
++ */
++void
++megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
++ struct IO_REQUEST_INFO *io_info, struct scsi_cmnd *scp,
++ struct MR_FW_RAID_MAP_ALL *local_map_ptr, u32 ref_tag)
++{
++ struct MR_LD_RAID *raid;
++ u32 ld;
++ u64 start_blk = io_info->pdBlock;
++ u8 *cdb = io_request->CDB.CDB32;
++ u32 num_blocks = io_info->numBlocks;
++ u8 opcode, flagvals, groupnum, control;
++
++ /* Check if T10 PI (DIF) is enabled for this LD */
++ ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr);
++ raid = MR_LdRaidGet(ld, local_map_ptr);
++ if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) {
++ memset(cdb, 0, sizeof(io_request->CDB.CDB32));
++ cdb[0] = MEGASAS_SCSI_VARIABLE_LENGTH_CMD;
++ cdb[7] = MEGASAS_SCSI_ADDL_CDB_LEN;
++
++ if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
++ cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_READ32;
++ else
++ cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_WRITE32;
++ cdb[10] = MEGASAS_RD_WR_PROTECT_CHECK_ALL;
++
++ /* LBA */
++ cdb[12] = (u8)((start_blk >> 56) & 0xff);
++ cdb[13] = (u8)((start_blk >> 48) & 0xff);
++ cdb[14] = (u8)((start_blk >> 40) & 0xff);
++ cdb[15] = (u8)((start_blk >> 32) & 0xff);
++ cdb[16] = (u8)((start_blk >> 24) & 0xff);
++ cdb[17] = (u8)((start_blk >> 16) & 0xff);
++ cdb[18] = (u8)((start_blk >> 8) & 0xff);
++ cdb[19] = (u8)(start_blk & 0xff);
++
++ /* Logical block reference tag */
++ io_request->CDB.EEDP32.PrimaryReferenceTag =
++ cpu_to_be32(ref_tag);
++ io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff;
++
++ io_request->DataLength = num_blocks * 512;
++ io_request->IoFlags = 32; /* Specify 32-byte cdb */
++
++ /* Transfer length */
++ cdb[28] = (u8)((num_blocks >> 24) & 0xff);
++ cdb[29] = (u8)((num_blocks >> 16) & 0xff);
++ cdb[30] = (u8)((num_blocks >> 8) & 0xff);
++ cdb[31] = (u8)(num_blocks & 0xff);
++
++ /* set SCSI IO EEDPFlags */
++ if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) {
++ io_request->EEDPFlags =
++ MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
++ MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
++ MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP |
++ MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG |
++ MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
++ } else {
++ io_request->EEDPFlags =
++ MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
++ MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
++ }
++ io_request->Control |= (0x4 << 26);
++ io_request->EEDPBlockSize = MEGASAS_EEDPBLOCKSIZE;
++ } else {
++ /* Some drives don't support 16/12 byte CDB's, convert to 10 */
++ if (((cdb_len == 12) || (cdb_len == 16)) &&
++ (start_blk <= 0xffffffff)) {
++ if (cdb_len == 16) {
++ opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10;
++ flagvals = cdb[1];
++ groupnum = cdb[14];
++ control = cdb[15];
++ } else {
++ opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10;
++ flagvals = cdb[1];
++ groupnum = cdb[10];
++ control = cdb[11];
++ }
++
++ memset(cdb, 0, sizeof(io_request->CDB.CDB32));
++
++ cdb[0] = opcode;
++ cdb[1] = flagvals;
++ cdb[6] = groupnum;
++ cdb[9] = control;
++
++ /* Transfer length */
++ cdb[8] = (u8)(num_blocks & 0xff);
++ cdb[7] = (u8)((num_blocks >> 8) & 0xff);
++
++ cdb_len = 10;
++ }
++
++ /* Normal case, just load LBA here */
++ switch (cdb_len) {
++ case 6:
++ {
++ u8 val = cdb[1] & 0xE0;
++ cdb[3] = (u8)(start_blk & 0xff);
++ cdb[2] = (u8)((start_blk >> 8) & 0xff);
++ cdb[1] = val | ((u8)(start_blk >> 16) & 0x1f);
++ break;
++ }
++ case 10:
++ cdb[5] = (u8)(start_blk & 0xff);
++ cdb[4] = (u8)((start_blk >> 8) & 0xff);
++ cdb[3] = (u8)((start_blk >> 16) & 0xff);
++ cdb[2] = (u8)((start_blk >> 24) & 0xff);
++ break;
++ case 12:
++ cdb[5] = (u8)(start_blk & 0xff);
++ cdb[4] = (u8)((start_blk >> 8) & 0xff);
++ cdb[3] = (u8)((start_blk >> 16) & 0xff);
++ cdb[2] = (u8)((start_blk >> 24) & 0xff);
++ break;
++ case 16:
++ cdb[9] = (u8)(start_blk & 0xff);
++ cdb[8] = (u8)((start_blk >> 8) & 0xff);
++ cdb[7] = (u8)((start_blk >> 16) & 0xff);
++ cdb[6] = (u8)((start_blk >> 24) & 0xff);
++ cdb[5] = (u8)((start_blk >> 32) & 0xff);
++ cdb[4] = (u8)((start_blk >> 40) & 0xff);
++ cdb[3] = (u8)((start_blk >> 48) & 0xff);
++ cdb[2] = (u8)((start_blk >> 56) & 0xff);
++ break;
++ }
++ }
++}
++
++/**
++ * megasas_build_ldio_fusion - Prepares IOs to devices
++ * @instance: Adapter soft state
++ * @scp: SCSI command
++ * @cmd: Command to be prepared
++ *
++ * Prepares the io_request and chain elements (sg_frame) for IO
++ * The IO can be for PD (Fast Path) or LD
++ */
++void
++megasas_build_ldio_fusion(struct megasas_instance *instance,
++ struct scsi_cmnd *scp,
++ struct megasas_cmd_fusion *cmd)
++{
++ u8 fp_possible;
++ u32 start_lba_lo, start_lba_hi, device_id;
++ struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
++ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
++ struct IO_REQUEST_INFO io_info;
++ struct fusion_context *fusion;
++ struct MR_FW_RAID_MAP_ALL *local_map_ptr;
++
++ device_id = MEGASAS_DEV_INDEX(instance, scp);
++
++ fusion = instance->ctrl_context;
++
++ io_request = cmd->io_request;
++ io_request->RaidContext.VirtualDiskTgtId = device_id;
++ io_request->RaidContext.status = 0;
++ io_request->RaidContext.exStatus = 0;
++
++ req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc;
++
++ start_lba_lo = 0;
++ start_lba_hi = 0;
++ fp_possible = 0;
++
++ /*
++ * 6-byte READ(0x08) or WRITE(0x0A) cdb
++ */
++ if (scp->cmd_len == 6) {
++ io_request->DataLength = (u32) scp->cmnd[4];
++ start_lba_lo = ((u32) scp->cmnd[1] << 16) |
++ ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3];
++
++ start_lba_lo &= 0x1FFFFF;
++ }
++
++ /*
++ * 10-byte READ(0x28) or WRITE(0x2A) cdb
++ */
++ else if (scp->cmd_len == 10) {
++ io_request->DataLength = (u32) scp->cmnd[8] |
++ ((u32) scp->cmnd[7] << 8);
++ start_lba_lo = ((u32) scp->cmnd[2] << 24) |
++ ((u32) scp->cmnd[3] << 16) |
++ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
++ }
++
++ /*
++ * 12-byte READ(0xA8) or WRITE(0xAA) cdb
++ */
++ else if (scp->cmd_len == 12) {
++ io_request->DataLength = ((u32) scp->cmnd[6] << 24) |
++ ((u32) scp->cmnd[7] << 16) |
++ ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
++ start_lba_lo = ((u32) scp->cmnd[2] << 24) |
++ ((u32) scp->cmnd[3] << 16) |
++ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
++ }
++
++ /*
++ * 16-byte READ(0x88) or WRITE(0x8A) cdb
++ */
++ else if (scp->cmd_len == 16) {
++ io_request->DataLength = ((u32) scp->cmnd[10] << 24) |
++ ((u32) scp->cmnd[11] << 16) |
++ ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13];
++ start_lba_lo = ((u32) scp->cmnd[6] << 24) |
++ ((u32) scp->cmnd[7] << 16) |
++ ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
++
++ start_lba_hi = ((u32) scp->cmnd[2] << 24) |
++ ((u32) scp->cmnd[3] << 16) |
++ ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
++ }
++
++ memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO));
++ io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo;
++ io_info.numBlocks = io_request->DataLength;
++ io_info.ldTgtId = device_id;
++
++ if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
++ io_info.isRead = 1;
++
++ local_map_ptr = fusion->ld_map[(instance->map_id & 1)];
++
++ if ((MR_TargetIdToLdGet(device_id, local_map_ptr) >=
++ MAX_LOGICAL_DRIVES) || (!fusion->fast_path_io)) {
++ io_request->RaidContext.regLockFlags = 0;
++ fp_possible = 0;
++ } else {
++ if (MR_BuildRaidContext(&io_info, &io_request->RaidContext,
++ local_map_ptr))
++ fp_possible = io_info.fpOkForIo;
++ }
++
++ if (fp_possible) {
++ megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp,
++ local_map_ptr, start_lba_lo);
++ io_request->DataLength = scsi_bufflen(scp);
++ io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
++ cmd->request_desc->SCSIIO.RequestFlags =
++ (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY
++ << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
++ if ((fusion->load_balance_info[device_id].loadBalanceFlag) &&
++ (io_info.isRead)) {
++ io_info.devHandle =
++ get_updated_dev_handle(
++ &fusion->load_balance_info[device_id],
++ &io_info);
++ scp->SCp.Status |= MEGASAS_LOAD_BALANCE_FLAG;
++ } else
++ scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
++ cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle;
++ io_request->DevHandle = io_info.devHandle;
++ } else {
++ io_request->RaidContext.timeoutValue =
++ local_map_ptr->raidMap.fpPdIoTimeoutSec;
++ io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
++ io_request->DevHandle = device_id;
++ cmd->request_desc->SCSIIO.RequestFlags =
++ (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
++ << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
++ } /* Not FP */
++}
++
++/**
++ * megasas_build_dcdb_fusion - Prepares IOs to devices
++ * @instance: Adapter soft state
++ * @scp: SCSI command
++ * @cmd: Command to be prepared
++ *
++ * Prepares the io_request frame for non-io cmds
++ */
++static void
++megasas_build_dcdb_fusion(struct megasas_instance *instance,
++ struct scsi_cmnd *scmd,
++ struct megasas_cmd_fusion *cmd)
++{
++ u32 device_id;
++ struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
++ u16 pd_index = 0;
++ struct MR_FW_RAID_MAP_ALL *local_map_ptr;
++ struct fusion_context *fusion = instance->ctrl_context;
++
++ io_request = cmd->io_request;
++ device_id = MEGASAS_DEV_INDEX(instance, scmd);
++ pd_index = (scmd->device->channel * MEGASAS_MAX_DEV_PER_CHANNEL)
++ +scmd->device->id;
++ local_map_ptr = fusion->ld_map[(instance->map_id & 1)];
++
++ /* Check if this is a system PD I/O */
++ if ((instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) &&
++ (instance->pd_list[pd_index].driveType == TYPE_DISK)) {
++ io_request->Function = 0;
++ io_request->DevHandle =
++ local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
++ io_request->RaidContext.timeoutValue =
++ local_map_ptr->raidMap.fpPdIoTimeoutSec;
++ io_request->RaidContext.regLockFlags = 0;
++ io_request->RaidContext.regLockRowLBA = 0;
++ io_request->RaidContext.regLockLength = 0;
++ io_request->RaidContext.RAIDFlags =
++ MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD <<
++ MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
++ cmd->request_desc->SCSIIO.RequestFlags =
++ (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
++ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
++ } else {
++ io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
++ io_request->DevHandle = device_id;
++ cmd->request_desc->SCSIIO.RequestFlags =
++ (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
++ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
++ }
++ io_request->RaidContext.VirtualDiskTgtId = device_id;
++ io_request->LUN[0] = scmd->device->lun;
++ io_request->DataLength = scsi_bufflen(scmd);
++}
++
++/**
++ * megasas_build_io_fusion - Prepares IOs to devices
++ * @instance: Adapter soft state
++ * @scp: SCSI command
++ * @cmd: Command to be prepared
++ *
++ * Invokes helper functions to prepare request frames
++ * and sets flags appropriate for IO/Non-IO cmd
++ */
++int
++megasas_build_io_fusion(struct megasas_instance *instance,
++ struct scsi_cmnd *scp,
++ struct megasas_cmd_fusion *cmd)
++{
++ u32 device_id, sge_count;
++ struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request;
++
++ device_id = MEGASAS_DEV_INDEX(instance, scp);
++
++ /* Zero out some fields so they don't get reused */
++ io_request->LUN[0] = 0;
++ io_request->CDB.EEDP32.PrimaryReferenceTag = 0;
++ io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0;
++ io_request->EEDPFlags = 0;
++ io_request->Control = 0;
++ io_request->EEDPBlockSize = 0;
++ io_request->IoFlags = 0;
++ io_request->RaidContext.RAIDFlags = 0;
++
++ memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len);
++ /*
++ * Just the CDB length,rest of the Flags are zero
++ * This will be modified for FP in build_ldio_fusion
++ */
++ io_request->IoFlags = scp->cmd_len;
++
++ if (megasas_is_ldio(scp))
++ megasas_build_ldio_fusion(instance, scp, cmd);
++ else
++ megasas_build_dcdb_fusion(instance, scp, cmd);
++
++ /*
++ * Construct SGL
++ */
++
++ sge_count =
++ megasas_make_sgl_fusion(instance, scp,
++ (struct MPI25_IEEE_SGE_CHAIN64 *)
++ &io_request->SGL, cmd);
++
++ if (sge_count > instance->max_num_sge) {
++ printk(KERN_ERR "megasas: Error. sge_count (0x%x) exceeds "
++ "max (0x%x) allowed\n", sge_count,
++ instance->max_num_sge);
++ return 1;
++ }
++
++ io_request->RaidContext.numSGE = sge_count;
++
++ io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
++
++ if (scp->sc_data_direction == PCI_DMA_TODEVICE)
++ io_request->Control |= MPI2_SCSIIO_CONTROL_WRITE;
++ else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
++ io_request->Control |= MPI2_SCSIIO_CONTROL_READ;
++
++ io_request->SGLOffset0 =
++ offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL) / 4;
++
++ io_request->SenseBufferLowAddress = cmd->sense_phys_addr;
++ io_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
++
++ cmd->scmd = scp;
++ scp->SCp.ptr = (char *)cmd;
++
++ return 0;
++}
++
++union MEGASAS_REQUEST_DESCRIPTOR_UNION *
++megasas_get_request_descriptor(struct megasas_instance *instance, u16 index)
++{
++ u8 *p;
++ struct fusion_context *fusion;
++
++ if (index >= instance->max_fw_cmds) {
++ printk(KERN_ERR "megasas: Invalid SMID (0x%x)request for "
++ "descriptor\n", index);
++ return NULL;
++ }
++ fusion = instance->ctrl_context;
++ p = fusion->req_frames_desc
++ +sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *index;
++
++ return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p;
++}
++
++/**
++ * megasas_build_and_issue_cmd_fusion -Main routine for building and
++ * issuing non IOCTL cmd
++ * @instance: Adapter soft state
++ * @scmd: pointer to scsi cmd from OS
++ */
++static u32
++megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
++ struct scsi_cmnd *scmd)
++{
++ struct megasas_cmd_fusion *cmd;
++ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
++ u32 index;
++ struct fusion_context *fusion;
++
++ fusion = instance->ctrl_context;
++
++ cmd = megasas_get_cmd_fusion(instance);
++ if (!cmd)
++ return SCSI_MLQUEUE_HOST_BUSY;
++
++ index = cmd->index;
++
++ req_desc = megasas_get_request_descriptor(instance, index-1);
++ if (!req_desc)
++ return 1;
++
++ req_desc->Words = 0;
++ cmd->request_desc = req_desc;
++ cmd->request_desc->Words = 0;
++
++ if (megasas_build_io_fusion(instance, scmd, cmd)) {
++ megasas_return_cmd_fusion(instance, cmd);
++ printk(KERN_ERR "megasas: Error building command.\n");
++ cmd->request_desc = NULL;
++ return 1;
++ }
++
++ req_desc = cmd->request_desc;
++ req_desc->SCSIIO.SMID = index;
++
++ if (cmd->io_request->ChainOffset != 0 &&
++ cmd->io_request->ChainOffset != 0xF)
++ printk(KERN_ERR "megasas: The chain offset value is not "
++ "correct : %x\n", cmd->io_request->ChainOffset);
++
++ /*
++ * Issue the command to the FW
++ */
++ atomic_inc(&instance->fw_outstanding);
++
++ instance->instancet->fire_cmd(instance,
++ req_desc->u.low, req_desc->u.high,
++ instance->reg_set);
++
++ return 0;
++}
++
++/**
++ * complete_cmd_fusion - Completes command
++ * @instance: Adapter soft state
++ * Completes all commands that is in reply descriptor queue
++ */
++int
++complete_cmd_fusion(struct megasas_instance *instance)
++{
++ union MPI2_REPLY_DESCRIPTORS_UNION *desc;
++ struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
++ struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req;
++ struct fusion_context *fusion;
++ struct megasas_cmd *cmd_mfi;
++ struct megasas_cmd_fusion *cmd_fusion;
++ u16 smid, num_completed;
++ u8 reply_descript_type, arm;
++ u32 status, extStatus, device_id;
++ union desc_value d_val;
++ struct LD_LOAD_BALANCE_INFO *lbinfo;
++
++ fusion = instance->ctrl_context;
++
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
++ return IRQ_HANDLED;
++
++ desc = fusion->reply_frames_desc;
++ desc += fusion->last_reply_idx;
++
++ reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
++
++ d_val.word = desc->Words;
++
++ reply_descript_type = reply_desc->ReplyFlags &
++ MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
++
++ if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
++ return IRQ_NONE;
++
++ d_val.word = desc->Words;
++
++ num_completed = 0;
++
++ while ((d_val.u.low != UINT_MAX) && (d_val.u.high != UINT_MAX)) {
++ smid = reply_desc->SMID;
++
++ cmd_fusion = fusion->cmd_list[smid - 1];
++
++ scsi_io_req =
++ (struct MPI2_RAID_SCSI_IO_REQUEST *)
++ cmd_fusion->io_request;
++
++ if (cmd_fusion->scmd)
++ cmd_fusion->scmd->SCp.ptr = NULL;
++
++ status = scsi_io_req->RaidContext.status;
++ extStatus = scsi_io_req->RaidContext.exStatus;
++
++ switch (scsi_io_req->Function) {
++ case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/
++ /* Update load balancing info */
++ device_id = MEGASAS_DEV_INDEX(instance,
++ cmd_fusion->scmd);
++ lbinfo = &fusion->load_balance_info[device_id];
++ if (cmd_fusion->scmd->SCp.Status &
++ MEGASAS_LOAD_BALANCE_FLAG) {
++ arm = lbinfo->raid1DevHandle[0] ==
++ cmd_fusion->io_request->DevHandle ? 0 :
++ 1;
++ atomic_dec(&lbinfo->scsi_pending_cmds[arm]);
++ cmd_fusion->scmd->SCp.Status &=
++ ~MEGASAS_LOAD_BALANCE_FLAG;
++ }
++ if (reply_descript_type ==
++ MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) {
++ if (megasas_dbg_lvl == 5)
++ printk(KERN_ERR "\nmegasas: FAST Path "
++ "IO Success\n");
++ }
++ /* Fall thru and complete IO */
++ case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */
++ /* Map the FW Cmd Status */
++ map_cmd_status(cmd_fusion, status, extStatus);
++ scsi_dma_unmap(cmd_fusion->scmd);
++ cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
++ scsi_io_req->RaidContext.status = 0;
++ scsi_io_req->RaidContext.exStatus = 0;
++ megasas_return_cmd_fusion(instance, cmd_fusion);
++ atomic_dec(&instance->fw_outstanding);
++
++ break;
++ case MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST: /*MFI command */
++ cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
++ megasas_complete_cmd(instance, cmd_mfi, DID_OK);
++ cmd_fusion->flags = 0;
++ megasas_return_cmd_fusion(instance, cmd_fusion);
++
++ break;
++ }
++
++ fusion->last_reply_idx++;
++ if (fusion->last_reply_idx >= fusion->reply_q_depth)
++ fusion->last_reply_idx = 0;
++
++ desc->Words = ULLONG_MAX;
++ num_completed++;
++
++ /* Get the next reply descriptor */
++ if (!fusion->last_reply_idx)
++ desc = fusion->reply_frames_desc;
++ else
++ desc++;
++
++ reply_desc =
++ (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
++
++ d_val.word = desc->Words;
++
++ reply_descript_type = reply_desc->ReplyFlags &
++ MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
++
++ if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
++ break;
++ }
++
++ if (!num_completed)
++ return IRQ_NONE;
++
++ wmb();
++ writel(fusion->last_reply_idx,
++ &instance->reg_set->reply_post_host_index);
++
++ return IRQ_HANDLED;
++}
++
++/**
++ * megasas_complete_cmd_dpc_fusion - Completes command
++ * @instance: Adapter soft state
++ *
++ * Tasklet to complete cmds
++ */
++void
++megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
++{
++ struct megasas_instance *instance =
++ (struct megasas_instance *)instance_addr;
++ unsigned long flags;
++
++ /* If we have already declared adapter dead, donot complete cmds */
++ spin_lock_irqsave(&instance->hba_lock, flags);
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++ return;
++ }
++ spin_unlock_irqrestore(&instance->hba_lock, flags);
++
++ spin_lock_irqsave(&instance->completion_lock, flags);
++ complete_cmd_fusion(instance);
++ spin_unlock_irqrestore(&instance->completion_lock, flags);
++}
++
++/**
++ * megasas_isr_fusion - isr entry point
++ */
++irqreturn_t megasas_isr_fusion(int irq, void *devp)
++{
++ struct megasas_instance *instance = (struct megasas_instance *)devp;
++ u32 mfiStatus, fw_state;
++
++ if (!instance->msi_flag) {
++ mfiStatus = instance->instancet->clear_intr(instance->reg_set);
++ if (!mfiStatus)
++ return IRQ_NONE;
++ }
++
++ /* If we are resetting, bail */
++ if (test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags))
++ return IRQ_HANDLED;
++
++ if (!complete_cmd_fusion(instance)) {
++ /* If we didn't complete any commands, check for FW fault */
++ fw_state = instance->instancet->read_fw_status_reg(
++ instance->reg_set) & MFI_STATE_MASK;
++ if (fw_state == MFI_STATE_FAULT)
++ schedule_work(&instance->work_init);
++ }
++
++ return IRQ_HANDLED;
++}
++
++/**
++ * build_mpt_mfi_pass_thru - builds a cmd fo MFI Pass thru
++ * @instance: Adapter soft state
++ * mfi_cmd: megasas_cmd pointer
++ *
++ */
++u8
++build_mpt_mfi_pass_thru(struct megasas_instance *instance,
++ struct megasas_cmd *mfi_cmd)
++{
++ struct MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain;
++ struct MPI2_RAID_SCSI_IO_REQUEST *io_req;
++ struct megasas_cmd_fusion *cmd;
++ struct fusion_context *fusion;
++ struct megasas_header *frame_hdr = &mfi_cmd->frame->hdr;
++
++ cmd = megasas_get_cmd_fusion(instance);
++ if (!cmd)
++ return 1;
++
++ /* Save the smid. To be used for returning the cmd */
++ mfi_cmd->context.smid = cmd->index;
++
++ cmd->sync_cmd_idx = mfi_cmd->index;
++
++ /*
++ * For cmds where the flag is set, store the flag and check
++ * on completion. For cmds with this flag, don't call
++ * megasas_complete_cmd
++ */
++
++ if (frame_hdr->flags & MFI_FRAME_DONT_POST_IN_REPLY_QUEUE)
++ cmd->flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
++
++ fusion = instance->ctrl_context;
++ io_req = cmd->io_request;
++ mpi25_ieee_chain =
++ (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;
++
++ io_req->Function = MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
++ io_req->SGLOffset0 = offsetof(struct MPI2_RAID_SCSI_IO_REQUEST,
++ SGL) / 4;
++ io_req->ChainOffset = fusion->chain_offset_mfi_pthru;
++
++ mpi25_ieee_chain->Address = mfi_cmd->frame_phys_addr;
++
++ mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT |
++ MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
++
++ mpi25_ieee_chain->Length = MEGASAS_MAX_SZ_CHAIN_FRAME;
++
++ return 0;
++}
++
++/**
++ * build_mpt_cmd - Calls helper function to build a cmd MFI Pass thru cmd
++ * @instance: Adapter soft state
++ * @cmd: mfi cmd to build
++ *
++ */
++union MEGASAS_REQUEST_DESCRIPTOR_UNION *
++build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
++{
++ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
++ u16 index;
++
++ if (build_mpt_mfi_pass_thru(instance, cmd)) {
++ printk(KERN_ERR "Couldn't build MFI pass thru cmd\n");
++ return NULL;
++ }
++
++ index = cmd->context.smid;
++
++ req_desc = megasas_get_request_descriptor(instance, index - 1);
++
++ if (!req_desc)
++ return NULL;
++
++ req_desc->Words = 0;
++ req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
++ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
++
++ req_desc->SCSIIO.SMID = index;
++
++ return req_desc;
++}
++
++/**
++ * megasas_issue_dcmd_fusion - Issues a MFI Pass thru cmd
++ * @instance: Adapter soft state
++ * @cmd: mfi cmd pointer
++ *
++ */
++void
++megasas_issue_dcmd_fusion(struct megasas_instance *instance,
++ struct megasas_cmd *cmd)
++{
++ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
++ union desc_value d_val;
++
++ req_desc = build_mpt_cmd(instance, cmd);
++ if (!req_desc) {
++ printk(KERN_ERR "Couldn't issue MFI pass thru cmd\n");
++ return;
++ }
++ d_val.word = req_desc->Words;
++
++ instance->instancet->fire_cmd(instance, req_desc->u.low,
++ req_desc->u.high, instance->reg_set);
++}
++
++/**
++ * megasas_release_fusion - Reverses the FW initialization
++ * @intance: Adapter soft state
++ */
++void
++megasas_release_fusion(struct megasas_instance *instance)
++{
++ megasas_free_cmds(instance);
++ megasas_free_cmds_fusion(instance);
++
++ iounmap(instance->reg_set);
++
++ pci_release_selected_regions(instance->pdev, instance->bar);
++}
++
++/**
++ * megasas_read_fw_status_reg_fusion - returns the current FW status value
++ * @regs: MFI register set
++ */
++static u32
++megasas_read_fw_status_reg_fusion(struct megasas_register_set __iomem *regs)
++{
++ return readl(&(regs)->outbound_scratch_pad);
++}
++
++/**
++ * megasas_adp_reset_fusion - For controller reset
++ * @regs: MFI register set
++ */
++static int
++megasas_adp_reset_fusion(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
++}
++
++/**
++ * megasas_check_reset_fusion - For controller reset check
++ * @regs: MFI register set
++ */
++static int
++megasas_check_reset_fusion(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *regs)
++{
++ return 0;
++}
++
++/* This function waits for outstanding commands on fusion to complete */
++int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
++{
++ int i, outstanding, retval = 0;
++ u32 fw_state, wait_time = MEGASAS_RESET_WAIT_TIME;
++
++ for (i = 0; i < wait_time; i++) {
++ /* Check if firmware is in fault state */
++ fw_state = instance->instancet->read_fw_status_reg(
++ instance->reg_set) & MFI_STATE_MASK;
++ if (fw_state == MFI_STATE_FAULT) {
++ printk(KERN_WARNING "megasas: Found FW in FAULT state,"
++ " will reset adapter.\n");
++ retval = 1;
++ goto out;
++ }
++
++ outstanding = atomic_read(&instance->fw_outstanding);
++ if (!outstanding)
++ goto out;
++
++ if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
++ printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
++ "commands to complete\n", i, outstanding);
++ megasas_complete_cmd_dpc_fusion(
++ (unsigned long)instance);
++ }
++ msleep(1000);
++ }
++
++ if (atomic_read(&instance->fw_outstanding)) {
++ printk("megaraid_sas: pending commands remain after waiting, "
++ "will reset adapter.\n");
++ retval = 1;
++ }
++out:
++ return retval;
++}
++
++void megasas_reset_reply_desc(struct megasas_instance *instance)
++{
++ int i;
++ struct fusion_context *fusion;
++ union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
++
++ fusion = instance->ctrl_context;
++ fusion->last_reply_idx = 0;
++ reply_desc = fusion->reply_frames_desc;
++ for (i = 0 ; i < fusion->reply_q_depth; i++, reply_desc++)
++ reply_desc->Words = ULLONG_MAX;
++}
++
++/* Core fusion reset function */
++int megasas_reset_fusion(struct Scsi_Host *shost)
++{
++ int retval = SUCCESS, i, j, retry = 0;
++ struct megasas_instance *instance;
++ struct megasas_cmd_fusion *cmd_fusion;
++ struct fusion_context *fusion;
++ struct megasas_cmd *cmd_mfi;
++ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
++ u32 host_diag, abs_state;
++
++ instance = (struct megasas_instance *)shost->hostdata;
++ fusion = instance->ctrl_context;
++
++ mutex_lock(&instance->reset_mutex);
++ set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
++ instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
++ instance->instancet->disable_intr(instance->reg_set);
++ msleep(1000);
++
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
++ printk(KERN_WARNING "megaraid_sas: Hardware critical error, "
++ "returning FAILED.\n");
++ retval = FAILED;
++ goto out;
++ }
++
++ /* First try waiting for commands to complete */
++ if (megasas_wait_for_outstanding_fusion(instance)) {
++ printk(KERN_WARNING "megaraid_sas: resetting fusion "
++ "adapter.\n");
++ /* Now return commands back to the OS */
++ for (i = 0 ; i < instance->max_fw_cmds; i++) {
++ cmd_fusion = fusion->cmd_list[i];
++ if (cmd_fusion->scmd) {
++ scsi_dma_unmap(cmd_fusion->scmd);
++ cmd_fusion->scmd->result = (DID_RESET << 16);
++ cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
++ megasas_return_cmd_fusion(instance, cmd_fusion);
++ atomic_dec(&instance->fw_outstanding);
++ }
++ }
++
++ if (instance->disableOnlineCtrlReset == 1) {
++ /* Reset not supported, kill adapter */
++ printk(KERN_WARNING "megaraid_sas: Reset not supported"
++ ", killing adapter.\n");
++ megaraid_sas_kill_hba(instance);
++ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
++ retval = FAILED;
++ goto out;
++ }
++
++ /* Now try to reset the chip */
++ for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
++ writel(MPI2_WRSEQ_FLUSH_KEY_VALUE,
++ &instance->reg_set->fusion_seq_offset);
++ writel(MPI2_WRSEQ_1ST_KEY_VALUE,
++ &instance->reg_set->fusion_seq_offset);
++ writel(MPI2_WRSEQ_2ND_KEY_VALUE,
++ &instance->reg_set->fusion_seq_offset);
++ writel(MPI2_WRSEQ_3RD_KEY_VALUE,
++ &instance->reg_set->fusion_seq_offset);
++ writel(MPI2_WRSEQ_4TH_KEY_VALUE,
++ &instance->reg_set->fusion_seq_offset);
++ writel(MPI2_WRSEQ_5TH_KEY_VALUE,
++ &instance->reg_set->fusion_seq_offset);
++ writel(MPI2_WRSEQ_6TH_KEY_VALUE,
++ &instance->reg_set->fusion_seq_offset);
++
++ /* Check that the diag write enable (DRWE) bit is on */
++ host_diag = readl(&instance->reg_set->fusion_host_diag);
++ while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
++ msleep(100);
++ host_diag =
++ readl(&instance->reg_set->fusion_host_diag);
++ if (retry++ == 100) {
++ printk(KERN_WARNING "megaraid_sas: "
++ "Host diag unlock failed!\n");
++ break;
++ }
++ }
++ if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
++ continue;
++
++ /* Send chip reset command */
++ writel(host_diag | HOST_DIAG_RESET_ADAPTER,
++ &instance->reg_set->fusion_host_diag);
++ msleep(3000);
++
++ /* Make sure reset adapter bit is cleared */
++ host_diag = readl(&instance->reg_set->fusion_host_diag);
++ retry = 0;
++ while (host_diag & HOST_DIAG_RESET_ADAPTER) {
++ msleep(100);
++ host_diag =
++ readl(&instance->reg_set->fusion_host_diag);
++ if (retry++ == 1000) {
++ printk(KERN_WARNING "megaraid_sas: "
++ "Diag reset adapter never "
++ "cleared!\n");
++ break;
++ }
++ }
++ if (host_diag & HOST_DIAG_RESET_ADAPTER)
++ continue;
++
++ abs_state =
++ instance->instancet->read_fw_status_reg(
++ instance->reg_set);
++ retry = 0;
++
++ while ((abs_state <= MFI_STATE_FW_INIT) &&
++ (retry++ < 1000)) {
++ msleep(100);
++ abs_state =
++ instance->instancet->read_fw_status_reg(
++ instance->reg_set);
++ }
++ if (abs_state <= MFI_STATE_FW_INIT) {
++ printk(KERN_WARNING "megaraid_sas: firmware "
++ "state < MFI_STATE_FW_INIT, state = "
++ "0x%x\n", abs_state);
++ continue;
++ }
++
++ /* Wait for FW to become ready */
++ if (megasas_transition_to_ready(instance)) {
++ printk(KERN_WARNING "megaraid_sas: Failed to "
++ "transition controller to ready.\n");
++ continue;
++ }
++
++ megasas_reset_reply_desc(instance);
++ if (megasas_ioc_init_fusion(instance)) {
++ printk(KERN_WARNING "megaraid_sas: "
++ "megasas_ioc_init_fusion() failed!\n");
++ continue;
++ }
++
++ instance->instancet->enable_intr(instance->reg_set);
++ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
++
++ /* Re-fire management commands */
++ for (j = 0 ; j < instance->max_fw_cmds; j++) {
++ cmd_fusion = fusion->cmd_list[j];
++ if (cmd_fusion->sync_cmd_idx !=
++ (u32)ULONG_MAX) {
++ cmd_mfi =
++ instance->
++ cmd_list[cmd_fusion->sync_cmd_idx];
++ if (cmd_mfi->frame->dcmd.opcode ==
++ MR_DCMD_LD_MAP_GET_INFO) {
++ megasas_return_cmd(instance,
++ cmd_mfi);
++ megasas_return_cmd_fusion(
++ instance, cmd_fusion);
++ } else {
++ req_desc =
++ megasas_get_request_descriptor(
++ instance,
++ cmd_mfi->context.smid
++ -1);
++ if (!req_desc)
++ printk(KERN_WARNING
++ "req_desc NULL"
++ "\n");
++ else {
++ instance->instancet->
++ fire_cmd(instance,
++ req_desc->
++ u.low,
++ req_desc->
++ u.high,
++ instance->
++ reg_set);
++ }
++ }
++ }
++ }
++
++ /* Reset load balance info */
++ memset(fusion->load_balance_info, 0,
++ sizeof(struct LD_LOAD_BALANCE_INFO)
++ *MAX_LOGICAL_DRIVES);
++
++ if (!megasas_get_map_info(instance))
++ megasas_sync_map_info(instance);
++
++ /* Adapter reset completed successfully */
++ printk(KERN_WARNING "megaraid_sas: Reset "
++ "successful.\n");
++ retval = SUCCESS;
++ goto out;
++ }
++ /* Reset failed, kill the adapter */
++ printk(KERN_WARNING "megaraid_sas: Reset failed, killing "
++ "adapter.\n");
++ megaraid_sas_kill_hba(instance);
++ retval = FAILED;
++ } else {
++ instance->instancet->enable_intr(instance->reg_set);
++ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
++ }
++out:
++ clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
++ mutex_unlock(&instance->reset_mutex);
++ return retval;
++}
++
++/* Fusion OCR work queue */
++void megasas_fusion_ocr_wq(struct work_struct *work)
++{
++ struct megasas_instance *instance =
++ container_of(work, struct megasas_instance, work_init);
++
++ megasas_reset_fusion(instance->host);
++}
++
++struct megasas_instance_template megasas_instance_template_fusion = {
++ .fire_cmd = megasas_fire_cmd_fusion,
++ .enable_intr = megasas_enable_intr_fusion,
++ .disable_intr = megasas_disable_intr_fusion,
++ .clear_intr = megasas_clear_intr_fusion,
++ .read_fw_status_reg = megasas_read_fw_status_reg_fusion,
++ .adp_reset = megasas_adp_reset_fusion,
++ .check_reset = megasas_check_reset_fusion,
++ .service_isr = megasas_isr_fusion,
++ .tasklet = megasas_complete_cmd_dpc_fusion,
++ .init_adapter = megasas_init_adapter_fusion,
++ .build_and_issue_cmd = megasas_build_and_issue_cmd_fusion,
++ .issue_dcmd = megasas_issue_dcmd_fusion,
++};
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
+new file mode 100644
+index 000000000000..82b577a72c8b
+--- /dev/null
++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
+@@ -0,0 +1,695 @@
++/*
++ * Linux MegaRAID driver for SAS based RAID controllers
++ *
++ * Copyright (c) 2009-2011 LSI Corporation.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * FILE: megaraid_sas_fusion.h
++ *
++ * Authors: LSI Corporation
++ * Manoj Jose
++ * Sumant Patro
++ *
++ * Send feedback to: <megaraidlinux at lsi.com>
++ *
++ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
++ * ATTN: Linuxraid
++ */
++
++#ifndef _MEGARAID_SAS_FUSION_H_
++#define _MEGARAID_SAS_FUSION_H_
++
++/* Fusion defines */
++#define MEGASAS_MAX_SZ_CHAIN_FRAME 1024
++#define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000009)
++#define MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 256
++#define MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0
++#define MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST 0xF1
++#define MEGASAS_LOAD_BALANCE_FLAG 0x1
++#define MEGASAS_DCMD_MBOX_PEND_FLAG 0x1
++#define HOST_DIAG_WRITE_ENABLE 0x80
++#define HOST_DIAG_RESET_ADAPTER 0x4
++#define MEGASAS_FUSION_MAX_RESET_TRIES 3
++
++/* T10 PI defines */
++#define MR_PROT_INFO_TYPE_CONTROLLER 0x8
++#define MEGASAS_SCSI_VARIABLE_LENGTH_CMD 0x7f
++#define MEGASAS_SCSI_SERVICE_ACTION_READ32 0x9
++#define MEGASAS_SCSI_SERVICE_ACTION_WRITE32 0xB
++#define MEGASAS_SCSI_ADDL_CDB_LEN 0x18
++#define MEGASAS_RD_WR_PROTECT_CHECK_ALL 0x20
++#define MEGASAS_RD_WR_PROTECT_CHECK_NONE 0x60
++#define MEGASAS_EEDPBLOCKSIZE 512
++
++/*
++ * Raid context flags
++ */
++
++#define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT 0x4
++#define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_MASK 0x30
++enum MR_RAID_FLAGS_IO_SUB_TYPE {
++ MR_RAID_FLAGS_IO_SUB_TYPE_NONE = 0,
++ MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD = 1,
++};
++
++/*
++ * Request descriptor types
++ */
++#define MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO 0x7
++#define MEGASAS_REQ_DESCRIPT_FLAGS_MFA 0x1
++
++#define MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT 1
++
++#define MEGASAS_FP_CMD_LEN 16
++#define MEGASAS_FUSION_IN_RESET 0
++
++/*
++ * Raid Context structure which describes MegaRAID specific IO Paramenters
++ * This resides at offset 0x60 where the SGL normally starts in MPT IO Frames
++ */
++
++struct RAID_CONTEXT {
++ u16 resvd0;
++ u16 timeoutValue;
++ u8 regLockFlags;
++ u8 resvd1;
++ u16 VirtualDiskTgtId;
++ u64 regLockRowLBA;
++ u32 regLockLength;
++ u16 nextLMId;
++ u8 exStatus;
++ u8 status;
++ u8 RAIDFlags;
++ u8 numSGE;
++ u16 configSeqNum;
++ u8 spanArm;
++ u8 resvd2[3];
++};
++
++#define RAID_CTX_SPANARM_ARM_SHIFT (0)
++#define RAID_CTX_SPANARM_ARM_MASK (0x1f)
++
++#define RAID_CTX_SPANARM_SPAN_SHIFT (5)
++#define RAID_CTX_SPANARM_SPAN_MASK (0xE0)
++
++/*
++ * define region lock types
++ */
++enum REGION_TYPE {
++ REGION_TYPE_UNUSED = 0,
++ REGION_TYPE_SHARED_READ = 1,
++ REGION_TYPE_SHARED_WRITE = 2,
++ REGION_TYPE_EXCLUSIVE = 3,
++};
++
++/* MPI2 defines */
++#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */
++#define MPI2_WHOINIT_HOST_DRIVER (0x04)
++#define MPI2_VERSION_MAJOR (0x02)
++#define MPI2_VERSION_MINOR (0x00)
++#define MPI2_VERSION_MAJOR_MASK (0xFF00)
++#define MPI2_VERSION_MAJOR_SHIFT (8)
++#define MPI2_VERSION_MINOR_MASK (0x00FF)
++#define MPI2_VERSION_MINOR_SHIFT (0)
++#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
++ MPI2_VERSION_MINOR)
++#define MPI2_HEADER_VERSION_UNIT (0x10)
++#define MPI2_HEADER_VERSION_DEV (0x00)
++#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
++#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
++#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF)
++#define MPI2_HEADER_VERSION_DEV_SHIFT (0)
++#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | \
++ MPI2_HEADER_VERSION_DEV)
++#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03)
++#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000)
++#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400)
++#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003)
++#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200)
++#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100)
++#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004)
++#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */
++#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06)
++#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00)
++#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02)
++#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000)
++#define MPI2_SCSIIO_CONTROL_READ (0x02000000)
++#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E)
++#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F)
++#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00)
++#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F)
++#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0)
++#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004)
++#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF)
++#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4)
++#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB)
++#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2)
++#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7)
++#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD)
++
++struct MPI25_IEEE_SGE_CHAIN64 {
++ u64 Address;
++ u32 Length;
++ u16 Reserved1;
++ u8 NextChainOffset;
++ u8 Flags;
++};
++
++struct MPI2_SGE_SIMPLE_UNION {
++ u32 FlagsLength;
++ union {
++ u32 Address32;
++ u64 Address64;
++ } u;
++};
++
++struct MPI2_SCSI_IO_CDB_EEDP32 {
++ u8 CDB[20]; /* 0x00 */
++ u32 PrimaryReferenceTag; /* 0x14 */
++ u16 PrimaryApplicationTag; /* 0x18 */
++ u16 PrimaryApplicationTagMask; /* 0x1A */
++ u32 TransferLength; /* 0x1C */
++};
++
++struct MPI2_SGE_CHAIN_UNION {
++ u16 Length;
++ u8 NextChainOffset;
++ u8 Flags;
++ union {
++ u32 Address32;
++ u64 Address64;
++ } u;
++};
++
++struct MPI2_IEEE_SGE_SIMPLE32 {
++ u32 Address;
++ u32 FlagsLength;
++};
++
++struct MPI2_IEEE_SGE_CHAIN32 {
++ u32 Address;
++ u32 FlagsLength;
++};
++
++struct MPI2_IEEE_SGE_SIMPLE64 {
++ u64 Address;
++ u32 Length;
++ u16 Reserved1;
++ u8 Reserved2;
++ u8 Flags;
++};
++
++struct MPI2_IEEE_SGE_CHAIN64 {
++ u64 Address;
++ u32 Length;
++ u16 Reserved1;
++ u8 Reserved2;
++ u8 Flags;
++};
++
++union MPI2_IEEE_SGE_SIMPLE_UNION {
++ struct MPI2_IEEE_SGE_SIMPLE32 Simple32;
++ struct MPI2_IEEE_SGE_SIMPLE64 Simple64;
++};
++
++union MPI2_IEEE_SGE_CHAIN_UNION {
++ struct MPI2_IEEE_SGE_CHAIN32 Chain32;
++ struct MPI2_IEEE_SGE_CHAIN64 Chain64;
++};
++
++union MPI2_SGE_IO_UNION {
++ struct MPI2_SGE_SIMPLE_UNION MpiSimple;
++ struct MPI2_SGE_CHAIN_UNION MpiChain;
++ union MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple;
++ union MPI2_IEEE_SGE_CHAIN_UNION IeeeChain;
++};
++
++union MPI2_SCSI_IO_CDB_UNION {
++ u8 CDB32[32];
++ struct MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
++ struct MPI2_SGE_SIMPLE_UNION SGE;
++};
++
++/*
++ * RAID SCSI IO Request Message
++ * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST
++ */
++struct MPI2_RAID_SCSI_IO_REQUEST {
++ u16 DevHandle; /* 0x00 */
++ u8 ChainOffset; /* 0x02 */
++ u8 Function; /* 0x03 */
++ u16 Reserved1; /* 0x04 */
++ u8 Reserved2; /* 0x06 */
++ u8 MsgFlags; /* 0x07 */
++ u8 VP_ID; /* 0x08 */
++ u8 VF_ID; /* 0x09 */
++ u16 Reserved3; /* 0x0A */
++ u32 SenseBufferLowAddress; /* 0x0C */
++ u16 SGLFlags; /* 0x10 */
++ u8 SenseBufferLength; /* 0x12 */
++ u8 Reserved4; /* 0x13 */
++ u8 SGLOffset0; /* 0x14 */
++ u8 SGLOffset1; /* 0x15 */
++ u8 SGLOffset2; /* 0x16 */
++ u8 SGLOffset3; /* 0x17 */
++ u32 SkipCount; /* 0x18 */
++ u32 DataLength; /* 0x1C */
++ u32 BidirectionalDataLength; /* 0x20 */
++ u16 IoFlags; /* 0x24 */
++ u16 EEDPFlags; /* 0x26 */
++ u32 EEDPBlockSize; /* 0x28 */
++ u32 SecondaryReferenceTag; /* 0x2C */
++ u16 SecondaryApplicationTag; /* 0x30 */
++ u16 ApplicationTagTranslationMask; /* 0x32 */
++ u8 LUN[8]; /* 0x34 */
++ u32 Control; /* 0x3C */
++ union MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */
++ struct RAID_CONTEXT RaidContext; /* 0x60 */
++ union MPI2_SGE_IO_UNION SGL; /* 0x80 */
++};
++
++/*
++ * MPT RAID MFA IO Descriptor.
++ */
++struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR {
++ u32 RequestFlags:8;
++ u32 MessageAddress1:24; /* bits 31:8*/
++ u32 MessageAddress2; /* bits 61:32 */
++};
++
++/* Default Request Descriptor */
++struct MPI2_DEFAULT_REQUEST_DESCRIPTOR {
++ u8 RequestFlags; /* 0x00 */
++ u8 MSIxIndex; /* 0x01 */
++ u16 SMID; /* 0x02 */
++ u16 LMID; /* 0x04 */
++ u16 DescriptorTypeDependent; /* 0x06 */
++};
++
++/* High Priority Request Descriptor */
++struct MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR {
++ u8 RequestFlags; /* 0x00 */
++ u8 MSIxIndex; /* 0x01 */
++ u16 SMID; /* 0x02 */
++ u16 LMID; /* 0x04 */
++ u16 Reserved1; /* 0x06 */
++};
++
++/* SCSI IO Request Descriptor */
++struct MPI2_SCSI_IO_REQUEST_DESCRIPTOR {
++ u8 RequestFlags; /* 0x00 */
++ u8 MSIxIndex; /* 0x01 */
++ u16 SMID; /* 0x02 */
++ u16 LMID; /* 0x04 */
++ u16 DevHandle; /* 0x06 */
++};
++
++/* SCSI Target Request Descriptor */
++struct MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR {
++ u8 RequestFlags; /* 0x00 */
++ u8 MSIxIndex; /* 0x01 */
++ u16 SMID; /* 0x02 */
++ u16 LMID; /* 0x04 */
++ u16 IoIndex; /* 0x06 */
++};
++
++/* RAID Accelerator Request Descriptor */
++struct MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR {
++ u8 RequestFlags; /* 0x00 */
++ u8 MSIxIndex; /* 0x01 */
++ u16 SMID; /* 0x02 */
++ u16 LMID; /* 0x04 */
++ u16 Reserved; /* 0x06 */
++};
++
++/* union of Request Descriptors */
++union MEGASAS_REQUEST_DESCRIPTOR_UNION {
++ struct MPI2_DEFAULT_REQUEST_DESCRIPTOR Default;
++ struct MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority;
++ struct MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO;
++ struct MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget;
++ struct MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator;
++ struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR MFAIo;
++ union {
++ struct {
++ u32 low;
++ u32 high;
++ } u;
++ u64 Words;
++ };
++};
++
++/* Default Reply Descriptor */
++struct MPI2_DEFAULT_REPLY_DESCRIPTOR {
++ u8 ReplyFlags; /* 0x00 */
++ u8 MSIxIndex; /* 0x01 */
++ u16 DescriptorTypeDependent1; /* 0x02 */
++ u32 DescriptorTypeDependent2; /* 0x04 */
++};
++
++/* Address Reply Descriptor */
++struct MPI2_ADDRESS_REPLY_DESCRIPTOR {
++ u8 ReplyFlags; /* 0x00 */
++ u8 MSIxIndex; /* 0x01 */
++ u16 SMID; /* 0x02 */
++ u32 ReplyFrameAddress; /* 0x04 */
++};
++
++/* SCSI IO Success Reply Descriptor */
++struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR {
++ u8 ReplyFlags; /* 0x00 */
++ u8 MSIxIndex; /* 0x01 */
++ u16 SMID; /* 0x02 */
++ u16 TaskTag; /* 0x04 */
++ u16 Reserved1; /* 0x06 */
++};
++
++/* TargetAssist Success Reply Descriptor */
++struct MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR {
++ u8 ReplyFlags; /* 0x00 */
++ u8 MSIxIndex; /* 0x01 */
++ u16 SMID; /* 0x02 */
++ u8 SequenceNumber; /* 0x04 */
++ u8 Reserved1; /* 0x05 */
++ u16 IoIndex; /* 0x06 */
++};
++
++/* Target Command Buffer Reply Descriptor */
++struct MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR {
++ u8 ReplyFlags; /* 0x00 */
++ u8 MSIxIndex; /* 0x01 */
++ u8 VP_ID; /* 0x02 */
++ u8 Flags; /* 0x03 */
++ u16 InitiatorDevHandle; /* 0x04 */
++ u16 IoIndex; /* 0x06 */
++};
++
++/* RAID Accelerator Success Reply Descriptor */
++struct MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR {
++ u8 ReplyFlags; /* 0x00 */
++ u8 MSIxIndex; /* 0x01 */
++ u16 SMID; /* 0x02 */
++ u32 Reserved; /* 0x04 */
++};
++
++/* union of Reply Descriptors */
++union MPI2_REPLY_DESCRIPTORS_UNION {
++ struct MPI2_DEFAULT_REPLY_DESCRIPTOR Default;
++ struct MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply;
++ struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess;
++ struct MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess;
++ struct MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
++ struct MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR
++ RAIDAcceleratorSuccess;
++ u64 Words;
++};
++
++/* IOCInit Request message */
++struct MPI2_IOC_INIT_REQUEST {
++ u8 WhoInit; /* 0x00 */
++ u8 Reserved1; /* 0x01 */
++ u8 ChainOffset; /* 0x02 */
++ u8 Function; /* 0x03 */
++ u16 Reserved2; /* 0x04 */
++ u8 Reserved3; /* 0x06 */
++ u8 MsgFlags; /* 0x07 */
++ u8 VP_ID; /* 0x08 */
++ u8 VF_ID; /* 0x09 */
++ u16 Reserved4; /* 0x0A */
++ u16 MsgVersion; /* 0x0C */
++ u16 HeaderVersion; /* 0x0E */
++ u32 Reserved5; /* 0x10 */
++ u16 Reserved6; /* 0x14 */
++ u8 Reserved7; /* 0x16 */
++ u8 HostMSIxVectors; /* 0x17 */
++ u16 Reserved8; /* 0x18 */
++ u16 SystemRequestFrameSize; /* 0x1A */
++ u16 ReplyDescriptorPostQueueDepth; /* 0x1C */
++ u16 ReplyFreeQueueDepth; /* 0x1E */
++ u32 SenseBufferAddressHigh; /* 0x20 */
++ u32 SystemReplyAddressHigh; /* 0x24 */
++ u64 SystemRequestFrameBaseAddress; /* 0x28 */
++ u64 ReplyDescriptorPostQueueAddress;/* 0x30 */
++ u64 ReplyFreeQueueAddress; /* 0x38 */
++ u64 TimeStamp; /* 0x40 */
++};
++
++/* mrpriv defines */
++#define MR_PD_INVALID 0xFFFF
++#define MAX_SPAN_DEPTH 8
++#define MAX_RAIDMAP_SPAN_DEPTH (MAX_SPAN_DEPTH)
++#define MAX_ROW_SIZE 32
++#define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE)
++#define MAX_LOGICAL_DRIVES 64
++#define MAX_RAIDMAP_LOGICAL_DRIVES (MAX_LOGICAL_DRIVES)
++#define MAX_RAIDMAP_VIEWS (MAX_LOGICAL_DRIVES)
++#define MAX_ARRAYS 128
++#define MAX_RAIDMAP_ARRAYS (MAX_ARRAYS)
++#define MAX_PHYSICAL_DEVICES 256
++#define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES)
++#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101
++
++struct MR_DEV_HANDLE_INFO {
++ u16 curDevHdl;
++ u8 validHandles;
++ u8 reserved;
++ u16 devHandle[2];
++};
++
++struct MR_ARRAY_INFO {
++ u16 pd[MAX_RAIDMAP_ROW_SIZE];
++};
++
++struct MR_QUAD_ELEMENT {
++ u64 logStart;
++ u64 logEnd;
++ u64 offsetInSpan;
++ u32 diff;
++ u32 reserved1;
++};
++
++struct MR_SPAN_INFO {
++ u32 noElements;
++ u32 reserved1;
++ struct MR_QUAD_ELEMENT quad[MAX_RAIDMAP_SPAN_DEPTH];
++};
++
++struct MR_LD_SPAN {
++ u64 startBlk;
++ u64 numBlks;
++ u16 arrayRef;
++ u8 reserved[6];
++};
++
++struct MR_SPAN_BLOCK_INFO {
++ u64 num_rows;
++ struct MR_LD_SPAN span;
++ struct MR_SPAN_INFO block_span_info;
++};
++
++struct MR_LD_RAID {
++ struct {
++ u32 fpCapable:1;
++ u32 reserved5:3;
++ u32 ldPiMode:4;
++ u32 pdPiMode:4;
++ u32 encryptionType:8;
++ u32 fpWriteCapable:1;
++ u32 fpReadCapable:1;
++ u32 fpWriteAcrossStripe:1;
++ u32 fpReadAcrossStripe:1;
++ u32 reserved4:8;
++ } capability;
++ u32 reserved6;
++ u64 size;
++ u8 spanDepth;
++ u8 level;
++ u8 stripeShift;
++ u8 rowSize;
++ u8 rowDataSize;
++ u8 writeMode;
++ u8 PRL;
++ u8 SRL;
++ u16 targetId;
++ u8 ldState;
++ u8 regTypeReqOnWrite;
++ u8 modFactor;
++ u8 reserved2[1];
++ u16 seqNum;
++
++ struct {
++ u32 ldSyncRequired:1;
++ u32 reserved:31;
++ } flags;
++
++ u8 reserved3[0x5C];
++};
++
++struct MR_LD_SPAN_MAP {
++ struct MR_LD_RAID ldRaid;
++ u8 dataArmMap[MAX_RAIDMAP_ROW_SIZE];
++ struct MR_SPAN_BLOCK_INFO spanBlock[MAX_RAIDMAP_SPAN_DEPTH];
++};
++
++struct MR_FW_RAID_MAP {
++ u32 totalSize;
++ union {
++ struct {
++ u32 maxLd;
++ u32 maxSpanDepth;
++ u32 maxRowSize;
++ u32 maxPdCount;
++ u32 maxArrays;
++ } validationInfo;
++ u32 version[5];
++ u32 reserved1[5];
++ };
++
++ u32 ldCount;
++ u32 Reserved1;
++ u8 ldTgtIdToLd[MAX_RAIDMAP_LOGICAL_DRIVES+
++ MAX_RAIDMAP_VIEWS];
++ u8 fpPdIoTimeoutSec;
++ u8 reserved2[7];
++ struct MR_ARRAY_INFO arMapInfo[MAX_RAIDMAP_ARRAYS];
++ struct MR_DEV_HANDLE_INFO devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES];
++ struct MR_LD_SPAN_MAP ldSpanMap[1];
++};
++
++struct IO_REQUEST_INFO {
++ u64 ldStartBlock;
++ u32 numBlocks;
++ u16 ldTgtId;
++ u8 isRead;
++ u16 devHandle;
++ u64 pdBlock;
++ u8 fpOkForIo;
++};
++
++struct MR_LD_TARGET_SYNC {
++ u8 targetId;
++ u8 reserved;
++ u16 seqNum;
++};
++
++#define IEEE_SGE_FLAGS_ADDR_MASK (0x03)
++#define IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00)
++#define IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01)
++#define IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02)
++#define IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03)
++#define IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80)
++#define IEEE_SGE_FLAGS_END_OF_LIST (0x40)
++
++struct megasas_register_set;
++struct megasas_instance;
++
++union desc_word {
++ u64 word;
++ struct {
++ u32 low;
++ u32 high;
++ } u;
++};
++
++struct megasas_cmd_fusion {
++ struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
++ dma_addr_t io_request_phys_addr;
++
++ union MPI2_SGE_IO_UNION *sg_frame;
++ dma_addr_t sg_frame_phys_addr;
++
++ u8 *sense;
++ dma_addr_t sense_phys_addr;
++
++ struct list_head list;
++ struct scsi_cmnd *scmd;
++ struct megasas_instance *instance;
++
++ u8 retry_for_fw_reset;
++ union MEGASAS_REQUEST_DESCRIPTOR_UNION *request_desc;
++
++ /*
++ * Context for a MFI frame.
++ * Used to get the mfi cmd from list when a MFI cmd is completed
++ */
++ u32 sync_cmd_idx;
++ u32 index;
++ u8 flags;
++};
++
++struct LD_LOAD_BALANCE_INFO {
++ u8 loadBalanceFlag;
++ u8 reserved1;
++ u16 raid1DevHandle[2];
++ atomic_t scsi_pending_cmds[2];
++ u64 last_accessed_block[2];
++};
++
++struct MR_FW_RAID_MAP_ALL {
++ struct MR_FW_RAID_MAP raidMap;
++ struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES - 1];
++} __attribute__ ((packed));
++
++struct fusion_context {
++ struct megasas_cmd_fusion **cmd_list;
++ struct list_head cmd_pool;
++
++ spinlock_t cmd_pool_lock;
++
++ dma_addr_t req_frames_desc_phys;
++ u8 *req_frames_desc;
++
++ struct dma_pool *io_request_frames_pool;
++ dma_addr_t io_request_frames_phys;
++ u8 *io_request_frames;
++
++ struct dma_pool *sg_dma_pool;
++ struct dma_pool *sense_dma_pool;
++
++ dma_addr_t reply_frames_desc_phys;
++ union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
++ struct dma_pool *reply_frames_desc_pool;
++
++ u16 last_reply_idx;
++
++ u32 reply_q_depth;
++ u32 request_alloc_sz;
++ u32 reply_alloc_sz;
++ u32 io_frames_alloc_sz;
++
++ u16 max_sge_in_main_msg;
++ u16 max_sge_in_chain;
++
++ u8 chain_offset_io_request;
++ u8 chain_offset_mfi_pthru;
++
++ struct MR_FW_RAID_MAP_ALL *ld_map[2];
++ dma_addr_t ld_map_phys[2];
++
++ u32 map_sz;
++ u8 fast_path_io;
++ struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES];
++};
++
++union desc_value {
++ u64 word;
++ struct {
++ u32 low;
++ u32 high;
++ } u;
++};
++
++#endif /* _MEGARAID_SAS_FUSION_H_ */
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0018-megaraid_sas-fix-instance-access-in-megasas_reset_timer.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0018-megaraid_sas-fix-instance-access-in-megasas_reset_timer.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,48 @@
+From 205bad93c4d085c41b07107011e91172e89fa057 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 13 Oct 2011 16:01:12 -0700
+Subject: [PATCH 18/53] [SCSI] megaraid_sas: Fix instance access in megasas_reset_timer
+
+commit f575c5d3ebdca3b0482847d8fcba971767754a9e upstream.
+
+The following patch for megaraid_sas will fix a potential bad pointer access
+in megasas_reset_timer(), when a MegaRAID 9265/9285 or 9360/9380 gets a
+timeout. megasas_build_io_fusion() sets SCp.ptr to be a struct
+megasas_cmd_fusion *, but then megasas_reset_timer() was casting SCp.ptr to be
+a struct megasas_cmd *, then trying to access cmd->instance, which is invalid.
+
+Just loading instance from scmd->device->host->hostdata in
+megasas_reset_timer() fixes the issue.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index d532b330e03f..31c612905ef6 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -1744,7 +1744,6 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
+ static enum
+ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+ {
+- struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
+ struct megasas_instance *instance;
+ unsigned long flags;
+
+@@ -1753,7 +1752,7 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+ return BLK_EH_NOT_HANDLED;
+ }
+
+- instance = cmd->instance;
++ instance = (struct megasas_instance *)scmd->device->host->hostdata;
+ if (!(instance->flag & MEGASAS_FW_BUSY)) {
+ /* FW is busy, throttle IO */
+ spin_lock_irqsave(instance->host->host_lock, flags);
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0019-megaraid_sas-tape-drive-support-fix.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0019-megaraid_sas-tape-drive-support-fix.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,44 @@
+From c5e3548418b026f10d6644305d10ee2ac5c4ab14 Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Tue, 6 Oct 2009 14:12:21 -0600
+Subject: [PATCH 19/53] [SCSI] megaraid_sas: tape drive support fix
+
+commit 8d56825321339f0ef7ad08eb58332e1836881e3b upstream.
+
+Add the Tape drive fix to the megaraid_sas driver: If the command is
+for the tape device, set the FW pthru timeout to the os layer timeout
+value.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 31c612905ef6..e9574ebaedad 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -1095,6 +1095,17 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
+
+ /*
++ * If the command is for the tape device, set the
++ * pthru timeout to the os layer timeout value.
++ */
++ if (scp->device->type == TYPE_TAPE) {
++ if ((scp->request->timeout / HZ) > 0xFFFF)
++ pthru->timeout = 0xFFFF;
++ else
++ pthru->timeout = scp->request->timeout / HZ;
++ }
++
++ /*
+ * Construct SGL
+ */
+ if (instance->flag_ieee == 1) {
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0020-megaraid_sas-report-system-pds-to-os.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0020-megaraid_sas-report-system-pds-to-os.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,142 @@
+From 9dcd9cb49827ebaffb9c4242bec7ea71c81c2e1d Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Tue, 6 Oct 2009 14:33:06 -0600
+Subject: [PATCH 20/53] [SCSI] megaraid_sas: report system PDs to OS
+
+commit 044833b572b96afe91506a0edec42efd84ba4939 upstream.
+
+When OS issue inquiry, it will check driver's internal pd_list.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 91 ++++++++++++++++++++++---------
+ 1 file changed, 65 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index e9574ebaedad..a7e693259a40 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -1467,24 +1467,76 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
+ return 0;
+ }
+
++static struct megasas_instance *megasas_lookup_instance(u16 host_no)
++{
++ int i;
++
++ for (i = 0; i < megasas_mgmt_info.max_index; i++) {
++
++ if ((megasas_mgmt_info.instance[i]) &&
++ (megasas_mgmt_info.instance[i]->host->host_no == host_no))
++ return megasas_mgmt_info.instance[i];
++ }
++
++ return NULL;
++}
++
+ static int megasas_slave_configure(struct scsi_device *sdev)
+ {
++ u16 pd_index = 0;
++ struct megasas_instance *instance ;
++
++ instance = megasas_lookup_instance(sdev->host->host_no);
++
+ /*
+- * Don't export physical disk devices to the disk driver.
+- *
+- * FIXME: Currently we don't export them to the midlayer at all.
+- * That will be fixed once LSI engineers have audited the
+- * firmware for possible issues.
+- */
+- if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && sdev->type == TYPE_DISK)
++ * Don't export physical disk devices to the disk driver.
++ *
++ * FIXME: Currently we don't export them to the midlayer at all.
++ * That will be fixed once LSI engineers have audited the
++ * firmware for possible issues.
++ */
++ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
++ sdev->type == TYPE_DISK) {
++ pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
++ sdev->id;
++ if (instance->pd_list[pd_index].driveState ==
++ MR_PD_STATE_SYSTEM) {
++ blk_queue_rq_timeout(sdev->request_queue,
++ MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
++ return 0;
++ }
+ return -ENXIO;
++ }
+
+ /*
+- * The RAID firmware may require extended timeouts.
+- */
+- if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS)
+- blk_queue_rq_timeout(sdev->request_queue,
+- MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
++ * The RAID firmware may require extended timeouts.
++ */
++ blk_queue_rq_timeout(sdev->request_queue,
++ MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
++ return 0;
++}
++
++static int megasas_slave_alloc(struct scsi_device *sdev)
++{
++ u16 pd_index = 0;
++ struct megasas_instance *instance ;
++ instance = megasas_lookup_instance(sdev->host->host_no);
++ if ((sdev->channel < MEGASAS_MAX_PD_CHANNELS) &&
++ (sdev->type == TYPE_DISK)) {
++ /*
++ * Open the OS scan to the SYSTEM PD
++ */
++ pd_index =
++ (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
++ sdev->id;
++ if ((instance->pd_list[pd_index].driveState ==
++ MR_PD_STATE_SYSTEM) &&
++ (instance->pd_list[pd_index].driveType ==
++ TYPE_DISK)) {
++ return 0;
++ }
++ return -ENXIO;
++ }
+ return 0;
+ }
+
+@@ -1914,6 +1966,7 @@ static struct scsi_host_template megasas_template = {
+ .name = "LSI SAS based MegaRAID driver",
+ .proc_name = "megaraid_sas",
+ .slave_configure = megasas_slave_configure,
++ .slave_alloc = megasas_slave_alloc,
+ .queuecommand = megasas_queue_command,
+ .eh_device_reset_handler = megasas_reset_device,
+ .eh_bus_reset_handler = megasas_reset_bus_host,
+@@ -4545,20 +4598,6 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
+ return error;
+ }
+
+-static struct megasas_instance *megasas_lookup_instance(u16 host_no)
+-{
+- int i;
+-
+- for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+-
+- if ((megasas_mgmt_info.instance[i]) &&
+- (megasas_mgmt_info.instance[i]->host->host_no == host_no))
+- return megasas_mgmt_info.instance[i];
+- }
+-
+- return NULL;
+-}
+-
+ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
+ {
+ struct megasas_iocpacket __user *user_ioc =
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0021-megaraid_sas-use-the-firmware-boot-timeout-when-waiting-for-commands.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0021-megaraid_sas-use-the-firmware-boot-timeout-when-waiting-for-commands.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,130 @@
+From 7efd8525e290c2b6ae3eed07e3e4cf442d77bafb Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Tue, 6 Oct 2009 14:52:20 -0600
+Subject: [PATCH 21/53] [SCSI] megaraid_sas: use the firmware boot timeout when waiting for commands
+
+commit 7218df69e3609d1fcf4d83cf8f3fc89dbfbf82a8 upstream.
+
+use the constant MEGASAS_RESET_WAIT_TIME when waiting for firmware
+commands to complete (currently 3 minutes).
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 28 +++++++++++++++++-----------
+ 1 file changed, 17 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index a7e693259a40..4da5e8f5c42f 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -2505,6 +2505,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ u8 max_wait;
+ u32 fw_state;
+ u32 cur_state;
++ u32 abs_state, curr_abs_state;
+
+ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+
+@@ -2514,6 +2515,9 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+
+ while (fw_state != MFI_STATE_READY) {
+
++ abs_state =
++ instance->instancet->read_fw_status_reg(instance->reg_set);
++
+ switch (fw_state) {
+
+ case MFI_STATE_FAULT:
+@@ -2540,7 +2544,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ &instance->reg_set->inbound_doorbell);
+ }
+
+- max_wait = 2;
++ max_wait = MEGASAS_RESET_WAIT_TIME;
+ cur_state = MFI_STATE_WAIT_HANDSHAKE;
+ break;
+
+@@ -2557,7 +2561,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ writel(MFI_INIT_HOTPLUG,
+ &instance->reg_set->inbound_doorbell);
+
+- max_wait = 10;
++ max_wait = MEGASAS_RESET_WAIT_TIME;
+ cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
+ break;
+
+@@ -2590,7 +2594,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ writel(MFI_RESET_FLAGS,
+ &instance->reg_set->inbound_doorbell);
+
+- max_wait = 60;
++ max_wait = MEGASAS_RESET_WAIT_TIME;
+ cur_state = MFI_STATE_OPERATIONAL;
+ break;
+
+@@ -2598,32 +2602,32 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ /*
+ * This state should not last for more than 2 seconds
+ */
+- max_wait = 2;
++ max_wait = MEGASAS_RESET_WAIT_TIME;
+ cur_state = MFI_STATE_UNDEFINED;
+ break;
+
+ case MFI_STATE_BB_INIT:
+- max_wait = 2;
++ max_wait = MEGASAS_RESET_WAIT_TIME;
+ cur_state = MFI_STATE_BB_INIT;
+ break;
+
+ case MFI_STATE_FW_INIT:
+- max_wait = 20;
++ max_wait = MEGASAS_RESET_WAIT_TIME;
+ cur_state = MFI_STATE_FW_INIT;
+ break;
+
+ case MFI_STATE_FW_INIT_2:
+- max_wait = 20;
++ max_wait = MEGASAS_RESET_WAIT_TIME;
+ cur_state = MFI_STATE_FW_INIT_2;
+ break;
+
+ case MFI_STATE_DEVICE_SCAN:
+- max_wait = 20;
++ max_wait = MEGASAS_RESET_WAIT_TIME;
+ cur_state = MFI_STATE_DEVICE_SCAN;
+ break;
+
+ case MFI_STATE_FLUSH_CACHE:
+- max_wait = 20;
++ max_wait = MEGASAS_RESET_WAIT_TIME;
+ cur_state = MFI_STATE_FLUSH_CACHE;
+ break;
+
+@@ -2639,8 +2643,10 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ for (i = 0; i < (max_wait * 1000); i++) {
+ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &
+ MFI_STATE_MASK ;
++ curr_abs_state =
++ instance->instancet->read_fw_status_reg(instance->reg_set);
+
+- if (fw_state == cur_state) {
++ if (abs_state == curr_abs_state) {
+ msleep(1);
+ } else
+ break;
+@@ -2649,7 +2655,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ /*
+ * Return error if fw_state hasn't changed after max_wait
+ */
+- if (fw_state == cur_state) {
++ if (curr_abs_state == abs_state) {
+ printk(KERN_DEBUG "FW state [%d] hasn't changed "
+ "in %d secs\n", fw_state, max_wait);
+ return -ENODEV;
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0022-megaraid_sas-update-version-number-and-documentation.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0022-megaraid_sas-update-version-number-and-documentation.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,120 @@
+From 32ce6408b5d67e3db1533ae61c80b089897e3e97 Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Tue, 6 Oct 2009 14:55:09 -0600
+Subject: [PATCH 22/53] [SCSI] megaraid_sas: Update version number and documentation
+
+commit a0b7736828f7615823a7dec680632656d9a9edde upstream.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ Documentation/scsi/ChangeLog.megaraid_sas | 62 +++++++++++++++++++++++++++++++
+ drivers/scsi/megaraid/megaraid_sas.h | 6 +--
+ drivers/scsi/megaraid/megaraid_sas_base.c | 2 +-
+ 3 files changed, 66 insertions(+), 4 deletions(-)
+
+diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
+index c851ef497795..151a7b718b8c 100644
+--- a/Documentation/scsi/ChangeLog.megaraid_sas
++++ b/Documentation/scsi/ChangeLog.megaraid_sas
+@@ -1,3 +1,65 @@
++1 Release Date : Tues. July 28, 2009 10:12:45 PST 2009 -
++ (emaild-id:megaraidlinux at lsi.com)
++ Bo Yang
++
++2 Current Version : 00.00.04.12
++3 Older Version : 00.00.04.10
++
++1. Change the AEN sys PD update from scsi_scan to
++ scsi_add_device and scsi_remove_device.
++2. Takeoff the debug print-out in aen_polling routine.
++
++1 Release Date : Thur. July 02, 2009 10:12:45 PST 2009 -
++ (emaild-id:megaraidlinux at lsi.com)
++ Bo Yang
++
++2 Current Version : 00.00.04.10
++3 Older Version : 00.00.04.08
++
++1. Add the 3 mins timeout during the controller initialize.
++2. Add the fix for 64bit sense date errors.
++
++1 Release Date : Tues. May 05, 2009 10:12:45 PST 2009 -
++ (emaild-id:megaraidlinux at lsi.com)
++ Bo Yang
++
++2 Current Version : 00.00.04.08
++3 Older Version : 00.00.04.06
++
++1. Add the fix of pending in FW after deleted the logic drives.
++2. Add the fix of deallocating memory after get pdlist.
++
++1 Release Date : Tues. March 26, 2009 10:12:45 PST 2009 -
++ (emaild-id:megaraidlinux at lsi.com)
++ Bo Yang
++
++2 Current Version : 00.00.04.06
++3 Older Version : 00.00.04.04
++
++1. Add the fix of the driver cmd empty fix of the driver cmd empty.
++2. Add the fix of the driver MSM AEN CMD cause the system slow.
++
++1 Release Date : Tues. March 03, 2009 10:12:45 PST 2009 -
++ (emaild-id:megaraidlinux at lsi.com)
++ Bo Yang
++
++2 Current Version : 00.00.04.04
++3 Older Version : 00.00.04.01
++
++1. Add the Tape drive fix to the driver: If the command is for
++ the tape device, set the pthru timeout to the os layer timeout value.
++
++2. Add Poll_wait mechanism to Gen-2 Linux driv.
++ In the aen handler, driver needs to wakeup poll handler similar to
++ the way it raises SIGIO.
++
++3. Add new controller new SAS2 support to the driver.
++
++4. Report the unconfigured PD (system PD) to OS.
++
++5. Add the IEEE SGL support to the driver
++
++6. Reasign the Application cmds to SAS2 controller
+
+ 1 Release Date : Thur.July. 24 11:41:51 PST 2008 -
+ (emaild-id:megaraidlinux at lsi.com)
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 887f33ebcf21..d98fca4ae70f 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -18,9 +18,9 @@
+ /*
+ * MegaRAID SAS Driver meta data
+ */
+-#define MEGASAS_VERSION "00.00.04.01"
+-#define MEGASAS_RELDATE "July 24, 2008"
+-#define MEGASAS_EXT_VERSION "Thu July 24 11:41:51 PST 2008"
++#define MEGASAS_VERSION "00.00.04.12-rc1"
++#define MEGASAS_RELDATE "Sep. 17, 2009"
++#define MEGASAS_EXT_VERSION "Thu Sep. 17 11:41:51 PST 2009"
+
+ /*
+ * Device IDs
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 4da5e8f5c42f..d3aa84309025 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -10,7 +10,7 @@
+ * 2 of the License, or (at your option) any later version.
+ *
+ * FILE : megaraid_sas.c
+- * Version : v00.00.04.01-rc1
++ * Version : v00.00.04.12-rc1
+ *
+ * Authors:
+ * (email-id : megaraidlinux at lsi.com)
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0023-megaraid_sas-zero-pad_0-in-mfi-structure.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0023-megaraid_sas-zero-pad_0-in-mfi-structure.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,81 @@
+From 3f7e260e80ed745924528c60e31d0bce1f3c315f Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Sun, 6 Dec 2009 08:24:21 -0700
+Subject: [PATCH 23/53] [SCSI] megaraid_sas: Zero pad_0 in mfi structure
+
+commit 780a3762fb9208748baac5aa9c63a4d4c9287753 upstream.
+
+Add the pad_0 in mfi frame structure to 0 to fix the context value
+larger than 32bit value issue.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index d3aa84309025..8bd792452866 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -1089,6 +1089,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
+ pthru->lun = scp->device->lun;
+ pthru->cdb_len = scp->cmd_len;
+ pthru->timeout = 0;
++ pthru->pad_0 = 0;
+ pthru->flags = flags;
+ pthru->data_xfer_len = scsi_bufflen(scp);
+
+@@ -2956,6 +2957,7 @@ megasas_get_pd_list(struct megasas_instance *instance)
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_READ;
+ dcmd->timeout = 0;
++ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
+ dcmd->opcode = MR_DCMD_PD_LIST_QUERY;
+ dcmd->sgl.sge32[0].phys_addr = ci_h;
+@@ -3125,6 +3127,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_READ;
+ dcmd->timeout = 0;
++ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = sizeof(struct megasas_ctrl_info);
+ dcmd->opcode = MR_DCMD_CTRL_GET_INFO;
+ dcmd->sgl.sge32[0].phys_addr = ci_h;
+@@ -3535,6 +3538,7 @@ megasas_get_seq_num(struct megasas_instance *instance,
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_READ;
+ dcmd->timeout = 0;
++ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = sizeof(struct megasas_evt_log_info);
+ dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;
+ dcmd->sgl.sge32[0].phys_addr = el_info_h;
+@@ -3649,6 +3653,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_READ;
+ dcmd->timeout = 0;
++ dcmd->pad_0 = 0;
+ instance->last_seq_num = seq_num;
+ dcmd->data_xfer_len = sizeof(struct megasas_evt_detail);
+ dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
+@@ -4047,6 +4052,7 @@ static void megasas_flush_cache(struct megasas_instance *instance)
+ dcmd->sge_count = 0;
+ dcmd->flags = MFI_FRAME_DIR_NONE;
+ dcmd->timeout = 0;
++ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = 0;
+ dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;
+ dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
+@@ -4091,6 +4097,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
+ dcmd->sge_count = 0;
+ dcmd->flags = MFI_FRAME_DIR_NONE;
+ dcmd->timeout = 0;
++ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = 0;
+ dcmd->opcode = opcode;
+
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0024-megaraid_sas-version-and-documentation-update.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0024-megaraid_sas-version-and-documentation-update.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,74 @@
+From e6b88128d46c31cedf537ba76384a8ce5acef3ef Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Sun, 6 Dec 2009 08:42:28 -0700
+Subject: [PATCH 24/53] [SCSI] megaraid_sas: version and documentation update
+
+commit 63bad45db1d4e8aafe0633c5741c9720641f336a upstream.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ Documentation/scsi/ChangeLog.megaraid_sas | 16 ++++++++++++++++
+ drivers/scsi/megaraid/megaraid_sas.h | 6 +++---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 2 +-
+ 3 files changed, 20 insertions(+), 4 deletions(-)
+
+diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
+index 151a7b718b8c..07e252c25b18 100644
+--- a/Documentation/scsi/ChangeLog.megaraid_sas
++++ b/Documentation/scsi/ChangeLog.megaraid_sas
+@@ -1,3 +1,19 @@
++1 Release Date : Thur. Oct 29, 2009 09:12:45 PST 2009 -
++ (emaild-id:megaraidlinux at lsi.com)
++ Bo Yang
++
++2 Current Version : 00.00.04.17.1-rc1
++3 Older Version : 00.00.04.12
++
++1. Add the pad_0 in mfi frame structure to 0 to fix the
++ context value larger than 32bit value issue.
++
++2. Add the logic drive list to the driver. Driver will
++ keep the logic drive list internal after driver load.
++
++3. driver fixed the device update issue after get the AEN
++ PD delete/ADD, LD add/delete from FW.
++
+ 1 Release Date : Tues. July 28, 2009 10:12:45 PST 2009 -
+ (emaild-id:megaraidlinux at lsi.com)
+ Bo Yang
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index d98fca4ae70f..8f03bcfd66ad 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -18,9 +18,9 @@
+ /*
+ * MegaRAID SAS Driver meta data
+ */
+-#define MEGASAS_VERSION "00.00.04.12-rc1"
+-#define MEGASAS_RELDATE "Sep. 17, 2009"
+-#define MEGASAS_EXT_VERSION "Thu Sep. 17 11:41:51 PST 2009"
++#define MEGASAS_VERSION "00.00.04.17.1-rc1"
++#define MEGASAS_RELDATE "Oct. 29, 2009"
++#define MEGASAS_EXT_VERSION "Thu. Oct. 29, 11:41:51 PST 2009"
+
+ /*
+ * Device IDs
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 8bd792452866..b797ed7a4882 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -10,7 +10,7 @@
+ * 2 of the License, or (at your option) any later version.
+ *
+ * FILE : megaraid_sas.c
+- * Version : v00.00.04.12-rc1
++ * Version : v00.00.04.17.1-rc1
+ *
+ * Authors:
+ * (email-id : megaraidlinux at lsi.com)
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0025-megaraid_sas-support-devices-update-flag.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0025-megaraid_sas-support-devices-update-flag.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,92 @@
+From 43d08b393de5dea0ed2ec8138687b3acbe2257e7 Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Mon, 11 Oct 2010 06:59:20 -0600
+Subject: [PATCH 25/53] [SCSI] megaraid_sas: support devices update flag
+
+commit 837f5fe89c843422452ef5e1a7e3d20e9caa3268 upstream.
+
+Driver added the Device update flag to tell LSI application driver
+whether to do the device Update. LSI MegaRAID SAS application will
+check this flag to decide if it needs to update the Device or not.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index b797ed7a4882..2a5e542e718e 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -110,6 +110,7 @@ static int megasas_poll_wait_aen;
+ static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
+ static u32 support_poll_for_event;
+ u32 megasas_dbg_lvl;
++static u32 support_device_change;
+
+ /* define lock for aen poll */
+ spinlock_t poll_aen_lock;
+@@ -4903,6 +4904,15 @@ megasas_sysfs_show_support_poll_for_event(struct device_driver *dd, char *buf)
+ static DRIVER_ATTR(support_poll_for_event, S_IRUGO,
+ megasas_sysfs_show_support_poll_for_event, NULL);
+
++ static ssize_t
++megasas_sysfs_show_support_device_change(struct device_driver *dd, char *buf)
++{
++ return sprintf(buf, "%u\n", support_device_change);
++}
++
++static DRIVER_ATTR(support_device_change, S_IRUGO,
++ megasas_sysfs_show_support_device_change, NULL);
++
+ static ssize_t
+ megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
+ {
+@@ -5224,6 +5234,7 @@ static int __init megasas_init(void)
+ MEGASAS_EXT_VERSION);
+
+ support_poll_for_event = 2;
++ support_device_change = 1;
+
+ memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
+
+@@ -5264,6 +5275,11 @@ static int __init megasas_init(void)
+ goto err_dcf_support_poll_for_event;
+
+ rval = driver_create_file(&megasas_pci_driver.driver,
++ &driver_attr_support_device_change);
++ if (rval)
++ goto err_dcf_support_device_change;
++
++ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_dbg_lvl);
+ if (rval)
+ goto err_dcf_dbg_lvl;
+@@ -5279,6 +5295,10 @@ err_dcf_poll_mode_io:
+ &driver_attr_dbg_lvl);
+ err_dcf_dbg_lvl:
+ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_support_device_change);
++
++err_dcf_support_device_change:
++ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_poll_for_event);
+
+ err_dcf_support_poll_for_event:
+@@ -5304,6 +5324,10 @@ static void __exit megasas_exit(void)
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_dbg_lvl);
+ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_support_poll_for_event);
++ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_support_device_change);
++ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_release_date);
+ driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0026-megaraid_sas-add-input-parameter-for-max_sectors.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0026-megaraid_sas-add-input-parameter-for-max_sectors.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,83 @@
+From e2adcc06886a309a9b7072f74476a66d8c44ed30 Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Tue, 12 Oct 2010 07:18:50 -0600
+Subject: [PATCH 26/53] [SCSI] megaraid_sas: Add input parameter for max_sectors
+
+commit 1fd106851698e9a858d20ab0e0f0afd5e9ec9332 upstream.
+
+Driver add the input parameters support for max_sectors for megaraid
+sas gen2 chip. Customer can set the max_sectors support to 1MB for
+gen2 chip during the driver load.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.h | 1 +
+ drivers/scsi/megaraid/megaraid_sas_base.c | 30 ++++++++++++++++++++++++++++++
+ 2 files changed, 31 insertions(+)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 8f03bcfd66ad..a029a6cd1341 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -707,6 +707,7 @@ struct megasas_ctrl_info {
+ #define MEGASAS_MAX_LD_IDS (MEGASAS_MAX_LD_CHANNELS * \
+ MEGASAS_MAX_DEV_PER_CHANNEL)
+
++#define MEGASAS_MAX_SECTORS (2*1024)
+ #define MEGASAS_DBG_LVL 1
+
+ #define MEGASAS_FW_BUSY 1
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 2a5e542e718e..ec17c0a1b127 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -61,6 +61,15 @@ static int msix_disable;
+ module_param(msix_disable, int, S_IRUGO);
+ MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
+
++/*
++ * Number of sectors per IO command
++ * Will be set in megasas_init_mfi if user does not provide
++ */
++static unsigned int max_sectors;
++module_param_named(max_sectors, max_sectors, int, 0);
++MODULE_PARM_DESC(max_sectors,
++ "Maximum number of sectors per IO command");
++
+ MODULE_LICENSE("GPL");
+ MODULE_VERSION(MEGASAS_VERSION);
+ MODULE_AUTHOR("megaraidlinux at lsi.com");
+@@ -3733,6 +3742,27 @@ static int megasas_io_attach(struct megasas_instance *instance)
+ instance->max_fw_cmds - MEGASAS_INT_CMDS;
+ host->this_id = instance->init_id;
+ host->sg_tablesize = instance->max_num_sge;
++ /*
++ * Check if the module parameter value for max_sectors can be used
++ */
++ if (max_sectors && max_sectors < instance->max_sectors_per_req)
++ instance->max_sectors_per_req = max_sectors;
++ else {
++ if (max_sectors) {
++ if (((instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
++ (instance->pdev->device ==
++ PCI_DEVICE_ID_LSI_SAS0079GEN2)) &&
++ (max_sectors <= MEGASAS_MAX_SECTORS)) {
++ instance->max_sectors_per_req = max_sectors;
++ } else {
++ printk(KERN_INFO "megasas: max_sectors should be > 0"
++ "and <= %d (or < 1MB for GEN2 controller)\n",
++ instance->max_sectors_per_req);
++ }
++ }
++ }
++
+ host->max_sectors = instance->max_sectors_per_req;
+ host->cmd_per_lun = MEGASAS_DEFAULT_CMD_PER_LUN;
+ host->max_channel = MEGASAS_MAX_CHANNELS - 1;
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0027-megaraid_sas-add-three-times-online-controller-reset.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0027-megaraid_sas-add-three-times-online-controller-reset.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,140 @@
+From 30e6d6db4faa246df1bcf2b5a01ec84c0dffec54 Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Tue, 12 Oct 2010 07:20:27 -0600
+Subject: [PATCH 27/53] [SCSI] megaraid_sas: Add three times Online controller reset
+
+commit 707e09bd867cee4cd0e5bff0a67513aa0232fcec upstream.
+
+If fw didn't raise the interrupt with the fw state change to driver
+and fw goes to failure state, driver Will check the FW state in
+driver's timeout routine and issue the reset if need. Driver will do
+the OCR upto three times until kill adapter. Also driver will issue
+OCR before driver kill adapter even if fw in operational state.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 70 ++++++++++++++++++++++++++++++-
+ 1 file changed, 69 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index ec17c0a1b127..733f7120817e 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -783,6 +783,10 @@ static int
+ megasas_check_reset_gen2(struct megasas_instance *instance,
+ struct megasas_register_set __iomem *regs)
+ {
++ if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
++ return 1;
++ }
++
+ return 0;
+ }
+
+@@ -992,6 +996,7 @@ megasas_make_sgl_skinny(struct megasas_instance *instance,
+ mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
+ mfi_sgl->sge_skinny[i].phys_addr =
+ sg_dma_address(os_sgl);
++ mfi_sgl->sge_skinny[i].flag = 0;
+ }
+ }
+ return sge_count;
+@@ -1645,6 +1650,28 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+ megasas_check_and_restore_queue_depth(instance);
+ }
+
++static void
++megasas_internal_reset_defer_cmds(struct megasas_instance *instance);
++
++static void
++process_fw_state_change_wq(struct work_struct *work);
++
++void megasas_do_ocr(struct megasas_instance *instance)
++{
++ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
++ (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
++ (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
++ *instance->consumer = MEGASAS_ADPRESET_INPROG_SIGN;
++ }
++ instance->instancet->disable_intr(instance->reg_set);
++ instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
++ instance->issuepend_done = 0;
++
++ atomic_set(&instance->fw_outstanding, 0);
++ megasas_internal_reset_defer_cmds(instance);
++ process_fw_state_change_wq(&instance->work_init);
++}
++
+ /**
+ * megasas_wait_for_outstanding - Wait for all outstanding cmds
+ * @instance: Adapter soft state
+@@ -1662,6 +1689,8 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
+ unsigned long flags;
+ struct list_head clist_local;
+ struct megasas_cmd *reset_cmd;
++ u32 fw_state;
++ u8 kill_adapter_flag;
+
+ spin_lock_irqsave(&instance->hba_lock, flags);
+ adprecovery = instance->adprecovery;
+@@ -1747,7 +1776,45 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
+ msleep(1000);
+ }
+
+- if (atomic_read(&instance->fw_outstanding)) {
++ i = 0;
++ kill_adapter_flag = 0;
++ do {
++ fw_state = instance->instancet->read_fw_status_reg(
++ instance->reg_set) & MFI_STATE_MASK;
++ if ((fw_state == MFI_STATE_FAULT) &&
++ (instance->disableOnlineCtrlReset == 0)) {
++ if (i == 3) {
++ kill_adapter_flag = 2;
++ break;
++ }
++ megasas_do_ocr(instance);
++ kill_adapter_flag = 1;
++
++ /* wait for 1 secs to let FW finish the pending cmds */
++ msleep(1000);
++ }
++ i++;
++ } while (i <= 3);
++
++ if (atomic_read(&instance->fw_outstanding) &&
++ !kill_adapter_flag) {
++ if (instance->disableOnlineCtrlReset == 0) {
++
++ megasas_do_ocr(instance);
++
++ /* wait for 5 secs to let FW finish the pending cmds */
++ for (i = 0; i < wait_time; i++) {
++ int outstanding =
++ atomic_read(&instance->fw_outstanding);
++ if (!outstanding)
++ return SUCCESS;
++ msleep(1000);
++ }
++ }
++ }
++
++ if (atomic_read(&instance->fw_outstanding) ||
++ (kill_adapter_flag == 2)) {
+ printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n");
+ /*
+ * Send signal to FW to stop processing any pending cmds.
+@@ -2810,6 +2877,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
+ return -ENOMEM;
+ }
+
++ memset(cmd->frame, 0, total_sz);
+ cmd->frame->io.context = cmd->index;
+ cmd->frame->io.pad_0 = 0;
+ }
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0028-megaraid_sas-version-and-documentation-update.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0028-megaraid_sas-version-and-documentation-update.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,105 @@
+From b402f0d112b558e0e37f7af3b02705ec2fb426de Mon Sep 17 00:00:00 2001
+From: "Yang, Bo" <Bo.Yang at lsi.com>
+Date: Tue, 12 Oct 2010 07:21:59 -0600
+Subject: [PATCH 28/53] [SCSI] megaraid_sas: Version and documentation update
+
+commit e340c3537239d5b6a2b21d4245c8577d457b0476 upstream.
+
+Signed-off-by: Bo Yang <bo.yang at lsi.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ Documentation/scsi/ChangeLog.megaraid_sas | 47 +++++++++++++++++++++++++++++++
+ drivers/scsi/megaraid/megaraid_sas.h | 6 ++--
+ drivers/scsi/megaraid/megaraid_sas_base.c | 2 +-
+ 3 files changed, 51 insertions(+), 4 deletions(-)
+
+diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
+index 07e252c25b18..e9e619613b1f 100644
+--- a/Documentation/scsi/ChangeLog.megaraid_sas
++++ b/Documentation/scsi/ChangeLog.megaraid_sas
+@@ -1,3 +1,50 @@
++1 Release Date : Thur. May 03, 2010 09:12:45 PST 2009 -
++ (emaild-id:megaraidlinux at lsi.com)
++ Bo Yang
++
++2 Current Version : 00.00.04.31-rc1
++3 Older Version : 00.00.04.17.1-rc1
++
++1. Add the Online Controller Reset (OCR) to the Driver.
++ OCR is the new feature for megaraid_sas driver which
++ will allow the fw to do the chip reset which will not
++ affact the OS behavious.
++
++ To add the OCR support, driver need to do:
++ a). reset the controller chips -- Xscale and Gen2 which
++ will change the function calls and add the reset function
++ related to this two chips.
++
++ b). during the reset, driver will store the pending cmds
++ which not returned by FW to driver's pending queue. Driver
++ will re-issue those pending cmds again to FW after the OCR
++ finished.
++
++ c). In driver's timeout routine, driver will report to
++ OS as reset. Also driver's queue routine will block the
++ cmds until the OCR finished.
++
++ d). in Driver's ISR routine, if driver get the FW state as
++ state change, FW in Failure status and FW support online controller
++ reset (OCR), driver will start to do the controller reset.
++
++ e). In driver's IOCTL routine, the application cmds will wait for the
++ OCR to finish, then issue the cmds to FW.
++
++ f). Before driver kill adapter, driver will do last chance of
++ OCR to see if driver can bring back the FW.
++
++2. Add the support update flag to the driver to tell LSI megaraid_sas
++ application which driver will support the device update. So application
++ will not need to do the device update after application add/del the device
++ from the system.
++3. In driver's timeout routine, driver will do three time reset if fw is in
++ failed state. Driver will kill adapter if can't bring back FW after the
++ this three times reset.
++4. Add the input parameter max_sectors to 1MB support to our GEN2 controller.
++ customer can use the input paramenter max_sectors to add 1MB support to GEN2
++ controller.
++
+ 1 Release Date : Thur. Oct 29, 2009 09:12:45 PST 2009 -
+ (emaild-id:megaraidlinux at lsi.com)
+ Bo Yang
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index a029a6cd1341..f029f2389405 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -18,9 +18,9 @@
+ /*
+ * MegaRAID SAS Driver meta data
+ */
+-#define MEGASAS_VERSION "00.00.04.17.1-rc1"
+-#define MEGASAS_RELDATE "Oct. 29, 2009"
+-#define MEGASAS_EXT_VERSION "Thu. Oct. 29, 11:41:51 PST 2009"
++#define MEGASAS_VERSION "00.00.04.31-rc1"
++#define MEGASAS_RELDATE "May 3, 2010"
++#define MEGASAS_EXT_VERSION "Mon. May 3, 11:41:51 PST 2010"
+
+ /*
+ * Device IDs
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 733f7120817e..d0107e110895 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -10,7 +10,7 @@
+ * 2 of the License, or (at your option) any later version.
+ *
+ * FILE : megaraid_sas.c
+- * Version : v00.00.04.17.1-rc1
++ * Version : v00.00.04.31-rc1
+ *
+ * Authors:
+ * (email-id : megaraidlinux at lsi.com)
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0029-megaraid_sas-update-gpl-headers.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0029-megaraid_sas-update-gpl-headers.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,118 @@
+From 669f7026c69b4c6d300f24dc11b56665f84b15ee Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Tue, 14 Dec 2010 18:51:48 -0800
+Subject: [PATCH 29/53] [SCSI] megaraid_sas: Update GPL headers.
+
+commit 3f1530c1e1f7fc570672f4a54565949070fad05f upstream.
+
+This patch updates the GPL headers in megaraid_sas_base.c and megaraid_sas.h.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.h | 29 +++++++++++++++++------
+ drivers/scsi/megaraid/megaraid_sas_base.c | 39 ++++++++++++++++++-------------
+ 2 files changed, 45 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index f029f2389405..6accf4c73a5d 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -1,15 +1,30 @@
+ /*
++ * Linux MegaRAID driver for SAS based RAID controllers
+ *
+- * Linux MegaRAID driver for SAS based RAID controllers
++ * Copyright (c) 2009-2011 LSI Corporation.
+ *
+- * Copyright (c) 2003-2005 LSI Corporation.
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
+ *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License
+- * as published by the Free Software Foundation; either version
+- * 2 of the License, or (at your option) any later version.
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
+ *
+- * FILE : megaraid_sas.h
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * FILE: megaraid_sas.h
++ *
++ * Authors: LSI Corporation
++ *
++ * Send feedback to: <megaraidlinux at lsi.com>
++ *
++ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
++ * ATTN: Linuxraid
+ */
+
+ #ifndef LSI_MEGARAID_SAS_H
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index d0107e110895..e73f011680e2 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -1,27 +1,34 @@
+ /*
++ * Linux MegaRAID driver for SAS based RAID controllers
+ *
+- * Linux MegaRAID driver for SAS based RAID controllers
++ * Copyright (c) 2009-2011 LSI Corporation.
+ *
+- * Copyright (c) 2003-2005 LSI Corporation.
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
+ *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License
+- * as published by the Free Software Foundation; either version
+- * 2 of the License, or (at your option) any later version.
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
+ *
+- * FILE : megaraid_sas.c
+- * Version : v00.00.04.31-rc1
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+- * Authors:
+- * (email-id : megaraidlinux at lsi.com)
+- * Sreenivas Bagalkote
+- * Sumant Patro
+- * Bo Yang
++ * FILE: megaraid_sas_base.c
++ * Version : v00.00.05.29-rc1
+ *
+- * List of supported controllers
++ * Authors: LSI Corporation
++ * Sreenivas Bagalkote
++ * Sumant Patro
++ * Bo Yang
+ *
+- * OEM Product Name VID DID SSVID SSID
+- * --- ------------ --- --- ---- ----
++ * Send feedback to: <megaraidlinux at lsi.com>
++ *
++ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
++ * ATTN: Linuxraid
+ */
+
+ #include <linux/kernel.h>
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0030-megaraid_sas-fix-failure-gotos.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0030-megaraid_sas-fix-failure-gotos.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,101 @@
+From 4240f3c8af7f47e565754394875116d13edd1ba1 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:55:56 -0800
+Subject: [PATCH 30/53] [SCSI] megaraid_sas: Fix failure gotos
+
+commit eb1b12377376e43aae4be338ffbbc32931ca4d10 upstream.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 17 ++++++++---------
+ drivers/scsi/megaraid/megaraid_sas_fusion.c | 6 ++++--
+ 2 files changed, 12 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index e73f011680e2..a630915f69f8 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -3421,7 +3421,6 @@ fail_reply_queue:
+ megasas_free_cmds(instance);
+
+ fail_alloc_cmds:
+- iounmap(instance->reg_set);
+ return 1;
+ }
+
+@@ -3491,7 +3490,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
+
+ /* Get operational params, sge flags, send init cmd to controller */
+ if (instance->instancet->init_adapter(instance))
+- return -ENODEV;
++ goto fail_init_adapter;
+
+ printk(KERN_ERR "megasas: INIT adapter done\n");
+
+@@ -3550,6 +3549,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
+ MEGASAS_COMPLETION_TIMER_INTERVAL);
+ return 0;
+
++fail_init_adapter:
+ fail_ready_state:
+ iounmap(instance->reg_set);
+
+@@ -4102,10 +4102,13 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ instance->instancet->disable_intr(instance->reg_set);
+ free_irq(instance->msi_flag ? instance->msixentry.vector :
+ instance->pdev->irq, instance);
++fail_irq:
+ if (instance->msi_flag)
+ pci_disable_msix(instance->pdev);
+-
+- fail_irq:
++ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
++ megasas_release_fusion(instance);
++ else
++ megasas_release_mfi(instance);
+ fail_init_mfi:
+ fail_alloc_dma_buf:
+ if (instance->evt_detail)
+@@ -4113,13 +4116,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ instance->evt_detail,
+ instance->evt_detail_h);
+
+- if (instance->producer) {
++ if (instance->producer)
+ pci_free_consistent(pdev, sizeof(u32), instance->producer,
+ instance->producer_h);
+- megasas_release_mfi(instance);
+- } else {
+- megasas_release_fusion(instance);
+- }
+ if (instance->consumer)
+ pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+ instance->consumer_h);
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+index c1e09d5a6196..26865290c22a 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+@@ -984,13 +984,15 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
+
+ return 0;
+
+-fail_alloc_cmds:
+-fail_alloc_mfi_cmds:
+ fail_map_info:
+ if (i == 1)
+ dma_free_coherent(&instance->pdev->dev, fusion->map_sz,
+ fusion->ld_map[0], fusion->ld_map_phys[0]);
+ fail_ioc_init:
++ megasas_free_cmds_fusion(instance);
++fail_alloc_cmds:
++ megasas_free_cmds(instance);
++fail_alloc_mfi_cmds:
+ return 1;
+ }
+
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0031-megaraid_sas-add-missing-check_and_restore_queue_depth-call.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0031-megaraid_sas-add-missing-check_and_restore_queue_depth-call.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,42 @@
+From 83436b6fea981934bcfce3879bbafe050221bb9d Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:56:05 -0800
+Subject: [PATCH 31/53] [SCSI] megaraid_sas: Add missing check_and_restore_queue_depth call
+
+commit 53ef2bbd2068097ac453dff4a3d82858446be5bb upstream.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_fusion.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+index 26865290c22a..eb4f4de19338 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+@@ -82,6 +82,10 @@ u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
+ struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
+
+ u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
++
++void
++megasas_check_and_restore_queue_depth(struct megasas_instance *instance);
++
+ u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
+ struct LD_LOAD_BALANCE_INFO *lbInfo);
+ u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo,
+@@ -1746,7 +1750,7 @@ complete_cmd_fusion(struct megasas_instance *instance)
+ wmb();
+ writel(fusion->last_reply_idx,
+ &instance->reg_set->reply_post_host_index);
+-
++ megasas_check_and_restore_queue_depth(instance);
+ return IRQ_HANDLED;
+ }
+
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0032-megaraid_sas-enable-msi-x-before-calling-megasas_init_fw.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0032-megaraid_sas-enable-msi-x-before-calling-megasas_init_fw.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,86 @@
+From 0a50715a36817e49dcd0d25364aeccad5010d441 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:56:12 -0800
+Subject: [PATCH 32/53] [SCSI] megaraid_sas: Enable MSI-X before calling megasas_init_fw
+
+commit 0a77066acc78b4048b0afc9d70b7e91c06e63356 upstream.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index a630915f69f8..c78bff2f29e7 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -4036,12 +4036,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ else
+ INIT_WORK(&instance->work_init, process_fw_state_change_wq);
+
+- /*
+- * Initialize MFI Firmware
+- */
+- if (megasas_init_fw(instance))
+- goto fail_init_mfi;
+-
+ /* Try to enable MSI-X */
+ if ((instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078R) &&
+ (instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078DE) &&
+@@ -4051,6 +4045,12 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ instance->msi_flag = 1;
+
+ /*
++ * Initialize MFI Firmware
++ */
++ if (megasas_init_fw(instance))
++ goto fail_init_mfi;
++
++ /*
+ * Register IRQ
+ */
+ if (request_irq(instance->msi_flag ? instance->msixentry.vector :
+@@ -4103,13 +4103,13 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ free_irq(instance->msi_flag ? instance->msixentry.vector :
+ instance->pdev->irq, instance);
+ fail_irq:
+- if (instance->msi_flag)
+- pci_disable_msix(instance->pdev);
+ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
+ megasas_release_fusion(instance);
+ else
+ megasas_release_mfi(instance);
+ fail_init_mfi:
++ if (instance->msi_flag)
++ pci_disable_msix(instance->pdev);
+ fail_alloc_dma_buf:
+ if (instance->evt_detail)
+ pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
+@@ -4293,6 +4293,10 @@ megasas_resume(struct pci_dev *pdev)
+ if (megasas_set_dma_mask(pdev))
+ goto fail_set_dma_mask;
+
++ /* Now re-enable MSI-X */
++ if (instance->msi_flag)
++ pci_enable_msix(instance->pdev, &instance->msixentry, 1);
++
+ /*
+ * Initialize MFI Firmware
+ */
+@@ -4329,10 +4333,6 @@ megasas_resume(struct pci_dev *pdev)
+ tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
+ (unsigned long)instance);
+
+- /* Now re-enable MSI-X */
+- if (instance->msi_flag)
+- pci_enable_msix(instance->pdev, &instance->msixentry, 1);
+-
+ /*
+ * Register IRQ
+ */
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0033-megaraid_sas-call-tasklet_schedule-for-msi-x.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0033-megaraid_sas-call-tasklet_schedule-for-msi-x.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,36 @@
+From 3e8028252819b6aa3106a239749a84b7eadd6894 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:56:21 -0800
+Subject: [PATCH 33/53] [SCSI] megaraid_sas: Call tasklet_schedule for MSI-X
+
+commit e1419191d8d38098fb6ef29e94aadd15dabff3da upstream.
+
+The following patch for megaraid_sas calls tasklet_schedule() even if
+outbound_intr_status == 0 for MFI based boards in MSI-X mode.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index c78bff2f29e7..1ad032984a90 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -2500,7 +2500,9 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
+ if ((mfiStatus = instance->instancet->clear_intr(
+ instance->reg_set)
+ ) == 0) {
+- return IRQ_NONE;
++ /* Hardware may not set outbound_intr_status in MSI-X mode */
++ if (!instance->msi_flag)
++ return IRQ_NONE;
+ }
+
+ instance->mfiStatus = mfiStatus;
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0034-megaraid_sas-fix-probe_one-to-clear-msi-x-flags-in-kdump.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0034-megaraid_sas-fix-probe_one-to-clear-msi-x-flags-in-kdump.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,67 @@
+From 2afb7e045b531590b7f6f8c40268e08be013ccae Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:56:28 -0800
+Subject: [PATCH 34/53] [SCSI] megaraid_sas: Fix probe_one to clear MSI-X flags in kdump
+
+commit 66192dfe1e74eae31a76cfc36092dabdba1324e6 upstream.
+
+The following patch for megaraid_sas fixes megasas_probe_one() to
+clear MSI-X flags in kdump when the 'reset_devices' kernel parameter
+is passed in.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.h | 3 +++
+ drivers/scsi/megaraid/megaraid_sas_base.c | 19 ++++++++++++++++++-
+ 2 files changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 6accf4c73a5d..9788121e2778 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -1477,4 +1477,7 @@ struct megasas_mgmt_info {
+ int max_index;
+ };
+
++#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
++#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
++
+ #endif /*LSI_MEGARAID_SAS_H */
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 1ad032984a90..d8000f5ba571 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -3898,9 +3898,26 @@ fail_set_dma_mask:
+ static int __devinit
+ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ {
+- int rval;
++ int rval, pos;
+ struct Scsi_Host *host;
+ struct megasas_instance *instance;
++ u16 control = 0;
++
++ /* Reset MSI-X in the kdump kernel */
++ if (reset_devices) {
++ pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
++ if (pos) {
++ pci_read_config_word(pdev, msi_control_reg(pos),
++ &control);
++ if (control & PCI_MSIX_FLAGS_ENABLE) {
++ dev_info(&pdev->dev, "resetting MSI-X\n");
++ pci_write_config_word(pdev,
++ msi_control_reg(pos),
++ control &
++ ~PCI_MSIX_FLAGS_ENABLE);
++ }
++ }
++ }
+
+ /*
+ * Announce PCI information
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0035-megaraid_sas-fix-megasas_build_dcdb_fusion-to-not-filter-by-type_disk.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0035-megaraid_sas-fix-megasas_build_dcdb_fusion-to-not-filter-by-type_disk.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,32 @@
+From bf7eb1761d7564f1d02369e2c72cd4c2dc6a6c34 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:56:43 -0800
+Subject: [PATCH 35/53] [SCSI] megaraid_sas: Fix megasas_build_dcdb_fusion to not filter by TYPE_DISK
+
+commit f512440589632c73e7c2f42d9d723994cd45958b upstream.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_fusion.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+index eb4f4de19338..4ac1f6837532 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+@@ -1438,8 +1438,7 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
+ local_map_ptr = fusion->ld_map[(instance->map_id & 1)];
+
+ /* Check if this is a system PD I/O */
+- if ((instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) &&
+- (instance->pd_list[pd_index].driveType == TYPE_DISK)) {
++ if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
+ io_request->Function = 0;
+ io_request->DevHandle =
+ local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0036-megaraid_sas-fix-megasas_build_dcdb_fusion-to-use-correct-lun-field.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0036-megaraid_sas-fix-megasas_build_dcdb_fusion-to-use-correct-lun-field.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,40 @@
+From 420932ed3eb35c11530b66bf3aed041a1b30c81f Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:56:49 -0800
+Subject: [PATCH 36/53] [SCSI] megaraid_sas: Fix megasas_build_dcdb_fusion to use correct LUN field
+
+commit eaa3c240de25c6e52ee1329e4acadfd99d7d104b upstream.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_fusion.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+index 4ac1f6837532..905c1e9317b6 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+@@ -1461,7 +1461,7 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ }
+ io_request->RaidContext.VirtualDiskTgtId = device_id;
+- io_request->LUN[0] = scmd->device->lun;
++ io_request->LUN[1] = scmd->device->lun;
+ io_request->DataLength = scsi_bufflen(scmd);
+ }
+
+@@ -1485,7 +1485,7 @@ megasas_build_io_fusion(struct megasas_instance *instance,
+ device_id = MEGASAS_DEV_INDEX(instance, scp);
+
+ /* Zero out some fields so they don't get reused */
+- io_request->LUN[0] = 0;
++ io_request->LUN[1] = 0;
+ io_request->CDB.EEDP32.PrimaryReferenceTag = 0;
+ io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0;
+ io_request->EEDPFlags = 0;
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0037-megaraid_sas-add-cfg_cleared-aen.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0037-megaraid_sas-add-cfg_cleared-aen.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,33 @@
+From 9a59327ed9c5271f41422405e1fc3d8c4b9e76e3 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:56:53 -0800
+Subject: [PATCH 37/53] [SCSI] megaraid_sas: Add CFG_CLEARED AEN
+
+commit 4c598b23807a3bf0e4f7e65f7934965acc47e1b9 upstream.
+
+The following patch for megaraid_sas adds a missing check for
+MR_EVT_CFG_CLEARED in megasas_aen_polling().
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index d8000f5ba571..6d7bed00aa14 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -5195,6 +5195,7 @@ megasas_aen_polling(struct work_struct *work)
+ break;
+
+ case MR_EVT_LD_OFFLINE:
++ case MR_EVT_CFG_CLEARED:
+ case MR_EVT_LD_DELETED:
+ megasas_get_ld_list(instance);
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0038-megaraid_sas-fix-tasklet_init-call.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0038-megaraid_sas-fix-tasklet_init-call.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,34 @@
+From 2f06e458f26575334e71dc7f1e3f677aef1d0cac Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:57:00 -0800
+Subject: [PATCH 38/53] [SCSI] megaraid_sas: Fix tasklet_init call
+
+commit f86c5424b02717a9eb9b1049a67ff3e7e9e92edf upstream.
+
+The following patch fixes an incorrect tasklet_init() call in
+megasas_init_fw() to use instancet->tasklet.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 6d7bed00aa14..c9426cd93502 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -3541,7 +3541,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
+ * Setup tasklet for cmd completion
+ */
+
+- tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
++ tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
+ (unsigned long)instance);
+
+ /* Initialize the cmd completion timer */
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0039-megaraid_sas-fix-fault-state-handling.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0039-megaraid_sas-fix-fault-state-handling.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,36 @@
+From 224b576bd5ed3414b2910eb3600a216cde17f250 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:57:04 -0800
+Subject: [PATCH 39/53] [SCSI] megaraid_sas: Fix fault state handling
+
+commit 1ac515ef3f2f7ab32498b0e4907933ff8b9b98c0 upstream.
+
+The following patch for megaraid_sas fixes fault state handling in
+megasas_transition_to_ready().
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index c9426cd93502..17e47ce05e90 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -2610,7 +2610,9 @@ megasas_transition_to_ready(struct megasas_instance* instance)
+ case MFI_STATE_FAULT:
+
+ printk(KERN_DEBUG "megasas: FW in FAULT state!!\n");
+- return -ENODEV;
++ max_wait = MEGASAS_RESET_WAIT_TIME;
++ cur_state = MFI_STATE_FAULT;
++ break;
+
+ case MFI_STATE_WAIT_HANDSHAKE:
+ /*
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0040-megaraid_sas-fix-max_sectors-for-ieee-sgl.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0040-megaraid_sas-fix-max_sectors-for-ieee-sgl.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,46 @@
+From ee8d96232234db1e7d7a945d9717c21c36d26642 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:57:09 -0800
+Subject: [PATCH 40/53] [SCSI] megaraid_sas: Fix max_sectors for IEEE SGL
+
+commit 42a8d2b34d107df34533ea4840daf8d62bdc90aa upstream.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.h | 1 +
+ drivers/scsi/megaraid/megaraid_sas_base.c | 4 ++++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 9788121e2778..742626b972a7 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -723,6 +723,7 @@ struct megasas_ctrl_info {
+ MEGASAS_MAX_DEV_PER_CHANNEL)
+
+ #define MEGASAS_MAX_SECTORS (2*1024)
++#define MEGASAS_MAX_SECTORS_IEEE (2*128)
+ #define MEGASAS_DBG_LVL 1
+
+ #define MEGASAS_FW_BUSY 1
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 17e47ce05e90..e5bd4d81c6e0 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -3821,6 +3821,10 @@ static int megasas_io_attach(struct megasas_instance *instance)
+ instance->max_fw_cmds - MEGASAS_INT_CMDS;
+ host->this_id = instance->init_id;
+ host->sg_tablesize = instance->max_num_sge;
++
++ if (instance->fw_support_ieee)
++ instance->max_sectors_per_req = MEGASAS_MAX_SECTORS_IEEE;
++
+ /*
+ * Check if the module parameter value for max_sectors can be used
+ */
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0041-megaraid_sas-fix-imr-ocr-support-to-work-correctly.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0041-megaraid_sas-fix-imr-ocr-support-to-work-correctly.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,151 @@
+From fe4427f117e25857e98d3b9259faa5b271b3d531 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:57:15 -0800
+Subject: [PATCH 41/53] [SCSI] megaraid_sas: Fix iMR OCR support to work correctly
+
+commit ebf054b00b0a6dfa81dc4472d8b19301318b7f47 upstream.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 62 ++++++++++++++++++-------------
+ 1 file changed, 37 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index e5bd4d81c6e0..3fa0be03e6ab 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -134,7 +134,11 @@ spinlock_t poll_aen_lock;
+ void
+ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ u8 alt_status);
+-
++static u32
++megasas_read_fw_status_reg_gen2(struct megasas_register_set __iomem *regs);
++static int
++megasas_adp_reset_gen2(struct megasas_instance *instance,
++ struct megasas_register_set __iomem *reg_set);
+ static irqreturn_t megasas_isr(int irq, void *devp);
+ static u32
+ megasas_init_adapter_mfi(struct megasas_instance *instance);
+@@ -554,6 +558,8 @@ static int
+ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
+ {
+ u32 status;
++ u32 mfiStatus = 0;
++
+ /*
+ * Check if it is our interrupt
+ */
+@@ -564,6 +570,15 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
+ }
+
+ /*
++ * Check if it is our interrupt
++ */
++ if ((megasas_read_fw_status_reg_gen2(regs) & MFI_STATE_MASK) ==
++ MFI_STATE_FAULT) {
++ mfiStatus = MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
++ } else
++ mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
++
++ /*
+ * Clear the interrupt by writing back the same value
+ */
+ writel(status, ®s->outbound_intr_status);
+@@ -573,7 +588,7 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
+ */
+ readl(®s->outbound_intr_status);
+
+- return 1;
++ return mfiStatus;
+ }
+
+ /**
+@@ -597,17 +612,6 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance,
+ }
+
+ /**
+- * megasas_adp_reset_skinny - For controller reset
+- * @regs: MFI register set
+- */
+-static int
+-megasas_adp_reset_skinny(struct megasas_instance *instance,
+- struct megasas_register_set __iomem *regs)
+-{
+- return 0;
+-}
+-
+-/**
+ * megasas_check_reset_skinny - For controller reset check
+ * @regs: MFI register set
+ */
+@@ -625,7 +629,7 @@ static struct megasas_instance_template megasas_instance_template_skinny = {
+ .disable_intr = megasas_disable_intr_skinny,
+ .clear_intr = megasas_clear_intr_skinny,
+ .read_fw_status_reg = megasas_read_fw_status_reg_skinny,
+- .adp_reset = megasas_adp_reset_skinny,
++ .adp_reset = megasas_adp_reset_gen2,
+ .check_reset = megasas_check_reset_skinny,
+ .service_isr = megasas_isr,
+ .tasklet = megasas_complete_cmd_dpc,
+@@ -740,20 +744,28 @@ megasas_adp_reset_gen2(struct megasas_instance *instance,
+ {
+ u32 retry = 0 ;
+ u32 HostDiag;
++ u32 *seq_offset = ®_set->seq_offset;
++ u32 *hostdiag_offset = ®_set->host_diag;
++
++ if (instance->instancet == &megasas_instance_template_skinny) {
++ seq_offset = ®_set->fusion_seq_offset;
++ hostdiag_offset = ®_set->fusion_host_diag;
++ }
++
++ writel(0, seq_offset);
++ writel(4, seq_offset);
++ writel(0xb, seq_offset);
++ writel(2, seq_offset);
++ writel(7, seq_offset);
++ writel(0xd, seq_offset);
+
+- writel(0, ®_set->seq_offset);
+- writel(4, ®_set->seq_offset);
+- writel(0xb, ®_set->seq_offset);
+- writel(2, ®_set->seq_offset);
+- writel(7, ®_set->seq_offset);
+- writel(0xd, ®_set->seq_offset);
+ msleep(1000);
+
+- HostDiag = (u32)readl(®_set->host_diag);
++ HostDiag = (u32)readl(hostdiag_offset);
+
+ while ( !( HostDiag & DIAG_WRITE_ENABLE) ) {
+ msleep(100);
+- HostDiag = (u32)readl(®_set->host_diag);
++ HostDiag = (u32)readl(hostdiag_offset);
+ printk(KERN_NOTICE "RESETGEN2: retry=%x, hostdiag=%x\n",
+ retry, HostDiag);
+
+@@ -764,14 +776,14 @@ megasas_adp_reset_gen2(struct megasas_instance *instance,
+
+ printk(KERN_NOTICE "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag);
+
+- writel((HostDiag | DIAG_RESET_ADAPTER), ®_set->host_diag);
++ writel((HostDiag | DIAG_RESET_ADAPTER), hostdiag_offset);
+
+ ssleep(10);
+
+- HostDiag = (u32)readl(®_set->host_diag);
++ HostDiag = (u32)readl(hostdiag_offset);
+ while ( ( HostDiag & DIAG_RESET_ADAPTER) ) {
+ msleep(100);
+- HostDiag = (u32)readl(®_set->host_diag);
++ HostDiag = (u32)readl(hostdiag_offset);
+ printk(KERN_NOTICE "RESET_GEN2: retry=%x, hostdiag=%x\n",
+ retry, HostDiag);
+
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0042-megaraid_sas-documentation-update.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0042-megaraid_sas-documentation-update.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,51 @@
+From be23aa1f2602caebd4544563421e042c03a47ce8 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Tue, 14 Dec 2010 19:11:56 -0800
+Subject: [PATCH 42/53] [SCSI] megaraid_sas: Documentation update
+
+commit 5f7bb3a439ce51ae8b92ca1dc93b91712224b69a upstream.
+
+The following patch updates the
+Documentation/scsi/ChangeLog.megaraid_sas file.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ Documentation/scsi/ChangeLog.megaraid_sas | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
+index e9e619613b1f..399d39437654 100644
+--- a/Documentation/scsi/ChangeLog.megaraid_sas
++++ b/Documentation/scsi/ChangeLog.megaraid_sas
+@@ -1,3 +1,25 @@
++Release Date : Tues. Dec 14, 2010 17:00:00 PST 2010 -
++ (emaild-id:megaraidlinux at lsi.com)
++ Adam Radford
++Current Version : 00.00.05.29-rc1
++Old Version : 00.00.04.31-rc1
++ 1. Rename megaraid_sas.c to megaraid_sas_base.c.
++ 2. Update GPL headers.
++ 3. Add MSI-X support and 'msix_disable' module parameter.
++ 4. Use lowest memory bar (for SR-IOV VF support).
++ 5. Add struct megasas_instance_temlate changes, and change all code to use
++ new instance entries:
++
++ irqreturn_t (*service_isr )(int irq, void *devp);
++ void (*tasklet)(unsigned long);
++ u32 (*init_adapter)(struct megasas_instance *);
++ u32 (*build_and_issue_cmd) (struct megasas_instance *,
++ struct scsi_cmnd *);
++ void (*issue_dcmd) (struct megasas_instance *instance,
++ struct megasas_cmd *cmd);
++
++ 6. Add code to support MegaRAID 9265/9285 controllers device id (0x5b).
++-------------------------------------------------------------------------------
+ 1 Release Date : Thur. May 03, 2010 09:12:45 PST 2009 -
+ (emaild-id:megaraidlinux at lsi.com)
+ Bo Yang
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0043-megaraid_sas-add-9565-9285-specific-code-version-bump.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0043-megaraid_sas-add-9565-9285-specific-code-version-bump.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,36 @@
+From 3dbd42f787b807b4b0f29f5264d556a9774d1803 Mon Sep 17 00:00:00 2001
+From: Jonathan Nieder <jrnieder at gmail.com>
+Date: Mon, 29 Oct 2012 02:31:55 -0700
+Subject: [PATCH 43/53] [SCSI] megaraid_sas: Add 9565/9285 specific code (Version bump)
+
+commit 9c915a8c99bce637226aa09cb05fc18486b229cb upstream.
+
+I dropped this hunk when first backporting because it did not apply
+cleanly and is not relevant to 9565/9285 support.
+
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.h | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 742626b972a7..c782bbc57cc8 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -33,9 +33,9 @@
+ /*
+ * MegaRAID SAS Driver meta data
+ */
+-#define MEGASAS_VERSION "00.00.04.31-rc1"
+-#define MEGASAS_RELDATE "May 3, 2010"
+-#define MEGASAS_EXT_VERSION "Mon. May 3, 11:41:51 PST 2010"
++#define MEGASAS_VERSION "00.00.05.29-rc1"
++#define MEGASAS_RELDATE "Dec. 7, 2010"
++#define MEGASAS_EXT_VERSION "Tue. Dec. 7 17:00:00 PDT 2010"
+
+ /*
+ * Device IDs
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0044-megaraid_sas-version-and-changelog-update.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0044-megaraid_sas-version-and-changelog-update.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,87 @@
+From 8062acd7fc775779e6807147b520a39d8a0e587b Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Thu, 24 Feb 2011 20:57:21 -0800
+Subject: [PATCH 44/53] [SCSI] megaraid_sas: Version and Changelog update
+
+commit 00fa2b191b4bd74e9d22ac177e3d9e8ecd3582d3 upstream.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <James.Bottomley at suse.de>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ Documentation/scsi/ChangeLog.megaraid_sas | 23 +++++++++++++++++++++++
+ drivers/scsi/megaraid/megaraid_sas.h | 6 +++---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 3 ++-
+ 3 files changed, 28 insertions(+), 4 deletions(-)
+
+diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
+index 399d39437654..6339bc7ef541 100644
+--- a/Documentation/scsi/ChangeLog.megaraid_sas
++++ b/Documentation/scsi/ChangeLog.megaraid_sas
+@@ -1,3 +1,26 @@
++Release Date : Thu. Feb 24, 2011 17:00:00 PST 2010 -
++ (emaild-id:megaraidlinux at lsi.com)
++ Adam Radford
++Current Version : 00.00.05.34-rc1
++Old Version : 00.00.05.29-rc1
++ 1. Fix some failure gotos from megasas_probe_one(), etc.
++ 2. Add missing check_and_restore_queue_depth() call in
++ complete_cmd_fusion().
++ 3. Enable MSI-X before calling megasas_init_fw().
++ 4. Call tasklet_schedule() even if outbound_intr_status == 0 for MFI based
++ boards in MSI-X mode.
++ 5. Fix megasas_probe_one() to clear PCI_MSIX_FLAGS_ENABLE in msi control
++ register in kdump kernel.
++ 6. Fix megasas_get_cmd() to only print "Command pool empty" if
++ megasas_dbg_lvl is set.
++ 7. Fix megasas_build_dcdb_fusion() to not filter by TYPE_DISK.
++ 8. Fix megasas_build_dcdb_fusion() to use io_request->LUN[1] field.
++ 9. Add MR_EVT_CFG_CLEARED to megasas_aen_polling().
++ 10. Fix tasklet_init() in megasas_init_fw() to use instancet->tasklet.
++ 11. Fix fault state handling in megasas_transition_to_ready().
++ 12. Fix max_sectors setting for IEEE SGL's.
++ 13. Fix iMR OCR support to work correctly.
++-------------------------------------------------------------------------------
+ Release Date : Tues. Dec 14, 2010 17:00:00 PST 2010 -
+ (emaild-id:megaraidlinux at lsi.com)
+ Adam Radford
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index c782bbc57cc8..635b228c3ead 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -33,9 +33,9 @@
+ /*
+ * MegaRAID SAS Driver meta data
+ */
+-#define MEGASAS_VERSION "00.00.05.29-rc1"
+-#define MEGASAS_RELDATE "Dec. 7, 2010"
+-#define MEGASAS_EXT_VERSION "Tue. Dec. 7 17:00:00 PDT 2010"
++#define MEGASAS_VERSION "00.00.05.34-rc1"
++#define MEGASAS_RELDATE "Feb. 24, 2011"
++#define MEGASAS_EXT_VERSION "Thu. Feb. 24 17:00:00 PDT 2011"
+
+ /*
+ * Device IDs
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 3fa0be03e6ab..b51e6a487d38 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -18,12 +18,13 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * FILE: megaraid_sas_base.c
+- * Version : v00.00.05.29-rc1
++ * Version : v00.00.05.34-rc1
+ *
+ * Authors: LSI Corporation
+ * Sreenivas Bagalkote
+ * Sumant Patro
+ * Bo Yang
++ * Adam Radford <linuxraid at lsi.com>
+ *
+ * Send feedback to: <megaraidlinux at lsi.com>
+ *
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0045-megaraid_sas-remove-msi-x-black-list-use-mfi_reg_state-instead.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0045-megaraid_sas-remove-msi-x-black-list-use-mfi_reg_state-instead.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,98 @@
+From d7090b197b347ebf29713a3e0c6932189b09ed0c Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Wed, 11 May 2011 18:33:47 -0700
+Subject: [PATCH 45/53] [SCSI] megaraid_sas: Remove MSI-X black list, use MFI_REG_STATE instead
+
+commit 3f1abce4aba4ced0ba8be54b22f2882bdd01c746 upstream.
+
+This patch for megaraid_sas removes the MSI-X black list and uses
+MFI_REG_STATE.ready.msiEnable instead.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <jbottomley at parallels.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 41 +++++++++++++++----------------
+ 1 file changed, 20 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index b51e6a487d38..e682f1ab09df 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -3452,7 +3452,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
+ {
+ u32 max_sectors_1;
+ u32 max_sectors_2;
+- u32 tmp_sectors;
++ u32 tmp_sectors, msix_enable;
+ struct megasas_register_set __iomem *reg_set;
+ struct megasas_ctrl_info *ctrl_info;
+ unsigned long bar_list;
+@@ -3505,6 +3505,13 @@ static int megasas_init_fw(struct megasas_instance *instance)
+ if (megasas_transition_to_ready(instance))
+ goto fail_ready_state;
+
++ /* Check if MSI-X is supported while in ready state */
++ msix_enable = (instance->instancet->read_fw_status_reg(reg_set) &
++ 0x4000000) >> 0x1a;
++ if (msix_enable && !msix_disable &&
++ !pci_enable_msix(instance->pdev, &instance->msixentry, 1))
++ instance->msi_flag = 1;
++
+ /* Get operational params, sge flags, send init cmd to controller */
+ if (instance->instancet->init_adapter(instance))
+ goto fail_init_adapter;
+@@ -4074,14 +4081,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ else
+ INIT_WORK(&instance->work_init, process_fw_state_change_wq);
+
+- /* Try to enable MSI-X */
+- if ((instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078R) &&
+- (instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078DE) &&
+- (instance->pdev->device != PCI_DEVICE_ID_LSI_VERDE_ZCR) &&
+- !msix_disable && !pci_enable_msix(instance->pdev,
+- &instance->msixentry, 1))
+- instance->msi_flag = 1;
+-
+ /*
+ * Initialize MFI Firmware
+ */
+@@ -4331,22 +4330,22 @@ megasas_resume(struct pci_dev *pdev)
+ if (megasas_set_dma_mask(pdev))
+ goto fail_set_dma_mask;
+
++ /*
++ * Initialize MFI Firmware
++ */
++
++ atomic_set(&instance->fw_outstanding, 0);
++
++ /*
++ * We expect the FW state to be READY
++ */
++ if (megasas_transition_to_ready(instance))
++ goto fail_ready_state;
++
+ /* Now re-enable MSI-X */
+ if (instance->msi_flag)
+ pci_enable_msix(instance->pdev, &instance->msixentry, 1);
+
+- /*
+- * Initialize MFI Firmware
+- */
+-
+- atomic_set(&instance->fw_outstanding, 0);
+-
+- /*
+- * We expect the FW state to be READY
+- */
+- if (megasas_transition_to_ready(instance))
+- goto fail_ready_state;
+-
+ switch (instance->pdev->device) {
+ case PCI_DEVICE_ID_LSI_FUSION:
+ {
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0046-megaraid_sas-remove-un-used-function.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0046-megaraid_sas-remove-un-used-function.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,48 @@
+From 15eb3dd67c96030cdfd94dc3b63f32fd8b17dd60 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Wed, 11 May 2011 18:33:58 -0700
+Subject: [PATCH 46/53] [SCSI] megaraid_sas: Remove un-used function
+
+commit 70d031f36fa50a53128d0d2b5f95032cd534778b upstream.
+
+The following patch for megaraid_sas removes un-used function
+megasas_return_cmd_for_smid().
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <jbottomley at parallels.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_fusion.c | 16 ----------------
+ 1 file changed, 16 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+index 905c1e9317b6..c25ef20ee907 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+@@ -697,22 +697,6 @@ fail_get_cmd:
+ }
+
+ /*
+- * megasas_return_cmd_for_smid - Returns a cmd_fusion for a SMID
+- * @instance: Adapter soft state
+- *
+- */
+-void
+-megasas_return_cmd_for_smid(struct megasas_instance *instance, u16 smid)
+-{
+- struct fusion_context *fusion;
+- struct megasas_cmd_fusion *cmd;
+-
+- fusion = instance->ctrl_context;
+- cmd = fusion->cmd_list[smid - 1];
+- megasas_return_cmd_fusion(instance, cmd);
+-}
+-
+-/*
+ * megasas_get_ld_map_info - Returns FW's ld_map structure
+ * @instance: Adapter soft state
+ * @pend: Pend the command or not
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0047-megaraid_sas-check-mfi_reg_state.fault.resetadapter.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0047-megaraid_sas-check-mfi_reg_state.fault.resetadapter.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,115 @@
+From 96ecbc1c5330e76b4b8f6334d66bdeb0177987fd Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Wed, 11 May 2011 18:34:08 -0700
+Subject: [PATCH 47/53] [SCSI] megaraid_sas: Check MFI_REG_STATE.fault.resetAdapter
+
+commit 7e70e7336515cd367b9cfcf5379e04808bdcbe96 upstream.
+
+The following patch for megaraid_sas fixes the function
+megasas_reset_fusion() and makes the reset code check
+MFI_REG_STATE.fault.resetAdapter.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <jbottomley at parallels.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas.h | 4 ++--
+ drivers/scsi/megaraid/megaraid_sas_fusion.c | 28 +++++++++++++++++-----------
+ 2 files changed, 19 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 635b228c3ead..32eb61787488 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -76,8 +76,8 @@
+ #define MFI_STATE_READY 0xB0000000
+ #define MFI_STATE_OPERATIONAL 0xC0000000
+ #define MFI_STATE_FAULT 0xF0000000
+-#define MFI_RESET_REQUIRED 0x00000001
+-
++#define MFI_RESET_REQUIRED 0x00000001
++#define MFI_RESET_ADAPTER 0x00000002
+ #define MEGAMFI_FRAME_SIZE 64
+
+ /*
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+index c25ef20ee907..c65bf5ad9440 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+@@ -2011,24 +2011,24 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
+ struct fusion_context *fusion;
+ struct megasas_cmd *cmd_mfi;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+- u32 host_diag, abs_state;
++ u32 host_diag, abs_state, status_reg, reset_adapter;
+
+ instance = (struct megasas_instance *)shost->hostdata;
+ fusion = instance->ctrl_context;
+
++ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
++ printk(KERN_WARNING "megaraid_sas: Hardware critical error, "
++ "returning FAILED.\n");
++ retval = FAILED;
++ goto out;
++ }
++
+ mutex_lock(&instance->reset_mutex);
+ set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
+ instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ instance->instancet->disable_intr(instance->reg_set);
+ msleep(1000);
+
+- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+- printk(KERN_WARNING "megaraid_sas: Hardware critical error, "
+- "returning FAILED.\n");
+- retval = FAILED;
+- goto out;
+- }
+-
+ /* First try waiting for commands to complete */
+ if (megasas_wait_for_outstanding_fusion(instance)) {
+ printk(KERN_WARNING "megaraid_sas: resetting fusion "
+@@ -2045,7 +2045,12 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
+ }
+ }
+
+- if (instance->disableOnlineCtrlReset == 1) {
++ status_reg = instance->instancet->read_fw_status_reg(
++ instance->reg_set);
++ abs_state = status_reg & MFI_STATE_MASK;
++ reset_adapter = status_reg & MFI_RESET_ADAPTER;
++ if (instance->disableOnlineCtrlReset ||
++ (abs_state == MFI_STATE_FAULT && !reset_adapter)) {
+ /* Reset not supported, kill adapter */
+ printk(KERN_WARNING "megaraid_sas: Reset not supported"
+ ", killing adapter.\n");
+@@ -2074,6 +2079,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
+
+ /* Check that the diag write enable (DRWE) bit is on */
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
++ retry = 0;
+ while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
+ msleep(100);
+ host_diag =
+@@ -2111,7 +2117,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
+
+ abs_state =
+ instance->instancet->read_fw_status_reg(
+- instance->reg_set);
++ instance->reg_set) & MFI_STATE_MASK;
+ retry = 0;
+
+ while ((abs_state <= MFI_STATE_FW_INIT) &&
+@@ -2119,7 +2125,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
+ msleep(100);
+ abs_state =
+ instance->instancet->read_fw_status_reg(
+- instance->reg_set);
++ instance->reg_set) & MFI_STATE_MASK;
+ }
+ if (abs_state <= MFI_STATE_FW_INIT) {
+ printk(KERN_WARNING "megaraid_sas: firmware "
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0048-megaraid_sas-disable-interrupts-free_irq-in-megasas_shutdown.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0048-megaraid_sas-disable-interrupts-free_irq-in-megasas_shutdown.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,37 @@
+From 827abc36e1c21775c23f6b180d86c08586ca1661 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Wed, 11 May 2011 18:34:17 -0700
+Subject: [PATCH 48/53] [SCSI] megaraid_sas: Disable interrupts/free_irq() in megasas_shutdown()
+
+commit 46fd256e05581e4a04d5a8ec107d35afe938c65b upstream.
+
+The following patch for megaraid_sas disables interrupts and
+free_irq() in megasas_shutdown().
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <jbottomley at parallels.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index e682f1ab09df..245378009ad7 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -4526,6 +4526,11 @@ static void megasas_shutdown(struct pci_dev *pdev)
+ instance->unload = 1;
+ megasas_flush_cache(instance);
+ megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
++ instance->instancet->disable_intr(instance->reg_set);
++ free_irq(instance->msi_flag ? instance->msixentry.vector :
++ instance->pdev->irq, instance);
++ if (instance->msi_flag)
++ pci_disable_msix(instance->pdev);
+ }
+
+ /**
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0049-megaraid_sas-fix-bug-where-aens-could-be-lost-in-probe-and-resume.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0049-megaraid_sas-fix-bug-where-aens-could-be-lost-in-probe-and-resume.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,79 @@
+From 360b5f45d49e4a6a22509ae79c750fcc4f684070 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Wed, 11 May 2011 18:34:29 -0700
+Subject: [PATCH 49/53] [SCSI] megaraid_sas: Fix bug where AENs could be lost in probe() and resume()
+
+commit 541f90b7c6dffe4cf4a3e8142ac8bd047da94733 upstream.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <jbottomley at parallels.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 31 ++++++++++++++++---------------
+ 1 file changed, 16 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 245378009ad7..4d655c98cf93 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -4113,20 +4113,21 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ megasas_mgmt_info.max_index++;
+
+ /*
+- * Initiate AEN (Asynchronous Event Notification)
+- */
+- if (megasas_start_aen(instance)) {
+- printk(KERN_DEBUG "megasas: start aen failed\n");
+- goto fail_start_aen;
+- }
+-
+- /*
+ * Register with SCSI mid-layer
+ */
+ if (megasas_io_attach(instance))
+ goto fail_io_attach;
+
+ instance->unload = 0;
++
++ /*
++ * Initiate AEN (Asynchronous Event Notification)
++ */
++ if (megasas_start_aen(instance)) {
++ printk(KERN_DEBUG "megasas: start aen failed\n");
++ goto fail_start_aen;
++ }
++
+ return 0;
+
+ fail_start_aen:
+@@ -4382,19 +4383,19 @@ megasas_resume(struct pci_dev *pdev)
+
+ instance->instancet->enable_intr(instance->reg_set);
+
++ /* Initialize the cmd completion timer */
++ if (poll_mode_io)
++ megasas_start_timer(instance, &instance->io_completion_timer,
++ megasas_io_completion_timer,
++ MEGASAS_COMPLETION_TIMER_INTERVAL);
++ instance->unload = 0;
++
+ /*
+ * Initiate AEN (Asynchronous Event Notification)
+ */
+ if (megasas_start_aen(instance))
+ printk(KERN_ERR "megasas: Start AEN failed\n");
+
+- /* Initialize the cmd completion timer */
+- if (poll_mode_io)
+- megasas_start_timer(instance, &instance->io_completion_timer,
+- megasas_io_completion_timer,
+- MEGASAS_COMPLETION_TIMER_INTERVAL);
+- instance->unload = 0;
+-
+ return 0;
+
+ fail_irq:
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0050-megaraid_sas-convert-6-10-12-byte-cdb-s-for-fastpath-io.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0050-megaraid_sas-convert-6-10-12-byte-cdb-s-for-fastpath-io.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,81 @@
+From 3e7c5d14efc4bf3281b961c26be49f022df60a40 Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Wed, 11 May 2011 18:34:40 -0700
+Subject: [PATCH 50/53] [SCSI] megaraid_sas: Convert 6,10,12 byte CDB's for FastPath IO
+
+commit 495c5609700e21059fa0a4651b0f4f5847332319 upstream.
+
+The following patch for megaraid_sas converts 6,10,12 byte CDB's to 16
+byte CDB for large LBA's for FastPath IO.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <jbottomley at parallels.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_fusion.c | 41 ++++++++++++++++++++++++++++-
+ 1 file changed, 40 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+index c65bf5ad9440..35000aed1c44 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+@@ -1138,7 +1138,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
+ u64 start_blk = io_info->pdBlock;
+ u8 *cdb = io_request->CDB.CDB32;
+ u32 num_blocks = io_info->numBlocks;
+- u8 opcode, flagvals, groupnum, control;
++ u8 opcode = 0, flagvals = 0, groupnum = 0, control = 0;
+
+ /* Check if T10 PI (DIF) is enabled for this LD */
+ ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr);
+@@ -1220,7 +1220,46 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
+ cdb[8] = (u8)(num_blocks & 0xff);
+ cdb[7] = (u8)((num_blocks >> 8) & 0xff);
+
++ io_request->IoFlags = 10; /* Specify 10-byte cdb */
+ cdb_len = 10;
++ } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) {
++ /* Convert to 16 byte CDB for large LBA's */
++ switch (cdb_len) {
++ case 6:
++ opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16;
++ control = cdb[5];
++ break;
++ case 10:
++ opcode =
++ cdb[0] == READ_10 ? READ_16 : WRITE_16;
++ flagvals = cdb[1];
++ groupnum = cdb[6];
++ control = cdb[9];
++ break;
++ case 12:
++ opcode =
++ cdb[0] == READ_12 ? READ_16 : WRITE_16;
++ flagvals = cdb[1];
++ groupnum = cdb[10];
++ control = cdb[11];
++ break;
++ }
++
++ memset(cdb, 0, sizeof(io_request->CDB.CDB32));
++
++ cdb[0] = opcode;
++ cdb[1] = flagvals;
++ cdb[14] = groupnum;
++ cdb[15] = control;
++
++ /* Transfer length */
++ cdb[13] = (u8)(num_blocks & 0xff);
++ cdb[12] = (u8)((num_blocks >> 8) & 0xff);
++ cdb[11] = (u8)((num_blocks >> 16) & 0xff);
++ cdb[10] = (u8)((num_blocks >> 24) & 0xff);
++
++ io_request->IoFlags = 16; /* Specify 16-byte cdb */
++ cdb_len = 16;
+ }
+
+ /* Normal case, just load LBA here */
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0051-megaraid_sas-add-1078-ocr-support.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0051-megaraid_sas-add-1078-ocr-support.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,106 @@
+From 38acd949b45e3e84fff8d2c5672ff7eddbacb35d Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Wed, 11 May 2011 18:34:52 -0700
+Subject: [PATCH 51/53] [SCSI] megaraid_sas: Add 1078 OCR support
+
+commit 3cc6851f9a3509e2ced0eb218599857b07c0ab46 upstream.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <jbottomley at parallels.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 34 +++++++++++++++----------------
+ 1 file changed, 17 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 4d655c98cf93..94d49fac658f 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -437,15 +437,18 @@ megasas_read_fw_status_reg_ppc(struct megasas_register_set __iomem * regs)
+ static int
+ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
+ {
+- u32 status;
++ u32 status, mfiStatus = 0;
++
+ /*
+ * Check if it is our interrupt
+ */
+ status = readl(®s->outbound_intr_status);
+
+- if (!(status & MFI_REPLY_1078_MESSAGE_INTERRUPT)) {
+- return 0;
+- }
++ if (status & MFI_REPLY_1078_MESSAGE_INTERRUPT)
++ mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
++
++ if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT)
++ mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
+
+ /*
+ * Clear the interrupt by writing back the same value
+@@ -455,8 +458,9 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
+ /* Dummy readl to force pci flush */
+ readl(®s->outbound_doorbell_clear);
+
+- return 1;
++ return mfiStatus;
+ }
++
+ /**
+ * megasas_fire_cmd_ppc - Sends command to the FW
+ * @frame_phys_addr : Physical address of cmd
+@@ -477,17 +481,6 @@ megasas_fire_cmd_ppc(struct megasas_instance *instance,
+ }
+
+ /**
+- * megasas_adp_reset_ppc - For controller reset
+- * @regs: MFI register set
+- */
+-static int
+-megasas_adp_reset_ppc(struct megasas_instance *instance,
+- struct megasas_register_set __iomem *regs)
+-{
+- return 0;
+-}
+-
+-/**
+ * megasas_check_reset_ppc - For controller reset check
+ * @regs: MFI register set
+ */
+@@ -495,8 +488,12 @@ static int
+ megasas_check_reset_ppc(struct megasas_instance *instance,
+ struct megasas_register_set __iomem *regs)
+ {
++ if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
++ return 1;
++
+ return 0;
+ }
++
+ static struct megasas_instance_template megasas_instance_template_ppc = {
+
+ .fire_cmd = megasas_fire_cmd_ppc,
+@@ -504,7 +501,7 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
+ .disable_intr = megasas_disable_intr_ppc,
+ .clear_intr = megasas_clear_intr_ppc,
+ .read_fw_status_reg = megasas_read_fw_status_reg_ppc,
+- .adp_reset = megasas_adp_reset_ppc,
++ .adp_reset = megasas_adp_reset_xscale,
+ .check_reset = megasas_check_reset_ppc,
+ .service_isr = megasas_isr,
+ .tasklet = megasas_complete_cmd_dpc,
+@@ -620,6 +617,9 @@ static int
+ megasas_check_reset_skinny(struct megasas_instance *instance,
+ struct megasas_register_set __iomem *regs)
+ {
++ if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
++ return 1;
++
+ return 0;
+ }
+
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0052-megaraid_sas-version-and-changelog-update.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0052-megaraid_sas-version-and-changelog-update.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,72 @@
+From eb2eee548e156baf3d3e6aef9a358488db022c9f Mon Sep 17 00:00:00 2001
+From: adam radford <aradford at gmail.com>
+Date: Wed, 11 May 2011 18:35:05 -0700
+Subject: [PATCH 52/53] [SCSI] megaraid_sas: Version and Changelog update
+
+commit 4f788dce0baf44295a8d9708d3f124587158c061 upstream.
+
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <jbottomley at parallels.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ Documentation/scsi/ChangeLog.megaraid_sas | 14 ++++++++++++++
+ drivers/scsi/megaraid/megaraid_sas.h | 6 +++---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 2 +-
+ 3 files changed, 18 insertions(+), 4 deletions(-)
+
+diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
+index 6339bc7ef541..a2e140095ef7 100644
+--- a/Documentation/scsi/ChangeLog.megaraid_sas
++++ b/Documentation/scsi/ChangeLog.megaraid_sas
+@@ -1,3 +1,17 @@
++Release Date : Wed. May 11, 2011 17:00:00 PST 2010 -
++ (emaild-id:megaraidlinux at lsi.com)
++ Adam Radford
++Current Version : 00.00.05.38-rc1
++Old Version : 00.00.05.34-rc1
++ 1. Remove MSI-X black list, use MFI_REG_STATE.ready.msiEnable.
++ 2. Remove un-used function megasas_return_cmd_for_smid().
++ 3. Check MFI_REG_STATE.fault.resetAdapter in megasas_reset_fusion().
++ 4. Disable interrupts/free_irq() in megasas_shutdown().
++ 5. Fix bug where AENs could be lost in probe() and resume().
++ 6. Convert 6,10,12 byte CDB's to 16 byte CDB for large LBA's for FastPath
++ IO.
++ 7. Add 1078 OCR support.
++-------------------------------------------------------------------------------
+ Release Date : Thu. Feb 24, 2011 17:00:00 PST 2010 -
+ (emaild-id:megaraidlinux at lsi.com)
+ Adam Radford
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
+index 32eb61787488..fcc09ca374b7 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -33,9 +33,9 @@
+ /*
+ * MegaRAID SAS Driver meta data
+ */
+-#define MEGASAS_VERSION "00.00.05.34-rc1"
+-#define MEGASAS_RELDATE "Feb. 24, 2011"
+-#define MEGASAS_EXT_VERSION "Thu. Feb. 24 17:00:00 PDT 2011"
++#define MEGASAS_VERSION "00.00.05.38-rc1"
++#define MEGASAS_RELDATE "May. 11, 2011"
++#define MEGASAS_EXT_VERSION "Wed. May. 11 17:00:00 PDT 2011"
+
+ /*
+ * Device IDs
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index 94d49fac658f..d89fa1d85d77 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -18,7 +18,7 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * FILE: megaraid_sas_base.c
+- * Version : v00.00.05.34-rc1
++ * Version : v00.00.05.38-rc1
+ *
+ * Authors: LSI Corporation
+ * Sreenivas Bagalkote
+--
+1.8.0
+
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0053-megaraid_sas-move-poll_aen_lock-initializer.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0053-megaraid_sas-move-poll_aen_lock-initializer.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,44 @@
+From 2b082e5d334030d5325a4f43a4b33514c1d211bf Mon Sep 17 00:00:00 2001
+From: Kashyap Desai <Kashyap.Desai at lsi.com>
+Date: Tue, 17 Jul 2012 18:20:44 -0700
+Subject: [PATCH 53/53] [SCSI] megaraid_sas: Move poll_aen_lock initializer
+
+commit bd8d6dd43a77bfd2b8fef5b094b9d6095e169dee upstream.
+
+The following patch moves the poll_aen_lock initializer from
+megasas_probe_one() to megasas_init(). This prevents a crash when a user
+loads the driver and tries to issue a poll() system call on the ioctl
+interface with no adapters present.
+
+Signed-off-by: Kashyap Desai <Kashyap.Desai at lsi.com>
+Signed-off-by: Adam Radford <aradford at gmail.com>
+Signed-off-by: James Bottomley <JBottomley at Parallels.com>
+Signed-off-by: Jonathan Nieder <jrnieder at gmail.com>
+---
+ drivers/scsi/megaraid/megaraid_sas_base.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
+index d89fa1d85d77..26d1ad44e4c7 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -4051,7 +4051,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ spin_lock_init(&instance->cmd_pool_lock);
+ spin_lock_init(&instance->hba_lock);
+ spin_lock_init(&instance->completion_lock);
+- spin_lock_init(&poll_aen_lock);
+
+ mutex_init(&instance->aen_mutex);
+ mutex_init(&instance->reset_mutex);
+@@ -5381,6 +5380,8 @@ static int __init megasas_init(void)
+ printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION,
+ MEGASAS_EXT_VERSION);
+
++ spin_lock_init(&poll_aen_lock);
++
+ support_poll_for_event = 2;
+ support_device_change = 1;
+
+--
+1.8.0
+
Added: dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0054-megaraid_sas-cosmetic-changes.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/megaraid_sas/0054-megaraid_sas-cosmetic-changes.patch Sun Dec 16 23:23:22 2012 (r19615)
@@ -0,0 +1,137 @@
+From: Ben Hutchings <ben at decadent.org.uk>
+Subject: megaraid_sas: Cosmetic changes to resync with upstream
+Date: Sun, 16 Dec 2012 23:17:41 +0000
+
+Apply cosmetic changes:
+- Spelling fixes from commits 25985edcedea, 80682fa9f7093 and others
+- commit 5cd049a59913 ('[SCSI] remove cmd->serial_number litter')
+- Code motion from merge commits
+
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -65,10 +65,6 @@
+ MODULE_PARM_DESC(poll_mode_io,
+ "Complete cmds from IO path, (default=0)");
+
+-static int msix_disable;
+-module_param(msix_disable, int, S_IRUGO);
+-MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
+-
+ /*
+ * Number of sectors per IO command
+ * Will be set in megasas_init_mfi if user does not provide
+@@ -78,6 +74,10 @@
+ MODULE_PARM_DESC(max_sectors,
+ "Maximum number of sectors per IO command");
+
++static int msix_disable;
++module_param(msix_disable, int, S_IRUGO);
++MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
++
+ MODULE_LICENSE("GPL");
+ MODULE_VERSION(MEGASAS_VERSION);
+ MODULE_AUTHOR("megaraidlinux at lsi.com");
+@@ -890,7 +890,7 @@
+ * @instance: Adapter soft state
+ * @cmd_to_abort: Previously issued cmd to be aborted
+ *
+- * MFI firmware can abort previously issued AEN comamnd (automatic event
++ * MFI firmware can abort previously issued AEN command (automatic event
+ * notification). The megasas_issue_blocked_abort_cmd() issues such abort
+ * cmd and waits for return status.
+ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
+@@ -1696,7 +1698,7 @@
+ * megasas_wait_for_outstanding - Wait for all outstanding cmds
+ * @instance: Adapter soft state
+ *
+- * This function waits for upto MEGASAS_RESET_WAIT_TIME seconds for FW to
++ * This function waits for up to MEGASAS_RESET_WAIT_TIME seconds for FW to
+ * complete all its outstanding commands. Returns error if one or more IOs
+ * are pending after this time period. It also marks the controller dead.
+ */
+@@ -1749,10 +1751,9 @@
+ list_del_init(&reset_cmd->list);
+ if (reset_cmd->scmd) {
+ reset_cmd->scmd->result = DID_RESET << 16;
+- printk(KERN_NOTICE "%d:%p reset [%02x], %#lx\n",
++ printk(KERN_NOTICE "%d:%p reset [%02x]\n",
+ reset_index, reset_cmd,
+- reset_cmd->scmd->cmnd[0],
+- reset_cmd->scmd->serial_number);
++ reset_cmd->scmd->cmnd[0]);
+
+ reset_cmd->scmd->scsi_done(reset_cmd->scmd);
+ megasas_return_cmd(instance, reset_cmd);
+@@ -1877,8 +1878,8 @@
+
+ instance = (struct megasas_instance *)scmd->device->host->hostdata;
+
+- scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n",
+- scmd->serial_number, scmd->cmnd[0], scmd->retries);
++ scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n",
++ scmd->cmnd[0], scmd->retries);
+
+ if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ printk(KERN_ERR "megasas: cannot recover from previous reset "
+@@ -2346,9 +2347,9 @@
+ cmd->frame_phys_addr ,
+ 0, instance->reg_set);
+ } else if (cmd->scmd) {
+- printk(KERN_NOTICE "megasas: %p scsi cmd [%02x],%#lx"
++ printk(KERN_NOTICE "megasas: %p scsi cmd [%02x]"
+ "detected on the internal queue, issue again.\n",
+- cmd, cmd->scmd->cmnd[0], cmd->scmd->serial_number);
++ cmd, cmd->scmd->cmnd[0]);
+
+ atomic_inc(&instance->fw_outstanding);
+ instance->instancet->fire_cmd(instance,
+@@ -5424,11 +5423,6 @@
+ goto err_dcf_support_poll_for_event;
+
+ rval = driver_create_file(&megasas_pci_driver.driver,
+- &driver_attr_support_device_change);
+- if (rval)
+- goto err_dcf_support_device_change;
+-
+- rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_dbg_lvl);
+ if (rval)
+ goto err_dcf_dbg_lvl;
+@@ -5437,17 +5431,22 @@
+ if (rval)
+ goto err_dcf_poll_mode_io;
+
++ rval = driver_create_file(&megasas_pci_driver.driver,
++ &driver_attr_support_device_change);
++ if (rval)
++ goto err_dcf_support_device_change;
++
+ return rval;
+
++err_dcf_support_device_change:
++ driver_remove_file(&megasas_pci_driver.driver,
++ &driver_attr_poll_mode_io);
++
+ err_dcf_poll_mode_io:
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_dbg_lvl);
+ err_dcf_dbg_lvl:
+ driver_remove_file(&megasas_pci_driver.driver,
+- &driver_attr_support_device_change);
+-
+-err_dcf_support_device_change:
+- driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_poll_for_event);
+
+ err_dcf_support_poll_for_event:
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -1347,7 +1347,7 @@
+ struct timer_list io_completion_timer;
+ struct list_head internal_reset_pending_q;
+
+- /* Ptr to hba specfic information */
++ /* Ptr to hba specific information */
+ void *ctrl_context;
+ u8 msi_flag;
+ struct msix_entry msixentry;
Modified: dists/squeeze/linux-2.6/debian/patches/series/47
==============================================================================
--- dists/squeeze/linux-2.6/debian/patches/series/47 Sun Dec 16 22:31:39 2012 (r19614)
+++ dists/squeeze/linux-2.6/debian/patches/series/47 Sun Dec 16 23:23:22 2012 (r19615)
@@ -66,3 +66,55 @@
+ features/all/hpsa/0136-hpsa-fix-handling-of-protocol-error.patch
+ features/all/hpsa/0137-hpsa-Use-LUN-reset-instead-of-target-reset.patch
+ features/all/hpsa/0138-hpsa-dial-down-lockup-detection-during-firmware-flas.patch
+
+# Update megaraid_sas to 3.0.56
+# First 5 commits already applied in -29
++ features/all/megaraid_sas/0006-megaraid_sas-infrastructure-to-get-pds-from-fw.patch
++ features/all/megaraid_sas/0007-megaraid_sas-add-the-support-for-updating-the-os-after-adding-removing-the-devices-from-fw.patch
++ features/all/megaraid_sas/0008-megaraid_sas-add-the-logical-drive-list-to-driver.patch
++ features/all/megaraid_sas/0009-megaraid_sas-driver-fixed-the-device-update-issue.patch
++ features/all/megaraid_sas/0010-megaraid_sas-add-the-ieee-sge-support-to-sas2-controller.patch
++ features/all/megaraid_sas/0011-megaraid_sas-add-online-controller-reset-to-megaraid-sas-drive.patch
++ features/all/megaraid_sas/0012-megaraid_sas-rename-megaraid_sas.c-to-megaraid_sas_base.c.patch
++ features/all/megaraid_sas/0013-megaraid_sas-add-msi-x-support-and-msix_disable-module-parameter.patch
++ features/all/megaraid_sas/0014-megaraid_sas-make-driver-pci-legacy-i-o-port-free-driver.patch
++ features/all/megaraid_sas/0015-megaraid_sas-use-lowest-memory-bar-for-sr-iov-vf-support.patch
++ features/all/megaraid_sas/0016-megaraid_sas-add-struct-megasas_instance_template-changes.patch
++ features/all/megaraid_sas/0017-megaraid_sas-add-9565-9285-specific-code.patch
++ features/all/megaraid_sas/0018-megaraid_sas-fix-instance-access-in-megasas_reset_timer.patch
++ features/all/megaraid_sas/0019-megaraid_sas-tape-drive-support-fix.patch
++ features/all/megaraid_sas/0020-megaraid_sas-report-system-pds-to-os.patch
++ features/all/megaraid_sas/0021-megaraid_sas-use-the-firmware-boot-timeout-when-waiting-for-commands.patch
++ features/all/megaraid_sas/0022-megaraid_sas-update-version-number-and-documentation.patch
++ features/all/megaraid_sas/0023-megaraid_sas-zero-pad_0-in-mfi-structure.patch
++ features/all/megaraid_sas/0024-megaraid_sas-version-and-documentation-update.patch
++ features/all/megaraid_sas/0025-megaraid_sas-support-devices-update-flag.patch
++ features/all/megaraid_sas/0026-megaraid_sas-add-input-parameter-for-max_sectors.patch
++ features/all/megaraid_sas/0027-megaraid_sas-add-three-times-online-controller-reset.patch
++ features/all/megaraid_sas/0028-megaraid_sas-version-and-documentation-update.patch
++ features/all/megaraid_sas/0029-megaraid_sas-update-gpl-headers.patch
++ features/all/megaraid_sas/0030-megaraid_sas-fix-failure-gotos.patch
++ features/all/megaraid_sas/0031-megaraid_sas-add-missing-check_and_restore_queue_depth-call.patch
++ features/all/megaraid_sas/0032-megaraid_sas-enable-msi-x-before-calling-megasas_init_fw.patch
++ features/all/megaraid_sas/0033-megaraid_sas-call-tasklet_schedule-for-msi-x.patch
++ features/all/megaraid_sas/0034-megaraid_sas-fix-probe_one-to-clear-msi-x-flags-in-kdump.patch
++ features/all/megaraid_sas/0035-megaraid_sas-fix-megasas_build_dcdb_fusion-to-not-filter-by-type_disk.patch
++ features/all/megaraid_sas/0036-megaraid_sas-fix-megasas_build_dcdb_fusion-to-use-correct-lun-field.patch
++ features/all/megaraid_sas/0037-megaraid_sas-add-cfg_cleared-aen.patch
++ features/all/megaraid_sas/0038-megaraid_sas-fix-tasklet_init-call.patch
++ features/all/megaraid_sas/0039-megaraid_sas-fix-fault-state-handling.patch
++ features/all/megaraid_sas/0040-megaraid_sas-fix-max_sectors-for-ieee-sgl.patch
++ features/all/megaraid_sas/0041-megaraid_sas-fix-imr-ocr-support-to-work-correctly.patch
++ features/all/megaraid_sas/0042-megaraid_sas-documentation-update.patch
++ features/all/megaraid_sas/0043-megaraid_sas-add-9565-9285-specific-code-version-bump.patch
++ features/all/megaraid_sas/0044-megaraid_sas-version-and-changelog-update.patch
++ features/all/megaraid_sas/0045-megaraid_sas-remove-msi-x-black-list-use-mfi_reg_state-instead.patch
++ features/all/megaraid_sas/0046-megaraid_sas-remove-un-used-function.patch
++ features/all/megaraid_sas/0047-megaraid_sas-check-mfi_reg_state.fault.resetadapter.patch
++ features/all/megaraid_sas/0048-megaraid_sas-disable-interrupts-free_irq-in-megasas_shutdown.patch
++ features/all/megaraid_sas/0049-megaraid_sas-fix-bug-where-aens-could-be-lost-in-probe-and-resume.patch
++ features/all/megaraid_sas/0050-megaraid_sas-convert-6-10-12-byte-cdb-s-for-fastpath-io.patch
++ features/all/megaraid_sas/0051-megaraid_sas-add-1078-ocr-support.patch
++ features/all/megaraid_sas/0052-megaraid_sas-version-and-changelog-update.patch
++ features/all/megaraid_sas/0053-megaraid_sas-move-poll_aen_lock-initializer.patch
++ features/all/megaraid_sas/0054-megaraid_sas-cosmetic-changes.patch
More information about the Kernel-svn-changes
mailing list