--- /dev/null
+Subject: Update MPT Fusion driver to v4.00.43.00
+From: Hannes Reinecke <hare@suse.de>
+Date: Tue Sep 30 13:38:53 2008 +0200:
+Git: a958ec0d1685af04282982f2e53b66c947fc7426
+
+References: bnc#425660
+
+This patch updates the MPT fusion drivers to v4.00.43.00.
+
+Signed-off-by: Sathya Prakash <Sathya.Prakash@lsi.com>
+Signed-off-by: Hannes Reinecke <hare@suse.de>
+
+---
+ drivers/message/fusion/Kconfig | 16
+ drivers/message/fusion/Makefile | 13
+ drivers/message/fusion/csmi/csmisas.c | 5888 ++++++++++++++++++
+ drivers/message/fusion/csmi/csmisas.h | 1854 +++++
+ drivers/message/fusion/lsi/mpi.h | 7
+ drivers/message/fusion/lsi/mpi_cnfg.h | 47
+ drivers/message/fusion/lsi/mpi_fc.h | 2
+ drivers/message/fusion/lsi/mpi_history.txt | 86
+ drivers/message/fusion/lsi/mpi_init.h | 2
+ drivers/message/fusion/lsi/mpi_ioc.h | 22
+ drivers/message/fusion/lsi/mpi_lan.h | 2
+ drivers/message/fusion/lsi/mpi_log_fc.h | 2
+ drivers/message/fusion/lsi/mpi_log_sas.h | 31
+ drivers/message/fusion/lsi/mpi_raid.h | 11
+ drivers/message/fusion/lsi/mpi_sas.h | 18
+ drivers/message/fusion/lsi/mpi_targ.h | 2
+ drivers/message/fusion/lsi/mpi_tool.h | 2
+ drivers/message/fusion/lsi/mpi_type.h | 19
+ drivers/message/fusion/mptbase.c | 2700 +++++---
+ drivers/message/fusion/mptbase.h | 291
+ drivers/message/fusion/mptctl.c | 1020 +--
+ drivers/message/fusion/mptctl.h | 5
+ drivers/message/fusion/mptdebug.h | 12
+ drivers/message/fusion/mptfc.c | 189
+ drivers/message/fusion/mptlan.c | 56
+ drivers/message/fusion/mptlan.h | 3
+ drivers/message/fusion/mptsas.c | 5921 ++++++++++++-------
+ drivers/message/fusion/mptsas.h | 71
+ drivers/message/fusion/mptscsih.c | 2252 +++----
+ drivers/message/fusion/mptscsih.h | 13
+ drivers/message/fusion/mptspi.c | 265
+ drivers/message/fusion/rejected_ioctls/diag_buffer.c | 667 ++
+ drivers/message/fusion/rejected_ioctls/diag_buffer.h | 101
+ 33 files changed, 16615 insertions(+), 4975 deletions(-)
+
+--- /dev/null
++++ b/drivers/message/fusion/csmi/csmisas.c
+@@ -0,0 +1,5888 @@
++/*
++ * linux/drivers/message/fusion/csmi/csmisas.c
++ * For use with LSI PCI chip/adapter(s)
++ * running LSI Fusion MPT (Message Passing Technology) firmware.
++ *
++ * Copyright (c) 1999-2008 LSI Corporation
++ * (mailto:DL-MPTFusionLinux@lsi.com)
++ */
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++/*
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; version 2 of the License.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ NO WARRANTY
++ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
++ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
++ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
++ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
++ solely responsible for determining the appropriateness of using and
++ distributing the Program and assumes all risks associated with its
++ exercise of rights under this Agreement, including but not limited to
++ the risks and costs of program errors, damage to or loss of data,
++ programs or equipment, and unavailability or interruption of operations.
++
++ DISCLAIMER OF LIABILITY
++ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
++ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
++ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
++ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++*/
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++
++#define MPT_CSMI_DESCRIPTION "LSI Corporation: Fusion MPT Driver "MPT_LINUX_VERSION_COMMON
++#define csmisas_is_this_sas_cntr(ioc) (ioc->bus_type == SAS) ? 1 : 0
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
++#define __user
++#include <asm/div64.h>
++#endif
++
++static int csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus,
++ u8 VolumeId, pMpiRaidActionReply_t reply);
++static u8 map_sas_status_to_csmi(u8 mpi_sas_status);
++
++/**
++ * reverse_byte_order64
++ *
++ * @data64
++ *
++ **/
++static u64
++reverse_byte_order64(u64 data64)
++{
++ int i;
++ u64 rc;
++ u8 *inWord = (u8*)&data64, *outWord = (u8*)&rc;
++
++ for (i = 0 ; i < 8 ; i++)
++ outWord[i] = inWord[7-i];
++
++ return rc;
++}
++
++/**
++ * csmisas_is_sata
++ *
++ * @phys_disk
++ *
++ **/
++static int
++csmisas_is_sata(RaidPhysDiskPage0_t *phys_disk)
++{
++ if ((phys_disk->ExtDiskIdentifier[0] == 'A') &&
++ (phys_disk->ExtDiskIdentifier[1] == 'T') &&
++ (phys_disk->ExtDiskIdentifier[2] == 'A'))
++ return 1;
++ else
++ return 0;
++}
++
++/**
++ * csmisas_is_end_device
++ *
++ * @attached
++ *
++ **/
++static inline int
++csmisas_is_end_device(struct mptsas_devinfo * attached)
++{
++ if ((attached->sas_address) &&
++ (attached->device_info &
++ MPI_SAS_DEVICE_INFO_END_DEVICE) &&
++ ((attached->device_info &
++ MPI_SAS_DEVICE_INFO_SSP_TARGET) |
++ (attached->device_info &
++ MPI_SAS_DEVICE_INFO_STP_TARGET) |
++ (attached->device_info &
++ MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
++ return 1;
++ else
++ return 0;
++}
++
++/**
++ * csmisas_is_phys_disk
++ *
++ * returns (1) success (0) fail - not a phys disk
++ **/
++static int
++csmisas_is_phys_disk(MPT_ADAPTER *ioc, int channel, int id)
++{
++ struct inactive_raid_component_info *component_info;
++ int i;
++ int rc = 0;
++
++ if (!ioc->raid_data.pIocPg3)
++ goto out;
++ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
++ if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
++ (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
++ rc = 1;
++ goto out;
++ }
++ }
++
++ /*
++ * Check inactive list for matching phys disks
++ */
++ if (list_empty(&ioc->raid_data.inactive_list))
++ goto out;
++
++ down(&ioc->raid_data.inactive_list_mutex);
++ list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
++ list) {
++ if ((component_info->d.PhysDiskID == id) &&
++ (component_info->d.PhysDiskBus == channel))
++ rc = 1;
++ }
++ up(&ioc->raid_data.inactive_list_mutex);
++
++ out:
++ return rc;
++}
++
++/**
++ * csmisas_raid_id_to_num
++ *
++ * Obtains the phys disk num for given H:C:T nexus
++ *
++ * input (channel/id)
++ * output (phys disk number - used by SCSI_IO_PASSTHRU to access hidden component)
++ *
++ * returns - signed return means failure
++ **/
++static s8
++csmisas_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
++{
++ struct inactive_raid_component_info *component_info;
++ int i;
++ s8 rc = -ENXIO;
++
++ if (!ioc->raid_data.pIocPg3)
++ goto out;
++ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
++ if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
++ (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
++ rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
++ goto out;
++ }
++ }
++
++ /*
++ * Check inactive list for matching phys disks
++ */
++ if (list_empty(&ioc->raid_data.inactive_list))
++ goto out;
++
++ down(&ioc->raid_data.inactive_list_mutex);
++ list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
++ list) {
++ if ((component_info->d.PhysDiskID == id) &&
++ (component_info->d.PhysDiskBus == channel))
++ rc = component_info->d.PhysDiskNum;
++ }
++ up(&ioc->raid_data.inactive_list_mutex);
++
++ out:
++ return rc;
++}
++
++/**
++ * csmisas_get_device_component_by_os
++ *
++ * Obtain device component object by operating system mapping
++ *
++ * @ioc
++ * @channel
++ * @id
++ *
++ **/
++static struct sas_device_info *
++csmisas_get_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
++{
++ struct sas_device_info *sas_info, *p;
++
++ sas_info = NULL;
++
++ down(&ioc->sas_device_info_mutex);
++ list_for_each_entry(p, &ioc->sas_device_info_list, list) {
++ if (p->os.channel == channel && p->os.id == id) {
++ sas_info = p;
++ goto out;
++ }
++ }
++
++ out:
++ up(&ioc->sas_device_info_mutex);
++ return sas_info;
++}
++
++/**
++ * csmisas_get_device_component
++ *
++ * Obtain device component object by firmware system mapping
++ *
++ * @ioc
++ * @channel
++ * @id
++ *
++ **/
++static struct sas_device_info *
++csmisas_get_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
++{
++ struct sas_device_info *sas_info, *p;
++
++ sas_info = NULL;
++
++ down(&ioc->sas_device_info_mutex);
++ list_for_each_entry(p, &ioc->sas_device_info_list, list) {
++ if (p->fw.channel == channel && p->fw.id == id) {
++ sas_info = p;
++ goto out;
++ }
++ }
++
++ out:
++ up(&ioc->sas_device_info_mutex);
++ return sas_info;
++}
++
++
++/**
++ * csmisas_get_device_component_by_sas_addr
++ *
++ * Obtain device component object by sas address
++ *
++ * @ioc
++ * @channel
++ * @id
++ *
++ **/
++static struct sas_device_info *
++csmisas_get_device_component_by_sas_addr(MPT_ADAPTER *ioc, u64 sas_address)
++{
++ struct sas_device_info *sas_info, *p;
++
++ sas_info = NULL;
++
++ down(&ioc->sas_device_info_mutex);
++ list_for_each_entry(p, &ioc->sas_device_info_list, list) {
++ if (p->sas_address == sas_address) {
++ sas_info = p;
++ goto out;
++ }
++ }
++
++ out:
++ up(&ioc->sas_device_info_mutex);
++ return sas_info;
++}
++
++/**
++ * csmisas_send_command_wait
++ *
++ * Send mf to firmware
++ *
++ * @ioc
++ * @mf
++ * @timeout - timeout
++ *
++ * Return: 0 for success
++ * non-zero, failure
++ **/
++static int
++csmisas_send_command_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout)
++{
++ int rc;
++ unsigned long timeleft;
++
++ timeout = max_t(unsigned long, MPT_IOCTL_DEFAULT_TIMEOUT, timeout);
++ rc = 0;
++ timeleft = 0;
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
++
++ INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status)
++ ioc->ioctl_cmds.wait_done = 0;
++ ioc->ioctl_cmds.timer.expires = jiffies + (MPT_JIFFY * timeout);
++ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE;
++ ADD_TIMER(&ioc->ioctl_cmds.timer);
++ mpt_put_msg_frame(mptctl_id, ioc, mf);
++ WAIT_EVENT(mptctl_wait, ioc->ioctl_cmds.wait_done);
++
++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
++
++ INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status)
++ ioc->ioctl_cmds.wait_done = 0;
++ mpt_put_msg_frame(mptctl_id, ioc, mf);
++
++ if ((wait_event_timeout(mptctl_wait,
++ ioc->ioctl_cmds.wait_done == 1, HZ * timeout) <=0) &&
++ ioc->ioctl_cmds.wait_done != 1 ) {
++ mptctl_timeout_expired(ioc,mf);
++ mpt_free_msg_frame(ioc, mf);
++ rc = -1;
++ }
++
++#else
++
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
++ mf->u.hdr.MsgContext);
++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
++ mpt_put_msg_frame(mptctl_id, ioc, mf);
++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, timeout*HZ);
++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ rc = -1;
++ printk("%s: failed\n", __FUNCTION__);
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
++ mpt_free_msg_frame(ioc, mf);
++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
++ return rc;
++ }
++ if (!timeleft)
++ mptctl_timeout_expired(ioc, mf);
++ }
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
++#endif
++ return rc;
++}
++
++/**
++ * csmisas_send_handshake_wait
++ *
++ * Handshake a mf to firmware
++ *
++ * @ioc
++ * @mf
++ * @mf_size
++ * @timeout - timeout
++ *
++ * Return: 0 for success
++ * non-zero, failure
++ **/
++static int
++csmisas_send_handshake_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout)
++{
++ int rc;
++ unsigned long timeleft;
++
++ timeout = max_t(unsigned long, MPT_IOCTL_DEFAULT_TIMEOUT, timeout);
++ rc = 0;
++ timeleft = 0;
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
++
++ INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status)
++ ioc->taskmgmt_cmds.timer.expires = jiffies + (MPT_JIFFY*timeout);
++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE;
++ ioc->taskmgmt_cmds.wait_done = 0;
++ ADD_TIMER(&ioc->taskmgmt_cmds.timer);
++ rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc,
++ sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP);
++ if (rc != 0)
++ return rc;
++ WAIT_EVENT(mptctl_taskmgmt_wait, ioc->taskmgmt_cmds.wait_done);
++
++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
++
++ INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status)
++ ioc->taskmgmt_cmds.wait_done = 0;
++ rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc,
++ sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP);
++ if (rc != 0)
++ return rc;
++ if ((wait_event_timeout(mptctl_taskmgmt_wait,
++ ioc->taskmgmt_cmds.wait_done == 1, HZ * timeout) <=0) &&
++ ioc->taskmgmt_cmds.wait_done != 1 ) {
++ mptctl_timeout_expired(ioc, mf);
++ mpt_free_msg_frame(ioc, mf);
++ rc = -1;
++ }
++
++#else
++ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
++ mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf);
++ timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ rc = -1;
++ printk("%s: failed\n", __FUNCTION__);
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
++ mpt_free_msg_frame(ioc, mf);
++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
++ return rc;
++ }
++ if (!timeleft)
++ mptctl_timeout_expired(ioc, mf);
++ }
++#endif
++ return rc;
++}
++
++/**
++ * csmisas_get_number_hotspares - returns num hot spares in this ioc
++ * @ioc: Pointer to MPT_ADAPTER structure
++ *
++ * Return: number of hotspares
++ *
++ **/
++static int
++csmisas_get_number_hotspares(MPT_ADAPTER *ioc)
++{
++ ConfigPageHeader_t hdr;
++ CONFIGPARMS cfg;
++ IOCPage5_t *buffer = NULL;
++ dma_addr_t dma_handle;
++ int data_sz;
++ int rc;
++
++ memset(&hdr, 0, sizeof(ConfigPageHeader_t));
++ memset(&cfg, 0, sizeof(CONFIGPARMS));
++
++ rc = 0;
++ data_sz = 0;
++ hdr.PageNumber = 5;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_IOC;
++ cfg.cfghdr.hdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++
++ if (mpt_config(ioc, &cfg) != 0)
++ goto get_ioc_pg5;
++
++ if (hdr.PageLength == 0)
++ goto get_ioc_pg5;
++
++ data_sz = hdr.PageLength * 4;
++ buffer = (IOCPage5_t *) pci_alloc_consistent(ioc->pcidev,
++ data_sz, &dma_handle);
++ if (!buffer)
++ goto get_ioc_pg5;
++
++ memset((u8 *)buffer, 0, data_sz);
++ cfg.physAddr = dma_handle;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if (mpt_config(ioc, &cfg) != 0)
++ goto get_ioc_pg5;
++
++ rc = buffer->NumHotSpares;
++
++ get_ioc_pg5:
++
++ if (buffer)
++ pci_free_consistent(ioc->pcidev, data_sz,
++ (u8 *) buffer, dma_handle);
++
++ return rc;
++}
++
++
++/**
++ * csmisas_get_ioc_pg5 - ioc Page 5 hot spares
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @pIocPage5: ioc page 5
++ * @data_size: expected data size(units=bytes)
++ *
++ * Return: 0 for success
++ * -ENOMEM if no memory available
++ * -EPERM if not allowed due to ISR context
++ * -EAGAIN if no msg frames currently available
++ * -EFAULT for non-successful reply or no reply (timeout)
++ **/
++static int
++csmisas_get_ioc_pg5(MPT_ADAPTER *ioc, IOCPage5_t *iocPage5, int data_size)
++{
++ ConfigPageHeader_t hdr;
++ CONFIGPARMS cfg;
++ IOCPage5_t *buffer = NULL;
++ dma_addr_t dma_handle;
++ int data_sz;
++ int rc;
++
++ memset(&hdr, 0, sizeof(ConfigPageHeader_t));
++ memset(&cfg, 0, sizeof(CONFIGPARMS));
++
++ rc = 0;
++ data_sz = 0;
++ hdr.PageNumber = 5;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_IOC;
++ cfg.cfghdr.hdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0)
++ goto get_ioc_pg5;
++
++ if (hdr.PageLength == 0) {
++ rc = -EFAULT;
++ goto get_ioc_pg5;
++ }
++
++ data_sz = hdr.PageLength * 4;
++ buffer = (IOCPage5_t *) pci_alloc_consistent(ioc->pcidev,
++ data_sz, &dma_handle);
++ if (!buffer) {
++ rc = -ENOMEM;
++ goto get_ioc_pg5;
++ }
++
++ memset((u8 *)buffer, 0, data_sz);
++ cfg.physAddr = dma_handle;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0)
++ goto get_ioc_pg5;
++
++ memcpy(iocPage5, buffer, data_size);
++
++ get_ioc_pg5:
++
++ if (buffer)
++ pci_free_consistent(ioc->pcidev, data_sz,
++ (u8 *) buffer, dma_handle);
++
++ return rc;
++}
++
++/**
++ * csmisas_sas_device_pg0 - sas device page 0
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @mptsas_devinfo: structure found in mptsas.h
++ * @form, @form_specific - defines the Page Address field in the config page
++ * (pls refer to chapter 5.1 in the mpi spec)
++ *
++ * Return: 0 for success
++ * -ENOMEM if no memory available
++ * -EPERM if not allowed due to ISR context
++ * -EAGAIN if no msg frames currently available
++ * -EFAULT for non-successful reply or no reply (timeout)
++ **/
++static int
++csmisas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
++ u32 form, u32 form_specific)
++{
++ ConfigExtendedPageHeader_t hdr;
++ CONFIGPARMS cfg;
++ SasDevicePage0_t *buffer;
++ dma_addr_t dma_handle;
++ u64 sas_address;
++ int rc;
++
++ rc = 0;
++ hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
++ hdr.ExtPageLength = 0;
++ hdr.PageNumber = 0;
++ hdr.Reserved1 = 0;
++ hdr.Reserved2 = 0;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
++
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.pageAddr = form + form_specific;
++ cfg.physAddr = -1;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = 10;
++
++ memset(device_info, 0, sizeof(struct mptsas_devinfo));
++ if ((rc = mpt_config(ioc, &cfg)) != 0)
++ goto out;
++
++ if (!hdr.ExtPageLength) {
++ rc = -ENXIO;
++ goto out;
++ }
++
++ buffer = pci_alloc_consistent(ioc->pcidev,
++ hdr.ExtPageLength * 4, &dma_handle);
++ if (!buffer) {
++ rc = -ENOMEM;
++ goto out;
++ }
++
++ cfg.physAddr = dma_handle;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0)
++ goto out_free_consistent;
++
++ device_info->handle = le16_to_cpu(buffer->DevHandle);
++ device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
++ device_info->handle_enclosure =
++ le16_to_cpu(buffer->EnclosureHandle);
++ device_info->slot = le16_to_cpu(buffer->Slot);
++ device_info->phy_id = buffer->PhyNum;
++ device_info->port_id = buffer->PhysicalPort;
++ device_info->id = buffer->TargetID;
++ device_info->channel = buffer->Bus;
++ memcpy(&sas_address, &buffer->SASAddress, sizeof(u64));
++ device_info->sas_address = le64_to_cpu(sas_address);
++ device_info->device_info =
++ le32_to_cpu(buffer->DeviceInfo);
++
++ out_free_consistent:
++ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
++ buffer, dma_handle);
++ out:
++ return rc;
++}
++
++/**
++ * Routine for the CSMI Sas Get Driver Info command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_driver_info(unsigned long arg)
++{
++
++ CSMI_SAS_DRIVER_INFO_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_DRIVER_INFO_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++
++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to read in csmi_sas_get_driver_info_buffer struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ /* Fill in the data and return the structure to the calling
++ * program
++ */
++ memcpy( karg.Information.szName, MPT_MISCDEV_BASENAME,
++ sizeof(MPT_MISCDEV_BASENAME));
++ memcpy( karg.Information.szDescription, MPT_CSMI_DESCRIPTION,
++ sizeof(MPT_CSMI_DESCRIPTION));
++
++ karg.Information.usMajorRevision = MPT_LINUX_MAJOR_VERSION;
++ karg.Information.usMinorRevision = MPT_LINUX_MINOR_VERSION;
++ karg.Information.usBuildRevision = MPT_LINUX_BUILD_VERSION;
++ karg.Information.usReleaseRevision = MPT_LINUX_RELEASE_VERSION;
++
++ karg.Information.usCSMIMajorRevision = CSMI_MAJOR_REVISION;
++ karg.Information.usCSMIMinorRevision = CSMI_MINOR_REVISION;
++
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI_SAS_GET_CNTLR_CONFIG command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_cntlr_config(unsigned long arg)
++{
++
++ CSMI_SAS_CNTLR_CONFIG_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_CNTLR_CONFIG_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++ u64 mem_phys;
++
++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_CONFIG_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to read in csmi_sas_get_cntlr_config_buffer struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ /* Clear the struct before filling in data. */
++ memset( &karg.Configuration, 0, sizeof(CSMI_SAS_CNTLR_CONFIG));
++
++ /* Fill in the data and return the structure to the calling
++ * program
++ */
++
++ karg.Configuration.uBaseIoAddress = ioc->pio_mem_phys;
++ karg.Configuration.BaseMemoryAddress.uLowPart = ioc->mem_phys;
++ if (sizeof(ioc->mem_phys) == sizeof(u64)) {
++ mem_phys = ioc->mem_phys;
++ karg.Configuration.BaseMemoryAddress.uHighPart =
++ (u32)(mem_phys >> 32);
++ }
++
++ karg.Configuration.uBoardID = (ioc->pcidev->subsystem_device << 16) |
++ (ioc->pcidev->subsystem_vendor);
++
++ karg.Configuration.usSlotNumber =
++ (ioc->pci_slot_number = 0xff) ?
++ SLOT_NUMBER_UNKNOWN : ioc->pci_slot_number;
++ karg.Configuration.bControllerClass = CSMI_SAS_CNTLR_CLASS_HBA;
++ karg.Configuration.bIoBusType = CSMI_SAS_BUS_TYPE_PCI;
++ karg.Configuration.BusAddress.PciAddress.bBusNumber =
++ ioc->pcidev->bus->number;
++ karg.Configuration.BusAddress.PciAddress.bDeviceNumber =
++ PCI_SLOT(ioc->pcidev->devfn);
++ karg.Configuration.BusAddress.PciAddress.bFunctionNumber =
++ PCI_FUNC(ioc->pcidev->devfn);
++ karg.Configuration.BusAddress.PciAddress.bReserved = 0;
++ memcpy( &karg.Configuration.szSerialNumber, ioc->board_tracer, 16 );
++ karg.Configuration.usMajorRevision = ioc->facts.FWVersion.Struct.Major;
++ karg.Configuration.usMinorRevision = ioc->facts.FWVersion.Struct.Minor;
++ karg.Configuration.usBuildRevision = ioc->facts.FWVersion.Struct.Unit;
++ karg.Configuration.usReleaseRevision = ioc->facts.FWVersion.Struct.Dev;
++ karg.Configuration.usBIOSMajorRevision =
++ (ioc->biosVersion & 0xFF000000) >> 24;
++ karg.Configuration.usBIOSMinorRevision =
++ (ioc->biosVersion & 0x00FF0000) >> 16;
++ karg.Configuration.usBIOSBuildRevision =
++ (ioc->biosVersion & 0x0000FF00) >> 8;
++ karg.Configuration.usBIOSReleaseRevision =
++ (ioc->biosVersion & 0x000000FF);
++ karg.Configuration.uControllerFlags = CSMI_SAS_CNTLR_SAS_HBA |
++ CSMI_SAS_CNTLR_FWD_SUPPORT | CSMI_SAS_CNTLR_FWD_ONLINE |
++ CSMI_SAS_CNTLR_FWD_SRESET ;
++
++ /*
++ * Enabling CSMI_SAS_CNTLR_SAS_RAID bit when IR fw detected
++ */
++ if (ioc->ir_firmware)
++ karg.Configuration.uControllerFlags |= CSMI_SAS_CNTLR_SAS_RAID;
++
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ /* All Rrom entries will be zero. Skip them. */
++ /* bReserved will also be zeros. */
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI Sas Get Controller Status command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_cntlr_status(unsigned long arg)
++{
++
++ CSMI_SAS_CNTLR_STATUS_BUFFER __user *uarg = (void __user *) arg;
++ MPT_ADAPTER *ioc = NULL;
++ CSMI_SAS_CNTLR_STATUS_BUFFER karg;
++ int iocnum;
++ int rc;
++
++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to read in csmi_sas_get_cntlr_status_buffer struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ /* Fill in the data and return the structure to the calling
++ * program
++ */
++
++ rc = mpt_GetIocState(ioc, 1);
++ switch (rc) {
++ case MPI_IOC_STATE_OPERATIONAL:
++ karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_GOOD;
++ karg.Status.uOfflineReason = 0;
++ break;
++
++ case MPI_IOC_STATE_FAULT:
++ karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_FAILED;
++ karg.Status.uOfflineReason = 0;
++ break;
++
++ case MPI_IOC_STATE_RESET:
++ case MPI_IOC_STATE_READY:
++ default:
++ karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_OFFLINE;
++ karg.Status.uOfflineReason =
++ CSMI_SAS_OFFLINE_REASON_INITIALIZING;
++ break;
++ }
++
++ memset(&karg.Status.bReserved, 0, 28);
++
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to write out csmi_sas_get_cntlr_status @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI Sas Get Phy Info command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_phy_info(unsigned long arg)
++{
++ CSMI_SAS_PHY_INFO_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_PHY_INFO_BUFFER *karg;
++ MPT_ADAPTER *ioc = NULL;
++ ConfigExtendedPageHeader_t hdr;
++ CONFIGPARMS cfg;
++ SasIOUnitPage0_t *sasIoUnitPg0;
++ dma_addr_t sasIoUnitPg0_dma;
++ int sasIoUnitPg0_data_sz;
++ SasPhyPage0_t *sasPhyPg0;
++ dma_addr_t sasPhyPg0_dma;
++ int sasPhyPg0_data_sz;
++ u16 protocol;
++ int iocnum;
++ int rc;
++ int ii;
++ u64 sas_address;
++ struct mptsas_devinfo device_info;
++ int memory_pages;
++
++ sasIoUnitPg0=NULL;
++ sasPhyPg0=NULL;
++ sasIoUnitPg0_data_sz=0;
++ sasPhyPg0_data_sz=0;
++
++ memory_pages = get_order(sizeof(CSMI_SAS_PHY_INFO_BUFFER));
++ karg = (CSMI_SAS_PHY_INFO_BUFFER *)__get_free_pages(
++ GFP_KERNEL, memory_pages);
++ if (!karg){
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to malloc CSMI_SAS_PHY_INFO_BUFFER "
++ "malloc_data_sz=%d memory_pages=%d\n",
++ __FILE__, __LINE__, __FUNCTION__,
++ (int)sizeof(CSMI_SAS_PHY_INFO_BUFFER), memory_pages);
++ return -ENOMEM;
++ }
++
++ memset(karg, 0, sizeof(*karg));
++
++ if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_PHY_INFO_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to read in csmisas_get_phy_info_buffer struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)karg, memory_pages);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)karg, memory_pages);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ /* Fill in the data and return the structure to the calling
++ * program
++ */
++
++ /* Issue a config request to get the number of phys
++ */
++ hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
++ hdr.ExtPageLength = 0;
++ hdr.PageNumber = 0;
++ hdr.Reserved1 = 0;
++ hdr.Reserved2 = 0;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
++
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.pageAddr = 0;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ /* Don't check if this failed. Already in a
++ * failure case.
++ */
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: HEADER\n"));
++ dcsmisasprintk(ioc, printk(": rc=%x\n",rc));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto sas_get_phy_info_exit;
++ }
++
++ if (hdr.ExtPageLength == 0) {
++ /* Don't check if this failed. Already in a
++ * failure case.
++ */
++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto sas_get_phy_info_exit;
++ }
++
++ sasIoUnitPg0_data_sz = hdr.ExtPageLength * 4;
++ rc = -ENOMEM;
++
++ sasIoUnitPg0 = (SasIOUnitPage0_t *) pci_alloc_consistent(ioc->pcidev,
++ sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma);
++
++ if (!sasIoUnitPg0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto sas_get_phy_info_exit;
++ }
++
++ memset((u8 *)sasIoUnitPg0, 0, sasIoUnitPg0_data_sz);
++ cfg.physAddr = sasIoUnitPg0_dma;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++
++ /* Don't check if this failed. Already in a
++ * failure case.
++ */
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: PAGE\n"));
++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto sas_get_phy_info_exit;
++ }
++
++ /* Number of Phys. */
++ karg->Information.bNumberOfPhys = sasIoUnitPg0->NumPhys;
++
++ /* Fill in information for each phy. */
++ for (ii = 0; ii < karg->Information.bNumberOfPhys; ii++) {
++
++/* EDM : dump IO Unit Page 0 data*/
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n"));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
++ le16_to_cpu(sasIoUnitPg0->PhyData[ii].AttachedDeviceHandle)));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n",
++ le16_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerDevHandle)));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n",
++ sasIoUnitPg0->PhyData[ii].Port));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n",
++ sasIoUnitPg0->PhyData[ii].PortFlags));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n",
++ sasIoUnitPg0->PhyData[ii].PhyFlags));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n",
++ sasIoUnitPg0->PhyData[ii].NegotiatedLinkRate));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n",
++ le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo)));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n",
++ le32_to_cpu(sasIoUnitPg0->PhyData[ii].DiscoveryStatus)));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
++/* EDM : debug data */
++
++ /* PHY stuff. */
++ karg->Information.Phy[ii].bPortIdentifier =
++ sasIoUnitPg0->PhyData[ii].Port;
++
++ /* Get the negotiated link rate for the phy. */
++ switch (sasIoUnitPg0->PhyData[ii].NegotiatedLinkRate) {
++
++ case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
++ karg->Information.Phy[ii].bNegotiatedLinkRate =
++ CSMI_SAS_PHY_DISABLED;
++ break;
++
++ case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
++ karg->Information.Phy[ii].bNegotiatedLinkRate =
++ CSMI_SAS_LINK_RATE_FAILED;
++ break;
++
++ case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
++ break;
++
++ case MPI_SAS_IOUNIT0_RATE_1_5:
++ karg->Information.Phy[ii].bNegotiatedLinkRate =
++ CSMI_SAS_LINK_RATE_1_5_GBPS;
++ break;
++
++ case MPI_SAS_IOUNIT0_RATE_3_0:
++ karg->Information.Phy[ii].bNegotiatedLinkRate =
++ CSMI_SAS_LINK_RATE_3_0_GBPS;
++ break;
++
++ case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
++ default:
++ karg->Information.Phy[ii].bNegotiatedLinkRate =
++ CSMI_SAS_LINK_RATE_UNKNOWN;
++ break;
++ }
++
++ if (sasIoUnitPg0->PhyData[ii].PortFlags &
++ MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS) {
++ karg->Information.Phy[ii].bAutoDiscover =
++ CSMI_SAS_DISCOVER_IN_PROGRESS;
++ } else {
++ karg->Information.Phy[ii].bAutoDiscover =
++ CSMI_SAS_DISCOVER_COMPLETE;
++ }
++
++ /* Issue a config request to get
++ * phy information.
++ */
++ hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
++ hdr.ExtPageLength = 0;
++ hdr.PageNumber = 0;
++ hdr.Reserved1 = 0;
++ hdr.Reserved2 = 0;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
++
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.pageAddr = ii;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n"));
++ dcsmisasprintk(ioc, printk(": rc=%x\n",rc));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto sas_get_phy_info_exit;
++ }
++
++ if (hdr.ExtPageLength == 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto sas_get_phy_info_exit;
++ }
++
++ sasPhyPg0_data_sz = hdr.ExtPageLength * 4;
++ rc = -ENOMEM;
++
++ sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent(
++ ioc->pcidev, sasPhyPg0_data_sz, &sasPhyPg0_dma);
++
++ if (! sasPhyPg0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto sas_get_phy_info_exit;
++ }
++
++ memset((u8 *)sasPhyPg0, 0, sasPhyPg0_data_sz);
++ cfg.physAddr = sasPhyPg0_dma;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n"));
++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz,
++ (u8 *) sasPhyPg0, sasPhyPg0_dma);
++ goto sas_get_phy_info_exit;
++ }
++
++/* EDM : dump PHY Page 0 data*/
++ memcpy(&sas_address, &sasPhyPg0->SASAddress, sizeof(u64));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n"));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
++ le16_to_cpu(sasPhyPg0->AttachedDevHandle)));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
++ (unsigned long long)sas_address));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n",
++ sasPhyPg0->AttachedPhyIdentifier));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n",
++ le32_to_cpu(sasPhyPg0->AttachedDeviceInfo)));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n",
++ sasPhyPg0->ProgrammedLinkRate));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n",
++ sasPhyPg0->HwLinkRate));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n",
++ sasPhyPg0->ChangeCount));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n",
++ le32_to_cpu(sasPhyPg0->PhyInfo)));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
++/* EDM : debug data */
++
++ /* save the data */
++
++ /* Set Max hardware link rate.
++ * This value is hard coded
++ * because the HW link rate
++ * is currently being
++ * overwritten in FW.
++ */
++
++ /* Set Max hardware link rate. */
++ switch (sasPhyPg0->HwLinkRate &
++ MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
++
++ case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
++ karg->Information.Phy[ii].bMaximumLinkRate =
++ CSMI_SAS_LINK_RATE_1_5_GBPS;
++ break;
++
++ case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
++ karg->Information.Phy[ii].bMaximumLinkRate =
++ CSMI_SAS_LINK_RATE_3_0_GBPS;
++ break;
++ default:
++ break;
++ }
++
++ /* Set Max programmed link rate. */
++ switch (sasPhyPg0->ProgrammedLinkRate &
++ MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
++
++ case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
++ karg->Information.Phy[ii].bMaximumLinkRate |=
++ (CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS << 4);
++ break;
++
++ case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
++ karg->Information.Phy[ii].bMaximumLinkRate |=
++ (CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS << 4);
++ break;
++ default:
++ break;
++ }
++
++ /* Set Min hardware link rate. */
++ switch (sasPhyPg0->HwLinkRate &
++ MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
++
++ case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
++ karg->Information.Phy[ii].bMinimumLinkRate =
++ CSMI_SAS_LINK_RATE_1_5_GBPS;
++ break;
++
++ case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
++ karg->Information.Phy[ii].bMinimumLinkRate =
++ CSMI_SAS_LINK_RATE_3_0_GBPS;
++ break;
++ default:
++ break;
++ }
++
++ /* Set Min programmed link rate. */
++ switch (sasPhyPg0->ProgrammedLinkRate &
++ MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
++
++ case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
++ karg->Information.Phy[ii].bMinimumLinkRate |=
++ (CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS << 4);
++ break;
++
++ case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
++ karg->Information.Phy[ii].bMinimumLinkRate |=
++ (CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS << 4);
++ break;
++ default:
++ break;
++ }
++
++ karg->Information.Phy[ii].bPhyChangeCount = sasPhyPg0->ChangeCount;
++ if( sasPhyPg0->PhyInfo & MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY )
++ karg->Information.Phy[ii].bPhyFeatures = CSMI_SAS_PHY_VIRTUAL_SMP;
++
++ /* Fill in Attached Device
++ * Initiator Port Protocol.
++ * Bits 6:3
++ * More than one bit can be set.
++ */
++ protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x78;
++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol = 0;
++ if (protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol =
++ CSMI_SAS_PROTOCOL_SSP;
++ if (protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |=
++ CSMI_SAS_PROTOCOL_STP;
++ if (protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |=
++ CSMI_SAS_PROTOCOL_SMP;
++ if (protocol & MPI_SAS_DEVICE_INFO_SATA_HOST)
++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |=
++ CSMI_SAS_PROTOCOL_SATA;
++
++ /* Fill in Phy Target Port
++ * Protocol. Bits 10:7
++ * More than one bit can be set.
++ */
++ protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x780;
++ karg->Information.Phy[ii].Attached.bTargetPortProtocol = 0;
++ if (protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET)
++ karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
++ CSMI_SAS_PROTOCOL_SSP;
++ if (protocol & MPI_SAS_DEVICE_INFO_STP_TARGET)
++ karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
++ CSMI_SAS_PROTOCOL_STP;
++ if (protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET)
++ karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
++ CSMI_SAS_PROTOCOL_SMP;
++ if (protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
++ karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
++ CSMI_SAS_PROTOCOL_SATA;
++
++
++ /* Fill in Attached device type */
++ switch (le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) &
++ MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
++
++ case MPI_SAS_DEVICE_INFO_NO_DEVICE:
++ karg->Information.Phy[ii].Attached.bDeviceType =
++ CSMI_SAS_NO_DEVICE_ATTACHED;
++ break;
++
++ case MPI_SAS_DEVICE_INFO_END_DEVICE:
++ karg->Information.Phy[ii].Attached.bDeviceType =
++ CSMI_SAS_END_DEVICE;
++ break;
++
++ case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
++ karg->Information.Phy[ii].Attached.bDeviceType =
++ CSMI_SAS_EDGE_EXPANDER_DEVICE;
++ break;
++
++ case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
++ karg->Information.Phy[ii].Attached.bDeviceType =
++ CSMI_SAS_FANOUT_EXPANDER_DEVICE;
++ break;
++ }
++
++ /* Identify Info. */
++ switch (le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) &
++ MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
++
++ case MPI_SAS_DEVICE_INFO_NO_DEVICE:
++ karg->Information.Phy[ii].Identify.bDeviceType =
++ CSMI_SAS_NO_DEVICE_ATTACHED;
++ break;
++
++ case MPI_SAS_DEVICE_INFO_END_DEVICE:
++ karg->Information.Phy[ii].Identify.bDeviceType =
++ CSMI_SAS_END_DEVICE;
++ break;
++
++ case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
++ karg->Information.Phy[ii].Identify.bDeviceType =
++ CSMI_SAS_EDGE_EXPANDER_DEVICE;
++ break;
++
++ case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
++ karg->Information.Phy[ii].Identify.bDeviceType =
++ CSMI_SAS_FANOUT_EXPANDER_DEVICE;
++ break;
++ }
++
++ /* Fill in Phy Initiator Port Protocol. Bits 6:3
++ * More than one bit can be set, fall through cases.
++ */
++ protocol = le32_to_cpu(
++ sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x78;
++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol = 0;
++ if( protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR )
++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
++ CSMI_SAS_PROTOCOL_SSP;
++ if( protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR )
++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
++ CSMI_SAS_PROTOCOL_STP;
++ if( protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR )
++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
++ CSMI_SAS_PROTOCOL_SMP;
++ if( protocol & MPI_SAS_DEVICE_INFO_SATA_HOST )
++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
++ CSMI_SAS_PROTOCOL_SATA;
++
++ /* Fill in Phy Target Port Protocol. Bits 10:7
++ * More than one bit can be set, fall through cases.
++ */
++ protocol = le32_to_cpu(
++ sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x780;
++ karg->Information.Phy[ii].Identify.bTargetPortProtocol = 0;
++ if( protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET )
++ karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
++ CSMI_SAS_PROTOCOL_SSP;
++ if( protocol & MPI_SAS_DEVICE_INFO_STP_TARGET )
++ karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
++ CSMI_SAS_PROTOCOL_STP;
++ if( protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET )
++ karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
++ CSMI_SAS_PROTOCOL_SMP;
++ if( protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE )
++ karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
++ CSMI_SAS_PROTOCOL_SATA;
++
++ /* Setup SAS Address for the attached device */
++ if (sasPhyPg0->AttachedDevHandle) {
++ sas_address = reverse_byte_order64(sas_address);
++ memcpy(karg->Information.Phy[ii].Attached.bSASAddress,
++ &sas_address, sizeof(u64));
++ karg->Information.Phy[ii].Attached.bPhyIdentifier =
++ sasPhyPg0->AttachedPhyIdentifier;
++ }
++
++ /* Setup SAS Address for the parent device */
++ csmisas_sas_device_pg0(ioc, &device_info,
++ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
++ sasIoUnitPg0->PhyData[ii].ControllerDevHandle);
++ sas_address = reverse_byte_order64(device_info.sas_address);
++ memcpy(karg->Information.Phy[ii].Identify.bSASAddress,
++ &sas_address, sizeof(u64));
++ karg->Information.Phy[ii].Identify.bPhyIdentifier = ii;
++
++ pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz,
++ (u8 *) sasPhyPg0, sasPhyPg0_dma);
++ }
++
++sas_get_phy_info_exit:
++
++ if (sasIoUnitPg0)
++ pci_free_consistent(ioc->pcidev, sasIoUnitPg0_data_sz,
++ (u8 *) sasIoUnitPg0, sasIoUnitPg0_dma);
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, karg,
++ sizeof(CSMI_SAS_PHY_INFO_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to write out csmisas_get_phy_info_buffer @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ free_pages((unsigned long)karg, memory_pages);
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI SAS Set PHY Info command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_set_phy_info(unsigned long arg)
++{
++ CSMI_SAS_SET_PHY_INFO_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_SET_PHY_INFO_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++
++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_set_phy_info struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++/* TODO - implement IOCTL here */
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE;
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n"));
++
++// cim_set_phy_info_exit:
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_set_phy_info @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++
++}
++
++/**
++ * Prototype Routine for the CSMI Sas Get SCSI Address command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_scsi_address(unsigned long arg)
++{
++ CSMI_SAS_GET_SCSI_ADDRESS_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_GET_SCSI_ADDRESS_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++ u64 sas_address;
++ struct sas_device_info *sas_info;
++
++ if (copy_from_user(&karg, uarg,
++ sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_get_scsi_address struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ /* reverse byte order the sas address */
++ memcpy(&sas_address, karg.bSASAddress, sizeof(u64));
++ sas_address = reverse_byte_order64(sas_address);
++
++ /* Search the list for the matching SAS address. */
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_SCSI_ADDRESS;
++ karg.bPathId = 0;
++ karg.bTargetId = 0;
++ karg.bLun = 0;
++
++ sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address);
++ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume)
++ goto csmisas_get_scsi_address_exit;
++
++ karg.bPathId = sas_info->os.channel;
++ karg.bTargetId = sas_info->os.id;
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ csmisas_get_scsi_address_exit:
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_get_scsi_address @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI Sas Get SCSI Address command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_sata_signature(unsigned long arg)
++{
++ CSMI_SAS_SATA_SIGNATURE_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_SATA_SIGNATURE_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++ int rc, jj;
++ ConfigExtendedPageHeader_t hdr;
++ CONFIGPARMS cfg;
++ SasPhyPage0_t *sasPhyPg0;
++ dma_addr_t sasPhyPg0_dma;
++ int sasPhyPg0_data_sz;
++ SasDevicePage1_t *sasDevicePg1;
++ dma_addr_t sasDevicePg1_dma;
++ int sasDevicePg1_data_sz;
++ u8 phyId;
++ u64 sas_address;
++
++ sasPhyPg0=NULL;
++ sasPhyPg0_data_sz=0;
++ sasDevicePg1=NULL;
++ sasDevicePg1_data_sz=0;
++
++ if (copy_from_user(&karg, uarg,
++ sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_sata_signature struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++ phyId = karg.Signature.bPhyIdentifier;
++ if (phyId >= ioc->num_ports) {
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST;
++ dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n"));
++ goto cim_sata_signature_exit;
++ }
++
++ /* Default to success.*/
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ /* Issue a config request to get the devHandle of the attached device
++ */
++
++ /* Issue a config request to get phy information. */
++ hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
++ hdr.ExtPageLength = 0;
++ hdr.PageNumber = 0;
++ hdr.Reserved1 = 0;
++ hdr.Reserved2 = 0;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
++
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.pageAddr = phyId;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ /* Don't check if this failed. Already in a
++ * failure case.
++ */
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n"));
++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sata_signature_exit;
++ }
++
++ if (hdr.ExtPageLength == 0) {
++ /* Don't check if this failed. Already in a
++ * failure case.
++ */
++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sata_signature_exit;
++ }
++
++
++ sasPhyPg0_data_sz = hdr.ExtPageLength * 4;
++ rc = -ENOMEM;
++
++ sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent(ioc->pcidev,
++ sasPhyPg0_data_sz, &sasPhyPg0_dma);
++
++ if (! sasPhyPg0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sata_signature_exit;
++ }
++
++ memset((u8 *)sasPhyPg0, 0, sasPhyPg0_data_sz);
++ cfg.physAddr = sasPhyPg0_dma;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ /* Don't check if this failed. Already in a
++ * failure case.
++ */
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n"));
++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sata_signature_exit;
++ }
++
++ /* Make sure a SATA device is attached. */
++ if ((le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) &
++ MPI_SAS_DEVICE_INFO_SATA_DEVICE) == 0) {
++ dcsmisasprintk(ioc, printk(KERN_WARNING ": NOT A SATA DEVICE\n"));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_SATA_DEVICE;
++ goto cim_sata_signature_exit;
++ }
++
++ /* Get device page 1 for FIS signature. */
++ hdr.PageVersion = MPI_SASDEVICE1_PAGEVERSION;
++ hdr.ExtPageLength = 0;
++ hdr.PageNumber = 1 /* page number 1 */;
++ hdr.Reserved1 = 0;
++ hdr.Reserved2 = 0;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
++
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.physAddr = -1;
++
++ cfg.pageAddr = ((MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT) |
++ le16_to_cpu(sasPhyPg0->AttachedDevHandle));
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: MPI_SASDEVICE1_PAGEVERSION: HEADER\n"));
++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sata_signature_exit;
++ }
++
++ if (hdr.ExtPageLength == 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sata_signature_exit;
++ }
++
++ sasDevicePg1_data_sz = hdr.ExtPageLength * 4;
++ rc = -ENOMEM;
++
++ sasDevicePg1 = (SasDevicePage1_t *) pci_alloc_consistent
++ (ioc->pcidev, sasDevicePg1_data_sz, &sasDevicePg1_dma);
++
++ if (! sasDevicePg1) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sata_signature_exit;
++ }
++
++ memset((u8 *)sasDevicePg1, 0, sasDevicePg1_data_sz);
++ cfg.physAddr = sasDevicePg1_dma;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: MPI_SASDEVICE1_PAGEVERSION: PAGE\n"));
++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sata_signature_exit;
++ }
++
++/* EDM : dump Device Page 1 data*/
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 1 ---------\n"));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%x\n",sasDevicePg1->DevHandle));
++ memcpy(&sas_address, &sasDevicePg1->SASAddress, sizeof(u64));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
++ (unsigned long long)sas_address));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%x\n",sasDevicePg1->TargetID));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Bus=0x%x\n",sasDevicePg1->Bus));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Initial Reg Device FIS="));
++ for(jj=0;jj<20;jj++)
++ dcsmisasprintk(ioc, printk("%02x ",
++ ((u8 *)&sasDevicePg1->InitialRegDeviceFIS)[jj]));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n"));
++/* EDM : debug data */
++
++ memcpy(karg.Signature.bSignatureFIS,
++ sasDevicePg1->InitialRegDeviceFIS,20);
++
++ cim_sata_signature_exit:
++
++ if (sasPhyPg0)
++ pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz,
++ (u8 *) sasPhyPg0, sasPhyPg0_dma);
++
++ if (sasDevicePg1)
++ pci_free_consistent(ioc->pcidev, sasDevicePg1_data_sz,
++ (u8 *) sasDevicePg1, sasDevicePg1_dma);
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_sata_signature @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI Sas Get SCSI Address command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_device_address(unsigned long arg)
++{
++ CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++ struct sas_device_info *sas_info;
++ u64 sas_address;
++
++ if (copy_from_user(&karg, uarg,
++ sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_get_device_address_buffer struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_DEVICE_ADDRESS;
++ memset(karg.bSASAddress, 0, sizeof(u64));
++ memset(karg.bSASLun, 0, sizeof(karg.bSASLun));
++
++ /* Search the list for the matching SAS address. */
++ sas_info = csmisas_get_device_component_by_os(ioc, karg.bPathId,
++ karg.bTargetId);
++ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume)
++ goto csmisas_get_device_address_exit;
++
++ sas_address = reverse_byte_order64(sas_info->sas_address);
++ memcpy(karg.bSASAddress, &sas_address, sizeof(u64));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ csmisas_get_device_address_exit:
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_get_device_address_buffer @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI Sas Get Link Errors command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_link_errors(unsigned long arg)
++{
++ CSMI_SAS_LINK_ERRORS_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_LINK_ERRORS_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ MPT_FRAME_HDR *mf = NULL;
++ MPIHeader_t *mpi_hdr;
++ int iocnum;
++ int rc;
++ ConfigExtendedPageHeader_t hdr;
++ CONFIGPARMS cfg;
++ SasPhyPage1_t *sasPhyPage1;
++ dma_addr_t sasPhyPage1_dma;
++ int sasPhyPage1_data_sz;
++ SasIoUnitControlRequest_t *sasIoUnitCntrReq;
++ SasIoUnitControlReply_t *sasIoUnitCntrReply;
++ u8 phyId;
++ u16 ioc_status;
++ u32 MsgContext;
++
++ sasPhyPage1=NULL;
++ sasPhyPage1_data_sz=0;
++
++ if (copy_from_user(&karg, uarg,
++ sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmisas_get_link_errors struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++ phyId = karg.Information.bPhyIdentifier;
++ if (phyId >= ioc->num_ports) {
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST;
++ dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n"));
++ goto cim_get_link_errors_exit;
++ }
++
++ /* Default to success.*/
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ /* Issue a config request to get the devHandle of the attached device
++ */
++
++ /* Issue a config request to get phy information. */
++ hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
++ hdr.ExtPageLength = 0;
++ hdr.PageNumber = 1 /* page number 1*/;
++ hdr.Reserved1 = 0;
++ hdr.Reserved2 = 0;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
++
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.pageAddr = phyId;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ /* Don't check if this failed. Already in a
++ * failure case.
++ */
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: MPI_SASPHY1_PAGEVERSION: HEADER\n"));
++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_link_errors_exit;
++ }
++
++ if (hdr.ExtPageLength == 0) {
++ /* Don't check if this failed. Already in a
++ * failure case.
++ */
++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_link_errors_exit;
++ }
++
++
++ sasPhyPage1_data_sz = hdr.ExtPageLength * 4;
++ rc = -ENOMEM;
++
++ sasPhyPage1 = (SasPhyPage1_t *) pci_alloc_consistent(ioc->pcidev,
++ sasPhyPage1_data_sz, &sasPhyPage1_dma);
++
++ if (! sasPhyPage1) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_link_errors_exit;
++ }
++
++ memset((u8 *)sasPhyPage1, 0, sasPhyPage1_data_sz);
++ cfg.physAddr = sasPhyPage1_dma;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ /* Don't check if this failed. Already in a
++ * failure case.
++ */
++ dcsmisasprintk(ioc, printk(KERN_ERR ": FAILED: MPI_SASPHY1_PAGEVERSION: PAGE\n"));
++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_link_errors_exit;
++ }
++
++/* EDM : dump PHY Page 1 data*/
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n"));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n",
++ sasPhyPage1->InvalidDwordCount));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n",
++ sasPhyPage1->RunningDisparityErrorCount));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n",
++ sasPhyPage1->LossDwordSynchCount));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n",
++ sasPhyPage1->PhyResetProblemCount));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n"));
++/* EDM : debug data */
++
++ karg.Information.uInvalidDwordCount =
++ le32_to_cpu(sasPhyPage1->InvalidDwordCount);
++ karg.Information.uRunningDisparityErrorCount =
++ le32_to_cpu(sasPhyPage1->RunningDisparityErrorCount);
++ karg.Information.uLossOfDwordSyncCount =
++ le32_to_cpu(sasPhyPage1->LossDwordSynchCount);
++ karg.Information.uPhyResetProblemCount =
++ le32_to_cpu(sasPhyPage1->PhyResetProblemCount);
++
++ if (karg.Information.bResetCounts ==
++ CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS ) {
++ goto cim_get_link_errors_exit;
++ }
++
++ /* Clear Error log
++ *
++ * Issue IOUNIT Control Reqeust Message
++ */
++
++ /* Get a MF for this command.
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_link_errors_exit;
++ }
++
++ mpi_hdr = (MPIHeader_t *) mf;
++ MsgContext = mpi_hdr->MsgContext;
++ sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
++ memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
++ sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
++ sasIoUnitCntrReq->MsgContext = MsgContext;
++ sasIoUnitCntrReq->PhyNum = phyId;
++ sasIoUnitCntrReq->Operation = MPI_SAS_OP_PHY_CLEAR_ERROR_LOG;
++
++ if (csmisas_send_command_wait(ioc, mf, karg.IoctlHeader.Timeout) != 0) {
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_link_errors_exit;
++ }
++
++ /* process the completed Reply Message Frame */
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
++
++ sasIoUnitCntrReply =
++ (SasIoUnitControlReply_t *)ioc->ioctl_cmds.reply;
++ ioc_status = le16_to_cpu(sasIoUnitCntrReply->IOCStatus)
++ & MPI_IOCSTATUS_MASK;
++
++ if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": SAS IO Unit Control: "));
++ dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X\n",
++ sasIoUnitCntrReply->IOCStatus,
++ sasIoUnitCntrReply->IOCLogInfo));
++ }
++ }
++
++ cim_get_link_errors_exit:
++
++ if (sasPhyPage1)
++ pci_free_consistent(ioc->pcidev, sasPhyPage1_data_sz,
++ (u8 *) sasPhyPage1, sasPhyPage1_dma);
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmisas_get_link_errors @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++
++}
++
++/**
++ * Prototype Routine for the CSMI SAS SMP Passthru command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_smp_passthru(unsigned long arg)
++{
++ CSMI_SAS_SMP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg;
++ MPT_ADAPTER *ioc;
++ CSMI_SAS_SMP_PASSTHRU_BUFFER *karg;
++ pSmpPassthroughRequest_t smpReq;
++ pSmpPassthroughReply_t smpReply;
++ MPT_FRAME_HDR *mf = NULL;
++ MPIHeader_t *mpi_hdr;
++ char *psge;
++ int iocnum, flagsLength;
++ void * request_data;
++ dma_addr_t request_data_dma;
++ u32 request_data_sz;
++ void * response_data;
++ dma_addr_t response_data_dma;
++ u32 response_data_sz;
++ u16 ioc_status;
++ u64 sas_address;
++ u32 MsgContext;
++ int malloc_data_sz;
++ int memory_pages;
++
++ malloc_data_sz = sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER);
++ memory_pages = get_order(malloc_data_sz);
++ karg = (CSMI_SAS_SMP_PASSTHRU_BUFFER *)__get_free_pages(
++ GFP_KERNEL, memory_pages);
++ if (!karg){
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to malloc CSMI_SAS_SMP_PASSTHRU_BUFFER "
++ "malloc_data_sz=%d memory_pages=%d\n",
++ __FILE__, __LINE__, __FUNCTION__,
++ malloc_data_sz, memory_pages);
++ return -ENOMEM;
++ }
++
++ if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_smp_passthru struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ request_data = NULL;
++ response_data = NULL;
++ response_data_sz = sizeof(CSMI_SAS_SMP_RESPONSE);
++ request_data_sz = karg->Parameters.uRequestLength;
++
++ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)karg, memory_pages);
++ return -ENODEV;
++ }
++
++ if (ioc->ioc_reset_in_progress) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Busy with IOC Reset \n",
++ __FILE__, __LINE__,__FUNCTION__);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EBUSY;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)karg, memory_pages);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ /* Default to success.*/
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ /* Do some error checking on the request. */
++ if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT;
++ goto cim_smp_passthru_exit;
++ }
++
++ if ((request_data_sz > 0xFFFF) || (!request_data_sz)) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_smp_passthru_exit;
++ }
++
++ /* Get a free request frame and save the message context.
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_smp_passthru_exit;
++ }
++
++ mpi_hdr = (MPIHeader_t *) mf;
++ MsgContext = mpi_hdr->MsgContext;
++ smpReq = (pSmpPassthroughRequest_t ) mf;
++
++ memset(smpReq,0,ioc->req_sz);
++
++ memcpy(&sas_address, karg->Parameters.bDestinationSASAddress,
++ sizeof(u64));
++ sas_address = cpu_to_le64(reverse_byte_order64(sas_address));
++ memcpy(&smpReq->SASAddress, &sas_address, sizeof(u64));
++
++ /* Fill in smp request. */
++ smpReq->PhysicalPort = karg->Parameters.bPortIdentifier;
++ smpReq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
++ smpReq->RequestDataLength = cpu_to_le16(request_data_sz);
++ smpReq->ConnectionRate = karg->Parameters.bConnectionRate;
++ smpReq->MsgContext = MsgContext;
++ smpReq->Reserved2 = 0;
++ smpReq->Reserved3 = 0;
++
++ /*
++ * Prepare the necessary pointers to run
++ * through the SGL generation
++ */
++
++ psge = (char *)&smpReq->SGL;
++
++ /* setup the *Request* payload SGE */
++ flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
++ MPI_SGE_FLAGS_SYSTEM_ADDRESS |
++ MPI_SGE_FLAGS_HOST_TO_IOC |
++ MPI_SGE_FLAGS_END_OF_BUFFER;
++
++ flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
++ flagsLength |= request_data_sz;
++
++ request_data = pci_alloc_consistent(
++ ioc->pcidev, request_data_sz, &request_data_dma);
++
++ if (!request_data) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ mpt_free_msg_frame(ioc, mf);
++ goto cim_smp_passthru_exit;
++ }
++
++ ioc->add_sge(psge, flagsLength, request_data_dma);
++ psge += ioc->SGE_size;
++
++ memcpy(request_data, &karg->Parameters.Request, request_data_sz);
++
++ /* setup the *Response* payload SGE */
++ response_data = pci_alloc_consistent(
++ ioc->pcidev, response_data_sz, &response_data_dma);
++
++ if (!response_data) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ mpt_free_msg_frame(ioc, mf);
++ goto cim_smp_passthru_exit;
++ }
++
++ flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
++ MPI_SGE_FLAGS_SYSTEM_ADDRESS |
++ MPI_SGE_FLAGS_IOC_TO_HOST |
++ MPI_SGE_FLAGS_END_OF_BUFFER;
++
++ flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
++ flagsLength |= response_data_sz;
++
++ ioc->add_sge(psge, flagsLength, response_data_dma);
++
++ if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_smp_passthru_exit;
++ }
++
++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": SMP Passthru: oh no, there is no reply!!"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_smp_passthru_exit;
++ }
++
++ /* process the completed Reply Message Frame */
++ smpReply = (pSmpPassthroughReply_t )ioc->ioctl_cmds.reply;
++ ioc_status = le16_to_cpu(smpReply->IOCStatus) & MPI_IOCSTATUS_MASK;
++
++ if ((ioc_status != MPI_IOCSTATUS_SUCCESS) &&
++ (ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN)) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": SMP Passthru: "));
++ dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n",
++ le16_to_cpu(smpReply->IOCStatus),
++ le32_to_cpu(smpReply->IOCLogInfo),
++ smpReply->SASStatus));
++ goto cim_smp_passthru_exit;
++ }
++
++ karg->Parameters.bConnectionStatus =
++ map_sas_status_to_csmi(smpReply->SASStatus);
++
++
++ if (le16_to_cpu(smpReply->ResponseDataLength)) {
++ karg->Parameters.uResponseBytes = le16_to_cpu(smpReply->ResponseDataLength);
++ memcpy(&karg->Parameters.Response,
++ response_data, le16_to_cpu(smpReply->ResponseDataLength));
++ }
++
++ cim_smp_passthru_exit:
++
++ if (request_data)
++ pci_free_consistent(ioc->pcidev, request_data_sz,
++ (u8 *)request_data, request_data_dma);
++
++ if (response_data)
++ pci_free_consistent(ioc->pcidev, response_data_sz,
++ (u8 *)response_data, response_data_dma);
++
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, karg,
++ sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_smp_passthru @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ free_pages((unsigned long)karg, memory_pages);
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI SAS SSP Passthru command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int csmisas_ssp_passthru(unsigned long arg)
++{
++ CSMI_SAS_SSP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_SSP_PASSTHRU_BUFFER karg_hdr, * karg;
++ MPT_ADAPTER *ioc = NULL;
++ pSCSIIORequest_t pScsiRequest;
++ pSCSIIOReply_t pScsiReply;
++ MPT_FRAME_HDR *mf = NULL;
++ MPIHeader_t *mpi_hdr;
++ int iocnum,ii;
++ u64 sas_address;
++ u16 req_idx;
++ char *psge;
++ int flagsLength;
++ void * request_data;
++ dma_addr_t request_data_dma;
++ u32 request_data_sz;
++ int malloc_data_sz;
++ int memory_pages;
++ u16 ioc_status;
++ u8 volume_id;
++ u8 volume_bus;
++ u8 is_hidden_raid_component;
++ u8 channel;
++ u8 id;
++ struct sas_device_info *sas_info;
++ u8 skey, asc, ascq;
++ u32 MsgContext;
++
++ if (copy_from_user(&karg_hdr, uarg, sizeof(CSMI_SAS_SSP_PASSTHRU_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_ssp_passthru struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ request_data = NULL;
++ request_data_sz = karg_hdr.Parameters.uDataLength;
++ channel = 0;
++ id = 0;
++ volume_id = 0;
++ volume_bus = 0;
++ is_hidden_raid_component = 0;
++
++ malloc_data_sz = (request_data_sz +
++ offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER, bDataBuffer));
++ memory_pages = get_order(malloc_data_sz);
++ karg = (CSMI_SAS_SSP_PASSTHRU_BUFFER *)__get_free_pages(
++ GFP_KERNEL, memory_pages);
++ if (!karg){
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to malloc SAS_SSP_PASSTHRU_BUFFER "
++ "malloc_data_sz=%d memory_pages=%d\n",
++ __FILE__, __LINE__, __FUNCTION__,
++ malloc_data_sz, memory_pages);
++ return -ENOMEM;
++ }
++
++ memset(karg, 0, sizeof(*karg));
++
++ if (copy_from_user(karg, uarg, request_data_sz +
++ offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER,bDataBuffer))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_ssp_passthru struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ /*
++ * some checks of the incoming frame
++ */
++ if ( offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER,bDataBuffer) +
++ request_data_sz - sizeof(IOCTL_HEADER) >
++ karg->IoctlHeader.Length ) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ "%s::%s()"
++ " @%d - expected datalen incorrect!\n",
++ __FILE__, __FUNCTION__, __LINE__));
++ goto cim_ssp_passthru_exit;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ goto cim_ssp_passthru_exit;
++ }
++
++ if (ioc->ioc_reset_in_progress) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Busy with IOC Reset \n",
++ __FILE__, __LINE__,__FUNCTION__);
++ return -EBUSY;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
++ printk(KERN_ERR "%s::%s()@%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ goto cim_ssp_passthru_exit;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ /* Default to success.
++ */
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ /* Neither a phy nor a port has been selected.
++ */
++ if ((karg->Parameters.bPhyIdentifier == CSMI_SAS_USE_PORT_IDENTIFIER) &&
++ (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT)) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT;
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ "%s::%s()"
++ " @%d - incorrect bPhyIdentifier and bPortIdentifier!\n",
++ __FILE__, __FUNCTION__, __LINE__));
++ goto cim_ssp_passthru_exit;
++ }
++
++ /* A phy has been selected. Verify that it's valid.
++ */
++ if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) {
++
++ /* Is the phy in range? */
++ if (karg->Parameters.bPhyIdentifier >= ioc->num_ports) {
++ dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports (%d %d)\n",
++ karg->Parameters.bPhyIdentifier,
++ ioc->num_ports));
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_PHY_DOES_NOT_EXIST;
++ goto cim_ssp_passthru_exit;
++ }
++ }
++
++ if(karg->Parameters.bAdditionalCDBLength) {
++ /* TODO - SCSI IO (32) Request Message support
++ */
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": greater than 16-byte cdb "
++ "is not supported!\n"));
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ goto cim_ssp_passthru_exit;
++ }
++
++ /* we will use SAS address to resolve the scsi adddressing
++ */
++ memcpy(&sas_address, karg->Parameters.bDestinationSASAddress,
++ sizeof(u64));
++ sas_address = reverse_byte_order64(sas_address);
++
++ /* Search the list for the matching SAS address.
++ */
++ sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address);
++ if (!sas_info || sas_info->is_cached) {
++ /*
++ *Invalid SAS address
++ */
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ "%s::%s() @%d - couldn't find associated "
++ "SASAddress=%llX!\n", __FILE__, __FUNCTION__, __LINE__,
++ (unsigned long long)sas_address));
++ goto cim_ssp_passthru_exit;
++ }
++
++ id = sas_info->fw.id;
++ channel = sas_info->fw.channel;
++
++ if (csmisas_is_phys_disk(ioc, channel, id)) {
++ id = csmisas_raid_id_to_num(ioc, channel, id);
++ channel = 0;
++ is_hidden_raid_component = 1;
++ }
++
++ /* Get a free request frame and save the message context.
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_ssp_passthru_exit;
++ }
++
++ mpi_hdr = (MPIHeader_t *) mf;
++ MsgContext = mpi_hdr->MsgContext;
++ pScsiRequest = (pSCSIIORequest_t) mf;
++ req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
++
++ memset(pScsiRequest,0,sizeof(SCSIIORequest_t));
++
++ /* Fill in SCSI IO (16) request.
++ */
++
++ pScsiRequest->Function = (is_hidden_raid_component == 1) ?
++ MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH : MPI_FUNCTION_SCSI_IO_REQUEST;
++ pScsiRequest->TargetID = id;
++ pScsiRequest->Bus = channel;
++ memcpy(pScsiRequest->LUN, &karg->Parameters.bLun, 8);
++ pScsiRequest->CDBLength = karg->Parameters.bCDBLength;
++ pScsiRequest->DataLength = cpu_to_le32(request_data_sz);
++ pScsiRequest->MsgContext = MsgContext;
++ memcpy(pScsiRequest->CDB, karg->Parameters.bCDB,
++ pScsiRequest->CDBLength);
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\tchannel = %d id = %d ",
++ sas_info->fw.channel, sas_info->fw.id));
++ dcsmisasprintk(ioc, if(is_hidden_raid_component)
++ printk(KERN_DEBUG "num_id = %d ", id));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\tcdb_len = %d request_len = %d\n",
++ pScsiRequest->CDBLength, request_data_sz));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\t"));
++ dcsmisasprintk(ioc, for (ii = 0; ii < pScsiRequest->CDBLength; ++ii)
++ printk(" %02x", pScsiRequest->CDB[ii]));
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
++
++ /* direction
++ */
++ if (karg->Parameters.uFlags & CSMI_SAS_SSP_READ) {
++ pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ);
++ } else if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) {
++ pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_WRITE);
++ } else if ((karg->Parameters.uFlags & CSMI_SAS_SSP_UNSPECIFIED) &&
++ (!karg->Parameters.uDataLength)) {
++ /* no data transfer
++ */
++ pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_NODATATRANSFER);
++ } else {
++ /* no direction specified
++ */
++ pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ);
++ pScsiRequest->MsgFlags =
++ MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR;
++ }
++
++ pScsiRequest->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
++ if (ioc->sg_addr_size == sizeof(u64))
++ pScsiRequest->MsgFlags |= MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64;
++
++ /* task attributes
++ */
++ if((karg->Parameters.uFlags && 0xFF) == 0) {
++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ);
++ } else if (karg->Parameters.uFlags &
++ CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE) {
++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_HEADOFQ);
++ } else if (karg->Parameters.uFlags &
++ CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED) {
++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ORDEREDQ);
++ } else if (karg->Parameters.uFlags &
++ CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA) {
++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ACAQ);
++ } else {
++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_UNTAGGED);
++ }
++
++ /* setup sense
++ */
++ pScsiRequest->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
++ pScsiRequest->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma +
++ (req_idx * MPT_SENSE_BUFFER_ALLOC));
++
++ /* setup databuffer sg, assuming we fit everything one contiguous buffer
++ */
++ psge = (char *)&pScsiRequest->SGL;
++
++ if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) {
++ flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
++ } else if (karg->Parameters.uFlags & CSMI_SAS_SSP_READ) {
++ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
++ }else {
++ flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
++ MPI_SGE_FLAGS_DIRECTION )
++ << MPI_SGE_FLAGS_SHIFT;
++ }
++ flagsLength |= request_data_sz;
++
++ if ( request_data_sz > 0) {
++ request_data = pci_alloc_consistent(
++ ioc->pcidev, request_data_sz, &request_data_dma);
++
++ if (request_data == NULL) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED "
++ "request_data_sz=%d\n", request_data_sz));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ mpt_free_msg_frame(ioc, mf);
++ goto cim_ssp_passthru_exit;
++ }
++
++ ioc->add_sge(psge, flagsLength, request_data_dma);
++ if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE)
++ memcpy(request_data, karg->bDataBuffer, request_data_sz);
++ } else {
++ ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
++ }
++
++ if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_ssp_passthru_exit;
++ }
++
++ memset(&karg->Status,0,sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS));
++ karg->Status.bConnectionStatus = CSMI_SAS_OPEN_ACCEPT;
++ karg->Status.bDataPresent = CSMI_SAS_SSP_NO_DATA_PRESENT;
++ karg->Status.bStatus = GOOD;
++ karg->Status.bResponseLength[0] = 0;
++ karg->Status.bResponseLength[1] = 0;
++ karg->Status.uDataBytes = request_data_sz;
++
++ /* process the completed Reply Message Frame */
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
++
++ pScsiReply = (pSCSIIOReply_t ) ioc->ioctl_cmds.reply;
++ karg->Status.bStatus = pScsiReply->SCSIStatus;
++ karg->Status.uDataBytes = min(le32_to_cpu(pScsiReply->TransferCount),
++ request_data_sz);
++ ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
++
++ if (pScsiReply->SCSIState ==
++ MPI_SCSI_STATE_AUTOSENSE_VALID) {
++ karg->Status.bConnectionStatus =
++ CSMI_SAS_SSP_SENSE_DATA_PRESENT;
++ karg->Status.bResponseLength[0] =
++ (u8)le32_to_cpu(pScsiReply->SenseCount) & 0xFF;
++ memcpy(karg->Status.bResponse,
++ ioc->ioctl_cmds.sense, le32_to_cpu(pScsiReply->SenseCount));
++
++ skey = ioc->ioctl_cmds.sense[2] & 0x0F;
++ asc = ioc->ioctl_cmds.sense[12];
++ ascq = ioc->ioctl_cmds.sense[13];
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\t [sense_key,asc,ascq]: "
++ "[0x%02x,0x%02x,0x%02x]\n",
++ skey, asc, ascq));
++
++ } else if(pScsiReply->SCSIState ==
++ MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
++ karg->Status.bDataPresent =
++ CSMI_SAS_SSP_RESPONSE_DATA_PRESENT;
++ karg->Status.bResponseLength[0] =
++ sizeof(pScsiReply->ResponseInfo);
++ for (ii=0;ii<sizeof(pScsiReply->ResponseInfo);ii++) {
++ karg->Status.bResponse[ii] =
++ ((u8*)&pScsiReply->ResponseInfo)[
++ (sizeof(pScsiReply->ResponseInfo)-1)-ii];
++ }
++ } else if ((ioc_status != MPI_IOCSTATUS_SUCCESS) &&
++ (ioc_status != MPI_IOCSTATUS_SCSI_RECOVERED_ERROR) &&
++ (ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN)) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": SCSI IO : "));
++ dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X\n",
++ pScsiReply->IOCStatus,
++ pScsiReply->IOCLogInfo));
++ }
++ }
++
++ if ((karg->Status.uDataBytes) && (request_data) &&
++ (karg->Parameters.uFlags & CSMI_SAS_SSP_READ)) {
++ if (copy_to_user((void __user *)uarg->bDataBuffer,
++ request_data, karg->Status.uDataBytes)) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to write data to user %p\n",
++ __FILE__, __LINE__,__FUNCTION__,
++ (void*)karg->bDataBuffer);
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ }
++ }
++
++ cim_ssp_passthru_exit:
++
++
++ if (request_data)
++ pci_free_consistent(ioc->pcidev, request_data_sz,
++ (u8 *)request_data, request_data_dma);
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, karg,
++ offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER, bDataBuffer))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_ssp_passthru @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ free_pages((unsigned long)karg, memory_pages);
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI SAS STP Passthru command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_stp_passthru(unsigned long arg)
++{
++ CSMI_SAS_STP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_STP_PASSTHRU_BUFFER karg_hdr, *karg;
++ MPT_ADAPTER *ioc = NULL;
++ pSataPassthroughRequest_t pSataRequest;
++ pSataPassthroughReply_t pSataReply;
++ MPT_FRAME_HDR *mf = NULL;
++ MPIHeader_t *mpi_hdr;
++ int iocnum;
++ u32 data_sz;
++ u64 sas_address;
++ u16 req_idx;
++ char *psge;
++ int flagsLength;
++ void * request_data;
++ dma_addr_t request_data_dma;
++ u32 request_data_sz;
++ int malloc_data_sz;
++ int memory_pages;
++ u8 channel;
++ u8 id;
++ u8 volume_id;
++ u8 volume_bus;
++ struct sas_device_info *sas_info;
++ u16 ioc_status;
++ u32 MsgContext;
++
++ if (copy_from_user(&karg_hdr, uarg, sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ request_data=NULL;
++ request_data_sz = karg_hdr.Parameters.uDataLength;
++ volume_id = 0;
++ volume_bus = 0;
++ channel = 0;
++ id = 0;
++
++ malloc_data_sz = (request_data_sz +
++ offsetof(CSMI_SAS_STP_PASSTHRU_BUFFER, bDataBuffer));
++ memory_pages = get_order(malloc_data_sz);
++ karg = (CSMI_SAS_STP_PASSTHRU_BUFFER *)__get_free_pages(
++ GFP_KERNEL, memory_pages);
++ if (!karg){
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to malloc CSMI_SAS_STP_PASSTHRU_BUFFER "
++ "malloc_data_sz=%d memory_pages=%d\n",
++ __FILE__, __LINE__, __FUNCTION__,
++ malloc_data_sz, memory_pages);
++ return -ENOMEM;
++ }
++
++ memset(karg, 0, sizeof(*karg));
++
++ if (copy_from_user(karg, uarg, malloc_data_sz)) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_ssp_passthru struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)karg, memory_pages);
++ return -ENODEV;
++ }
++
++ if (ioc->ioc_reset_in_progress) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Busy with IOC Reset \n",
++ __FILE__, __LINE__,__FUNCTION__);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EBUSY;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)karg, memory_pages);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ /* Default to success.
++ */
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ /* Neither a phy nor a port has been selected.
++ */
++ if ((karg->Parameters.bPhyIdentifier == CSMI_SAS_USE_PORT_IDENTIFIER) &&
++ (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT)) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT;
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ "%s::%s() @%d - incorrect bPhyIdentifier and bPortIdentifier!\n",
++ __FILE__,__FUNCTION__, __LINE__));
++ goto cim_stp_passthru_exit;
++ }
++
++ /* A phy has been selected. Verify that it's valid.
++ */
++ if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) {
++
++ /* Is the phy in range? */
++ if (karg->Parameters.bPhyIdentifier >= ioc->num_ports) {
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_PHY_DOES_NOT_EXIST;
++ goto cim_stp_passthru_exit;
++ }
++ }
++
++ data_sz = sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) -
++ sizeof(IOCTL_HEADER) - sizeof(u8*) +
++ request_data_sz;
++
++ if ( data_sz > karg->IoctlHeader.Length ) {
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ "%s::%s() @%d - expected datalen incorrect!\n",
++ __FILE__, __FUNCTION__,__LINE__));
++ goto cim_stp_passthru_exit;
++ }
++
++
++ /* we will use SAS address to resolve the scsi adddressing
++ */
++ memcpy(&sas_address, karg->Parameters.bDestinationSASAddress,
++ sizeof(u64));
++ sas_address = reverse_byte_order64(sas_address);
++
++ /* Search the list for the matching SAS address.
++ */
++ sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address);
++ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume) {
++ /*
++ *Invalid SAS address
++ */
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ "%s::%s() @%d - couldn't find associated "
++ "SASAddress=%llX!\n", __FILE__, __FUNCTION__, __LINE__,
++ (unsigned long long)sas_address));
++ goto cim_stp_passthru_exit;
++ }
++
++ id = sas_info->fw.id;
++ channel = sas_info->fw.channel;
++
++ /* check that this is an STP or SATA target device
++ */
++ if ( !(sas_info->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET ) &&
++ !(sas_info->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE )) {
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ goto cim_stp_passthru_exit;
++ }
++
++ /* Get a free request frame and save the message context.
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_stp_passthru_exit;
++ }
++
++ mpi_hdr = (MPIHeader_t *) mf;
++ MsgContext = mpi_hdr->MsgContext;
++ pSataRequest = (pSataPassthroughRequest_t) mf;
++ req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
++
++ memset(pSataRequest,0,sizeof(pSataPassthroughRequest_t));
++
++ pSataRequest->TargetID = id;
++ pSataRequest->Bus = channel;
++ pSataRequest->Function = MPI_FUNCTION_SATA_PASSTHROUGH;
++ pSataRequest->PassthroughFlags = cpu_to_le16(karg->Parameters.uFlags);
++ pSataRequest->ConnectionRate = karg->Parameters.bConnectionRate;
++ pSataRequest->MsgContext = MsgContext;
++ pSataRequest->DataLength = cpu_to_le32(request_data_sz);
++ pSataRequest->MsgFlags = 0;
++ memcpy( pSataRequest->CommandFIS,karg->Parameters.bCommandFIS, 20);
++
++ psge = (char *)&pSataRequest->SGL;
++ if (karg->Parameters.uFlags & CSMI_SAS_STP_WRITE) {
++ flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
++ } else if (karg->Parameters.uFlags & CSMI_SAS_STP_READ) {
++ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
++ }else {
++ flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
++ MPI_SGE_FLAGS_DIRECTION )
++ << MPI_SGE_FLAGS_SHIFT;
++ }
++
++ flagsLength |= request_data_sz;
++ if (request_data_sz > 0) {
++ request_data = pci_alloc_consistent(
++ ioc->pcidev, request_data_sz, &request_data_dma);
++
++ if (request_data == NULL) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ mpt_free_msg_frame(ioc, mf);
++ goto cim_stp_passthru_exit;
++ }
++
++ ioc->add_sge(psge, flagsLength, request_data_dma);
++ if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE)
++ memcpy(request_data, karg->bDataBuffer, request_data_sz);
++ } else {
++ ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
++ }
++
++ if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_stp_passthru_exit;
++ }
++
++ memset(&karg->Status,0,sizeof(CSMI_SAS_STP_PASSTHRU_STATUS));
++
++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": STP Passthru: oh no, there is no reply!!"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_stp_passthru_exit;
++ }
++
++ /* process the completed Reply Message Frame */
++ pSataReply = (pSataPassthroughReply_t ) ioc->ioctl_cmds.reply;
++ ioc_status = le16_to_cpu(pSataReply->IOCStatus) & MPI_IOCSTATUS_MASK;
++
++ if (ioc_status != MPI_IOCSTATUS_SUCCESS &&
++ ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) {
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": STP Passthru: "));
++ dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n",
++ le16_to_cpu(pSataReply->IOCStatus),
++ le32_to_cpu(pSataReply->IOCLogInfo),
++ pSataReply->SASStatus));
++ }
++
++ karg->Status.bConnectionStatus =
++ map_sas_status_to_csmi(pSataReply->SASStatus);
++
++ memcpy(karg->Status.bStatusFIS,pSataReply->StatusFIS, 20);
++
++ /*
++ * for now, just zero out uSCR array,
++ * then copy the one dword returned
++ * in the reply frame into uSCR[0]
++ */
++ memset( karg->Status.uSCR, 0, 64);
++ karg->Status.uSCR[0] = le32_to_cpu(pSataReply->StatusControlRegisters);
++
++ if((le32_to_cpu(pSataReply->TransferCount)) && (request_data) &&
++ (karg->Parameters.uFlags & CSMI_SAS_STP_READ)) {
++ karg->Status.uDataBytes =
++ min(le32_to_cpu(pSataReply->TransferCount),request_data_sz);
++ if (copy_to_user((void __user *)uarg->bDataBuffer,
++ request_data, karg->Status.uDataBytes)) {
++ printk(KERN_ERR "%s::%s() @%d - "
++ "Unable to write data to user %p\n",
++ __FILE__, __FUNCTION__, __LINE__,
++ (void*)karg->bDataBuffer);
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ }
++ }
++
++ cim_stp_passthru_exit:
++
++ if (request_data)
++ pci_free_consistent(ioc->pcidev, request_data_sz,
++ (u8 *)request_data, request_data_dma);
++
++ /* Copy th data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, karg,
++ offsetof(CSMI_SAS_STP_PASSTHRU_BUFFER, bDataBuffer))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_ssp_passthru @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ free_pages((unsigned long)karg, memory_pages);
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI SAS Firmware Download command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_firmware_download(unsigned long arg)
++{
++ CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++ pMpiFwHeader_t pFwHeader=NULL;
++
++ if (copy_from_user(&karg, uarg,
++ sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_firmware_download struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ /* Default to success.*/
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++ karg.Information.usStatus = CSMI_SAS_FWD_SUCCESS;
++ karg.Information.usSeverity = CSMI_SAS_FWD_INFORMATION;
++
++ /* some checks of the incoming frame */
++ if ((karg.Information.uBufferLength +
++ sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD)) >
++ karg.IoctlHeader.Length) {
++ karg.IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ karg.Information.usStatus = CSMI_SAS_FWD_FAILED;
++ goto cim_firmware_download_exit;
++ }
++
++ if ( karg.Information.uDownloadFlags &
++ (CSMI_SAS_FWD_SOFT_RESET | CSMI_SAS_FWD_VALIDATE)) {
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ karg.Information.usStatus = CSMI_SAS_FWD_REJECT;
++ karg.Information.usSeverity = CSMI_SAS_FWD_ERROR;
++ goto cim_firmware_download_exit;
++ }
++
++ /* now we need to alloc memory so we can pull in the
++ * fw image attached to end of incoming packet.
++ */
++ pFwHeader = kmalloc(karg.Information.uBufferLength, GFP_KERNEL);
++ if (!pFwHeader){
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ karg.Information.usStatus = CSMI_SAS_FWD_REJECT;
++ karg.Information.usSeverity = CSMI_SAS_FWD_ERROR;
++ goto cim_firmware_download_exit;
++ }
++ memset(pFwHeader, 0, sizeof(*pFwHeader));
++
++ if (copy_from_user(pFwHeader, uarg->bDataBuffer,
++ karg.Information.uBufferLength)) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in pFwHeader @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if ( !((pFwHeader->Signature0 == MPI_FW_HEADER_SIGNATURE_0) &&
++ (pFwHeader->Signature1 == MPI_FW_HEADER_SIGNATURE_1) &&
++ (pFwHeader->Signature2 == MPI_FW_HEADER_SIGNATURE_2))) {
++ // the signature check failed
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ karg.Information.usStatus = CSMI_SAS_FWD_REJECT;
++ karg.Information.usSeverity = CSMI_SAS_FWD_ERROR;
++ goto cim_firmware_download_exit;
++ }
++
++ if ( mptctl_do_fw_download(karg.IoctlHeader.IOControllerNumber,
++ uarg->bDataBuffer, karg.Information.uBufferLength)
++ != 0) {
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ karg.Information.usStatus = CSMI_SAS_FWD_FAILED;
++ karg.Information.usSeverity = CSMI_SAS_FWD_FATAL;
++ goto cim_firmware_download_exit;
++ }
++
++ if((karg.Information.uDownloadFlags & CSMI_SAS_FWD_SOFT_RESET) ||
++ (karg.Information.uDownloadFlags & CSMI_SAS_FWD_HARD_RESET)) {
++ if (mpt_HardResetHandler(ioc, CAN_SLEEP) != 0) {
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ karg.Information.usStatus = CSMI_SAS_FWD_FAILED;
++ karg.Information.usSeverity = CSMI_SAS_FWD_FATAL;
++ }
++ }
++
++ cim_firmware_download_exit:
++
++ if(pFwHeader)
++ kfree(pFwHeader);
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_firmware_download @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI SAS Get RAID Info command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_raid_info(unsigned long arg)
++{
++ CSMI_SAS_RAID_INFO_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_RAID_INFO_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++ u32 raidFlags;
++ u8 maxRaidTypes;
++ u8 maxDrivesPerSet;
++
++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_INFO_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_get_raid_info struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ if (!ioc->raid_data.pIocPg2)
++ goto csmisas_get_raid_info_out;
++ karg.Information.uNumRaidSets =
++ ioc->raid_data.pIocPg2->NumActiveVolumes;
++ karg.Information.uMaxRaidSets = ioc->raid_data.pIocPg2->MaxVolumes;
++ if( ioc->raid_data.pIocPg6 ) {
++ // get absolute maximum for all RAID sets
++ maxDrivesPerSet = ioc->raid_data.pIocPg6->MaxDrivesIS;
++ maxDrivesPerSet = max(ioc->raid_data.pIocPg6->MaxDrivesIM,
++ maxDrivesPerSet);
++ maxDrivesPerSet = max(ioc->raid_data.pIocPg6->MaxDrivesIME,
++ maxDrivesPerSet);
++ karg.Information.uMaxDrivesPerSet = maxDrivesPerSet;
++ }
++ else
++ karg.Information.uMaxDrivesPerSet = 8;
++ // For bMaxRaidSets, count bits set in bits 0-6 of CapabilitiesFlags
++ raidFlags = ioc->raid_data.pIocPg2->CapabilitiesFlags & 0x0000007F;
++ for( maxRaidTypes=0; raidFlags; maxRaidTypes++ )
++ raidFlags &= raidFlags - 1;
++ karg.Information.bMaxRaidTypes = maxRaidTypes;
++ // ulMinRaidSetBlocks hard coded to 1MB until available from config page
++ karg.Information.ulMinRaidSetBlocks.uLowPart = 2048;
++ karg.Information.ulMinRaidSetBlocks.uHighPart = 0;
++ karg.Information.ulMaxRaidSetBlocks.uLowPart = 0xffffffff;
++ if( ioc->raid_data.pIocPg2->CapabilitiesFlags &
++ MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING )
++ karg.Information.ulMaxRaidSetBlocks.uHighPart = 0xffffffff;
++ else
++ karg.Information.ulMaxRaidSetBlocks.uHighPart = 0;
++ karg.Information.uMaxPhysicalDrives =
++ ioc->raid_data.pIocPg2->MaxPhysDisks;
++ karg.Information.uMaxExtents = 1;
++ karg.Information.uMaxModules = 0;
++ karg.Information.uMaxTransformationMemory = 0;
++ karg.Information.uChangeCount = ioc->csmi_change_count;
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++csmisas_get_raid_info_out:
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_RAID_INFO_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_get_raid_info @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * csmisas_do_raid - Format and Issue a RAID volume request message.
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @action: What do be done.
++ * @PhysDiskNum: Logical target id.
++ * @VolumeBus: Target locations bus.
++ * @VolumeId: Volume id
++ *
++ * Returns: < 0 on a fatal error
++ * 0 on success
++ *
++ * Remark: Wait to return until reply processed by the ISR.
++ **/
++static int
++csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus, u8 VolumeId, pMpiRaidActionReply_t reply)
++{
++ MpiRaidActionRequest_t *pReq;
++ MpiRaidActionReply_t *pReply;
++ MPT_FRAME_HDR *mf;
++
++ /* Get and Populate a free Frame
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
++ return -EAGAIN;
++ }
++ pReq = (MpiRaidActionRequest_t *)mf;
++ pReq->Action = action;
++ pReq->Reserved1 = 0;
++ pReq->ChainOffset = 0;
++ pReq->Function = MPI_FUNCTION_RAID_ACTION;
++ pReq->VolumeID = VolumeId;
++ pReq->VolumeBus = VolumeBus;
++ pReq->PhysDiskNum = PhysDiskNum;
++ pReq->MsgFlags = 0;
++ pReq->Reserved2 = 0;
++ pReq->ActionDataWord = 0; /* Reserved for this action */
++ //pReq->ActionDataSGE = 0;
++
++ ioc->add_sge((char *)&pReq->ActionDataSGE,
++ MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
++
++ if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0)
++ return -ENODATA;
++
++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) &&
++ (reply != NULL)){
++ pReply = (MpiRaidActionReply_t *)&(ioc->ioctl_cmds.reply);
++ memcpy(reply, pReply,
++ min(ioc->reply_sz,
++ 4*pReply->MsgLength));
++ }
++
++ return 0;
++}
++
++/**
++ * csmisas_raid_inq
++ * @ioc = per host instance
++ * @opcode = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH or
++ * MPI_FUNCTION_SCSI_IO_REQUEST
++ * @id = target id
++ * @bus = target bus
++ * @inq_vpd = inquiry data, returned
++ * @inq_vpd_sz = maximum size of inquiry data
++ *
++ * Return = 0(sucess), non-zero(failure)
++ **/
++static int
++csmisas_raid_inq(MPT_ADAPTER *ioc, u8 opcode, u8 bus, u8 id, u8 inq_vpd_page,
++ u8 * inq_vpd, u32 inq_vpd_sz)
++{
++ MPT_FRAME_HDR *mf = NULL;
++ MPIHeader_t *mpi_hdr;
++ pSCSIIORequest_t pScsiRequest;
++ u16 req_idx;
++ char *psge;
++ u8 inq_vpd_cdb[6];
++ u8 *request_data=NULL;
++ dma_addr_t request_data_dma;
++ u32 request_data_sz;
++ int rc = 0;
++ u32 MsgContext;
++
++ request_data_sz = inq_vpd_sz;
++
++ /* fill-in cdb */
++ memset(inq_vpd_cdb, 0, sizeof(inq_vpd_cdb));
++ inq_vpd_cdb[0] = 0x12;
++ if (inq_vpd_page) {
++ inq_vpd_cdb[1] = 0x01; /* evpd bit */
++ inq_vpd_cdb[2] = inq_vpd_page;
++ }
++ inq_vpd_cdb[3] = (u8)(request_data_sz >> 8);
++ inq_vpd_cdb[4] = (u8)request_data_sz;
++
++ /* Get a free request frame and save the message context.
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
++ goto csmisas_raid_inq_exit;
++ }
++
++ mpi_hdr = (MPIHeader_t *) mf;
++ MsgContext = mpi_hdr->MsgContext;
++ pScsiRequest = (pSCSIIORequest_t) mf;
++ req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
++
++ memset(pScsiRequest,0,sizeof(SCSIIORequest_t));
++ pScsiRequest->Function = opcode;
++ pScsiRequest->TargetID = id;
++ pScsiRequest->Bus = bus;
++ pScsiRequest->CDBLength = 6;
++ pScsiRequest->DataLength = cpu_to_le32(request_data_sz);
++ pScsiRequest->MsgContext = MsgContext;
++ memcpy(pScsiRequest->CDB,inq_vpd_cdb,pScsiRequest->CDBLength);
++ pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ);
++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ);
++ pScsiRequest->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
++ if (ioc->sg_addr_size == sizeof(u64))
++ pScsiRequest->MsgFlags |= MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64;
++
++ /* setup sense
++ */
++ pScsiRequest->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
++ pScsiRequest->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma +
++ (req_idx * MPT_SENSE_BUFFER_ALLOC));
++
++ request_data = pci_alloc_consistent(
++ ioc->pcidev, request_data_sz, &request_data_dma);
++
++ if (request_data == NULL) {
++ mpt_free_msg_frame(ioc, mf);
++ rc=-1;
++ goto csmisas_raid_inq_exit;
++ }
++
++ memset(request_data,0,request_data_sz);
++ psge = (char *)&pScsiRequest->SGL;
++ ioc->add_sge(psge, (MPT_SGE_FLAGS_SSIMPLE_READ | 0xFC) ,
++ request_data_dma);
++
++ if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0) {
++ rc=-1;
++ goto csmisas_raid_inq_exit;
++ }
++
++ /* copy the request_data */
++ memcpy(inq_vpd, request_data, request_data_sz);
++
++ csmisas_raid_inq_exit:
++
++ if (request_data)
++ pci_free_consistent(ioc->pcidev, request_data_sz,
++ request_data, request_data_dma);
++
++ return rc;
++}
++
++/**
++ * Prototype Routine for the CSMI SAS Get RAID Config command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_raid_config(unsigned long arg)
++{
++ CSMI_SAS_RAID_CONFIG_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_RAID_CONFIG_BUFFER karg,*pKarg=NULL;
++ CONFIGPARMS cfg;
++ ConfigPageHeader_t header;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++ u8 volumeID, VolumeBus;
++ u8 physDiskNum, physDiskNumMax;
++ int volumepage0sz = 0;
++ int physdiskpage0sz = 0, ioc_page5_sz = 0;
++ dma_addr_t volume0_dma, physdisk0_dma;
++ dma_addr_t ioc_page5_dma = 0;
++ pRaidVolumePage0_t pVolume0 = NULL;
++ pRaidPhysDiskPage0_t pPhysDisk0 = NULL;
++ pMpiRaidActionReply_t pRaidActionReply = NULL;
++ u32 device_info = 0;
++ pIOCPage5_t pIocPage5 = NULL;
++ int i, idx, csmi_sas_raid_config_buffer_sz;
++ int memory_pages;
++ int copy_buffer_sz = 0;
++ u64 totalMaxLBA, tmpTotalMaxLBA;
++ u64 sas_address;
++ struct sas_device_info *sas_info;
++
++ if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmisas_get_raid_config struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ csmi_sas_raid_config_buffer_sz = karg.IoctlHeader.Length;
++ memory_pages = get_order(csmi_sas_raid_config_buffer_sz);
++ pKarg = (CSMI_SAS_RAID_CONFIG_BUFFER *)__get_free_pages(
++ GFP_KERNEL, memory_pages);
++ if (!pKarg){
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to malloc RAID_CONFIG_BUFFER "
++ "csmi_sas_raid_config_buffer_sz=%d memory_pages=%d\n",
++ __FILE__, __LINE__, __FUNCTION__,
++ csmi_sas_raid_config_buffer_sz, memory_pages);
++ return -ENOMEM;
++ }
++ memset(pKarg, 0, sizeof(*pKarg));
++
++ if (copy_from_user(pKarg, uarg, csmi_sas_raid_config_buffer_sz)) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmisas_get_raid_config struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ if (pKarg->Configuration.uChangeCount != 0 &&
++ pKarg->Configuration.uChangeCount != ioc->csmi_change_count ) {
++ pKarg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ pKarg->Configuration.uFailureCode =
++ CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID;
++ goto cim_get_raid_config_exit;
++ }
++
++ if (!ioc->raid_data.pIocPg2) {
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_raid_config_exit;
++ }
++
++ /*
++ * Check to see if the input uRaidSetIndex is
++ * greater than the number of RAID sets
++ */
++ if (pKarg->Configuration.uRaidSetIndex >=
++ ioc->raid_data.pIocPg2->NumActiveVolumes) {
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_RAID_SET_OUT_OF_RANGE;
++ goto cim_get_raid_config_exit;
++ }
++
++ /*
++ * get RAID Volume Page 0
++ */
++ volumeID = ioc->raid_data.pIocPg2->RaidVolume[pKarg->Configuration.uRaidSetIndex].VolumeID;
++ VolumeBus = ioc->raid_data.pIocPg2->RaidVolume[pKarg->Configuration.uRaidSetIndex].VolumeBus;
++
++ header.PageVersion = 0;
++ header.PageLength = 0;
++ header.PageNumber = 0;
++ header.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
++ cfg.cfghdr.hdr = &header;
++ cfg.physAddr = -1;
++ cfg.pageAddr = (VolumeBus << 8) + volumeID;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0;
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++ if (mpt_config(ioc, &cfg) != 0) {
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_raid_config_exit;
++ }
++
++ if (header.PageLength == 0) {
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_raid_config_exit;
++ }
++
++ volumepage0sz = header.PageLength * 4;
++ pVolume0 = pci_alloc_consistent(ioc->pcidev, volumepage0sz,
++ &volume0_dma);
++ if (!pVolume0) {
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_raid_config_exit;
++ }
++
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ cfg.physAddr = volume0_dma;
++ if (mpt_config(ioc, &cfg) != 0) {
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_raid_config_exit;
++ }
++
++ totalMaxLBA = (u64)le32_to_cpu(pVolume0->MaxLBA) |
++ ((u64)le32_to_cpu(pVolume0->MaxLBAHigh)) << 32;
++ tmpTotalMaxLBA = totalMaxLBA + 1;
++ do_div(tmpTotalMaxLBA, 2048);
++ pKarg->Configuration.bDriveCount = 0;
++ pKarg->Configuration.uCapacity = tmpTotalMaxLBA;
++ pKarg->Configuration.uStripeSize =
++ le32_to_cpu(pVolume0->StripeSize)/2;
++
++ switch(pVolume0->VolumeType) {
++ case MPI_RAID_VOL_TYPE_IS:
++ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_0;
++ break;
++ case MPI_RAID_VOL_TYPE_IME:
++ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_10;
++ break;
++ case MPI_RAID_VOL_TYPE_IM:
++ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_1;
++ break;
++ default:
++ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_OTHER;
++ break;
++ }
++
++ switch (pVolume0->VolumeStatus.State) {
++ case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
++ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_OK;
++ break;
++ case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
++ /* Volume is degraded, check if Resyncing or Inactive */
++ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_DEGRADED;
++ break;
++ case MPI_RAIDVOL0_STATUS_STATE_FAILED:
++ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_FAILED;
++ break;
++ }
++
++ /* check flags */
++ if (pVolume0->VolumeStatus.Flags &
++ MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)
++ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_OFFLINE;
++ else if (pVolume0->VolumeStatus.Flags &
++ MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
++ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_REBUILDING;
++
++ pKarg->Configuration.bInformation = 0; /* default */
++ if(pVolume0->VolumeStatus.Flags &
++ MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS ) {
++
++ uint64_t * ptrUint64;
++ uint64_t totalBlocks64, blocksRemaining64;
++ uint32_t totalBlocks32, blocksRemaining32;
++
++ /* get percentage complete */
++ pRaidActionReply = kmalloc( sizeof(MPI_RAID_VOL_INDICATOR) +
++ offsetof(MSG_RAID_ACTION_REPLY,ActionData),
++ GFP_KERNEL);
++
++ if (!pRaidActionReply){
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to malloc @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__,pKarg);
++ goto cim_get_raid_config_exit;
++ }
++ memset(pRaidActionReply, 0, sizeof(*pRaidActionReply));
++
++ csmisas_do_raid(ioc,
++ MPI_RAID_ACTION_INDICATOR_STRUCT,
++ 0, VolumeBus, volumeID, pRaidActionReply);
++
++ ptrUint64 = (uint64_t *)&pRaidActionReply->ActionData;
++ totalBlocks64 = *ptrUint64;
++ ptrUint64++;
++ blocksRemaining64 = *ptrUint64;
++ while(totalBlocks64 > 0xFFFFFFFFUL){
++ totalBlocks64 = totalBlocks64 >> 1;
++ blocksRemaining64 = blocksRemaining64 >> 1;
++ }
++ totalBlocks32 = (uint32_t)totalBlocks64;
++ blocksRemaining32 = (uint32_t)blocksRemaining64;
++
++ if(totalBlocks32)
++ pKarg->Configuration.bInformation =
++ (totalBlocks32 - blocksRemaining32) /
++ (totalBlocks32 / 100);
++
++ kfree(pRaidActionReply);
++ }
++
++ /* fill-in more information depending on data type */
++ if (pKarg->Configuration.bDataType ==
++ CSMI_SAS_RAID_DATA_ADDITIONAL_DATA) {
++ pKarg->Configuration.Data->bLabel[0] = '\0';
++ pKarg->Configuration.Data->bRaidSetLun[1] = 0;
++ pKarg->Configuration.Data->bWriteProtection =
++ CSMI_SAS_RAID_SET_WRITE_PROTECT_UNKNOWN;
++ pKarg->Configuration.Data->bCacheSetting =
++ CSMI_SAS_RAID_SET_CACHE_UNKNOWN;
++ pKarg->Configuration.Data->bCacheRatio = 0;
++ pKarg->Configuration.Data->usBlockSize = 512;
++ pKarg->Configuration.Data->ulRaidSetExtentOffset.uLowPart = 0;
++ pKarg->Configuration.Data->ulRaidSetExtentOffset.uHighPart = 0;
++ pKarg->Configuration.Data->ulRaidSetBlocks.uLowPart =
++ le32_to_cpu(pVolume0->MaxLBA);
++ pKarg->Configuration.Data->ulRaidSetBlocks.uHighPart =
++ le32_to_cpu(pVolume0->MaxLBAHigh);
++ if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS ||
++ pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME ) {
++ pKarg->Configuration.Data->uStripeSizeInBlocks =
++ le32_to_cpu(pVolume0->StripeSize);
++ } else {
++ pKarg->Configuration.Data->uStripeSizeInBlocks = 0;
++ }
++ pKarg->Configuration.Data->uSectorsPerTrack = 128;
++ for (i=0; i<16; i++) {
++ // unsupported
++ pKarg->Configuration.Data->bApplicationScratchPad[i] =
++ 0xFF;
++ }
++ pKarg->Configuration.Data->uNumberOfHeads = 16;
++
++ tmpTotalMaxLBA = totalMaxLBA;
++ do_div(tmpTotalMaxLBA,
++ (pKarg->Configuration.Data->uNumberOfHeads *
++ pKarg->Configuration.Data->uSectorsPerTrack));
++ pKarg->Configuration.Data->uNumberOfTracks = tmpTotalMaxLBA;
++ } else if ( pKarg->Configuration.bDataType ==
++ CSMI_SAS_RAID_DATA_DEVICE_ID ) {
++ /* Send inquiry to get VPD Page 0x83 */
++ u32 vpd_page_sz;
++ vpd_page_sz = csmi_sas_raid_config_buffer_sz -
++ offsetof(CSMI_SAS_RAID_CONFIG,DeviceId);
++ if (csmisas_raid_inq(ioc, MPI_FUNCTION_SCSI_IO_REQUEST,
++ VolumeBus, volumeID, 0x83,
++ (u8*)&pKarg->Configuration.DeviceId->bDeviceIdentificationVPDPage,
++ vpd_page_sz) != 0) {
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_raid_config_exit;
++ }
++ } else {
++ /* suppress drive information */
++ if (pKarg->Configuration.bDriveCount ==
++ CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED) {
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++ goto cim_get_raid_config_exit;
++ }
++ }
++
++ /* get hotspare info, used later in this function */
++ if (pVolume0->VolumeSettings.HotSparePool) {
++ /* Read and save IOC Page 5
++ */
++ header.PageVersion = 0;
++ header.PageLength = 0;
++ header.PageNumber = 5;
++ header.PageType = MPI_CONFIG_PAGETYPE_IOC;
++ cfg.cfghdr.hdr = &header;
++ cfg.physAddr = -1;
++ cfg.pageAddr = 0;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0;
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++ if ((mpt_config(ioc, &cfg) == 0) && (header.PageLength)) {
++ ioc_page5_sz = header.PageLength * 4;
++ pIocPage5 = pci_alloc_consistent(ioc->pcidev,
++ ioc_page5_sz,
++ &ioc_page5_dma);
++ memset(pIocPage5,0,ioc_page5_sz);
++ if (ioc_page5_dma) {
++ cfg.physAddr = ioc_page5_dma;
++ cfg.action =
++ MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ mpt_config(ioc, &cfg);
++ }
++ }
++ }
++
++ /*
++ * get RAID Physical Disk Page 0
++ */
++ header.PageVersion = 0;
++ header.PageLength = 0;
++ header.PageNumber = 0;
++ header.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
++ cfg.cfghdr.hdr = &header;
++ cfg.physAddr = -1;
++ cfg.pageAddr = 0;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0;
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++ if (mpt_config(ioc, &cfg) != 0) {
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_raid_config_exit;
++ }
++
++ if (header.PageLength == 0) {
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_raid_config_exit;
++ }
++
++ physdiskpage0sz = header.PageLength * 4;
++ pPhysDisk0 = pci_alloc_consistent(ioc->pcidev, physdiskpage0sz,
++ &physdisk0_dma);
++ if (!pPhysDisk0) {
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_raid_config_exit;
++ }
++ cfg.physAddr = physdisk0_dma;
++
++ physDiskNumMax = (csmi_sas_raid_config_buffer_sz -
++ offsetof(CSMI_SAS_RAID_CONFIG,Drives))
++ / sizeof(CSMI_SAS_RAID_DRIVES);
++
++ tmpTotalMaxLBA = totalMaxLBA;
++ if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS) {
++ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks);
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "IS Volume tmpTotalMaxLBA=%llX\n",
++ (unsigned long long)tmpTotalMaxLBA));
++ }
++ else if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME) {
++ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks * 2);
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "IME Volume tmpTotalMaxLBA=%llX\n",
++ (unsigned long long)tmpTotalMaxLBA));
++ } else {
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "IM Volume tmpTotalMaxLBA=%llX\n",
++ (unsigned long long)tmpTotalMaxLBA));
++ }
++
++ for (i=0; i< min(pVolume0->NumPhysDisks, physDiskNumMax); i++) {
++
++ physDiskNum = pVolume0->PhysDisk[i].PhysDiskNum;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ cfg.pageAddr = physDiskNum;
++ if (mpt_config(ioc, &cfg) != 0){
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_raid_config_exit;
++ }
++
++ pKarg->Configuration.bDriveCount++;
++ if (pKarg->Configuration.bDataType != CSMI_SAS_RAID_DATA_DRIVES)
++ continue;
++
++ /* Search the list for the matching SAS address. */
++ sas_info = csmisas_get_device_component_by_fw(ioc, pPhysDisk0->PhysDiskBus,
++ pPhysDisk0->PhysDiskID);
++ if (sas_info) {
++ sas_address = reverse_byte_order64(sas_info->sas_address);
++ memcpy(pKarg->Configuration.Drives[i].bSASAddress,
++ &sas_address,sizeof(u64));
++ if (!device_info)
++ device_info = sas_info->device_info;
++ }
++
++ memcpy(pKarg->Configuration.Drives[i].bModel,
++ pPhysDisk0->InquiryData.VendorID,
++ offsetof(RAID_PHYS_DISK0_INQUIRY_DATA,ProductRevLevel));
++ memcpy(pKarg->Configuration.Drives[i].bFirmware,
++ pPhysDisk0->InquiryData.ProductRevLevel,
++ sizeof(pPhysDisk0->InquiryData.ProductRevLevel));
++ if (csmisas_is_sata(pPhysDisk0)) {
++ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber,
++ &pPhysDisk0->ExtDiskIdentifier[4],
++ 4);
++ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber[4],
++ &pPhysDisk0->DiskIdentifier,
++ sizeof(pPhysDisk0->DiskIdentifier));
++ } else {
++ memcpy(pKarg->Configuration.Drives[i].bSerialNumber,
++ pPhysDisk0->DiskIdentifier,
++ sizeof(pPhysDisk0->DiskIdentifier));
++ }
++
++ pKarg->Configuration.Drives[i].bDriveUsage =
++ (pPhysDisk0->PhysDiskStatus.Flags &
++ MPI_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME) ?
++ CSMI_SAS_DRIVE_CONFIG_NOT_USED :
++ CSMI_SAS_DRIVE_CONFIG_MEMBER;
++
++ pKarg->Configuration.Drives[i].bDriveStatus =
++ CSMI_SAS_DRIVE_STATUS_OK;
++ if (pPhysDisk0->PhysDiskStatus.State ==
++ MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED) {
++ pKarg->Configuration.Drives[i].bDriveStatus =
++ CSMI_SAS_DRIVE_STATUS_OFFLINE;
++ } else if(pPhysDisk0->PhysDiskStatus.State) {
++ pKarg->Configuration.Drives[i].bDriveStatus =
++ CSMI_SAS_DRIVE_STATUS_FAILED;
++ if(pKarg->Configuration.bStatus ==
++ CSMI_SAS_RAID_SET_STATUS_DEGRADED)
++ pKarg->Configuration.bInformation = i;
++ } else if((pVolume0->VolumeStatus.Flags &
++ MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) &&
++ (pPhysDisk0->PhysDiskStatus.Flags &
++ MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC))
++ pKarg->Configuration.Drives[i].bDriveStatus =
++ CSMI_SAS_DRIVE_STATUS_REBUILDING;
++ else if(pPhysDisk0->ErrorData.SmartCount ||
++ (pPhysDisk0->PhysDiskStatus.Flags &
++ MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC))
++ pKarg->Configuration.Drives[i].bDriveStatus =
++ CSMI_SAS_DRIVE_STATUS_DEGRADED;
++
++ memset(pKarg->Configuration.Drives[i].bSASLun,
++ 0, sizeof(pKarg->Configuration.Drives[i].bSASLun));
++ if (csmisas_is_sata(pPhysDisk0)) {
++ pKarg->Configuration.Drives[i].bDriveType =
++ CSMI_SAS_DRIVE_TYPE_SATA;
++ } else { /* drive in a volume can only be SAS/SATA */
++ pKarg->Configuration.Drives[i].bDriveType =
++ CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS;
++ if (mpt_raid_phys_disk_get_num_paths(ioc,
++ pVolume0->PhysDisk[i].PhysDiskNum) > 1)
++ pKarg->Configuration.Drives[i].bDriveType =
++ CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS;
++ }
++
++ pKarg->Configuration.Drives[i].usBlockSize = 512;
++ pKarg->Configuration.Drives[i].uDriveIndex =
++ pPhysDisk0->PhysDiskNum;
++ pKarg->Configuration.Drives[i].ulTotalUserBlocks.uLowPart =
++ (u32)tmpTotalMaxLBA;
++ pKarg->Configuration.Drives[i].ulTotalUserBlocks.uHighPart =
++ (u32)(tmpTotalMaxLBA >> 32);
++ }
++
++ /* adding hot spare info at the end */
++ if ((pVolume0->VolumeSettings.HotSparePool) && (pIocPage5) &&
++ (pVolume0->VolumeType != MPI_RAID_VOL_TYPE_IS)) {
++ for (idx = 0, i = pVolume0->NumPhysDisks ;
++ idx < pIocPage5->NumHotSpares ; idx++) {
++ if (i >= physDiskNumMax)
++ break;
++ if ((pVolume0->VolumeSettings.HotSparePool &
++ pIocPage5->HotSpare[idx].HotSparePool) == 0)
++ continue;
++ if(pIocPage5->HotSpare[idx].Flags !=
++ MPI_IOC_PAGE_5_HOT_SPARE_ACTIVE)
++ continue;
++ physDiskNum = pIocPage5->HotSpare[idx].PhysDiskNum;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ cfg.pageAddr = physDiskNum;
++ if (mpt_config(ioc, &cfg) != 0)
++ continue;
++
++ /* don't mix SSP hot spare
++ * in SATA volume
++ */
++ if (!csmisas_is_sata(pPhysDisk0) &&
++ (device_info &
++ MPI_SAS_DEVICE_INFO_SATA_DEVICE))
++ continue;
++
++ /* don't mix SATA hot spare
++ * in SSP volume
++ */
++ if (csmisas_is_sata(pPhysDisk0) &&
++ (device_info &
++ MPI_SAS_DEVICE_INFO_SSP_TARGET))
++ continue;
++
++ /* capacity check for IM volumes*/
++ if ((pVolume0->VolumeType ==
++ MPI_RAID_VOL_TYPE_IM) &&
++ (totalMaxLBA +
++ (64*2*1024) /* metadata = 64MB*/ >
++ le32_to_cpu(pPhysDisk0->MaxLBA)))
++ continue;
++
++ tmpTotalMaxLBA = totalMaxLBA;
++ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks);
++ /* capacity check for IME volumes*/
++ if ((pVolume0->VolumeType ==
++ MPI_RAID_VOL_TYPE_IME) &&
++ (((totalMaxLBA +
++ pVolume0->NumPhysDisks) * 2) +
++ (64*2*1024 ) /*metadata = 64MB*/ >
++ le32_to_cpu(pPhysDisk0->MaxLBA)))
++ continue;
++
++ pKarg->Configuration.bDriveCount++;
++ if (pKarg->Configuration.bDataType !=
++ CSMI_SAS_RAID_DATA_DRIVES) {
++ i++;
++ continue;
++ }
++
++ /* Search the list for the matching SAS address. */
++ sas_info = csmisas_get_device_component_by_fw(ioc,
++ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID);
++ if (sas_info) {
++ sas_address = reverse_byte_order64(sas_info->sas_address);
++ memcpy(pKarg->Configuration.Drives[i].bSASAddress,
++ &sas_address,sizeof(u64));
++ }
++
++ memcpy(pKarg->Configuration.Drives[i].bModel,
++ pPhysDisk0->InquiryData.VendorID,
++ offsetof(RAID_PHYS_DISK0_INQUIRY_DATA,ProductRevLevel));
++ memcpy(pKarg->Configuration.Drives[i].bFirmware,
++ pPhysDisk0->InquiryData.ProductRevLevel,
++ sizeof(pPhysDisk0->InquiryData.ProductRevLevel));
++ if (csmisas_is_sata(pPhysDisk0)) {
++ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber,
++ &pPhysDisk0->ExtDiskIdentifier[4],
++ 4);
++ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber[4],
++ &pPhysDisk0->DiskIdentifier,
++ sizeof(pPhysDisk0->DiskIdentifier));
++ } else {
++ memcpy(pKarg->Configuration.Drives[i].bSerialNumber,
++ pPhysDisk0->DiskIdentifier,
++ sizeof(pPhysDisk0->DiskIdentifier));
++ }
++ pKarg->Configuration.Drives[i].bDriveStatus =
++ CSMI_SAS_DRIVE_STATUS_OK;
++ if(pPhysDisk0->PhysDiskStatus.State)
++ pKarg->Configuration.Drives[i].bDriveStatus =
++ CSMI_SAS_DRIVE_STATUS_FAILED;
++ else if(pPhysDisk0->ErrorData.SmartCount)
++ pKarg->Configuration.Drives[i].bDriveStatus =
++ CSMI_SAS_DRIVE_STATUS_DEGRADED;
++ pKarg->Configuration.Drives[i].bDriveUsage =
++ CSMI_SAS_DRIVE_CONFIG_SPARE;
++ pKarg->Configuration.Drives[i].usBlockSize = 512;
++ pKarg->Configuration.Drives[i].uDriveIndex =
++ pPhysDisk0->PhysDiskNum;
++ if (csmisas_is_sata(pPhysDisk0)) {
++ pKarg->Configuration.Drives[i].bDriveType =
++ CSMI_SAS_DRIVE_TYPE_SATA;
++ } else { /* drive in a volume can only be SAS/SATA */
++ pKarg->Configuration.Drives[i].bDriveType =
++ CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS;
++ if (mpt_raid_phys_disk_get_num_paths(ioc,
++ pVolume0->PhysDisk[i].PhysDiskNum) > 1)
++ pKarg->Configuration.Drives[i].bDriveType =
++ CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS;
++ }
++ i++;
++ }
++ }
++
++ // Only return data on the first 240 drives
++ if( pKarg->Configuration.bDriveCount > 0xF0 )
++ pKarg->Configuration.bDriveCount =
++ CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG;
++
++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ cim_get_raid_config_exit:
++
++ if (pVolume0 != NULL)
++ pci_free_consistent(ioc->pcidev, volumepage0sz, pVolume0,
++ volume0_dma);
++
++ if(pPhysDisk0 != NULL)
++ pci_free_consistent(ioc->pcidev, physdiskpage0sz, pPhysDisk0,
++ physdisk0_dma);
++
++ if(pIocPage5 != NULL)
++ pci_free_consistent(ioc->pcidev, ioc_page5_sz, pIocPage5,
++ ioc_page5_dma);
++
++ /* Copy the data from kernel memory to user memory
++ */
++
++ /* find the buffer size to copy depending on how much is filled-in */
++ switch (pKarg->Configuration.bDataType) {
++ case CSMI_SAS_RAID_DATA_ADDITIONAL_DATA:
++ copy_buffer_sz = sizeof(IOCTL_HEADER) +
++ offsetof(CSMI_SAS_RAID_CONFIG,Data) +
++ sizeof(CSMI_SAS_RAID_SET_ADDITIONAL_DATA);
++ break;
++ case CSMI_SAS_RAID_DATA_DRIVES:
++ if (pKarg->Configuration.bDriveCount ==
++ CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED)
++ copy_buffer_sz = sizeof(IOCTL_HEADER) +
++ offsetof(CSMI_SAS_RAID_CONFIG,Drives);
++ else
++ copy_buffer_sz = sizeof(IOCTL_HEADER) +
++ offsetof(CSMI_SAS_RAID_CONFIG,Drives) +
++ (pKarg->Configuration.bDriveCount *
++ sizeof(CSMI_SAS_RAID_DRIVES));
++ break;
++ case CSMI_SAS_RAID_DATA_DEVICE_ID:
++ copy_buffer_sz = csmi_sas_raid_config_buffer_sz;
++ break;
++ }
++
++ if (copy_to_user(uarg, pKarg, copy_buffer_sz)) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_get_raid_config @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ free_pages((unsigned long)pKarg, memory_pages);
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI SAS Get RAID Features command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_raid_features(unsigned long arg)
++{
++ CSMI_SAS_RAID_FEATURES_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_RAID_FEATURES_BUFFER karg, *pKarg=NULL;
++ int csmi_sas_raid_features_buffer_sz, iocnum;
++ int memory_pages;
++ MPT_ADAPTER *ioc = NULL;
++
++ if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_get_raid_features struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ csmi_sas_raid_features_buffer_sz = karg.IoctlHeader.Length;
++ memory_pages = get_order(csmi_sas_raid_features_buffer_sz);
++ pKarg = (CSMI_SAS_RAID_FEATURES_BUFFER *)__get_free_pages(
++ GFP_KERNEL, memory_pages);
++ if (!pKarg){
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to malloc RAID_FEATURES_BUFFER "
++ "csmi_sas_raid_features_buffer_sz=%d memory_pages=%d\n",
++ __FILE__, __LINE__, __FUNCTION__,
++ csmi_sas_raid_features_buffer_sz, memory_pages);
++ return -ENOMEM;
++ }
++ memset(pKarg, 0, sizeof(*pKarg));
++
++ if (copy_from_user(pKarg, uarg, csmi_sas_raid_features_buffer_sz)) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_get_raid_features struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ if (pKarg->Information.uChangeCount != 0 &&
++ pKarg->Information.uChangeCount != ioc->csmi_change_count ) {
++ pKarg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ pKarg->Information.uFailureCode =
++ CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID;
++ goto cim_get_raid_features_exit;
++ }
++
++ pKarg->Information.uFeatures = CSMI_SAS_RAID_FEATURE_REBUILD |
++ CSMI_SAS_RAID_FEATURE_SURFACE_SCAN |
++ CSMI_SAS_RAID_FEATURE_SPARES_SHARED;
++ pKarg->Information.bDefaultTransformPriority =
++ CSMI_SAS_PRIORITY_UNKNOWN;
++ pKarg->Information.bTransformPriority = CSMI_SAS_PRIORITY_UNKNOWN;
++ pKarg->Information.bDefaultRebuildPriority = CSMI_SAS_PRIORITY_UNKNOWN;
++ pKarg->Information.bRebuildPriority =
++ pKarg->Information.bDefaultRebuildPriority;
++ pKarg->Information.bDefaultSurfaceScanPriority =
++ CSMI_SAS_PRIORITY_UNKNOWN;
++ pKarg->Information.bSurfaceScanPriority = CSMI_SAS_PRIORITY_UNKNOWN;
++ pKarg->Information.uRaidSetTransformationRules = 0;
++
++ /* IS */
++ pKarg->Information.RaidType[0].bRaidType = CSMI_SAS_RAID_TYPE_0;
++ pKarg->Information.RaidType[0].uSupportedStripeSizeMap = 0x80;
++
++ /* IM */
++ pKarg->Information.RaidType[1].bRaidType = CSMI_SAS_RAID_TYPE_1;
++ pKarg->Information.RaidType[1].uSupportedStripeSizeMap = 0;
++
++ /* IME */
++ pKarg->Information.RaidType[2].bRaidType = CSMI_SAS_RAID_TYPE_1E;
++ pKarg->Information.RaidType[2].uSupportedStripeSizeMap = 0x80;
++
++ pKarg->Information.RaidType[3].bRaidType = CSMI_SAS_RAID_TYPE_END;
++ pKarg->Information.bCacheRatiosSupported[0] =
++ CSMI_SAS_RAID_CACHE_RATIO_END;
++
++ cim_get_raid_features_exit:
++
++ /*
++ * Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, pKarg,
++ sizeof(CSMI_SAS_RAID_FEATURES_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_get_raid_features @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ free_pages((unsigned long)pKarg, memory_pages);
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI SAS Set RAID Control command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_set_raid_control(unsigned long arg)
++{
++ CSMI_SAS_RAID_CONTROL_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_RAID_CONTROL_BUFFER karg, *pKarg=NULL;
++ int csmi_sas_raid_control_buffer_sz, iocnum;
++ int memory_pages;
++ MPT_ADAPTER *ioc = NULL;
++
++ if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_set_raid_control struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ csmi_sas_raid_control_buffer_sz = karg.IoctlHeader.Length;
++ memory_pages = get_order(csmi_sas_raid_control_buffer_sz);
++ pKarg = (CSMI_SAS_RAID_CONTROL_BUFFER *)__get_free_pages(
++ GFP_KERNEL, memory_pages);
++ if (!pKarg){
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to malloc RAID_CONTROL_BUFFER "
++ "csmi_sas_raid_control_buffer_sz=%d memory_pages=%d\n",
++ __FILE__, __LINE__, __FUNCTION__,
++ csmi_sas_raid_control_buffer_sz, memory_pages);
++ return -ENOMEM;
++ }
++ memset(pKarg, 0, sizeof(*pKarg));
++
++ if (copy_from_user(pKarg, uarg, csmi_sas_raid_control_buffer_sz)) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_set_raid_control struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ if (pKarg->Information.uChangeCount != 0 &&
++ pKarg->Information.uChangeCount != ioc->csmi_change_count ) {
++ pKarg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ pKarg->Information.uFailureCode =
++ CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID;
++ goto cim_set_raid_control_exit;
++ }
++
++ if (pKarg->Information.bTransformPriority !=
++ CSMI_SAS_PRIORITY_UNCHANGED) {
++ pKarg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ pKarg->Information.uFailureCode =
++ CSMI_SAS_FAIL_CODE_TRANSFORM_PRIORITY_INVALID;
++ goto cim_set_raid_control_exit;
++ }
++
++ if (pKarg->Information.bRebuildPriority !=
++ CSMI_SAS_PRIORITY_AUTO &&
++ pKarg->Information.bRebuildPriority !=
++ CSMI_SAS_PRIORITY_UNCHANGED) {
++ pKarg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ pKarg->Information.uFailureCode =
++ CSMI_SAS_FAIL_CODE_REBUILD_PRIORITY_INVALID;
++ goto cim_set_raid_control_exit;
++ }
++
++ if (pKarg->Information.bCacheRatioFlag ==
++ CSMI_SAS_RAID_CACHE_RATIO_DISABLE) {
++ pKarg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ pKarg->Information.uFailureCode =
++ CSMI_SAS_FAIL_CODE_CACHE_RATIO_INVALID;
++ goto cim_set_raid_control_exit;
++ }
++
++ if( !strcmp(pKarg->Information.bClearConfiguration,
++ CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE) ) {
++ pKarg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ pKarg->Information.uFailureCode =
++ CSMI_SAS_FAIL_CODE_CLEAR_CONFIGURATION_INVALID;
++ goto cim_set_raid_control_exit;
++ }
++
++ pKarg->Information.bFailureDescription[0] = '\0';
++
++ cim_set_raid_control_exit:
++
++ /*
++ * Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, pKarg,
++ sizeof(CSMI_SAS_RAID_CONTROL_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_set_raid_control @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)pKarg, memory_pages);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ free_pages((unsigned long)pKarg, memory_pages);
++ return 0;
++}
++
++/**
++ * Prototype Routine for the CSMI SAS Get Raid Element.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_raid_element(unsigned long arg)
++{
++ CSMI_SAS_RAID_ELEMENT_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_RAID_ELEMENT_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++
++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_ELEMENT_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmisas_get_raid_element struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++/* TODO - implement IOCTL here */
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE;
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n"));
++
++// csmisas_get_raid_element_exit:
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_RAID_ELEMENT_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmisas_get_raid_element @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++
++}
++
++/**
++ * Prototype Routine for the CSMI SAS Set Raid Operation
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_set_raid_operation(unsigned long arg)
++{
++ CSMI_SAS_RAID_SET_OPERATION_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_RAID_SET_OPERATION_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++
++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_SET_OPERATION_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_set_raid_operation struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++/* TODO - implement IOCTL here */
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE;
++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n"));
++
++// cim_set_raid_operation:
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_RAID_SET_OPERATION_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_set_raid_operation @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++
++}
++
++
++/**
++ * Prototype Routine for the CSMI SAS Task Managment Config command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_task_managment(unsigned long arg)
++{
++ CSMI_SAS_SSP_TASK_IU_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_SSP_TASK_IU_BUFFER karg;
++ pSCSITaskMgmt_t pScsiTm;
++ pSCSITaskMgmtReply_t pScsiTmReply;
++ MPT_ADAPTER *ioc = NULL;
++ MPT_SCSI_HOST *hd;
++ MPT_FRAME_HDR *mf = NULL;
++ MPIHeader_t *mpi_hdr;
++ int iocnum;
++ u8 taskType;
++ u8 channel;
++ u8 id;
++ u8 queueTag;
++ u32 TaskMsgContext = 0;
++ int i;
++ u8 found_qtag;
++ struct sas_device_info *sas_info;
++ u16 ioc_status;
++ u32 MsgContext;
++
++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_SSP_TASK_IU_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_task_managment struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
++
++ sas_info = csmisas_get_device_component_by_os(ioc,
++ karg.Parameters.bPathId, karg.Parameters.bTargetId);
++ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume)
++ goto cim_get_task_managment_exit;
++
++ channel = sas_info->fw.channel;
++ id = sas_info->fw.id;
++ queueTag = (u8)karg.Parameters.uQueueTag & 0xFF;
++ hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
++
++ /* try to catch an error
++ */
++ if ((karg.Parameters.uFlags & CSMI_SAS_TASK_IU) &&
++ (karg.Parameters.uFlags & CSMI_SAS_HARD_RESET_SEQUENCE))
++ goto cim_get_task_managment_exit;
++
++ if (karg.Parameters.uFlags & CSMI_SAS_TASK_IU) {
++ switch (karg.Parameters.bTaskManagementFunction) {
++
++ case CSMI_SAS_SSP_ABORT_TASK:
++ taskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
++ break;
++ case CSMI_SAS_SSP_ABORT_TASK_SET:
++ taskType = MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET;
++ break;
++ case CSMI_SAS_SSP_CLEAR_TASK_SET:
++ taskType = MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET;
++ break;
++ case CSMI_SAS_SSP_LOGICAL_UNIT_RESET:
++ taskType = MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET;
++ break;
++ case CSMI_SAS_SSP_CLEAR_ACA:
++ case CSMI_SAS_SSP_QUERY_TASK:
++ default:
++ goto cim_get_task_managment_exit;
++ }
++ } else if (karg.Parameters.uFlags & CSMI_SAS_HARD_RESET_SEQUENCE)
++ taskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
++ else
++ goto cim_get_task_managment_exit;
++
++ switch (karg.Parameters.uInformation) {
++ case CSMI_SAS_SSP_TEST:
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request for test purposes\n"));
++ break;
++ case CSMI_SAS_SSP_EXCEEDED:
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request due to timeout\n"));
++ break;
++ case CSMI_SAS_SSP_DEMAND:
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request demanded by app\n"));
++ break;
++ case CSMI_SAS_SSP_TRIGGER:
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request sent to trigger event\n"));
++ break;
++ }
++
++ switch (taskType) {
++
++ case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
++ /*
++ * look up qtag in the ScsiLookup[] table
++ */
++ for (i = 0, found_qtag = 0; i < hd->ioc->req_depth; i++) {
++ if ((ioc->ScsiLookup[i]) &&
++ (ioc->ScsiLookup[i]->tag == queueTag)) {
++ mf = MPT_INDEX_2_MFPTR(hd->ioc, i);
++ TaskMsgContext =
++ mf->u.frame.hwhdr.msgctxu.MsgContext;
++ found_qtag=1;
++ break;
++ }
++ }
++
++ if(!found_qtag)
++ goto cim_get_task_managment_exit;
++
++ case MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
++ case MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
++ case MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET:
++ /* for now, this should work
++ */
++ case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
++
++ /* Single threading ....
++ */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
++ mutex_lock(&ioc->taskmgmt_cmds.mutex);
++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++ karg.IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_FAILED;
++ goto cim_get_task_managment_exit;
++ }
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
++ if (mptctl_set_tm_flags(hd) != 0) {
++ karg.IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_FAILED;
++ goto cim_get_task_managment_exit;
++ }
++#endif
++ /* Send request
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
++ mptctl_free_tm_flags(ioc);
++#endif
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_task_managment_exit;
++ }
++
++ mpi_hdr = (MPIHeader_t *) mf;
++ MsgContext = mpi_hdr->MsgContext;
++ pScsiTm = (pSCSITaskMgmt_t ) mf;
++
++ memset(pScsiTm,0,sizeof(SCSITaskMgmt_t));
++ pScsiTm->TaskType = taskType;
++ pScsiTm->Bus = channel;
++ pScsiTm->TargetID = id;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
++ int_to_scsilun(karg.Parameters.bLun,
++ (struct scsi_lun *)pScsiTm->LUN);
++#else
++ pScsiTm->LUN[1] = karg.Parameters.bLun;
++#endif
++ pScsiTm->MsgContext = MsgContext;
++ pScsiTm->TaskMsgContext = TaskMsgContext;
++ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
++
++ if (csmisas_send_handshake_wait(ioc, mf,
++ karg.IoctlHeader.Timeout) != 0) {
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++#endif
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_get_task_managment_exit;
++ }
++
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
++
++ pScsiTmReply =
++ (pSCSITaskMgmtReply_t ) ioc->ioctl_cmds.reply;
++
++ ioc_status = le16_to_cpu(pScsiTmReply->IOCStatus)
++ & MPI_IOCSTATUS_MASK;
++
++ memset(&karg.Status,0,
++ sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS));
++
++ if(ioc_status == MPI_IOCSTATUS_SUCCESS) {
++ karg.IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_SUCCESS;
++ karg.Status.bSSPStatus =
++ CSMI_SAS_SSP_STATUS_COMPLETED;
++ }else if(ioc_status == MPI_IOCSTATUS_INSUFFICIENT_RESOURCES) {
++ karg.IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_SUCCESS;
++ karg.Status.bSSPStatus =
++ CSMI_SAS_SSP_STATUS_RETRY;
++ }else {
++ karg.IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_FAILED;
++ karg.Status.bSSPStatus =
++ CSMI_SAS_SSP_STATUS_FATAL_ERROR;
++ }
++ } else
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++
++ break;
++
++ default:
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
++ break;
++ }
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++#endif
++
++ cim_get_task_managment_exit:
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_SSP_TASK_IU_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_task_managment @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * map_sas_status_to_csmi - Conversion for Connection Status
++ * @mpi_sas_status: Sas status returned by the firmware
++ *
++ * Returns converted connection status
++ *
++ **/
++static u8
++map_sas_status_to_csmi(u8 mpi_sas_status)
++{
++ u8 csmi_connect_status;
++
++ switch (mpi_sas_status) {
++
++ case MPI_SASSTATUS_SUCCESS:
++ csmi_connect_status = CSMI_SAS_OPEN_ACCEPT;
++ break;
++
++ case MPI_SASSTATUS_UTC_BAD_DEST:
++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_BAD_DESTINATION;
++ break;
++
++ case MPI_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED:
++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RATE_NOT_SUPPORTED;
++ break;
++
++ case MPI_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED:
++ csmi_connect_status =
++ CSMI_SAS_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED;
++ break;
++
++ case MPI_SASSTATUS_UTC_STP_RESOURCES_BUSY:
++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY;
++ break;
++
++ case MPI_SASSTATUS_UTC_WRONG_DESTINATION:
++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION;
++ break;
++
++ case MPI_SASSTATUS_SDSF_NAK_RECEIVED:
++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RETRY;
++ break;
++
++ case MPI_SASSTATUS_SDSF_CONNECTION_FAILED:
++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_PATHWAY_BLOCKED;
++ break;
++
++ case MPI_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT:
++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_NO_DESTINATION;
++ break;
++
++ case MPI_SASSTATUS_UNKNOWN_ERROR:
++ case MPI_SASSTATUS_INVALID_FRAME:
++ case MPI_SASSTATUS_UTC_BREAK_RECEIVED:
++ case MPI_SASSTATUS_UTC_PORT_LAYER_REQUEST:
++ case MPI_SASSTATUS_SHORT_INFORMATION_UNIT:
++ case MPI_SASSTATUS_LONG_INFORMATION_UNIT:
++ case MPI_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA:
++ case MPI_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR:
++ case MPI_SASSTATUS_XFER_RDY_NOT_EXPECTED:
++ case MPI_SASSTATUS_DATA_INCORRECT_DATA_LENGTH:
++ case MPI_SASSTATUS_DATA_TOO_MUCH_READ_DATA:
++ case MPI_SASSTATUS_DATA_OFFSET_ERROR:
++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RESERVE_STOP;
++ break;
++
++ default:
++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RESERVE_STOP;
++ break;
++ }
++
++ return csmi_connect_status;
++}
++
++/**
++ * csmisas_phy_reset
++ * Issues a phy link reset or phy hard reset
++ *
++ * @ioc - Pointer to MPT_ADAPTER structure
++ * @PhyNum - phy number
++ * @opcode - {MPI_SAS_OP_PHY_LINK_RESET,MPI_SAS_OP_PHY_HARD_RESET}
++ *
++ * Returns: 0 for success, non-zero error
++ **/
++static int
++csmisas_phy_reset(MPT_ADAPTER *ioc, u8 PhyNum, u8 opcode)
++{
++ SasIoUnitControlRequest_t *sasIoUnitCntrReq;
++ SasIoUnitControlReply_t *sasIoUnitCntrReply;
++ MPT_FRAME_HDR *mf = NULL;
++ MPIHeader_t *mpi_hdr;
++ u16 ioc_status;
++ u32 MsgContext;
++
++ if ((opcode != MPI_SAS_OP_PHY_LINK_RESET) &&
++ (opcode != MPI_SAS_OP_PHY_HARD_RESET))
++ return -1;
++
++ /* Get a MF for this command.
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
++ return -1;
++ }
++
++ mpi_hdr = (MPIHeader_t *) mf;
++ MsgContext = mpi_hdr->MsgContext;
++ sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
++ memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
++ sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
++ sasIoUnitCntrReq->MsgContext = MsgContext;
++ sasIoUnitCntrReq->Operation = opcode;
++ sasIoUnitCntrReq->PhyNum = PhyNum;
++
++ if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0)
++ return -1;
++
++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0)
++ return -1;
++
++ /* process the completed Reply Message Frame */
++ sasIoUnitCntrReply = (SasIoUnitControlReply_t *)ioc->ioctl_cmds.reply;
++ ioc_status = le16_to_cpu(sasIoUnitCntrReply->IOCStatus)
++ & MPI_IOCSTATUS_MASK;
++ if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
++ printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
++ __FUNCTION__,
++ sasIoUnitCntrReply->IOCStatus,
++ sasIoUnitCntrReply->IOCLogInfo);
++ return -1;
++ }
++ return 0;
++}
++
++/** Prototype Routine for the CSMI SAS Phy Control command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_phy_control(unsigned long arg)
++{
++ CSMI_SAS_PHY_CONTROL_BUFFER __user *uarg = (void __user *) arg;
++ IOCTL_HEADER ioctl_header;
++ PCSMI_SAS_PHY_CONTROL_BUFFER karg;
++ SasIOUnitPage0_t *sasIoUnitPg0=NULL;
++ dma_addr_t sasIoUnitPg0_dma;
++ int sasIoUnitPg0_data_sz=0;
++ SasIOUnitPage1_t *sasIoUnitPg1=NULL;
++ dma_addr_t sasIoUnitPg1_dma;
++ int sasIoUnitPg1_data_sz=0;
++ ConfigExtendedPageHeader_t hdr;
++ CONFIGPARMS cfg;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum;
++ int csmi_sas_phy_control_buffer_sz;
++ int memory_pages;
++
++ if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in IOCTL_HEADER"
++ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ csmi_sas_phy_control_buffer_sz = ioctl_header.Length;
++ memory_pages = get_order(csmi_sas_phy_control_buffer_sz);
++ karg = (PCSMI_SAS_PHY_CONTROL_BUFFER)__get_free_pages(
++ GFP_KERNEL, memory_pages);
++ if (!karg){
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to malloc SAS_PHY_CONTROL_BUFFER "
++ "csmi_sas_phy_control_buffer_sz=%d memory_pages=%d\n",
++ __FILE__, __LINE__, __FUNCTION__,
++ csmi_sas_phy_control_buffer_sz, memory_pages);
++ return -ENOMEM;
++ }
++ memset(karg, 0, sizeof(*karg));
++
++ if (copy_from_user(karg, uarg, csmi_sas_phy_control_buffer_sz)) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_phy_control_buffer "
++ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(ioctl_header.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)karg, memory_pages);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)karg, memory_pages);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ if (karg->bPhyIdentifier >= ioc->num_ports) {
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ goto cim_sas_phy_control_exit;
++ }
++
++ /*
++ * Retreive SAS IOUNIT PAGE 0
++ */
++
++ hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
++ hdr.ExtPageLength = 0;
++ hdr.PageNumber = 0;
++ hdr.Reserved1 = 0;
++ hdr.Reserved2 = 0;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
++
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.pageAddr = 0;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++
++ if (mpt_config(ioc, &cfg) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: READ MPI_SASIOUNITPAGE0: HEADER\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++
++ if (hdr.ExtPageLength == 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++
++ sasIoUnitPg0_data_sz = hdr.ExtPageLength * 4;
++ sasIoUnitPg0 = (SasIOUnitPage0_t *) pci_alloc_consistent(ioc->pcidev,
++ sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma);
++
++ if (!sasIoUnitPg0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++
++ memset((u8 *)sasIoUnitPg0, 0, sasIoUnitPg0_data_sz);
++ cfg.physAddr = sasIoUnitPg0_dma;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if (mpt_config(ioc, &cfg) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: READ MPI_SASIOUNITPAGE0: CURRENT\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++
++ /*
++ * Retreive SAS IOUNIT PAGE 1
++ */
++
++ hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
++ hdr.ExtPageLength = 0;
++ hdr.PageNumber = 1;
++ hdr.Reserved1 = 0;
++ hdr.Reserved2 = 0;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
++
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.pageAddr = 0;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++
++ if (mpt_config(ioc, &cfg) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: READ MPI_SASIOUNITPAGE1: HEADER\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++
++ if (hdr.ExtPageLength == 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++
++ sasIoUnitPg1_data_sz = hdr.ExtPageLength * 4;
++ sasIoUnitPg1 = (SasIOUnitPage1_t *) pci_alloc_consistent(ioc->pcidev,
++ sasIoUnitPg1_data_sz, &sasIoUnitPg1_dma);
++
++ if (!sasIoUnitPg1) {
++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++
++ memset((u8 *)sasIoUnitPg1, 0, sasIoUnitPg1_data_sz);
++ cfg.physAddr = sasIoUnitPg1_dma;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if (mpt_config(ioc, &cfg) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: READ MPI_SASIOUNITPAGE1: CURRENT\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++
++ switch (karg->uFunction) {
++
++ case CSMI_SAS_PC_LINK_RESET:
++ case CSMI_SAS_PC_HARD_RESET:
++ {
++ u8 opcode = (karg->uFunction==CSMI_SAS_PC_LINK_RESET) ?
++ MPI_SAS_OP_PHY_LINK_RESET : MPI_SAS_OP_PHY_HARD_RESET;
++
++ if((karg->uLinkFlags & CSMI_SAS_PHY_ACTIVATE_CONTROL) &&
++ (karg->usLengthOfControl >= sizeof(CSMI_SAS_PHY_CONTROL)) &&
++ (karg->bNumberOfControls > 0)){
++ if(karg->Control[0].bRate ==
++ CSMI_SAS_LINK_RATE_1_5_GBPS) {
++ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate =
++ MPI_SAS_IOUNIT1_MAX_RATE_1_5 |
++ MPI_SAS_IOUNIT1_MIN_RATE_1_5;
++ }
++ else if(karg->Control[0].bRate ==
++ CSMI_SAS_LINK_RATE_3_0_GBPS) {
++ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate =
++ MPI_SAS_IOUNIT1_MAX_RATE_3_0 |
++ MPI_SAS_IOUNIT1_MIN_RATE_3_0;
++ }
++ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].PhyFlags &=
++ ~MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
++ cfg.dir = 1;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
++ if (mpt_config(ioc, &cfg) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: WRITE MPI_SASIOUNITPAGE1 NVRAM\n"));
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
++ if (mpt_config(ioc, &cfg) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: WRITE MPI_SASIOUNITPAGE1 CURRENT\n"));
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++ }
++ if (csmisas_phy_reset(ioc,
++ karg->bPhyIdentifier, opcode) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: csmisas_phy_reset\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++ break;
++
++ }
++ case CSMI_SAS_PC_PHY_DISABLE:
++ if(karg->usLengthOfControl || karg->bNumberOfControls) {
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ break;
++ }
++ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].PhyFlags |=
++ MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
++ cfg.dir = 1;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
++ if (mpt_config(ioc, &cfg) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: WRITE MPI_SASIOUNITPAGE1 NVRAM\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
++ if (mpt_config(ioc, &cfg) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: WRITE MPI_SASIOUNITPAGE1 CURRENT\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++ if (csmisas_phy_reset(ioc,
++ karg->bPhyIdentifier, MPI_SAS_OP_PHY_HARD_RESET) != 0) {
++ dcsmisasprintk(ioc, printk(KERN_ERR
++ ": FAILED: csmisas_phy_reset\n"));
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_phy_control_exit;
++ }
++ break;
++
++ case CSMI_SAS_PC_GET_PHY_SETTINGS:
++ if(karg->usLengthOfControl || karg->bNumberOfControls) {
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ break;
++ }
++ if(csmi_sas_phy_control_buffer_sz <
++ offsetof(CSMI_SAS_PHY_CONTROL_BUFFER,Control) +
++ (4* sizeof(CSMI_SAS_PHY_CONTROL))) {
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_INVALID_PARAMETER;
++ break;
++ }
++ karg->usLengthOfControl = sizeof(CSMI_SAS_PHY_CONTROL);
++ karg->bNumberOfControls = 4;
++ karg->Control[0].bType = CSMI_SAS_SAS;
++ karg->Control[0].bRate = CSMI_SAS_LINK_RATE_1_5_GBPS;
++ karg->Control[1].bType = CSMI_SAS_SAS;
++ karg->Control[1].bRate = CSMI_SAS_LINK_RATE_3_0_GBPS;
++ karg->Control[2].bType = CSMI_SAS_SATA;
++ karg->Control[2].bRate = CSMI_SAS_LINK_RATE_1_5_GBPS;
++ karg->Control[3].bType = CSMI_SAS_SATA;
++ karg->Control[3].bRate = CSMI_SAS_LINK_RATE_3_0_GBPS;
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++ break;
++ default:
++ break;
++ }
++
++ cim_sas_phy_control_exit:
++
++ if (sasIoUnitPg0)
++ pci_free_consistent(ioc->pcidev, sasIoUnitPg0_data_sz,
++ (u8 *) sasIoUnitPg0, sasIoUnitPg0_dma);
++
++ if (sasIoUnitPg1)
++ pci_free_consistent(ioc->pcidev, sasIoUnitPg1_data_sz,
++ (u8 *) sasIoUnitPg1, sasIoUnitPg1_dma);
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, karg,csmi_sas_phy_control_buffer_sz)) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_phy_control_buffer @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ free_pages((unsigned long)karg, memory_pages);
++ return 0;
++}
++
++/**
++ * csmisas_get_manuf_pg_7 - Fetch Manufacturing config Page7.
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @mfgpage7_buffer: pointer to ManufacturingPage7_t that returns config
++ * page data
++ * @mfg_size - max size of buffer
++ *
++ * Return: 0 for success
++ * -ENOMEM if no memory available
++ * -EPERM if not allowed due to ISR context
++ * -EAGAIN if no msg frames currently available
++ * -EFAULT for non-successful reply or no reply (timeout)
++ **/
++static int
++csmisas_get_manuf_pg_7(MPT_ADAPTER *ioc, ManufacturingPage7_t *mfgpage7_buffer, int mfg_size)
++{
++ ConfigPageHeader_t hdr;
++ CONFIGPARMS cfg;
++ ManufacturingPage7_t *mfgPage7 = NULL;
++ dma_addr_t mfgPage7_dma;
++ int data_sz = 0;
++ int rc;
++
++ /* Get Manufacturing Page 7 header */
++ hdr.PageVersion = MPI_MANUFACTURING0_PAGEVERSION;
++ hdr.PageLength = 0;
++ hdr.PageNumber = 7;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
++ cfg.cfghdr.hdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0;
++ cfg.pageAddr = 0;
++ cfg.timeout = 0;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0)
++ goto csmisas_get_manuf_pg_7_exit;
++
++ if (hdr.PageLength == 0) {
++ rc = -EFAULT;
++ goto csmisas_get_manuf_pg_7_exit;
++ }
++
++ data_sz = hdr.PageLength * 4;
++ mfgPage7 = pci_alloc_consistent(ioc->pcidev, data_sz, &mfgPage7_dma);
++ if (!mfgPage7) {
++ rc = -ENOMEM;
++ goto csmisas_get_manuf_pg_7_exit;
++ }
++
++ memset((u8 *)mfgPage7, 0, data_sz);
++ cfg.physAddr = mfgPage7_dma;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0)
++ goto csmisas_get_manuf_pg_7_exit;
++
++ /* copy buffer back to user */
++ memcpy(mfgpage7_buffer, mfgPage7, min(data_sz, mfg_size));
++
++ csmisas_get_manuf_pg_7_exit:
++
++ if (mfgPage7)
++ pci_free_consistent(ioc->pcidev, data_sz, (u8 *)mfgPage7,
++ mfgPage7_dma);
++
++ return rc;
++}
++
++/**
++ * Prototype Routine for the CSMI SAS Get Connector info command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ **/
++static int
++csmisas_get_connector_info(unsigned long arg)
++{
++ CSMI_SAS_CONNECTOR_INFO_BUFFER __user *uarg = (void __user *) arg;
++ CSMI_SAS_CONNECTOR_INFO_BUFFER karg;
++ MPT_ADAPTER *ioc = NULL;
++ ManufacturingPage7_t *mfgPg7 = NULL;
++ int mfgPg7_sz;
++ int iocnum;
++ int i;
++
++ if (copy_from_user(&karg, uarg,
++ sizeof(CSMI_SAS_CONNECTOR_INFO_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_connector_info_buffer"
++ " struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++
++ /* `32` is the sizeof MPI_MANPAGE7_CONNECTOR_INFO */
++ for (i = 0; i < 32; i++) {
++ karg.Reference[i].uPinout = CSMI_SAS_CON_UNKNOWN;
++ strcpy(karg.Reference[i].bConnector,"");
++ karg.Reference[i].bLocation = CSMI_SAS_CON_UNKNOWN;
++ }
++
++ mfgPg7_sz = offsetof(CONFIG_PAGE_MANUFACTURING_7,ConnectorInfo) +
++ (ioc->num_ports * sizeof(MPI_MANPAGE7_CONNECTOR_INFO));
++ mfgPg7 = kmalloc(mfgPg7_sz, GFP_KERNEL);
++ if (!mfgPg7){
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to malloc @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, mfgPg7);
++ return -EFAULT;
++ }
++ memset(mfgPg7, 0, mfgPg7_sz);
++
++ if (!csmisas_get_manuf_pg_7(ioc, mfgPg7, mfgPg7_sz)) {
++ for (i = 0; i < ioc->num_ports; i++) {
++ karg.Reference[i].uPinout =
++ le32_to_cpu(mfgPg7->ConnectorInfo[i].Pinout);
++ /*endian conversion , this is u8 * 16 ?? */
++ strncpy(karg.Reference[i].bConnector,
++ mfgPg7->ConnectorInfo[i].Connector, 16);
++ karg.Reference[i].bLocation =
++ mfgPg7->ConnectorInfo[i].Location;
++ }
++ }
++
++ kfree(mfgPg7);
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, &karg,
++ sizeof(CSMI_SAS_CONNECTOR_INFO_BUFFER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_connector_info_buffer @"
++ "%p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return 0;
++}
++
++/**
++ * csmisas_fill_location_data
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ **/
++static int
++csmisas_fill_location_data(MPT_ADAPTER *ioc, u8 bus, u8 id, u8 opcode,
++ CSMI_SAS_LOCATION_IDENTIFIER * location_ident)
++{
++
++ ConfigExtendedPageHeader_t hdr;
++ CONFIGPARMS cfg;
++ int rc;
++ SasDevicePage0_t *sasDevicePg0=NULL;
++ SasEnclosurePage0_t *sasEnclosurePg0=NULL;
++ dma_addr_t sasDevicePg0_dma,sasEnclosurePg0_dma;
++ int sasDevicePg0_data_sz=0;
++ int sasEnclosurePg0_data_sz=0;
++ u64 sas_address;
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++ memset (location_ident, 0, sizeof(*location_ident));
++
++ /* SAS Device Page 0 */
++ hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
++ hdr.ExtPageLength = 0;
++ hdr.PageNumber = 0;
++ hdr.Reserved1 = 0;
++ hdr.Reserved2 = 0;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
++
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ rc=-1;
++ goto fill_location_data_exit;
++ }
++
++ if (hdr.ExtPageLength == 0) {
++ rc=-1;
++ goto fill_location_data_exit;
++ }
++
++ sasDevicePg0_data_sz = hdr.ExtPageLength * 4;
++ sasDevicePg0 = (SasDevicePage0_t *) pci_alloc_consistent(
++ ioc->pcidev, sasDevicePg0_data_sz, &sasDevicePg0_dma);
++ if (!sasDevicePg0) {
++ rc=-1;
++ goto fill_location_data_exit;
++ }
++
++ memset((u8 *)sasDevicePg0, 0, sasDevicePg0_data_sz);
++ cfg.physAddr = sasDevicePg0_dma;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ cfg.pageAddr = (bus << 8) + id
++ + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT);
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ rc=-1;
++ goto fill_location_data_exit;
++ }
++
++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_SAS_ADDRESS_VALID;
++ memcpy(&sas_address, &sasDevicePg0->SASAddress, sizeof(u64));
++ sas_address = reverse_byte_order64(sas_address);
++ memcpy(location_ident->bSASAddress, &sas_address, sizeof(u64));
++
++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_SAS_LUN_VALID;
++ memset(location_ident->bSASLun, 0, sizeof(location_ident->bSASLun));
++
++ /* SAS Enclosure Page 0 */
++ hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
++ hdr.ExtPageLength = 0;
++ hdr.PageNumber = 0;
++ hdr.Reserved1 = 0;
++ hdr.Reserved2 = 0;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
++
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ rc=0;
++ goto fill_location_data_exit;
++ }
++
++ if (hdr.ExtPageLength == 0) {
++ rc=0;
++ goto fill_location_data_exit;
++ }
++
++ sasEnclosurePg0_data_sz = hdr.ExtPageLength * 4;
++ sasEnclosurePg0 = (SasEnclosurePage0_t *) pci_alloc_consistent(
++ ioc->pcidev, sasEnclosurePg0_data_sz, &sasEnclosurePg0_dma);
++ if (!sasEnclosurePg0) {
++ rc=0;
++ goto fill_location_data_exit;
++ }
++ cfg.physAddr = sasEnclosurePg0_dma;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ cfg.pageAddr = sasDevicePg0->EnclosureHandle
++ + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << MPI_SAS_ENCLOS_PGAD_FORM_SHIFT);
++
++ if ((rc = mpt_config(ioc, &cfg)) != 0) {
++ rc=0;
++ goto fill_location_data_exit;
++ }
++
++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID;
++ memcpy(&sas_address, &sasEnclosurePg0->EnclosureLogicalID, sizeof(u64));
++ sas_address = reverse_byte_order64(sas_address);
++ if (sas_address)
++ memcpy(location_ident->bEnclosureIdentifier, &sas_address, sizeof(u64));
++ else
++ strcpy(location_ident->bEnclosureIdentifier,"Internal");
++
++// bBayPrefix - not supported
++
++// TODO - We need to look at sasEnclosurePg0-.Flags , to determine
++// whether SEP BUS/TargetID is valid. Ifs its a SES device, then
++// issue internal inquiry to (bus/id) to gather the Enclosure name.
++// If the device is SMP, then issue SMP_MANUFACTURING to get enclosure name
++// If its direct attached, there is no enclosure name
++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID;
++ strcpy(location_ident->bEnclosureName,"Not Supported");
++
++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_LOCATION_STATE_VALID;
++ location_ident->bLocationState = CSMI_SAS_LOCATE_UNKNOWN;
++
++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_BAY_IDENTIFIER_VALID;
++ location_ident->bBayIdentifier = le16_to_cpu(sasDevicePg0->Slot);
++
++
++// TODO - illuminating LEDs,
++// karg->bIdentify = CSMI_SAS_LOCATE_FORCE_OFF, CSMI_SAS_LOCATE_FORCE_ON
++// We can enable/disable LEDs by SCSI Enclosure Processor MPI request message
++// printk("Flags=0x%x\n",sasEnclosurePg0->Flags);
++
++/* check sasEnclosurePg0->Flags -
++ * to validate whether we need to send the SEPRequest
++ * bit:5 should be set
++ * bit:3-0 any bit should be set. If zero, then SEPRequest will fail
++*/
++
++/* MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR
++ * Look in mpi_init.h
++ * SEPRequest_t = structure
++ *
++ * SEPRequest_t->Action should be set to MPI_SEP_REQ_ACTION_WRITE_STATUS
++ *
++ * SEPRequest_t->Flags should be set to
++ * MPI_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS, to pass along enclosure/slot ids
++ *
++ * SEPRequest_t->SlotStatus |= MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST - this
++ * will illuminate the LEDs
++ */
++
++fill_location_data_exit:
++
++ if (sasDevicePg0 != NULL)
++ pci_free_consistent(ioc->pcidev, sasDevicePg0_data_sz,
++ sasDevicePg0, sasDevicePg0_dma);
++
++ if (sasEnclosurePg0 != NULL)
++ pci_free_consistent(ioc->pcidev, sasEnclosurePg0_data_sz,
++ sasEnclosurePg0, sasEnclosurePg0_dma);
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ return rc;
++}
++
++static int
++csmisas_fill_location_data_raid(MPT_ADAPTER *ioc, PCSMI_SAS_GET_LOCATION_BUFFER karg, u8 VolumeBus,
++ u8 volumeID)
++{
++ pRaidVolumePage0_t pVolume0 = NULL;
++ pRaidPhysDiskPage0_t pPhysDisk0 = NULL;
++ CONFIGPARMS cfg;
++ ConfigPageHeader_t header;
++ u8 physDiskNumMax;
++ int volumepage0sz = 0, physdiskpage0sz = 0;
++ dma_addr_t volume0_dma, physdisk0_dma;
++ int csmi_sas_get_location_sz;
++ int rc = 0, i, idx;
++ int num_hotpares;
++ u64 totalMaxLBA, tmpTotalMaxLBA;
++ IOCPage5_t *iocPage5 = NULL;
++ u32 device_info = 0;
++ struct sas_device_info *sas_info;
++
++ int sz;
++
++ csmi_sas_get_location_sz = karg->IoctlHeader.Length;
++ physDiskNumMax = (csmi_sas_get_location_sz -
++ offsetof(CSMI_SAS_GET_LOCATION_BUFFER,Location))
++ / sizeof(CSMI_SAS_LOCATION_IDENTIFIER);
++ karg->bNumberOfLocationIdentifiers=0;
++
++ /*
++ * get RAID Volume Page 0
++ */
++
++ header.PageVersion = 0;
++ header.PageLength = 0;
++ header.PageNumber = 0;
++ header.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
++ cfg.cfghdr.hdr = &header;
++ cfg.physAddr = -1;
++ cfg.pageAddr = (VolumeBus << 8) + volumeID;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0;
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++ if (mpt_config(ioc, &cfg) != 0) {
++ rc = -1;
++ goto sas_fill_location_data_raid_exit;
++ }
++
++ if (header.PageLength == 0) {
++ rc = -1;
++ goto sas_fill_location_data_raid_exit;
++ }
++
++ volumepage0sz = header.PageLength * 4;
++ pVolume0 = pci_alloc_consistent(ioc->pcidev, volumepage0sz,
++ &volume0_dma);
++ if (!pVolume0) {
++ rc = -1;
++ goto sas_fill_location_data_raid_exit;
++ }
++
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ cfg.physAddr = volume0_dma;
++ if (mpt_config(ioc, &cfg) != 0){
++ rc = -1;
++ goto sas_fill_location_data_raid_exit;
++ }
++
++ totalMaxLBA = (u64)le32_to_cpu(pVolume0->MaxLBA) |
++ ((u64)le32_to_cpu(pVolume0->MaxLBAHigh)) << 32;
++
++ /*
++ * get RAID Physical Disk Page 0
++ */
++ header.PageVersion = 0;
++ header.PageLength = 0;
++ header.PageNumber = 0;
++ header.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
++ cfg.cfghdr.hdr = &header;
++ cfg.physAddr = -1;
++ cfg.pageAddr = 0;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0;
++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
++ if (mpt_config(ioc, &cfg) != 0) {
++ rc = -1;
++ goto sas_fill_location_data_raid_exit;
++ }
++
++ if (header.PageLength == 0) {
++ rc = -1;
++ goto sas_fill_location_data_raid_exit;
++ }
++
++ physdiskpage0sz = header.PageLength * 4;
++ pPhysDisk0 = pci_alloc_consistent(ioc->pcidev, physdiskpage0sz,
++ &physdisk0_dma);
++ if (!pPhysDisk0) {
++ rc = -1;
++ goto sas_fill_location_data_raid_exit;
++ }
++ cfg.physAddr = physdisk0_dma;
++
++ for (i=0; i < min(pVolume0->NumPhysDisks, physDiskNumMax); i++) {
++
++ /* obtain a refresh of pPhysDisk0 */
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ cfg.pageAddr = pVolume0->PhysDisk[i].PhysDiskNum;
++ if (mpt_config(ioc, &cfg) != 0){
++ rc = -1;
++ goto sas_fill_location_data_raid_exit;
++ }
++
++ if((csmisas_fill_location_data(ioc, pPhysDisk0->PhysDiskBus,
++ pPhysDisk0->PhysDiskID, karg->bIdentify,
++ &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0)
++ karg->bNumberOfLocationIdentifiers++;
++
++ if (device_info)
++ continue;
++ sas_info = csmisas_get_device_component_by_fw(ioc,
++ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID);
++ if (!sas_info || sas_info->is_cached)
++ continue;
++ device_info = sas_info->device_info;
++ }
++
++ if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS)
++ goto sas_fill_location_data_raid_exit;
++
++ /*
++ * hot spare support
++ *
++ */
++
++ num_hotpares = csmisas_get_number_hotspares(ioc);
++
++ if (num_hotpares) {
++
++ sz = offsetof(IOCPage5_t, HotSpare) +
++ num_hotpares * sizeof(IOC_5_HOT_SPARE);
++ iocPage5 = kmalloc(sz, GFP_KERNEL);
++
++ if (!iocPage5)
++ goto sas_fill_location_data_raid_exit;
++ memset(iocPage5, 0, sizeof(*iocPage5));
++
++ if (csmisas_get_ioc_pg5(ioc, iocPage5, sz) != 0)
++ goto sas_fill_location_data_raid_exit;
++
++ for(i = 0, idx = pVolume0->NumPhysDisks ; i < num_hotpares;
++ i++, idx++) {
++
++ if (idx >= physDiskNumMax)
++ break;
++
++ /* obtain a refresh of pPhysDisk0 */
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ cfg.pageAddr = iocPage5->HotSpare[i].PhysDiskNum;
++ if (mpt_config(ioc, &cfg) != 0)
++ goto sas_fill_location_data_raid_exit;
++
++ /* Search the list for the matching SAS address. */
++ sas_info = csmisas_get_device_component_by_fw(ioc,
++ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID);
++
++ if (!sas_info || sas_info->is_cached)
++ continue;
++
++ /* don't mix SSP hot spare
++ * in SATA volume
++ */
++ if (!csmisas_is_sata(pPhysDisk0) &&
++ (device_info &
++ MPI_SAS_DEVICE_INFO_SATA_DEVICE))
++ continue;
++
++ /* don't mix SATA hot spare
++ * in SSP volume
++ */
++ if (csmisas_is_sata(pPhysDisk0) &&
++ (device_info &
++ MPI_SAS_DEVICE_INFO_SSP_TARGET))
++ continue;
++
++ /* capacity check for IM volumes*/
++ if ((pVolume0->VolumeType ==
++ MPI_RAID_VOL_TYPE_IM) &&
++ (totalMaxLBA +
++ (64*2*1024) /* metadata = 64MB*/ >
++ le32_to_cpu(pPhysDisk0->MaxLBA)))
++ continue;
++
++ tmpTotalMaxLBA = totalMaxLBA;
++ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks);
++ /* capacity check for IME volumes*/
++ if ((pVolume0->VolumeType ==
++ MPI_RAID_VOL_TYPE_IME) &&
++ ((tmpTotalMaxLBA * 2) +
++ (64*2*1024 ) /*metadata = 64MB*/ >
++ le32_to_cpu(pPhysDisk0->MaxLBA)))
++ continue;
++
++ if((csmisas_fill_location_data(ioc,
++ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID,
++ karg->bIdentify,
++ &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0)
++ karg->bNumberOfLocationIdentifiers++;
++ }
++ }
++
++
++ sas_fill_location_data_raid_exit:
++
++ kfree(iocPage5);
++
++ if (pVolume0)
++ pci_free_consistent(ioc->pcidev, volumepage0sz, pVolume0,
++ volume0_dma);
++
++ if(pPhysDisk0)
++ pci_free_consistent(ioc->pcidev, physdiskpage0sz, pPhysDisk0,
++ physdisk0_dma);
++
++ return rc;
++}
++
++/**
++ * Prototype Routine for the CSMI SAS Get location command.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -ENODEV if no such device/adapter
++ */
++static int
++csmisas_get_location(unsigned long arg)
++{
++ CSMI_SAS_GET_LOCATION_BUFFER __user *uarg = (void __user *) arg;
++ PCSMI_SAS_GET_LOCATION_BUFFER karg;
++ IOCTL_HEADER ioctl_header;
++ MPT_ADAPTER *ioc = NULL;
++ int iocnum,i;
++ int csmi_sas_get_location_sz;
++ int memory_pages;
++ struct sas_device_info *sas_info;
++
++ if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in IOCTL_HEADER"
++ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ csmi_sas_get_location_sz = ioctl_header.Length;
++ memory_pages = get_order(csmi_sas_get_location_sz);
++ karg = (PCSMI_SAS_GET_LOCATION_BUFFER)__get_free_pages(
++ GFP_KERNEL, memory_pages);
++ if (!karg){
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to malloc GET_LOCATION_BUFFER "
++ "csmi_sas_get_location_sz=%d memory_pages=%d\n",
++ __FILE__, __LINE__, __FUNCTION__,
++ csmi_sas_get_location_sz, memory_pages);
++ return -ENOMEM;
++ }
++ memset(karg, 0, sizeof(*karg));
++
++ if (copy_from_user(karg, uarg, csmi_sas_get_location_sz)) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to read in csmi_sas_phy_control_buffer "
++ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
++ &ioc)) < 0) || (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)karg, memory_pages);
++ return -ENODEV;
++ }
++
++ if (!csmisas_is_this_sas_cntr(ioc)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ free_pages((unsigned long)karg, memory_pages);
++ return -ENODEV;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
++
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
++ if(karg->bLengthOfLocationIdentifier !=
++ sizeof(CSMI_SAS_LOCATION_IDENTIFIER))
++ goto cim_sas_get_location_exit;
++
++ sas_info = csmisas_get_device_component_by_os(ioc, karg->bPathId,
++ karg->bTargetId);
++ if (!sas_info)
++ goto cim_sas_get_location_exit;
++
++ /* RAID SUPPORT */
++ if (ioc->raid_data.pIocPg2 && sas_info->is_logical_volume) {
++ for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++){
++ if (sas_info->fw.id ==
++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID &&
++ sas_info->fw.channel ==
++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus) {
++ if(csmisas_fill_location_data_raid(ioc, karg,
++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus,
++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) == 0)
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_SUCCESS;
++ else
++ karg->IoctlHeader.ReturnCode =
++ CSMI_SAS_STATUS_FAILED;
++ goto cim_sas_get_location_exit;
++ }
++ }
++ }
++
++ /* NON-RAID SUPPORT */
++ if (sas_info->is_cached || sas_info->is_logical_volume)
++ goto cim_sas_get_location_exit;
++
++ /* make sure there's enough room to populate the Location[] struct */
++ if ((csmi_sas_get_location_sz -
++ offsetof(CSMI_SAS_GET_LOCATION_BUFFER,Location)) <
++ sizeof(CSMI_SAS_LOCATION_IDENTIFIER))
++ goto cim_sas_get_location_exit;
++
++ karg->bNumberOfLocationIdentifiers=1;
++ karg->Location[0].bLocationFlags=0;
++ if((csmisas_fill_location_data(ioc, sas_info->fw.channel,
++ sas_info->fw.id, karg->bIdentify, &karg->Location[0])) == 0)
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
++ else
++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
++
++ cim_sas_get_location_exit:
++
++ /* Copy the data from kernel memory to user memory
++ */
++ if (copy_to_user(uarg, karg, csmi_sas_get_location_sz)) {
++ printk(KERN_ERR "%s@%d::%s() - "
++ "Unable to write out csmi_sas_get_location_buffer "
++ "@ %p\n",__FILE__, __LINE__, __FUNCTION__, uarg);
++ free_pages((unsigned long)karg, memory_pages);
++ return -EFAULT;
++ }
++
++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
++ free_pages((unsigned long)karg, memory_pages);
++ return 0;
++}
+--- /dev/null
++++ b/drivers/message/fusion/csmi/csmisas.h
+@@ -0,0 +1,1854 @@
++/**************************************************************************
++
++Module Name:
++
++ CSMISAS.H
++
++
++Abstract:
++
++ This file contains constants and data structure definitions used by drivers
++ that support the Common Storage Management Interface specification for
++ SAS or SATA in either the Windows or Linux.
++
++ This should be considered as a reference implementation only. Changes may
++ be necessary to accommodate a specific build environment or target OS.
++
++Revision History:
++
++ 001 SEF 8/12/03 Initial release.
++ 002 SEF 8/20/03 Cleanup to match documentation.
++ 003 SEF 9/12/03 Additional cleanup, created combined header
++ 004 SEF 9/23/03 Changed base types to match linux defaults
++ Added RAID signature
++ Added bControllerFlags to CSMI_SAS_CNTLR_CONFIG
++ Changed CSMI_SAS_BEGIN_PACK to 8 for common structures
++ Fixed other typos identified in first compilation test
++ 005 SEF 10/03/03 Additions to match first version of CSMI document
++ 006 SEF 10/14/03 Fixed typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER
++ Added defines for bConnectionRate
++ 007 SEF 10/15/03 Added Firmware Download Control Code and support
++ Added CSMI revision support
++ 008 SEF 10/30/03 No functional change, just updated version to track
++ spec changes
++ 009 SEF 12/09/03 No functional change, just updated version to track
++ spec changes
++ 010 SEF 3/11/04 Fixed typedef struct CSMI_SAS_RAID_DRIVES to include the
++ bFirmware member that is defined in the spec, but
++ was missing in this file,
++ added CC_CSMI_SAS_TASK_MANAGEMENT
++ 011 SEF 4/02/04 No functional change, added comment line before
++ CC_CSMI_SAS_TASK_MANAGEMENT
++ 012 SEF 4/16/04 Added IOControllerNumber to linux header,
++ Modified linux control codes to have upper word of
++ 0xCC77.... to indicate CSMI version 77
++ Added bSignalClass to CC_CSMI_SET_PHY_INFO
++ Added CC_CSMI_SAS_PHY_CONTROL support
++ 013 SEF 5/14/04 Added CC_CSMI_SAS_GET_CONNECTOR_INFO support
++ 014 SEF 5/24/04 No functional change, just updated version to track spec
++ changes
++ 015 SEF 6/16/04 changed bPinout to uPinout to reflect proper size,
++ changed width of bLocation defines to reflect size
++ 016 SEF 6/17/04 changed bLengthOfControls in CSMI_SAS_PHY_CONTROL
++ to be proper size
++ 017 SEF 9/17/04 added CSMI_SAS_SATA_PORT_SELECTOR,
++ CSMI_SAS_LINK_VIRTUAL, CSMI_SAS_CON_NOT_PRESENT, and
++ CSMI_SAS_CON_NOT_CONNECTED
++ 018 SEF 9/20/04 added CSMI_SAS_PHY_USER_PATTERN,
++ changed definition of CSMI_SAS_PHY_FIXED_PATTERN to not
++ conflict with activate definition
++ 019 SEF 12/06/04 added CSMI_SAS_GET_LOCATION
++ added bSSPStatus to CSMI_SAS_SSP_PASSTHRU_STATUS
++ structure
++ 020 SEF 5/25/05 added CSMI_SAS_PHY_VIRTUAL_SMP, and changes to
++ CSMI_SAS_GET_LOCATION
++ 021 SEF 11/03/05 added new RAID creation functionality
++ 022 SEF 2/01/06 corrected typo bNegotitiatedLInkRate
++ Added two more RAID_TYPES, 7 and 8
++ 023 SEF 4/04/06 added CSMI_RAID_TYPE_1E
++ changed structures that contained surface scan
++ to priority approach rather than time, causes
++ 0.89 to incompatible with 0.87, so a version
++ check is necessary when interpreting the
++ raid structures
++ Added netware section
++ 024 DRG 5/22/06 Added uFailureCode to CSMI_SAS_RAID_CONFIG and
++ CSMI_SAS_RAID_FEATURES
++ Changed __u64 fields to high and low __u32 fields in
++ order to avoid backward compatibility issues with
++ packing and alignment.
++ Fixed alignment problem in CSMI_SAS_RAID_DRIVES.
++ Added CSMI_SAS_CNTLR_SMART_ARRAY to uControllerFlags
++ Reassigned the value of CSMI_SAS_CNTLR_RAID_CFG_SUPPORT
++ to avoid a conflict.
++
++**************************************************************************/
++
++#ifndef _CSMI_SAS_H_
++#define _CSMI_SAS_H_
++
++// CSMI Specification Revision, the intent is that all versions of the
++// specification will be backward compatible after the 1.00 release.
++// Major revision number, corresponds to xxxx. of CSMI specification
++// Minor revision number, corresponds to .xxxx of CSMI specification
++#define CSMI_MAJOR_REVISION 0
++#define CSMI_MINOR_REVISION 90
++
++/*************************************************************************/
++/* PATCHES FOR TYPOS */
++/*************************************************************************/
++
++#define bNegotitiatedLInkRate bNegotiatedLinkRate
++
++/*************************************************************************/
++/* TARGET OS LINUX SPECIFIC CODE */
++/*************************************************************************/
++
++// EDM #ifdef _linux
++#ifdef __KERNEL__
++
++// Linux base types
++
++#include <linux/types.h>
++
++#define __i8 char
++
++// pack definition
++
++// EDM #define CSMI_SAS_BEGIN_PACK(x) pack(x)
++// EDM #define CSMI_SAS_END_PACK pack()
++
++// IOCTL Control Codes
++// (IoctlHeader.ControlCode)
++
++// Control Codes prior to 0.77
++
++// Control Codes requiring CSMI_ALL_SIGNATURE
++
++// #define CC_CSMI_SAS_GET_DRIVER_INFO 0x12345678
++// #define CC_CSMI_SAS_GET_CNTLR_CONFIG 0x23456781
++// #define CC_CSMI_SAS_GET_CNTLR_STATUS 0x34567812
++// #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0x92345678
++
++// Control Codes requiring CSMI_RAID_SIGNATURE
++
++// #define CC_CSMI_SAS_GET_RAID_INFO 0x45678123
++// #define CC_CSMI_SAS_GET_RAID_CONFIG 0x56781234
++
++// Control Codes requiring CSMI_SAS_SIGNATURE
++
++// #define CC_CSMI_SAS_GET_PHY_INFO 0x67812345
++// #define CC_CSMI_SAS_SET_PHY_INFO 0x78123456
++// #define CC_CSMI_SAS_GET_LINK_ERRORS 0x81234567
++// #define CC_CSMI_SAS_SMP_PASSTHRU 0xA1234567
++// #define CC_CSMI_SAS_SSP_PASSTHRU 0xB1234567
++// #define CC_CSMI_SAS_STP_PASSTHRU 0xC1234567
++// #define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xD1234567
++// #define CC_CSMI_SAS_GET_SCSI_ADDRESS 0xE1234567
++// #define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xF1234567
++// #define CC_CSMI_SAS_TASK_MANAGEMENT 0xA2345678
++
++// Control Codes for 0.77 and later
++
++// Control Codes requiring CSMI_ALL_SIGNATURE
++
++#define CC_CSMI_SAS_GET_DRIVER_INFO 0xCC770001
++#define CC_CSMI_SAS_GET_CNTLR_CONFIG 0xCC770002
++#define CC_CSMI_SAS_GET_CNTLR_STATUS 0xCC770003
++#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0xCC770004
++
++// Control Codes requiring CSMI_RAID_SIGNATURE
++
++#define CC_CSMI_SAS_GET_RAID_INFO 0xCC77000A
++#define CC_CSMI_SAS_GET_RAID_CONFIG 0xCC77000B
++#define CC_CSMI_SAS_GET_RAID_FEATURES 0xCC77000C
++#define CC_CSMI_SAS_SET_RAID_CONTROL 0xCC77000D
++#define CC_CSMI_SAS_GET_RAID_ELEMENT 0xCC77000E
++#define CC_CSMI_SAS_SET_RAID_OPERATION 0xCC77000F
++
++// Control Codes requiring CSMI_SAS_SIGNATURE
++
++#define CC_CSMI_SAS_GET_PHY_INFO 0xCC770014
++#define CC_CSMI_SAS_SET_PHY_INFO 0xCC770015
++#define CC_CSMI_SAS_GET_LINK_ERRORS 0xCC770016
++#define CC_CSMI_SAS_SMP_PASSTHRU 0xCC770017
++#define CC_CSMI_SAS_SSP_PASSTHRU 0xCC770018
++#define CC_CSMI_SAS_STP_PASSTHRU 0xCC770019
++#define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xCC770020
++#define CC_CSMI_SAS_GET_SCSI_ADDRESS 0xCC770021
++#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xCC770022
++#define CC_CSMI_SAS_TASK_MANAGEMENT 0xCC770023
++#define CC_CSMI_SAS_GET_CONNECTOR_INFO 0xCC770024
++#define CC_CSMI_SAS_GET_LOCATION 0xCC770025
++
++
++// Control Codes requiring CSMI_PHY_SIGNATURE
++
++#define CC_CSMI_SAS_PHY_CONTROL 0xCC77003C
++
++// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
++#pragma pack(8)
++
++// IOCTL_HEADER
++typedef struct _IOCTL_HEADER {
++ __u32 IOControllerNumber;
++ __u32 Length;
++ __u32 ReturnCode;
++ __u32 Timeout;
++ __u16 Direction;
++} IOCTL_HEADER,
++ *PIOCTL_HEADER;
++
++// EDM #pragma CSMI_SAS_END_PACK
++#pragma pack()
++
++#endif
++
++/*************************************************************************/
++/* TARGET OS WINDOWS SPECIFIC CODE */
++/*************************************************************************/
++
++#ifdef _WIN32
++
++// windows IOCTL definitions
++
++#ifndef _NTDDSCSIH_
++#include <ntddscsi.h>
++#endif
++
++// pack definition
++
++#if defined _MSC_VER
++ #define CSMI_SAS_BEGIN_PACK(x) pack(push,x)
++ #define CSMI_SAS_END_PACK pack(pop)
++#elif defined __BORLANDC__
++ #define CSMI_SAS_BEGIN_PACK(x) option -a##x
++ #define CSMI_SAS_END_PACK option -a.
++#else
++ #error "CSMISAS.H - Must externally define a pack compiler designator."
++#endif
++
++// base types
++
++#define __u8 unsigned char
++#define __u16 unsigned short
++#define __u32 unsigned long
++#define __u64 unsigned __int64
++
++#define __i8 char
++
++// IOCTL Control Codes
++// (IoctlHeader.ControlCode)
++
++// Control Codes requiring CSMI_ALL_SIGNATURE
++
++#define CC_CSMI_SAS_GET_DRIVER_INFO 1
++#define CC_CSMI_SAS_GET_CNTLR_CONFIG 2
++#define CC_CSMI_SAS_GET_CNTLR_STATUS 3
++#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 4
++
++// Control Codes requiring CSMI_RAID_SIGNATURE
++
++#define CC_CSMI_SAS_GET_RAID_INFO 10
++#define CC_CSMI_SAS_GET_RAID_CONFIG 11
++#define CC_CSMI_SAS_GET_RAID_FEATURES 12
++#define CC_CSMI_SAS_SET_RAID_CONTROL 13
++#define CC_CSMI_SAS_GET_RAID_ELEMENT 14
++#define CC_CSMI_SAS_SET_RAID_OPERATION 15
++
++// Control Codes requiring CSMI_SAS_SIGNATURE
++
++#define CC_CSMI_SAS_GET_PHY_INFO 20
++#define CC_CSMI_SAS_SET_PHY_INFO 21
++#define CC_CSMI_SAS_GET_LINK_ERRORS 22
++#define CC_CSMI_SAS_SMP_PASSTHRU 23
++#define CC_CSMI_SAS_SSP_PASSTHRU 24
++#define CC_CSMI_SAS_STP_PASSTHRU 25
++#define CC_CSMI_SAS_GET_SATA_SIGNATURE 26
++#define CC_CSMI_SAS_GET_SCSI_ADDRESS 27
++#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 28
++#define CC_CSMI_SAS_TASK_MANAGEMENT 29
++#define CC_CSMI_SAS_GET_CONNECTOR_INFO 30
++#define CC_CSMI_SAS_GET_LOCATION 31
++
++// Control Codes requiring CSMI_PHY_SIGNATURE
++
++#define CC_CSMI_SAS_PHY_CONTROL 60
++
++#define IOCTL_HEADER SRB_IO_CONTROL
++#define PIOCTL_HEADER PSRB_IO_CONTROL
++
++#endif
++
++/*************************************************************************/
++/* TARGET OS NETWARE SPECIFIC CODE */
++/*************************************************************************/
++
++#ifdef _NETWARE
++
++// NetWare IOCTL definitions
++
++#define CSMI_SAS_BEGIN_PACK(x) pack(x)
++#define CSMI_SAS_END_PACK pack()
++
++#ifndef LONG
++typedef unsigned long LONG;
++#endif
++
++#ifndef WORD
++typedef unsigned short WORD;
++#endif
++
++#ifndef BYTE
++typedef unsigned char BYTE;
++#endif
++
++/* Need to have these definitions for Netware */
++#define __u8 unsigned char
++#define __u16 unsigned short
++#define __u32 unsigned long
++#define __u64 unsigned __int64
++
++#define __i8 char
++
++
++// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
++#pragma pack(8)
++
++// IOCTL_HEADER
++typedef struct _IOCTL_HEADER {
++ __u32 Length;
++ __u32 ReturnCode;
++} IOCTL_HEADER,
++ *PIOCTL_HEADER;
++
++// EDM #pragma CSMI_SAS_END_PACK
++#pragma pack()
++
++// IOCTL Control Codes
++// (IoctlHeader.ControlCode)
++
++// Control Codes requiring CSMI_ALL_SIGNATURE
++
++#define CC_CSMI_SAS_GET_DRIVER_INFO 0x01FF0001
++#define CC_CSMI_SAS_GET_CNTLR_CONFIG 0x01FF0002
++#define CC_CSMI_SAS_GET_CNTLR_STATUS 0x01FF0003
++#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0x01FF0004
++
++// Control Codes requiring CSMI_RAID_SIGNATURE
++
++#define CC_CSMI_SAS_GET_RAID_INFO 0x01FF000A
++#define CC_CSMI_SAS_GET_RAID_CONFIG 0x01FF000B
++#define CC_CSMI_SAS_GET_RAID_FEATURES 0x01FF000C
++#define CC_CSMI_SAS_SET_RAID_CONTROL 0x01FF000D
++#define CC_CSMI_SAS_GET_RAID_ELEMENT 0x01FF000E
++#define CC_CSMI_SAS_SET_RAID_OPERATION 0x01FF000F
++
++// Control Codes requiring CSMI_SAS_SIGNATURE
++
++#define CC_CSMI_SAS_GET_PHY_INFO 0x01FF0014
++#define CC_CSMI_SAS_SET_PHY_INFO 0x01FF0015
++#define CC_CSMI_SAS_GET_LINK_ERRORS 0x01FF0016
++#define CC_CSMI_SAS_SMP_PASSTHRU 0x01FF0017
++#define CC_CSMI_SAS_SSP_PASSTHRU 0x01FF0018
++#define CC_CSMI_SAS_STP_PASSTHRU 0x01FF0019
++#define CC_CSMI_SAS_GET_SATA_SIGNATURE 0x01FF001A
++#define CC_CSMI_SAS_GET_SCSI_ADDRESS 0x01FF001B
++#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0x01FF001C
++#define CC_CSMI_SAS_TASK_MANAGEMENT 0x01FF001D
++#define CC_CSMI_SAS_GET_CONNECTOR_INFO 0x01FF001E
++#define CC_CSMI_SAS_GET_LOCATION 0x01FF001F
++
++// Control Codes requiring CSMI_PHY_SIGNATURE
++
++#define CC_CSMI_SAS_PHY_CONTROL 60
++
++#endif
++
++/*************************************************************************/
++/* TARGET OS NOT DEFINED ERROR */
++/*************************************************************************/
++
++// EDM
++//#if (!_WIN32 && !_linux && !_NETWARE)
++// #error "Unknown target OS."
++//#endif
++
++/*************************************************************************/
++/* OS INDEPENDENT CODE */
++/*************************************************************************/
++
++/* * * * * * * * * * Class Independent IOCTL Constants * * * * * * * * * */
++
++// Return codes for all IOCTL's regardless of class
++// (IoctlHeader.ReturnCode)
++
++#define CSMI_SAS_STATUS_SUCCESS 0
++#define CSMI_SAS_STATUS_FAILED 1
++#define CSMI_SAS_STATUS_BAD_CNTL_CODE 2
++#define CSMI_SAS_STATUS_INVALID_PARAMETER 3
++#define CSMI_SAS_STATUS_WRITE_ATTEMPTED 4
++
++// Signature value
++// (IoctlHeader.Signature)
++
++#define CSMI_ALL_SIGNATURE "CSMIALL"
++
++// Timeout value default of 60 seconds
++// (IoctlHeader.Timeout)
++
++#define CSMI_ALL_TIMEOUT 60
++
++// Direction values for data flow on this IOCTL
++// (IoctlHeader.Direction, Linux only)
++#define CSMI_SAS_DATA_READ 0
++#define CSMI_SAS_DATA_WRITE 1
++
++// I/O Bus Types
++// ISA and EISA bus types are not supported
++// (bIoBusType)
++
++#define CSMI_SAS_BUS_TYPE_PCI 3
++#define CSMI_SAS_BUS_TYPE_PCMCIA 4
++
++// Controller Status
++// (uStatus)
++
++#define CSMI_SAS_CNTLR_STATUS_GOOD 1
++#define CSMI_SAS_CNTLR_STATUS_FAILED 2
++#define CSMI_SAS_CNTLR_STATUS_OFFLINE 3
++#define CSMI_SAS_CNTLR_STATUS_POWEROFF 4
++
++// Offline Status Reason
++// (uOfflineReason)
++
++#define CSMI_SAS_OFFLINE_REASON_NO_REASON 0
++#define CSMI_SAS_OFFLINE_REASON_INITIALIZING 1
++#define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_DEGRADED 2
++#define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_FAILURE 3
++
++// Controller Class
++// (bControllerClass)
++
++#define CSMI_SAS_CNTLR_CLASS_HBA 5
++
++// Controller Flag bits
++// (uControllerFlags)
++
++#define CSMI_SAS_CNTLR_SAS_HBA 0x00000001
++#define CSMI_SAS_CNTLR_SAS_RAID 0x00000002
++#define CSMI_SAS_CNTLR_SATA_HBA 0x00000004
++#define CSMI_SAS_CNTLR_SATA_RAID 0x00000008
++#define CSMI_SAS_CNTLR_SMART_ARRAY 0x00000010
++
++// for firmware download
++#define CSMI_SAS_CNTLR_FWD_SUPPORT 0x00010000
++#define CSMI_SAS_CNTLR_FWD_ONLINE 0x00020000
++#define CSMI_SAS_CNTLR_FWD_SRESET 0x00040000
++#define CSMI_SAS_CNTLR_FWD_HRESET 0x00080000
++#define CSMI_SAS_CNTLR_FWD_RROM 0x00100000
++
++// for RAID configuration supported
++#define CSMI_SAS_CNTLR_RAID_CFG_SUPPORT 0x01000000
++
++// Download Flag bits
++// (uDownloadFlags)
++#define CSMI_SAS_FWD_VALIDATE 0x00000001
++#define CSMI_SAS_FWD_SOFT_RESET 0x00000002
++#define CSMI_SAS_FWD_HARD_RESET 0x00000004
++
++// Firmware Download Status
++// (usStatus)
++#define CSMI_SAS_FWD_SUCCESS 0
++#define CSMI_SAS_FWD_FAILED 1
++#define CSMI_SAS_FWD_USING_RROM 2
++#define CSMI_SAS_FWD_REJECT 3
++#define CSMI_SAS_FWD_DOWNREV 4
++
++// Firmware Download Severity
++// (usSeverity>
++#define CSMI_SAS_FWD_INFORMATION 0
++#define CSMI_SAS_FWD_WARNING 1
++#define CSMI_SAS_FWD_ERROR 2
++#define CSMI_SAS_FWD_FATAL 3
++
++/* * * * * * * * * * SAS RAID Class IOCTL Constants * * * * * * * * */
++
++// Return codes for the RAID IOCTL's regardless of class
++// (IoctlHeader.ReturnCode)
++
++#define CSMI_SAS_RAID_SET_OUT_OF_RANGE 1000
++#define CSMI_SAS_RAID_SET_BUFFER_TOO_SMALL 1001
++#define CSMI_SAS_RAID_SET_DATA_CHANGED 1002
++
++// Signature value
++// (IoctlHeader.Signature)
++
++#define CSMI_RAID_SIGNATURE "CSMIARY"
++
++// Timeout value default of 60 seconds
++// (IoctlHeader.Timeout)
++
++#define CSMI_RAID_TIMEOUT 60
++
++// RAID Types
++// (bRaidType)
++#define CSMI_SAS_RAID_TYPE_NONE 0
++#define CSMI_SAS_RAID_TYPE_0 1
++#define CSMI_SAS_RAID_TYPE_1 2
++#define CSMI_SAS_RAID_TYPE_10 3
++#define CSMI_SAS_RAID_TYPE_5 4
++#define CSMI_SAS_RAID_TYPE_15 5
++#define CSMI_SAS_RAID_TYPE_6 6
++#define CSMI_SAS_RAID_TYPE_50 7
++#define CSMI_SAS_RAID_TYPE_VOLUME 8
++#define CSMI_SAS_RAID_TYPE_1E 9
++#define CSMI_SAS_RAID_TYPE_OTHER 255
++// the last value 255 was already defined for other
++// so end is defined as 254
++#define CSMI_SAS_RAID_TYPE_END 254
++
++// RAID Status
++// (bStatus)
++#define CSMI_SAS_RAID_SET_STATUS_OK 0
++#define CSMI_SAS_RAID_SET_STATUS_DEGRADED 1
++#define CSMI_SAS_RAID_SET_STATUS_REBUILDING 2
++#define CSMI_SAS_RAID_SET_STATUS_FAILED 3
++#define CSMI_SAS_RAID_SET_STATUS_OFFLINE 4
++#define CSMI_SAS_RAID_SET_STATUS_TRANSFORMING 5
++#define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_REBUILD 6
++#define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_TRANSFORMATION 7
++
++// RAID Drive Count
++// (bDriveCount, 0xF1 to 0xFF are reserved)
++#define CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG 0xF1
++#define CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED 0xF2
++
++// RAID Data Type
++// (bDataType)
++#define CSMI_SAS_RAID_DATA_DRIVES 0
++#define CSMI_SAS_RAID_DATA_DEVICE_ID 1
++#define CSMI_SAS_RAID_DATA_ADDITIONAL_DATA 2
++
++// RAID Drive Status
++// (bDriveStatus)
++#define CSMI_SAS_DRIVE_STATUS_OK 0
++#define CSMI_SAS_DRIVE_STATUS_REBUILDING 1
++#define CSMI_SAS_DRIVE_STATUS_FAILED 2
++#define CSMI_SAS_DRIVE_STATUS_DEGRADED 3
++#define CSMI_SAS_DRIVE_STATUS_OFFLINE 4
++#define CSMI_SAS_DRIVE_STATUS_QUEUED_FOR_REBUILD 5
++
++// RAID Drive Usage
++// (bDriveUsage)
++#define CSMI_SAS_DRIVE_CONFIG_NOT_USED 0
++#define CSMI_SAS_DRIVE_CONFIG_MEMBER 1
++#define CSMI_SAS_DRIVE_CONFIG_SPARE 2
++#define CSMI_SAS_DRIVE_CONFIG_SPARE_ACTIVE 3
++
++// RAID Drive Type
++// (bDriveType)
++#define CSMI_SAS_DRIVE_TYPE_UNKNOWN 0
++#define CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS 1
++#define CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS 2
++#define CSMI_SAS_DRIVE_TYPE_SATA 3
++#define CSMI_SAS_DRIVE_TYPE_SATA_PS 4
++#define CSMI_SAS_DRIVE_TYPE_OTHER 255
++
++// RAID Write Protect
++// (bWriteProtect)
++#define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNKNOWN 0
++#define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNCHANGED 0
++#define CSMI_SAS_RAID_SET_WRITE_PROTECT_ENABLED 1
++#define CSMI_SAS_RAID_SET_WRITE_PROTECT_DISABLED 2
++
++// RAID Cache Setting
++// (bCacheSetting)
++#define CSMI_SAS_RAID_SET_CACHE_UNKNOWN 0
++#define CSMI_SAS_RAID_SET_CACHE_UNCHANGED 0
++#define CSMI_SAS_RAID_SET_CACHE_ENABLED 1
++#define CSMI_SAS_RAID_SET_CACHE_DISABLED 2
++#define CSMI_SAS_RAID_SET_CACHE_CORRUPT 3
++
++// RAID Features
++// (uFeatures)
++#define CSMI_SAS_RAID_FEATURE_TRANSFORMATION 0x00000001
++#define CSMI_SAS_RAID_FEATURE_REBUILD 0x00000002
++#define CSMI_SAS_RAID_FEATURE_SPLIT_MIRROR 0x00000004
++#define CSMI_SAS_RAID_FEATURE_MERGE_MIRROR 0x00000008
++#define CSMI_SAS_RAID_FEATURE_LUN_RENUMBER 0x00000010
++#define CSMI_SAS_RAID_FEATURE_SURFACE_SCAN 0x00000020
++#define CSMI_SAS_RAID_FEATURE_SPARES_SHARED 0x00000040
++
++// RAID Priority
++// (bDefaultTransformPriority, etc.)
++#define CSMI_SAS_PRIORITY_UNKNOWN 0
++#define CSMI_SAS_PRIORITY_UNCHANGED 0
++#define CSMI_SAS_PRIORITY_AUTO 1
++#define CSMI_SAS_PRIORITY_OFF 2
++#define CSMI_SAS_PRIORITY_LOW 3
++#define CSMI_SAS_PRIORITY_MEDIUM 4
++#define CSMI_SAS_PRIORITY_HIGH 5
++
++// RAID Transformation Rules
++// (uRaidSetTransformationRules)
++#define CSMI_SAS_RAID_RULE_AVAILABLE_MEMORY 0x00000001
++#define CSMI_SAS_RAID_RULE_OVERLAPPED_EXTENTS 0x00000002
++
++// RAID Cache Ratios Supported
++// (bCacheRatiosSupported)
++// from 0 to 100 defines the write to read ratio, 0 is 100% write
++#define CSMI_SAS_RAID_CACHE_RATIO_RANGE 101
++#define CSMI_SAS_RAID_CACHE_RATIO_FIXED 102
++#define CSMI_SAS_RAID_CACHE_RATIO_AUTO 103
++#define CSMI_SAS_RAID_CACHE_RATIO_END 255
++
++// RAID Cache Ratio Flag
++// (bCacheRatioFlag)
++#define CSMI_SAS_RAID_CACHE_RATIO_DISABLE 0
++#define CSMI_SAS_RAID_CACHE_RATIO_ENABLE 1
++
++// RAID Clear Configuration Signature
++// (bClearConfiguration)
++#define CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE "RAIDCLR"
++
++// RAID Failure Codes
++// (uFailureCode)
++#define CSMI_SAS_FAIL_CODE_OK 0
++#define CSMI_SAS_FAIL_CODE_PARAMETER_INVALID 1000
++#define CSMI_SAS_FAIL_CODE_TRANSFORM_PRIORITY_INVALID 1001
++#define CSMI_SAS_FAIL_CODE_REBUILD_PRIORITY_INVALID 1002
++#define CSMI_SAS_FAIL_CODE_CACHE_RATIO_INVALID 1003
++#define CSMI_SAS_FAIL_CODE_SURFACE_SCAN_INVALID 1004
++#define CSMI_SAS_FAIL_CODE_CLEAR_CONFIGURATION_INVALID 1005
++#define CSMI_SAS_FAIL_CODE_ELEMENT_INDEX_INVALID 1006
++#define CSMI_SAS_FAIL_CODE_SUBELEMENT_INDEX_INVALID 1007
++#define CSMI_SAS_FAIL_CODE_EXTENT_INVALID 1008
++#define CSMI_SAS_FAIL_CODE_BLOCK_COUNT_INVALID 1009
++#define CSMI_SAS_FAIL_CODE_DRIVE_INDEX_INVALID 1010
++#define CSMI_SAS_FAIL_CODE_EXISTING_LUN_INVALID 1011
++#define CSMI_SAS_FAIL_CODE_RAID_TYPE_INVALID 1012
++#define CSMI_SAS_FAIL_CODE_STRIPE_SIZE_INVALID 1013
++#define CSMI_SAS_FAIL_CODE_TRANSFORMATION_INVALID 1014
++#define CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID 1015
++#define CSMI_SAS_FAIL_CODE_ENUMERATION_TYPE_INVALID 1016
++
++#define CSMI_SAS_FAIL_CODE_EXCEEDED_RAID_SET_COUNT 2000
++#define CSMI_SAS_FAIL_CODE_DUPLICATE_LUN 2001
++
++#define CSMI_SAS_FAIL_CODE_WAIT_FOR_OPERATION 3000
++
++// RAID Enumeration Types
++// (uEnumerationType)
++#define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE 0
++#define CSMI_SAS_RAID_ELEMENT_TYPE_MODULE 1
++#define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE_RAID_SET 2
++#define CSMI_SAS_RAID_ELEMENT_TYPE_EXTENT_DRIVE 3
++
++// RAID Extent Types
++// (bExtentType)
++#define CSMI_SAS_RAID_EXTENT_RESERVED 0
++#define CSMI_SAS_RAID_EXTENT_METADATA 1
++#define CSMI_SAS_RAID_EXTENT_ALLOCATED 2
++#define CSMI_SAS_RAID_EXTENT_UNALLOCATED 3
++
++// RAID Operation Types
++// (uOperationType)
++#define CSMI_SAS_RAID_SET_CREATE 0
++#define CSMI_SAS_RAID_SET_LABEL 1
++#define CSMI_SAS_RAID_SET_TRANSFORM 2
++#define CSMI_SAS_RAID_SET_DELETE 3
++#define CSMI_SAS_RAID_SET_WRITE_PROTECT 4
++#define CSMI_SAS_RAID_SET_CACHE 5
++#define CSMI_SAS_RAID_SET_ONLINE_STATE 6
++#define CSMI_SAS_RAID_SET_SPARE 7
++
++// RAID Transform Types
++// (bTransformType)
++#define CSMI_SAS_RAID_SET_TRANSFORM_SPLIT_MIRROR 0
++#define CSMI_SAS_RAID_SET_TRANSFORM_MERGE_RAID_0 1
++#define CSMI_SAS_RAID_SET_TRANSFORM_LUN_RENUMBER 2
++#define CSMI_SAS_RAID_SET_TRANSFORM_RAID_SET 3
++
++// RAID Online State
++// (bOnlineState)
++#define CSMI_SAS_RAID_SET_STATE_UNKNOWN 0
++#define CSMI_SAS_RAID_SET_STATE_ONLINE 1
++#define CSMI_SAS_RAID_SET_STATE_OFFLINE 2
++
++/* * * * * * * * * * SAS HBA Class IOCTL Constants * * * * * * * * * */
++
++// Return codes for SAS IOCTL's
++// (IoctlHeader.ReturnCode)
++
++#define CSMI_SAS_PHY_INFO_CHANGED CSMI_SAS_STATUS_SUCCESS
++#define CSMI_SAS_PHY_INFO_NOT_CHANGEABLE 2000
++#define CSMI_SAS_LINK_RATE_OUT_OF_RANGE 2001
++
++#define CSMI_SAS_PHY_DOES_NOT_EXIST 2002
++#define CSMI_SAS_PHY_DOES_NOT_MATCH_PORT 2003
++#define CSMI_SAS_PHY_CANNOT_BE_SELECTED 2004
++#define CSMI_SAS_SELECT_PHY_OR_PORT 2005
++#define CSMI_SAS_PORT_DOES_NOT_EXIST 2006
++#define CSMI_SAS_PORT_CANNOT_BE_SELECTED 2007
++#define CSMI_SAS_CONNECTION_FAILED 2008
++
++#define CSMI_SAS_NO_SATA_DEVICE 2009
++#define CSMI_SAS_NO_SATA_SIGNATURE 2010
++#define CSMI_SAS_SCSI_EMULATION 2011
++#define CSMI_SAS_NOT_AN_END_DEVICE 2012
++#define CSMI_SAS_NO_SCSI_ADDRESS 2013
++#define CSMI_SAS_NO_DEVICE_ADDRESS 2014
++
++// Signature value
++// (IoctlHeader.Signature)
++
++#define CSMI_SAS_SIGNATURE "CSMISAS"
++
++// Timeout value default of 60 seconds
++// (IoctlHeader.Timeout)
++
++#define CSMI_SAS_TIMEOUT 60
++
++// Device types
++// (bDeviceType)
++
++#define CSMI_SAS_PHY_UNUSED 0x00
++#define CSMI_SAS_NO_DEVICE_ATTACHED 0x00
++#define CSMI_SAS_END_DEVICE 0x10
++#define CSMI_SAS_EDGE_EXPANDER_DEVICE 0x20
++#define CSMI_SAS_FANOUT_EXPANDER_DEVICE 0x30
++
++// Protocol options
++// (bInitiatorPortProtocol, bTargetPortProtocol)
++
++#define CSMI_SAS_PROTOCOL_SATA 0x01
++#define CSMI_SAS_PROTOCOL_SMP 0x02
++#define CSMI_SAS_PROTOCOL_STP 0x04
++#define CSMI_SAS_PROTOCOL_SSP 0x08
++
++// Negotiated and hardware link rates
++// (bNegotiatedLinkRate, bMinimumLinkRate, bMaximumLinkRate)
++
++#define CSMI_SAS_LINK_RATE_UNKNOWN 0x00
++#define CSMI_SAS_PHY_DISABLED 0x01
++#define CSMI_SAS_LINK_RATE_FAILED 0x02
++#define CSMI_SAS_SATA_SPINUP_HOLD 0x03
++#define CSMI_SAS_SATA_PORT_SELECTOR 0x04
++#define CSMI_SAS_LINK_RATE_1_5_GBPS 0x08
++#define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09
++#define CSMI_SAS_LINK_VIRTUAL 0x10
++
++// Discover state
++// (bAutoDiscover)
++
++#define CSMI_SAS_DISCOVER_NOT_SUPPORTED 0x00
++#define CSMI_SAS_DISCOVER_NOT_STARTED 0x01
++#define CSMI_SAS_DISCOVER_IN_PROGRESS 0x02
++#define CSMI_SAS_DISCOVER_COMPLETE 0x03
++#define CSMI_SAS_DISCOVER_ERROR 0x04
++
++// Phy features
++
++#define CSMI_SAS_PHY_VIRTUAL_SMP 0x01
++
++// Programmed link rates
++// (bMinimumLinkRate, bMaximumLinkRate)
++// (bProgrammedMinimumLinkRate, bProgrammedMaximumLinkRate)
++
++#define CSMI_SAS_PROGRAMMED_LINK_RATE_UNCHANGED 0x00
++#define CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS 0x08
++#define CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS 0x09
++
++// Link rate
++// (bNegotiatedLinkRate in CSMI_SAS_SET_PHY_INFO)
++
++#define CSMI_SAS_LINK_RATE_NEGOTIATE 0x00
++#define CSMI_SAS_LINK_RATE_PHY_DISABLED 0x01
++
++// Signal class
++// (bSignalClass in CSMI_SAS_SET_PHY_INFO)
++
++#define CSMI_SAS_SIGNAL_CLASS_UNKNOWN 0x00
++#define CSMI_SAS_SIGNAL_CLASS_DIRECT 0x01
++#define CSMI_SAS_SIGNAL_CLASS_SERVER 0x02
++#define CSMI_SAS_SIGNAL_CLASS_ENCLOSURE 0x03
++
++// Link error reset
++// (bResetCounts)
++
++#define CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS 0x00
++#define CSMI_SAS_LINK_ERROR_RESET_COUNTS 0x01
++
++// Phy identifier
++// (bPhyIdentifier)
++
++#define CSMI_SAS_USE_PORT_IDENTIFIER 0xFF
++
++// Port identifier
++// (bPortIdentifier)
++
++#define CSMI_SAS_IGNORE_PORT 0xFF
++
++// Programmed link rates
++// (bConnectionRate)
++
++#define CSMI_SAS_LINK_RATE_NEGOTIATED 0x00
++#define CSMI_SAS_LINK_RATE_1_5_GBPS 0x08
++#define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09
++
++// Connection status
++// (bConnectionStatus)
++
++#define CSMI_SAS_OPEN_ACCEPT 0
++#define CSMI_SAS_OPEN_REJECT_BAD_DESTINATION 1
++#define CSMI_SAS_OPEN_REJECT_RATE_NOT_SUPPORTED 2
++#define CSMI_SAS_OPEN_REJECT_NO_DESTINATION 3
++#define CSMI_SAS_OPEN_REJECT_PATHWAY_BLOCKED 4
++#define CSMI_SAS_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED 5
++#define CSMI_SAS_OPEN_REJECT_RESERVE_ABANDON 6
++#define CSMI_SAS_OPEN_REJECT_RESERVE_CONTINUE 7
++#define CSMI_SAS_OPEN_REJECT_RESERVE_INITIALIZE 8
++#define CSMI_SAS_OPEN_REJECT_RESERVE_STOP 9
++#define CSMI_SAS_OPEN_REJECT_RETRY 10
++#define CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY 11
++#define CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION 12
++
++// SSP Status
++// (bSSPStatus)
++
++#define CSMI_SAS_SSP_STATUS_UNKNOWN 0x00
++#define CSMI_SAS_SSP_STATUS_WAITING 0x01
++#define CSMI_SAS_SSP_STATUS_COMPLETED 0x02
++#define CSMI_SAS_SSP_STATUS_FATAL_ERROR 0x03
++#define CSMI_SAS_SSP_STATUS_RETRY 0x04
++#define CSMI_SAS_SSP_STATUS_NO_TAG 0x05
++
++// SSP Flags
++// (uFlags)
++
++#define CSMI_SAS_SSP_READ 0x00000001
++#define CSMI_SAS_SSP_WRITE 0x00000002
++#define CSMI_SAS_SSP_UNSPECIFIED 0x00000004
++
++#define CSMI_SAS_SSP_TASK_ATTRIBUTE_SIMPLE 0x00000000
++#define CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE 0x00000010
++#define CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED 0x00000020
++#define CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA 0x00000040
++
++// SSP Data present
++// (bDataPresent)
++
++#define CSMI_SAS_SSP_NO_DATA_PRESENT 0x00
++#define CSMI_SAS_SSP_RESPONSE_DATA_PRESENT 0x01
++#define CSMI_SAS_SSP_SENSE_DATA_PRESENT 0x02
++
++// STP Flags
++// (uFlags)
++
++#define CSMI_SAS_STP_READ 0x00000001
++#define CSMI_SAS_STP_WRITE 0x00000002
++#define CSMI_SAS_STP_UNSPECIFIED 0x00000004
++#define CSMI_SAS_STP_PIO 0x00000010
++#define CSMI_SAS_STP_DMA 0x00000020
++#define CSMI_SAS_STP_PACKET 0x00000040
++#define CSMI_SAS_STP_DMA_QUEUED 0x00000080
++#define CSMI_SAS_STP_EXECUTE_DIAG 0x00000100
++#define CSMI_SAS_STP_RESET_DEVICE 0x00000200
++
++// Task Management Flags
++// (uFlags)
++
++#define CSMI_SAS_TASK_IU 0x00000001
++#define CSMI_SAS_HARD_RESET_SEQUENCE 0x00000002
++#define CSMI_SAS_SUPPRESS_RESULT 0x00000004
++
++// Task Management Functions
++// (bTaskManagement)
++
++#define CSMI_SAS_SSP_ABORT_TASK 0x01
++#define CSMI_SAS_SSP_ABORT_TASK_SET 0x02
++#define CSMI_SAS_SSP_CLEAR_TASK_SET 0x04
++#define CSMI_SAS_SSP_LOGICAL_UNIT_RESET 0x08
++#define CSMI_SAS_SSP_CLEAR_ACA 0x40
++#define CSMI_SAS_SSP_QUERY_TASK 0x80
++
++// Task Management Information
++// (uInformation)
++
++#define CSMI_SAS_SSP_TEST 1
++#define CSMI_SAS_SSP_EXCEEDED 2
++#define CSMI_SAS_SSP_DEMAND 3
++#define CSMI_SAS_SSP_TRIGGER 4
++
++// Connector Pinout Information
++// (uPinout)
++
++#define CSMI_SAS_CON_UNKNOWN 0x00000001
++#define CSMI_SAS_CON_SFF_8482 0x00000002
++#define CSMI_SAS_CON_SFF_8470_LANE_1 0x00000100
++#define CSMI_SAS_CON_SFF_8470_LANE_2 0x00000200
++#define CSMI_SAS_CON_SFF_8470_LANE_3 0x00000400
++#define CSMI_SAS_CON_SFF_8470_LANE_4 0x00000800
++#define CSMI_SAS_CON_SFF_8484_LANE_1 0x00010000
++#define CSMI_SAS_CON_SFF_8484_LANE_2 0x00020000
++#define CSMI_SAS_CON_SFF_8484_LANE_3 0x00040000
++#define CSMI_SAS_CON_SFF_8484_LANE_4 0x00080000
++
++// Connector Location Information
++// (bLocation)
++
++// same as uPinout above...
++// #define CSMI_SAS_CON_UNKNOWN 0x01
++#define CSMI_SAS_CON_INTERNAL 0x02
++#define CSMI_SAS_CON_EXTERNAL 0x04
++#define CSMI_SAS_CON_SWITCHABLE 0x08
++#define CSMI_SAS_CON_AUTO 0x10
++#define CSMI_SAS_CON_NOT_PRESENT 0x20
++#define CSMI_SAS_CON_NOT_CONNECTED 0x80
++
++// Device location identification
++// (bIdentify)
++
++#define CSMI_SAS_LOCATE_UNKNOWN 0x00
++#define CSMI_SAS_LOCATE_FORCE_OFF 0x01
++#define CSMI_SAS_LOCATE_FORCE_ON 0x02
++
++// Location Valid flags
++// (uLocationFlags)
++
++#define CSMI_SAS_LOCATE_SAS_ADDRESS_VALID 0x00000001
++#define CSMI_SAS_LOCATE_SAS_LUN_VALID 0x00000002
++#define CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID 0x00000004
++#define CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID 0x00000008
++#define CSMI_SAS_LOCATE_BAY_PREFIX_VALID 0x00000010
++#define CSMI_SAS_LOCATE_BAY_IDENTIFIER_VALID 0x00000020
++#define CSMI_SAS_LOCATE_LOCATION_STATE_VALID 0x00000040
++
++/* * * * * * * * SAS Phy Control Class IOCTL Constants * * * * * * * * */
++
++// Return codes for SAS Phy Control IOCTL's
++// (IoctlHeader.ReturnCode)
++
++// Signature value
++// (IoctlHeader.Signature)
++
++#define CSMI_PHY_SIGNATURE "CSMIPHY"
++
++// Phy Control Functions
++// (bFunction)
++
++// values 0x00 to 0xFF are consistent in definition with the SMP PHY CONTROL
++// function defined in the SAS spec
++#define CSMI_SAS_PC_NOP 0x00000000
++#define CSMI_SAS_PC_LINK_RESET 0x00000001
++#define CSMI_SAS_PC_HARD_RESET 0x00000002
++#define CSMI_SAS_PC_PHY_DISABLE 0x00000003
++// 0x04 to 0xFF reserved...
++#define CSMI_SAS_PC_GET_PHY_SETTINGS 0x00000100
++
++// Link Flags
++#define CSMI_SAS_PHY_ACTIVATE_CONTROL 0x00000001
++#define CSMI_SAS_PHY_UPDATE_SPINUP_RATE 0x00000002
++#define CSMI_SAS_PHY_AUTO_COMWAKE 0x00000004
++
++// Device Types for Phy Settings
++// (bType)
++#define CSMI_SAS_UNDEFINED 0x00
++#define CSMI_SAS_SATA 0x01
++#define CSMI_SAS_SAS 0x02
++
++// Transmitter Flags
++// (uTransmitterFlags)
++#define CSMI_SAS_PHY_PREEMPHASIS_DISABLED 0x00000001
++
++// Receiver Flags
++// (uReceiverFlags)
++#define CSMI_SAS_PHY_EQUALIZATION_DISABLED 0x00000001
++
++// Pattern Flags
++// (uPatternFlags)
++// #define CSMI_SAS_PHY_ACTIVATE_CONTROL 0x00000001
++#define CSMI_SAS_PHY_DISABLE_SCRAMBLING 0x00000002
++#define CSMI_SAS_PHY_DISABLE_ALIGN 0x00000004
++#define CSMI_SAS_PHY_DISABLE_SSC 0x00000008
++
++#define CSMI_SAS_PHY_FIXED_PATTERN 0x00000010
++#define CSMI_SAS_PHY_USER_PATTERN 0x00000020
++
++// Fixed Patterns
++// (bFixedPattern)
++#define CSMI_SAS_PHY_CJPAT 0x00000001
++#define CSMI_SAS_PHY_ALIGN 0x00000002
++
++// Type Flags
++// (bTypeFlags)
++#define CSMI_SAS_PHY_POSITIVE_DISPARITY 0x01
++#define CSMI_SAS_PHY_NEGATIVE_DISPARITY 0x02
++#define CSMI_SAS_PHY_CONTROL_CHARACTER 0x04
++
++// Miscellaneous
++#define SLOT_NUMBER_UNKNOWN 0xFFFF
++
++/*************************************************************************/
++/* DATA STRUCTURES */
++/*************************************************************************/
++
++/* * * * * * * * * * Class Independent Structures * * * * * * * * * */
++
++// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
++#pragma pack(8)
++
++// CC_CSMI_SAS_DRIVER_INFO
++
++typedef struct _CSMI_SAS_DRIVER_INFO {
++ __u8 szName[81];
++ __u8 szDescription[81];
++ __u16 usMajorRevision;
++ __u16 usMinorRevision;
++ __u16 usBuildRevision;
++ __u16 usReleaseRevision;
++ __u16 usCSMIMajorRevision;
++ __u16 usCSMIMinorRevision;
++} CSMI_SAS_DRIVER_INFO,
++ *PCSMI_SAS_DRIVER_INFO;
++
++typedef struct _CSMI_SAS_DRIVER_INFO_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_DRIVER_INFO Information;
++} CSMI_SAS_DRIVER_INFO_BUFFER,
++ *PCSMI_SAS_DRIVER_INFO_BUFFER;
++
++// CC_CSMI_SAS_CNTLR_CONFIGURATION
++
++typedef struct _CSMI_SAS_PCI_BUS_ADDRESS {
++ __u8 bBusNumber;
++ __u8 bDeviceNumber;
++ __u8 bFunctionNumber;
++ __u8 bReserved;
++} CSMI_SAS_PCI_BUS_ADDRESS,
++ *PCSMI_SAS_PCI_BUS_ADDRESS;
++
++typedef union _CSMI_SAS_IO_BUS_ADDRESS {
++ CSMI_SAS_PCI_BUS_ADDRESS PciAddress;
++ __u8 bReserved[32];
++} CSMI_SAS_IO_BUS_ADDRESS,
++ *PCSMI_SAS_IO_BUS_ADDRESS;
++
++typedef struct _CSMI_SAS_CNTLR_CONFIG {
++ __u32 uBaseIoAddress;
++ struct {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } BaseMemoryAddress;
++ __u32 uBoardID;
++ __u16 usSlotNumber;
++ __u8 bControllerClass;
++ __u8 bIoBusType;
++ CSMI_SAS_IO_BUS_ADDRESS BusAddress;
++ __u8 szSerialNumber[81];
++ __u16 usMajorRevision;
++ __u16 usMinorRevision;
++ __u16 usBuildRevision;
++ __u16 usReleaseRevision;
++ __u16 usBIOSMajorRevision;
++ __u16 usBIOSMinorRevision;
++ __u16 usBIOSBuildRevision;
++ __u16 usBIOSReleaseRevision;
++ __u32 uControllerFlags;
++ __u16 usRromMajorRevision;
++ __u16 usRromMinorRevision;
++ __u16 usRromBuildRevision;
++ __u16 usRromReleaseRevision;
++ __u16 usRromBIOSMajorRevision;
++ __u16 usRromBIOSMinorRevision;
++ __u16 usRromBIOSBuildRevision;
++ __u16 usRromBIOSReleaseRevision;
++ __u8 bReserved[7];
++} CSMI_SAS_CNTLR_CONFIG,
++ *PCSMI_SAS_CNTLR_CONFIG;
++
++typedef struct _CSMI_SAS_CNTLR_CONFIG_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_CNTLR_CONFIG Configuration;
++} CSMI_SAS_CNTLR_CONFIG_BUFFER,
++ *PCSMI_SAS_CNTLR_CONFIG_BUFFER;
++
++// CC_CSMI_SAS_CNTLR_STATUS
++
++typedef struct _CSMI_SAS_CNTLR_STATUS {
++ __u32 uStatus;
++ __u32 uOfflineReason;
++ __u8 bReserved[28];
++} CSMI_SAS_CNTLR_STATUS,
++ *PCSMI_SAS_CNTLR_STATUS;
++
++typedef struct _CSMI_SAS_CNTLR_STATUS_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_CNTLR_STATUS Status;
++} CSMI_SAS_CNTLR_STATUS_BUFFER,
++ *PCSMI_SAS_CNTLR_STATUS_BUFFER;
++
++// CC_CSMI_SAS_FIRMWARE_DOWNLOAD
++
++typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD {
++ __u32 uBufferLength;
++ __u32 uDownloadFlags;
++ __u8 bReserved[32];
++ __u16 usStatus;
++ __u16 usSeverity;
++} CSMI_SAS_FIRMWARE_DOWNLOAD,
++ *PCSMI_SAS_FIRMWARE_DOWNLOAD;
++
++typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_FIRMWARE_DOWNLOAD Information;
++ __u8 bDataBuffer[1];
++} CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER,
++ *PCSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER;
++
++// CC_CSMI_SAS_RAID_INFO
++
++typedef struct _CSMI_SAS_RAID_INFO {
++ __u32 uNumRaidSets;
++ __u32 uMaxDrivesPerSet;
++ __u32 uMaxRaidSets;
++ __u8 bMaxRaidTypes;
++ __u8 bReservedByteFields[7];
++ struct
++ {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } ulMinRaidSetBlocks;
++ struct
++ {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } ulMaxRaidSetBlocks;
++ __u32 uMaxPhysicalDrives;
++ __u32 uMaxExtents;
++ __u32 uMaxModules;
++ __u32 uMaxTransformationMemory;
++ __u32 uChangeCount;
++ __u8 bReserved[44];
++} CSMI_SAS_RAID_INFO,
++ *PCSMI_SAS_RAID_INFO;
++
++typedef struct _CSMI_SAS_RAID_INFO_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_RAID_INFO Information;
++} CSMI_SAS_RAID_INFO_BUFFER,
++ *PCSMI_SAS_RAID_INFO_BUFFER;
++
++// CC_CSMI_SAS_GET_RAID_CONFIG
++
++typedef struct _CSMI_SAS_RAID_DRIVES {
++ __u8 bModel[40];
++ __u8 bFirmware[8];
++ __u8 bSerialNumber[40];
++ __u8 bSASAddress[8];
++ __u8 bSASLun[8];
++ __u8 bDriveStatus;
++ __u8 bDriveUsage;
++ __u16 usBlockSize;
++ __u8 bDriveType;
++ __u8 bReserved[15];
++ __u32 uDriveIndex;
++ struct
++ {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } ulTotalUserBlocks;
++} CSMI_SAS_RAID_DRIVES,
++ *PCSMI_SAS_RAID_DRIVES;
++
++typedef struct _CSMI_SAS_RAID_DEVICE_ID {
++ __u8 bDeviceIdentificationVPDPage[1];
++} CSMI_SAS_RAID_DEVICE_ID,
++ *PCSMI_SAS_RAID_DEVICE_ID;
++
++typedef struct _CSMI_SAS_RAID_SET_ADDITIONAL_DATA {
++ __u8 bLabel[16];
++ __u8 bRaidSetLun[8];
++ __u8 bWriteProtection;
++ __u8 bCacheSetting;
++ __u8 bCacheRatio;
++ __u16 usBlockSize;
++ __u8 bReservedBytes[11];
++ struct
++ {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } ulRaidSetExtentOffset;
++ struct
++ {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } ulRaidSetBlocks;
++ __u32 uStripeSizeInBlocks;
++ __u32 uSectorsPerTrack;
++ __u8 bApplicationScratchPad[16];
++ __u32 uNumberOfHeads;
++ __u32 uNumberOfTracks;
++ __u8 bReserved[24];
++} CSMI_SAS_RAID_SET_ADDITIONAL_DATA,
++ *PCSMI_SAS_RAID_SET_ADDITIONAL_DATA;
++
++typedef struct _CSMI_SAS_RAID_CONFIG {
++ __u32 uRaidSetIndex;
++ __u32 uCapacity;
++ __u32 uStripeSize;
++ __u8 bRaidType;
++ __u8 bStatus;
++ __u8 bInformation;
++ __u8 bDriveCount;
++ __u8 bDataType;
++ __u8 bReserved[11];
++ __u32 uFailureCode;
++ __u32 uChangeCount;
++ union {
++ CSMI_SAS_RAID_DRIVES Drives[1];
++ CSMI_SAS_RAID_DEVICE_ID DeviceId[1];
++ CSMI_SAS_RAID_SET_ADDITIONAL_DATA Data[1];
++ };
++} CSMI_SAS_RAID_CONFIG,
++ *PCSMI_SAS_RAID_CONFIG;
++
++typedef struct _CSMI_SAS_RAID_CONFIG_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_RAID_CONFIG Configuration;
++} CSMI_SAS_RAID_CONFIG_BUFFER,
++ *PCSMI_SAS_RAID_CONFIG_BUFFER;
++
++// CC_CSMI_SAS_GET_RAID_FEATURES
++
++typedef struct _CSMI_SAS_RAID_TYPE_DESCRIPTION {
++ __u8 bRaidType;
++ __u8 bReservedBytes[7];
++ __u32 uSupportedStripeSizeMap;
++ __u8 bReserved[24];
++} CSMI_SAS_RAID_TYPE_DESCRIPTION,
++ *PCSMI_SAS_RAID_TYPE_DESCRIPTION;
++
++typedef struct _CSMI_SAS_RAID_FEATURES {
++ __u32 uFeatures;
++ __u8 bReservedFeatures[32];
++ __u8 bDefaultTransformPriority;
++ __u8 bTransformPriority;
++ __u8 bDefaultRebuildPriority;
++ __u8 bRebuildPriority;
++ __u8 bDefaultSurfaceScanPriority;
++ __u8 bSurfaceScanPriority;
++ __u16 usReserved;
++ __u32 uRaidSetTransformationRules;
++ __u32 uReserved[11];
++ CSMI_SAS_RAID_TYPE_DESCRIPTION RaidType[24];
++ __u8 bCacheRatiosSupported[104];
++ __u32 uChangeCount;
++ __u32 uFailureCode;
++ __u8 bReserved[120];
++} CSMI_SAS_RAID_FEATURES,
++ *PCSMI_SAS_RAID_FEATURES;
++
++typedef struct _CSMI_SAS_RAID_FEATURES_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_RAID_FEATURES Information;
++} CSMI_SAS_RAID_FEATURES_BUFFER,
++ *PCSMI_SAS_RAID_FEATURES_BUFFER;
++
++// CC_CSMI_SAS_SET_RAID_CONTROL
++
++typedef struct _CSMI_SAS_RAID_CONTROL {
++ __u8 bTransformPriority;
++ __u8 bRebuildPriority;
++ __u8 bCacheRatioFlag;
++ __u8 bCacheRatio;
++ __u8 bSurfaceScanPriority;
++ __u8 bReservedBytes[15];
++ __u8 bClearConfiguration[8];
++ __u32 uChangeCount;
++ __u8 bReserved[88];
++ __u32 uFailureCode;
++ __u8 bFailureDescription[80];
++} CSMI_SAS_RAID_CONTROL,
++ *PCSMI_SAS_RAID_CONTROL;
++
++typedef struct _CSMI_SAS_RAID_CONTROL_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_RAID_CONTROL Information;
++} CSMI_SAS_RAID_CONTROL_BUFFER,
++ *PCSMI_SAS_RAID_CONTROL_BUFFER;
++
++// CC_CSMI_SAS_GET_RAID_ELEMENT
++
++typedef struct _CSMI_SAS_DRIVE_EXTENT_INFO {
++ __u32 uDriveIndex;
++ __u8 bExtentType;
++ __u8 bReservedBytes[7];
++ struct
++ {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } ulExtentOffset;
++ struct
++ {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } ulExtentBlocks;
++ __u32 uRaidSetIndex;
++ __u8 bReserved[96];
++} CSMI_SAS_DRIVE_EXTENT_INFO,
++ *PCSMI_SAS_DRIVE_EXTENT_INFO;
++
++typedef struct _CSMI_SAS_RAID_MODULE_INFO {
++ __u8 bReserved[128];
++} CSMI_SAS_RAID_MODULE_INFO,
++ *PCSMI_SAS_RAID_MODULE_INFO;
++
++typedef struct _CSMI_SAS_DRIVE_LOCATION {
++ __u8 bConnector[16];
++ __u8 bBoxName[16];
++ __u32 uBay;
++ __u8 bReservedBytes[4];
++ __u8 bAttachedSASAddress[8];
++ __u8 bAttachedPhyIdentifier;
++ __u8 bReserved[79];
++} CSMI_SAS_DRIVE_LOCATION,
++ *PCSMI_SAS_DRIVE_LOCATION;
++
++typedef struct _CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA {
++ __u8 bNegotiatedLinkRate[2];
++ __u8 bReserved[126];
++} CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA,
++ *PCSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA;
++
++typedef struct _CSMI_SAS_DRIVE_INFO {
++ CSMI_SAS_RAID_DRIVES Device;
++ CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA Data;
++ CSMI_SAS_DRIVE_LOCATION Location;
++ __u8 bReserved[16];
++} CSMI_SAS_DRIVE_INFO,
++ *PCSMI_SAS_DRIVE_INFO;
++
++typedef struct _CSMI_SAS_RAID_ELEMENT {
++ __u32 uEnumerationType;
++ __u32 uElementIndex;
++ __u32 uNumElements;
++ __u32 uChangeCount;
++ __u32 uSubElementIndex;
++ __u8 bReserved[32];
++ __u32 uFailureCode;
++ __u8 bFailureDescription[80];
++ union {
++ CSMI_SAS_DRIVE_INFO Drive;
++ CSMI_SAS_RAID_MODULE_INFO Module;
++ CSMI_SAS_DRIVE_EXTENT_INFO Extent;
++ } Element;
++} CSMI_SAS_RAID_ELEMENT,
++ *PCSMI_SAS_RAID_ELEMENT;
++
++typedef struct _CSMI_SAS_RAID_ELEMENT_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_RAID_ELEMENT Information;
++} CSMI_SAS_RAID_ELEMENT_BUFFER,
++ *PCSMI_SAS_RAID_ELEMENT_BUFFER;
++
++// CC_CSMI_SAS_SET_RAID_OPERATION
++
++typedef struct _CSMI_SAS_RAID_SET_LIST {
++ __u32 uRaidSetIndex;
++ __u8 bExistingLun[8];
++ __u8 bNewLun[8];
++ __u8 bReserved[12];
++} CSMI_SAS_RAID_SET_LIST,
++ *PCSMI_SAS_RAID_SET_LIST;
++
++typedef struct _CSMI_SAS_RAID_SET_DRIVE_LIST {
++ __u32 uDriveIndex;
++ __u8 bDriveUsage;
++ __u8 bReserved[27];
++} CSMI_SAS_RAID_SET_DRIVE_LIST,
++ *PCSMI_SAS_RAID_SET_DRIVE_LIST;
++
++typedef struct _CSMI_SAS_RAID_SET_SPARE_INFO {
++ __u32 uRaidSetIndex;
++ __u32 uDriveCount;
++ __u8 bApplicationScratchPad[16];
++ __u8 bReserved[104];
++} CSMI_SAS_RAID_SET_SPARE_INFO,
++ *PCSMI_SAS_RAID_SET_SPARE_INFO;
++
++typedef struct _CSMI_SAS_RAID_SET_ONLINE_STATE_INFO {
++ __u32 uRaidSetIndex;
++ __u8 bOnlineState;
++ __u8 bReserved[123];
++} CSMI_SAS_RAID_SET_ONLINE_STATE_INFO,
++ *PCSMI_SAS_RAID_SET_ONLINE_STATE_INFO;
++
++typedef struct _CSMI_SAS_RAID_SET_CACHE_INFO {
++ __u32 uRaidSetIndex;
++ __u8 bCacheSetting;
++ __u8 bCacheRatioFlag;
++ __u8 bCacheRatio;
++ __u8 bReserved[121];
++} CSMI_SAS_RAID_SET_CACHE_INFO,
++ *PCSMI_SAS_RAID_SET_CACHE_INFO;
++
++typedef struct _CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO {
++ __u32 uRaidSetIndex;
++ __u8 bWriteProtectSetting;
++ __u8 bReserved[123];
++} CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO,
++ *PCSMI_SAS_RAID_SET_WRITE_PROTECT_INFO;
++
++typedef struct _CSMI_SAS_RAID_SET_DELETE_INFO {
++ __u32 uRaidSetIndex;
++ __u8 bReserved[124];
++} CSMI_SAS_RAID_SET_DELETE_INFO,
++ *PCSMI_SAS_RAID_SET_DELETE_INFO;
++
++typedef struct _CSMI_SAS_RAID_SET_MODIFY_INFO {
++ __u8 bRaidType;
++ __u8 bReservedBytes[7];
++ __u32 uStripeSize;
++ struct
++ {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } ulRaidSetBlocks;
++ struct
++ {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } ulRaidSetExtentOffset;
++ __u32 uDriveCount;
++ __u8 bReserved[96];
++} CSMI_SAS_RAID_SET_MODIFY_INFO,
++ *PCSMI_SAS_RAID_SET_MODIFY_INFO;
++
++typedef struct _CSMI_SAS_RAID_SET_TRANSFORM_INFO {
++ __u8 bTransformType;
++ __u8 bReservedBytes[3];
++ __u32 uRaidSetIndex;
++ __u8 bRaidType;
++ __u8 bReservedBytes2[11];
++ __u32 uAdditionalRaidSetIndex;
++ __u32 uRaidSetCount;
++ __u8 bApplicationScratchPad[16];
++ CSMI_SAS_RAID_SET_MODIFY_INFO Modify;
++ __u8 bReserved[80];
++} CSMI_SAS_RAID_SET_TRANSFORM_INFO,
++ *PCSMI_SAS_RAID_SET_TRANSFORM_INFO;
++
++typedef struct _CSMI_SAS_RAID_SET_LABEL_INFO {
++ __u32 uRaidSetIndex;
++ __u8 bLabel[16];
++ __u8 bReserved[108];
++} CSMI_SAS_RAID_SET_LABEL_INFO,
++ *PCSMI_SAS_RAID_SET_LABEL_INFO;
++
++typedef struct _CSMI_SAS_RAID_SET_CREATE_INFO {
++ __u8 bRaidType;
++ __u8 bReservedBytes[7];
++ __u32 uStripeSize;
++ __u32 uTrackSectorCount;
++ struct
++ {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } ulRaidSetBlocks;
++ struct
++ {
++ __u32 uLowPart;
++ __u32 uHighPart;
++ } ulRaidSetExtentOffset;
++ __u32 uDriveCount;
++ __u8 bLabel[16];
++ __u32 uRaidSetIndex;
++ __u8 bApplicationScratchPad[16];
++ __u32 uNumberOfHeads;
++ __u32 uNumberOfTracks;
++ __u8 bReserved[48];
++} CSMI_SAS_RAID_SET_CREATE_INFO,
++ *PCSMI_SAS_RAID_SET_CREATE_INFO;
++
++typedef struct _CSMI_SAS_RAID_SET_OPERATION {
++ __u32 uOperationType;
++ __u32 uChangeCount;
++ __u32 uFailureCode;
++ __u8 bFailureDescription[80];
++ __u8 bReserved[28];
++ union {
++ CSMI_SAS_RAID_SET_CREATE_INFO Create;
++ CSMI_SAS_RAID_SET_LABEL_INFO Label;
++ CSMI_SAS_RAID_SET_TRANSFORM_INFO Transform;
++ CSMI_SAS_RAID_SET_DELETE_INFO Delete;
++ CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO Protect;
++ CSMI_SAS_RAID_SET_CACHE_INFO Cache;
++ CSMI_SAS_RAID_SET_ONLINE_STATE_INFO State;
++ CSMI_SAS_RAID_SET_SPARE_INFO Spare;
++ } Operation;
++ union {
++ CSMI_SAS_RAID_SET_DRIVE_LIST DriveList[1];
++ CSMI_SAS_RAID_SET_LIST RaidSetList[1];
++ } Parameters;
++} CSMI_SAS_RAID_SET_OPERATION,
++ *PCSMI_SAS_RAID_SET_OPERATION;
++
++typedef struct _CSMI_SAS_RAID_SET_OPERATION_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_RAID_SET_OPERATION Information;
++} CSMI_SAS_RAID_SET_OPERATION_BUFFER,
++ *PCSMI_SAS_RAID_SET_OPERATION_BUFFER;
++
++/* * * * * * * * * * SAS HBA Class Structures * * * * * * * * * */
++
++// CC_CSMI_SAS_GET_PHY_INFO
++
++typedef struct _CSMI_SAS_IDENTIFY {
++ __u8 bDeviceType;
++ __u8 bRestricted;
++ __u8 bInitiatorPortProtocol;
++ __u8 bTargetPortProtocol;
++ __u8 bRestricted2[8];
++ __u8 bSASAddress[8];
++ __u8 bPhyIdentifier;
++ __u8 bSignalClass;
++ __u8 bReserved[6];
++} CSMI_SAS_IDENTIFY,
++ *PCSMI_SAS_IDENTIFY;
++
++typedef struct _CSMI_SAS_PHY_ENTITY {
++ CSMI_SAS_IDENTIFY Identify;
++ __u8 bPortIdentifier;
++ __u8 bNegotiatedLinkRate;
++ __u8 bMinimumLinkRate;
++ __u8 bMaximumLinkRate;
++ __u8 bPhyChangeCount;
++ __u8 bAutoDiscover;
++ __u8 bPhyFeatures;
++ __u8 bReserved;
++ CSMI_SAS_IDENTIFY Attached;
++} CSMI_SAS_PHY_ENTITY,
++ *PCSMI_SAS_PHY_ENTITY;
++
++typedef struct _CSMI_SAS_PHY_INFO {
++ __u8 bNumberOfPhys;
++ __u8 bReserved[3];
++ CSMI_SAS_PHY_ENTITY Phy[32];
++} CSMI_SAS_PHY_INFO,
++ *PCSMI_SAS_PHY_INFO;
++
++typedef struct _CSMI_SAS_PHY_INFO_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_PHY_INFO Information;
++} CSMI_SAS_PHY_INFO_BUFFER,
++ *PCSMI_SAS_PHY_INFO_BUFFER;
++
++// CC_CSMI_SAS_SET_PHY_INFO
++
++typedef struct _CSMI_SAS_SET_PHY_INFO {
++ __u8 bPhyIdentifier;
++ __u8 bNegotiatedLinkRate;
++ __u8 bProgrammedMinimumLinkRate;
++ __u8 bProgrammedMaximumLinkRate;
++ __u8 bSignalClass;
++ __u8 bReserved[3];
++} CSMI_SAS_SET_PHY_INFO,
++ *PCSMI_SAS_SET_PHY_INFO;
++
++typedef struct _CSMI_SAS_SET_PHY_INFO_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_SET_PHY_INFO Information;
++} CSMI_SAS_SET_PHY_INFO_BUFFER,
++ *PCSMI_SAS_SET_PHY_INFO_BUFFER;
++
++// CC_CSMI_SAS_GET_LINK_ERRORS
++
++typedef struct _CSMI_SAS_LINK_ERRORS {
++ __u8 bPhyIdentifier;
++ __u8 bResetCounts;
++ __u8 bReserved[2];
++ __u32 uInvalidDwordCount;
++ __u32 uRunningDisparityErrorCount;
++ __u32 uLossOfDwordSyncCount;
++ __u32 uPhyResetProblemCount;
++} CSMI_SAS_LINK_ERRORS,
++ *PCSMI_SAS_LINK_ERRORS;
++
++typedef struct _CSMI_SAS_LINK_ERRORS_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_LINK_ERRORS Information;
++} CSMI_SAS_LINK_ERRORS_BUFFER,
++ *PCSMI_SAS_LINK_ERRORS_BUFFER;
++
++// CC_CSMI_SAS_SMP_PASSTHRU
++
++typedef struct _CSMI_SAS_SMP_REQUEST {
++ __u8 bFrameType;
++ __u8 bFunction;
++ __u8 bReserved[2];
++ __u8 bAdditionalRequestBytes[1016];
++} CSMI_SAS_SMP_REQUEST,
++ *PCSMI_SAS_SMP_REQUEST;
++
++typedef struct _CSMI_SAS_SMP_RESPONSE {
++ __u8 bFrameType;
++ __u8 bFunction;
++ __u8 bFunctionResult;
++ __u8 bReserved;
++ __u8 bAdditionalResponseBytes[1016];
++} CSMI_SAS_SMP_RESPONSE,
++ *PCSMI_SAS_SMP_RESPONSE;
++
++typedef struct _CSMI_SAS_SMP_PASSTHRU {
++ __u8 bPhyIdentifier;
++ __u8 bPortIdentifier;
++ __u8 bConnectionRate;
++ __u8 bReserved;
++ __u8 bDestinationSASAddress[8];
++ __u32 uRequestLength;
++ CSMI_SAS_SMP_REQUEST Request;
++ __u8 bConnectionStatus;
++ __u8 bReserved2[3];
++ __u32 uResponseBytes;
++ CSMI_SAS_SMP_RESPONSE Response;
++} CSMI_SAS_SMP_PASSTHRU,
++ *PCSMI_SAS_SMP_PASSTHRU;
++
++typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_SMP_PASSTHRU Parameters;
++} CSMI_SAS_SMP_PASSTHRU_BUFFER,
++ *PCSMI_SAS_SMP_PASSTHRU_BUFFER;
++
++// CC_CSMI_SAS_SSP_PASSTHRU
++
++typedef struct _CSMI_SAS_SSP_PASSTHRU {
++ __u8 bPhyIdentifier;
++ __u8 bPortIdentifier;
++ __u8 bConnectionRate;
++ __u8 bReserved;
++ __u8 bDestinationSASAddress[8];
++ __u8 bLun[8];
++ __u8 bCDBLength;
++ __u8 bAdditionalCDBLength;
++ __u8 bReserved2[2];
++ __u8 bCDB[16];
++ __u32 uFlags;
++ __u8 bAdditionalCDB[24];
++ __u32 uDataLength;
++} CSMI_SAS_SSP_PASSTHRU,
++ *PCSMI_SAS_SSP_PASSTHRU;
++
++typedef struct _CSMI_SAS_SSP_PASSTHRU_STATUS {
++ __u8 bConnectionStatus;
++ __u8 bSSPStatus;
++ __u8 bReserved[2];
++ __u8 bDataPresent;
++ __u8 bStatus;
++ __u8 bResponseLength[2];
++ __u8 bResponse[256];
++ __u32 uDataBytes;
++} CSMI_SAS_SSP_PASSTHRU_STATUS,
++ *PCSMI_SAS_SSP_PASSTHRU_STATUS;
++
++typedef struct _CSMI_SAS_SSP_PASSTHRU_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_SSP_PASSTHRU Parameters;
++ CSMI_SAS_SSP_PASSTHRU_STATUS Status;
++ __u8 bDataBuffer[1];
++} CSMI_SAS_SSP_PASSTHRU_BUFFER,
++ *PCSMI_SAS_SSP_PASSTHRU_BUFFER;
++
++// CC_CSMI_SAS_STP_PASSTHRU
++
++typedef struct _CSMI_SAS_STP_PASSTHRU {
++ __u8 bPhyIdentifier;
++ __u8 bPortIdentifier;
++ __u8 bConnectionRate;
++ __u8 bReserved;
++ __u8 bDestinationSASAddress[8];
++ __u8 bReserved2[4];
++ __u8 bCommandFIS[20];
++ __u32 uFlags;
++ __u32 uDataLength;
++} CSMI_SAS_STP_PASSTHRU,
++ *PCSMI_SAS_STP_PASSTHRU;
++
++typedef struct _CSMI_SAS_STP_PASSTHRU_STATUS {
++ __u8 bConnectionStatus;
++ __u8 bReserved[3];
++ __u8 bStatusFIS[20];
++ __u32 uSCR[16];
++ __u32 uDataBytes;
++} CSMI_SAS_STP_PASSTHRU_STATUS,
++ *PCSMI_SAS_STP_PASSTHRU_STATUS;
++
++typedef struct _CSMI_SAS_STP_PASSTHRU_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_STP_PASSTHRU Parameters;
++ CSMI_SAS_STP_PASSTHRU_STATUS Status;
++ __u8 bDataBuffer[1];
++} CSMI_SAS_STP_PASSTHRU_BUFFER,
++ *PCSMI_SAS_STP_PASSTHRU_BUFFER;
++
++// CC_CSMI_SAS_GET_SATA_SIGNATURE
++
++typedef struct _CSMI_SAS_SATA_SIGNATURE {
++ __u8 bPhyIdentifier;
++ __u8 bReserved[3];
++ __u8 bSignatureFIS[20];
++} CSMI_SAS_SATA_SIGNATURE,
++ *PCSMI_SAS_SATA_SIGNATURE;
++
++typedef struct _CSMI_SAS_SATA_SIGNATURE_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_SATA_SIGNATURE Signature;
++} CSMI_SAS_SATA_SIGNATURE_BUFFER,
++ *PCSMI_SAS_SATA_SIGNATURE_BUFFER;
++
++// CC_CSMI_SAS_GET_SCSI_ADDRESS
++
++typedef struct _CSMI_SAS_GET_SCSI_ADDRESS_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ __u8 bSASAddress[8];
++ __u8 bSASLun[8];
++ __u8 bHostIndex;
++ __u8 bPathId;
++ __u8 bTargetId;
++ __u8 bLun;
++} CSMI_SAS_GET_SCSI_ADDRESS_BUFFER,
++ *PCSMI_SAS_GET_SCSI_ADDRESS_BUFFER;
++
++// CC_CSMI_SAS_GET_DEVICE_ADDRESS
++
++typedef struct _CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ __u8 bHostIndex;
++ __u8 bPathId;
++ __u8 bTargetId;
++ __u8 bLun;
++ __u8 bSASAddress[8];
++ __u8 bSASLun[8];
++} CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER,
++ *PCSMI_SAS_GET_DEVICE_ADDRESS_BUFFER;
++
++// CC_CSMI_SAS_TASK_MANAGEMENT
++
++typedef struct _CSMI_SAS_SSP_TASK_IU {
++ __u8 bHostIndex;
++ __u8 bPathId;
++ __u8 bTargetId;
++ __u8 bLun;
++ __u32 uFlags;
++ __u32 uQueueTag;
++ __u32 uReserved;
++ __u8 bTaskManagementFunction;
++ __u8 bReserved[7];
++ __u32 uInformation;
++} CSMI_SAS_SSP_TASK_IU,
++ *PCSMI_SAS_SSP_TASK_IU;
++
++typedef struct _CSMI_SAS_SSP_TASK_IU_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_SSP_TASK_IU Parameters;
++ CSMI_SAS_SSP_PASSTHRU_STATUS Status;
++} CSMI_SAS_SSP_TASK_IU_BUFFER,
++ *PCSMI_SAS_SSP_TASK_IU_BUFFER;
++
++// CC_CSMI_SAS_GET_CONNECTOR_INFO
++
++typedef struct _CSMI_SAS_GET_CONNECTOR_INFO {
++ __u32 uPinout;
++ __u8 bConnector[16];
++ __u8 bLocation;
++ __u8 bReserved[15];
++} CSMI_SAS_CONNECTOR_INFO,
++ *PCSMI_SAS_CONNECTOR_INFO;
++
++typedef struct _CSMI_SAS_CONNECTOR_INFO_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ CSMI_SAS_CONNECTOR_INFO Reference[32];
++} CSMI_SAS_CONNECTOR_INFO_BUFFER,
++ *PCSMI_SAS_CONNECTOR_INFO_BUFFER;
++
++// CC_CSMI_SAS_GET_LOCATION
++
++typedef struct _CSMI_SAS_LOCATION_IDENTIFIER {
++ __u32 bLocationFlags;
++ __u8 bSASAddress[8];
++ __u8 bSASLun[8];
++ __u8 bEnclosureIdentifier[8];
++ __u8 bEnclosureName[32];
++ __u8 bBayPrefix[32];
++ __u8 bBayIdentifier;
++ __u8 bLocationState;
++ __u8 bReserved[2];
++} CSMI_SAS_LOCATION_IDENTIFIER,
++ *PCSMI_SAS_LOCATION_IDENTIFIER;
++
++typedef struct _CSMI_SAS_GET_LOCATION_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ __u8 bHostIndex;
++ __u8 bPathId;
++ __u8 bTargetId;
++ __u8 bLun;
++ __u8 bIdentify;
++ __u8 bNumberOfLocationIdentifiers;
++ __u8 bLengthOfLocationIdentifier;
++ CSMI_SAS_LOCATION_IDENTIFIER Location[1];
++} CSMI_SAS_GET_LOCATION_BUFFER,
++ *PCSMI_SAS_GET_LOCATION_BUFFER;
++
++// CC_CSMI_SAS_PHY_CONTROL
++
++typedef struct _CSMI_SAS_CHARACTER {
++ __u8 bTypeFlags;
++ __u8 bValue;
++} CSMI_SAS_CHARACTER,
++ *PCSMI_SAS_CHARACTER;
++
++typedef struct _CSMI_SAS_PHY_CONTROL {
++ __u8 bType;
++ __u8 bRate;
++ __u8 bReserved[6];
++ __u32 uVendorUnique[8];
++ __u32 uTransmitterFlags;
++ __i8 bTransmitAmplitude;
++ __i8 bTransmitterPreemphasis;
++ __i8 bTransmitterSlewRate;
++ __i8 bTransmitterReserved[13];
++ __u8 bTransmitterVendorUnique[64];
++ __u32 uReceiverFlags;
++ __i8 bReceiverThreshold;
++ __i8 bReceiverEqualizationGain;
++ __i8 bReceiverReserved[14];
++ __u8 bReceiverVendorUnique[64];
++ __u32 uPatternFlags;
++ __u8 bFixedPattern;
++ __u8 bUserPatternLength;
++ __u8 bPatternReserved[6];
++ CSMI_SAS_CHARACTER UserPatternBuffer[16];
++} CSMI_SAS_PHY_CONTROL,
++ *PCSMI_SAS_PHY_CONTROL;
++
++typedef struct _CSMI_SAS_PHY_CONTROL_BUFFER {
++ IOCTL_HEADER IoctlHeader;
++ __u32 uFunction;
++ __u8 bPhyIdentifier;
++ __u16 usLengthOfControl;
++ __u8 bNumberOfControls;
++ __u8 bReserved[4];
++ __u32 uLinkFlags;
++ __u8 bSpinupRate;
++ __u8 bLinkReserved[7];
++ __u32 uVendorUnique[8];
++ CSMI_SAS_PHY_CONTROL Control[1];
++} CSMI_SAS_PHY_CONTROL_BUFFER,
++ *PCSMI_SAS_PHY_CONTROL_BUFFER;
++
++//EDM #pragma CSMI_SAS_END_PACK
++#pragma pack()
++
++#endif // _CSMI_SAS_H_
+--- a/drivers/message/fusion/Kconfig
++++ b/drivers/message/fusion/Kconfig
+@@ -61,13 +61,25 @@ config FUSION_SAS
+ LSISAS1078
+
+ config FUSION_MAX_SGE
+- int "Maximum number of scatter gather entries (16 - 128)"
++ int "Maximum number of scatter gather entries for SAS and SPI (16 - 128)"
+ default "128"
+ range 16 128
+ help
+ This option allows you to specify the maximum number of scatter-
+ gather entries per I/O. The driver default is 128, which matches
+- SCSI_MAX_PHYS_SEGMENTS. However, it may decreased down to 16.
++ SAFE_PHYS_SEGMENTS. However, it may decreased down to 16.
++ Decreasing this parameter will reduce memory requirements
++ on a per controller instance.
++
++config FUSION_MAX_FC_SGE
++ int "Maximum number of scatter gather entries for FC (16 - 256)"
++ depends on FUSION_FC
++ default "256"
++ range 16 256
++ help
++ This option allows you to specify the maximum number of scatter-
++ gather entries per I/O. The driver default is 256, which matches
++ MAX_PHYS_SEGMENTS. However, it may decreased down to 16.
+ Decreasing this parameter will reduce memory requirements
+ on a per controller instance.
+
+--- a/drivers/message/fusion/lsi/mpi_cnfg.h
++++ b/drivers/message/fusion/lsi/mpi_cnfg.h
+@@ -6,7 +6,7 @@
+ * Title: MPI Config message, structures, and Pages
+ * Creation Date: July 27, 2000
+ *
+- * mpi_cnfg.h Version: 01.05.15
++ * mpi_cnfg.h Version: 01.05.18
+ *
+ * Version History
+ * ---------------
+@@ -308,6 +308,20 @@
+ * Expander Page 0 Flags field.
+ * Fixed define for
+ * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED.
++ * 08-07-07 01.05.16 Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT
++ * define.
++ * Added BIOS Page 4 structure.
++ * Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID
++ * Physcial Disk Page 1.
++ * 01-15-07 01.05.17 Added additional bit defines for ExtFlags field of
++ * Manufacturing Page 4.
++ * Added Solid State Drives Supported bit to IOC Page 6
++ * Capabilities Flags.
++ * Added new value for AccessStatus field of SAS Device
++ * Page 0 (_SATA_NEEDS_INITIALIZATION).
++ * 03-28-08 01.05.18 Defined new bits in Manufacturing Page 4 ExtFlags field
++ * to control coercion size and the mixing of SAS and SATA
++ * SSD drives.
+ * --------------------------------------------------------------------------
+ */
+
+@@ -686,6 +700,14 @@ typedef struct _CONFIG_PAGE_MANUFACTURIN
+ #define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01)
+
+ /* defines for the ExtFlags field */
++#define MPI_MANPAGE4_EXTFLAGS_MASK_COERCION_SIZE (0x0180)
++#define MPI_MANPAGE4_EXTFLAGS_SHIFT_COERCION_SIZE (7)
++#define MPI_MANPAGE4_EXTFLAGS_1GB_COERCION_SIZE (0)
++#define MPI_MANPAGE4_EXTFLAGS_128MB_COERCION_SIZE (1)
++
++#define MPI_MANPAGE4_EXTFLAGS_NO_MIX_SSD_SAS_SATA (0x0040)
++#define MPI_MANPAGE4_EXTFLAGS_MIX_SSD_AND_NON_SSD (0x0020)
++#define MPI_MANPAGE4_EXTFLAGS_DUAL_PORT_SUPPORT (0x0010)
+ #define MPI_MANPAGE4_EXTFLAGS_HIDE_NON_IR_METADATA (0x0008)
+ #define MPI_MANPAGE4_EXTFLAGS_SAS_CACHE_DISABLE (0x0004)
+ #define MPI_MANPAGE4_EXTFLAGS_SATA_CACHE_DISABLE (0x0002)
+@@ -1159,6 +1181,8 @@ typedef struct _CONFIG_PAGE_IOC_6
+
+ /* IOC Page 6 Capabilities Flags */
+
++#define MPI_IOCPAGE6_CAP_FLAGS_SSD_SUPPORT (0x00000020)
++#define MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT (0x00000010)
+ #define MPI_IOCPAGE6_CAP_FLAGS_DISABLE_SMART_POLLING (0x00000008)
+
+ #define MPI_IOCPAGE6_CAP_FLAGS_MASK_METADATA_SIZE (0x00000006)
+@@ -1428,6 +1452,15 @@ typedef struct _CONFIG_PAGE_BIOS_2
+ #define MPI_BIOSPAGE2_FORM_SAS_WWN (0x05)
+ #define MPI_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06)
+
++typedef struct _CONFIG_PAGE_BIOS_4
++{
++ CONFIG_PAGE_HEADER Header; /* 00h */
++ U64 ReassignmentBaseWWID; /* 04h */
++} CONFIG_PAGE_BIOS_4, MPI_POINTER PTR_CONFIG_PAGE_BIOS_4,
++ BIOSPage4_t, MPI_POINTER pBIOSPage4_t;
++
++#define MPI_BIOSPAGE4_PAGEVERSION (0x00)
++
+
+ /****************************************************************************
+ * SCSI Port Config Pages
+@@ -2419,6 +2452,15 @@ typedef struct _RAID_PHYS_DISK1_PATH
+ #define MPI_RAID_PHYSDISK1_FLAG_BROKEN (0x0002)
+ #define MPI_RAID_PHYSDISK1_FLAG_INVALID (0x0001)
+
++
++/*
++ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
++ * one and check Header.PageLength or NumPhysDiskPaths at runtime.
++ */
++#ifndef MPI_RAID_PHYS_DISK1_PATH_MAX
++#define MPI_RAID_PHYS_DISK1_PATH_MAX (1)
++#endif
++
+ typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_1
+ {
+ CONFIG_PAGE_HEADER Header; /* 00h */
+@@ -2426,7 +2468,7 @@ typedef struct _CONFIG_PAGE_RAID_PHYS_DI
+ U8 PhysDiskNum; /* 05h */
+ U16 Reserved2; /* 06h */
+ U32 Reserved1; /* 08h */
+- RAID_PHYS_DISK1_PATH Path[1]; /* 0Ch */
++ RAID_PHYS_DISK1_PATH Path[MPI_RAID_PHYS_DISK1_PATH_MAX];/* 0Ch */
+ } CONFIG_PAGE_RAID_PHYS_DISK_1, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_1,
+ RaidPhysDiskPage1_t, MPI_POINTER pRaidPhysDiskPage1_t;
+
+@@ -2844,6 +2886,7 @@ typedef struct _CONFIG_PAGE_SAS_DEVICE_0
+ #define MPI_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01)
+ #define MPI_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02)
+ #define MPI_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03)
++#define MPI_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04)
+ /* specific values for SATA Init failures */
+ #define MPI_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10)
+ #define MPI_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11)
+--- a/drivers/message/fusion/lsi/mpi_fc.h
++++ b/drivers/message/fusion/lsi/mpi_fc.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2000-2004 LSI Corporation.
++ * Copyright (c) 2000-2008 LSI Corporation.
+ *
+ *
+ * Name: mpi_fc.h
+--- a/drivers/message/fusion/lsi/mpi.h
++++ b/drivers/message/fusion/lsi/mpi.h
+@@ -6,7 +6,7 @@
+ * Title: MPI Message independent structures and definitions
+ * Creation Date: July 27, 2000
+ *
+- * mpi.h Version: 01.05.13
++ * mpi.h Version: 01.05.16
+ *
+ * Version History
+ * ---------------
+@@ -79,6 +79,9 @@
+ * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
+ * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT.
+ * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT.
++ * 08-07-07 01.05.14 Bumped MPI_HEADER_VERSION_UNIT.
++ * 01-15-08 01.05.15 Bumped MPI_HEADER_VERSION_UNIT.
++ * 03-28-08 01.05.16 Bumped MPI_HEADER_VERSION_UNIT.
+ * --------------------------------------------------------------------------
+ */
+
+@@ -109,7 +112,7 @@
+ /* Note: The major versions of 0xe0 through 0xff are reserved */
+
+ /* versioning for this MPI header set */
+-#define MPI_HEADER_VERSION_UNIT (0x10)
++#define MPI_HEADER_VERSION_UNIT (0x13)
+ #define MPI_HEADER_VERSION_DEV (0x00)
+ #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00)
+ #define MPI_HEADER_VERSION_UNIT_SHIFT (8)
+--- a/drivers/message/fusion/lsi/mpi_history.txt
++++ b/drivers/message/fusion/lsi/mpi_history.txt
+@@ -3,28 +3,28 @@
+ MPI Header File Change History
+ ==============================
+
+- Copyright (c) 2000-2007 LSI Corporation.
++ Copyright (c) 2000-2008 LSI Corporation.
+
+ ---------------------------------------
+- Header Set Release Version: 01.05.16
+- Header Set Release Date: 05-24-07
++ Header Set Release Version: 01.05.19
++ Header Set Release Date: 03-28-08
+ ---------------------------------------
+
+ Filename Current version Prior version
+ ---------- --------------- -------------
+- mpi.h 01.05.13 01.05.12
+- mpi_ioc.h 01.05.14 01.05.13
+- mpi_cnfg.h 01.05.15 01.05.14
++ mpi.h 01.05.16 01.05.15
++ mpi_ioc.h 01.05.16 01.05.15
++ mpi_cnfg.h 01.05.18 01.05.17
+ mpi_init.h 01.05.09 01.05.09
+ mpi_targ.h 01.05.06 01.05.06
+ mpi_fc.h 01.05.01 01.05.01
+ mpi_lan.h 01.05.01 01.05.01
+- mpi_raid.h 01.05.03 01.05.03
++ mpi_raid.h 01.05.05 01.05.05
+ mpi_tool.h 01.05.03 01.05.03
+ mpi_inb.h 01.05.01 01.05.01
+- mpi_sas.h 01.05.04 01.05.04
++ mpi_sas.h 01.05.05 01.05.05
+ mpi_type.h 01.05.02 01.05.02
+- mpi_history.txt 01.05.14 01.05.14
++ mpi_history.txt 01.05.19 01.05.18
+
+
+ * Date Version Description
+@@ -96,6 +96,9 @@ mpi.h
+ * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
+ * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT.
+ * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT.
++ * 08-07-07 01.05.14 Bumped MPI_HEADER_VERSION_UNIT.
++ * 01-15-08 01.05.15 Bumped MPI_HEADER_VERSION_UNIT.
++ * 03-28-08 01.05.16 Bumped MPI_HEADER_VERSION_UNIT.
+ * --------------------------------------------------------------------------
+
+ mpi_ioc.h
+@@ -127,7 +130,7 @@ mpi_ioc.h
+ * 08-08-01 01.02.01 Original release for v1.2 work.
+ * New format for FWVersion and ProductId in
+ * MSG_IOC_FACTS_REPLY and MPI_FW_HEADER.
+- * 08-31-01 01.02.02 Added event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and
++ * 08-31-01 01.02.02 Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and
+ * related structure and defines.
+ * Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED.
+ * Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE.
+@@ -187,7 +190,7 @@ mpi_ioc.h
+ * 10-11-06 01.05.12 Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED.
+ * Added MaxInitiators field to PortFacts reply.
+ * Added SAS Device Status Change ReasonCode for
+- * asynchronous notification.
++ * asynchronous notificaiton.
+ * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event
+ * data structure.
+ * Added new ImageType values for FWDownload and FWUpload
+@@ -199,6 +202,16 @@ mpi_ioc.h
+ * added _MULTI_PORT_DOMAIN.
+ * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request.
+ * Added Common Boot Block type to FWUpload Request.
++ * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define.
++ * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and
++ * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data.
++ * Added SASAddress field to SAS Initiator Device Table
++ * Overflow event data structure.
++ * 03-28-08 01.05.16 Added two new ReasonCode values to SAS Device Status
++ * Change Event data to indicate completion of internally
++ * generated task management.
++ * Added MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE define.
++ * Added MPI_EVENT_SAS_INIT_RC_INACCESSIBLE define.
+ * --------------------------------------------------------------------------
+
+ mpi_cnfg.h
+@@ -213,7 +226,7 @@ mpi_cnfg.h
+ * Added _RESPONSE_ID_MASK definition to SCSI_PORT_1
+ * page and updated the page version.
+ * Added Information field and _INFO_PARAMS_NEGOTIATED
+- * definition to SCSI_DEVICE_0 page.
++ * definitionto SCSI_DEVICE_0 page.
+ * 06-22-00 01.00.03 Removed batch controls from LAN_0 page and updated the
+ * page version.
+ * Added BucketsRemaining to LAN_1 page, redefined the
+@@ -496,6 +509,20 @@ mpi_cnfg.h
+ * Expander Page 0 Flags field.
+ * Fixed define for
+ * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED.
++ * 08-07-07 01.05.16 Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT
++ * define.
++ * Added BIOS Page 4 structure.
++ * Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID
++ * Physcial Disk Page 1.
++ * 01-15-07 01.05.17 Added additional bit defines for ExtFlags field of
++ * Manufacturing Page 4.
++ * Added Solid State Drives Supported bit to IOC Page 6
++ * Capabilities Flags.
++ * Added new value for AccessStatus field of SAS Device
++ * Page 0 (_SATA_NEEDS_INITIALIZATION).
++ * 03-28-08 01.05.18 Defined new bits in Manufacturing Page 4 ExtFlags field
++ * to control coercion size and the mixing of SAS and SATA
++ * SSD drives.
+ * --------------------------------------------------------------------------
+
+ mpi_init.h
+@@ -661,6 +688,9 @@ mpi_raid.h
+ * _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
+ * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and
+ * associated defines.
++ * 08-07-07 01.05.04 Added Disable Full Rebuild bit to the ActionDataWord
++ * for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME.
++ * 01-15-08 01.05.05 Added define for MPI_RAID_ACTION_SET_VOLUME_NAME.
+ * --------------------------------------------------------------------------
+
+ mpi_tool.h
+@@ -694,6 +724,10 @@ mpi_sas.h
+ * reply.
+ * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO
+ * Unit Control request.
++ * 01-15-08 01.05.05 Added support for MPI_SAS_OP_SET_IOC_PARAMETER,
++ * including adding IOCParameter and IOCParameter value
++ * fields to SAS IO Unit Control Request.
++ * Added MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC define.
+ * --------------------------------------------------------------------------
+
+ mpi_type.h
+@@ -709,20 +743,20 @@ mpi_type.h
+
+ mpi_history.txt Parts list history
+
+-Filename 01.05.15 01.05.15
+----------- -------- --------
+-mpi.h 01.05.12 01.05.13
+-mpi_ioc.h 01.05.13 01.05.14
+-mpi_cnfg.h 01.05.14 01.05.15
+-mpi_init.h 01.05.09 01.05.09
+-mpi_targ.h 01.05.06 01.05.06
+-mpi_fc.h 01.05.01 01.05.01
+-mpi_lan.h 01.05.01 01.05.01
+-mpi_raid.h 01.05.03 01.05.03
+-mpi_tool.h 01.05.03 01.05.03
+-mpi_inb.h 01.05.01 01.05.01
+-mpi_sas.h 01.05.04 01.05.04
+-mpi_type.h 01.05.02 01.05.02
++Filename 01.05.19 01.05.18 01.05.17 01.05.16 01.05.15
++---------- -------- -------- -------- -------- --------
++mpi.h 01.05.16 01.05.15 01.05.14 01.05.13 01.05.12
++mpi_ioc.h 01.05.16 01.05.15 01.05.15 01.05.14 01.05.13
++mpi_cnfg.h 01.05.18 01.05.17 01.05.16 01.05.15 01.05.14
++mpi_init.h 01.05.09 01.05.09 01.05.09 01.05.09 01.05.09
++mpi_targ.h 01.05.06 01.05.06 01.05.06 01.05.06 01.05.06
++mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
++mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
++mpi_raid.h 01.05.05 01.05.05 01.05.04 01.05.03 01.05.03
++mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03
++mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
++mpi_sas.h 01.05.05 01.05.05 01.05.04 01.05.04 01.05.04
++mpi_type.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02
+
+ Filename 01.05.14 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09
+ ---------- -------- -------- -------- -------- -------- --------
+--- a/drivers/message/fusion/lsi/mpi_init.h
++++ b/drivers/message/fusion/lsi/mpi_init.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2000-2007 LSI Corporation.
++ * Copyright (c) 2000-2008 LSI Corporation.
+ *
+ *
+ * Name: mpi_init.h
+--- a/drivers/message/fusion/lsi/mpi_ioc.h
++++ b/drivers/message/fusion/lsi/mpi_ioc.h
+@@ -1,12 +1,12 @@
+ /*
+- * Copyright (c) 2000-2007 LSI Corporation.
++ * Copyright (c) 2000-2008 LSI Corporation.
+ *
+ *
+ * Name: mpi_ioc.h
+ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
+ * Creation Date: August 11, 2000
+ *
+- * mpi_ioc.h Version: 01.05.14
++ * mpi_ioc.h Version: 01.05.16
+ *
+ * Version History
+ * ---------------
+@@ -113,6 +113,16 @@
+ * added _MULTI_PORT_DOMAIN.
+ * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request.
+ * Added Common Boot Block type to FWUpload Request.
++ * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define.
++ * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and
++ * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data.
++ * Added SASAddress field to SAS Initiator Device Table
++ * Overflow event data structure.
++ * 03-28-08 01.05.16 Added two new ReasonCode values to SAS Device Status
++ * Change Event data to indicate completion of internally
++ * generated task management.
++ * Added MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE define.
++ * Added MPI_EVENT_SAS_INIT_RC_INACCESSIBLE define.
+ * --------------------------------------------------------------------------
+ */
+
+@@ -612,6 +622,8 @@ typedef struct _EVENT_DATA_SAS_DEVICE_ST
+ #define MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B)
+ #define MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C)
+ #define MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D)
++#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_INTERNAL_DEV_RESET (0x0E)
++#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_TASK_ABORT_INTERNAL (0x0F)
+
+
+ /* SCSI Event data for Queue Full event */
+@@ -708,6 +720,8 @@ typedef struct _MPI_EVENT_DATA_IR2
+ #define MPI_EVENT_IR2_RC_PD_REMOVED (0x05)
+ #define MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED (0x06)
+ #define MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR (0x07)
++#define MPI_EVENT_IR2_RC_DUAL_PORT_ADDED (0x08)
++#define MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED (0x09)
+
+ /* defines for logical disk states */
+ #define MPI_LD_STATE_OPTIMAL (0x00)
+@@ -867,6 +881,7 @@ typedef struct _EVENT_DATA_DISCOVERY_ERR
+ #define MPI_EVENT_DSCVRY_ERR_DS_UNSUPPORTED_DEVICE (0x00000800)
+ #define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000)
+ #define MPI_EVENT_DSCVRY_ERR_DS_MULTI_PORT_DOMAIN (0x00002000)
++#define MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE (0x00004000)
+
+ /* SAS SMP Error Event data */
+
+@@ -902,6 +917,8 @@ typedef struct _EVENT_DATA_SAS_INIT_DEV_
+
+ /* defines for the ReasonCode field of the SAS Initiator Device Status Change event */
+ #define MPI_EVENT_SAS_INIT_RC_ADDED (0x01)
++#define MPI_EVENT_SAS_INIT_RC_REMOVED (0x02)
++#define MPI_EVENT_SAS_INIT_RC_INACCESSIBLE (0x03)
+
+ /* SAS Initiator Device Table Overflow Event data */
+
+@@ -910,6 +927,7 @@ typedef struct _EVENT_DATA_SAS_INIT_TABL
+ U8 MaxInit; /* 00h */
+ U8 CurrentInit; /* 01h */
+ U16 Reserved1; /* 02h */
++ U64 SASAddress; /* 04h */
+ } EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
+ MPI_POINTER PTR_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
+ MpiEventDataSasInitTableOverflow_t,
+--- a/drivers/message/fusion/lsi/mpi_lan.h
++++ b/drivers/message/fusion/lsi/mpi_lan.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2000-2004 LSI Corporation.
++ * Copyright (c) 2000-2008 LSI Corporation.
+ *
+ *
+ * Name: mpi_lan.h
+--- a/drivers/message/fusion/lsi/mpi_log_fc.h
++++ b/drivers/message/fusion/lsi/mpi_log_fc.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2000-2001 LSI Corporation. All rights reserved.
++ * Copyright (c) 2000-2008 LSI Corporation. All rights reserved.
+ *
+ * NAME: fc_log.h
+ * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips
+--- a/drivers/message/fusion/lsi/mpi_log_sas.h
++++ b/drivers/message/fusion/lsi/mpi_log_sas.h
+@@ -1,6 +1,6 @@
+ /***************************************************************************
+ * *
+- * Copyright 2003 LSI Corporation. All rights reserved. *
++ * Copyright (c) 2000-2008 LSI Corporation. All rights reserved. *
+ * *
+ * Description *
+ * ------------ *
+@@ -73,6 +73,8 @@
+ #define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO (0x00070004)
+ #define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ (0x00070005)
+
++#define IOP_LOGINFO_CODE_LOG_TIMESTAMP_EVENT (0x00080000)
++
+ /****************************************************************************/
+ /* PL LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = PL */
+ /****************************************************************************/
+@@ -92,7 +94,7 @@
+ #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_OPEN_TIMEOUT_EXP (0x0000000C)
+ #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0D (0x0000000D)
+ #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_DVTBLE_ACCSS_FAIL (0x0000000E)
+-#define PL_LOGINFO_SUB CODE_OPEN_FAIL_BAD_DEST (0x00000011)
++#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_BAD_DEST (0x00000011)
+ #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RATE_NOT_SUPP (0x00000012)
+ #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PROT_NOT_SUPP (0x00000013)
+ #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON0 (0x00000014)
+@@ -162,7 +164,7 @@
+ #define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400) /* Bits 0-3 encode Transport Status Register (offset 0x08) */
+ /* Bit 0 is Status Bit 0: FrameXferErr */
+ /* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */
+- /* Bit 3 is Status Bit 18 WriteDataLengthGTDataLengthErr */
++ /* Bit 3 is Status Bit 18 WriteDataLenghtGTDataLengthErr */
+
+ #define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500)
+ #define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600)
+@@ -177,6 +179,10 @@
+ #define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET (0x00000E01)
+ #define PL_LOGINFO_SUB_CODE_SECOND_OPEN (0x00000F00)
+ #define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00001000)
++#define PL_LOGINFO_SUB_CODE_BREAK_ON_SATA_CONNECTION (0x00002000) /* not currently used in mainline */
++#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK (0x00003000)
++#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK_AIP (0x00004000)
++#define PL_LOGINFO_SUB_CODE_BREAK_ON_INCOMPLETE_BREAK_RCVD (0x00005000)
+
+ #define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE (0x00200000) /* Can't get SMP Frame */
+ #define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occured on SMP Read */
+@@ -243,6 +249,8 @@
+ #define IR_LOGINFO_VOLUME_ACTIVATE_VOLUME_FAILED (0x00010014)
+ /* Activation failed trying to import the volume */
+ #define IR_LOGINFO_VOLUME_ACTIVATING_IMPORT_VOLUME_FAILED (0x00010015)
++/* Activation failed trying to import the volume */
++#define IR_LOGINFO_VOLUME_ACTIVATING_TOO_MANY_PHYS_DISKS (0x00010016)
+
+ /* Phys Disk failed, too many phys disks */
+ #define IR_LOGINFO_PHYSDISK_CREATE_TOO_MANY_DISKS (0x00010020)
+@@ -285,6 +293,23 @@
+ /* Compatibility Error : IME size limited to < 2TB */
+ #define IR_LOGINFO_COMPAT_ERROR_IME_VOL_NOT_CURRENTLY_SUPPORTED (0x0001003D)
+
++/* Device Firmware Update: DFU can only be started once */
++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DFU_IN_PROGRESS (0x00010050)
++/* Device Firmware Update: Volume must be Optimal/Active/non-Quiesced */
++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DEVICE_IN_INVALID_STATE (0x00010051)
++/* Device Firmware Update: DFU Timeout cannot be zero */
++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_INVALID_TIMEOUT (0x00010052)
++/* Device Firmware Update: CREATE TIMER FAILED */
++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_NO_TIMERS (0x00010053)
++/* Device Firmware Update: Failed to read SAS_IO_UNIT_PG_1 */
++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_READING_CFG_PAGE (0x00010054)
++/* Device Firmware Update: Invalid SAS_IO_UNIT_PG_1 value(s) */
++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_PORT_IO_TIMEOUTS_REQUIRED (0x00010055)
++/* Device Firmware Update: Unable to allocate memory for page */
++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_ALLOC_CFG_PAGE (0x00010056)
++/* Device Firmware Update: */
++//#define IR_LOGINFO_DEV_FW_UPDATE_ERR_ (0x00010054)
++
+
+ /****************************************************************************/
+ /* Defines for convenience */
+--- a/drivers/message/fusion/lsi/mpi_raid.h
++++ b/drivers/message/fusion/lsi/mpi_raid.h
+@@ -1,12 +1,12 @@
+ /*
+- * Copyright (c) 2001-2007 LSI Corporation.
++ * Copyright (c) 2001-2008 LSI Corporation.
+ *
+ *
+ * Name: mpi_raid.h
+ * Title: MPI RAID message and structures
+ * Creation Date: February 27, 2001
+ *
+- * mpi_raid.h Version: 01.05.03
++ * mpi_raid.h Version: 01.05.05
+ *
+ * Version History
+ * ---------------
+@@ -34,6 +34,9 @@
+ * _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
+ * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and
+ * associated defines.
++ * 08-07-07 01.05.04 Added Disable Full Rebuild bit to the ActionDataWord
++ * for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME.
++ * 01-15-08 01.05.05 Added define for MPI_RAID_ACTION_SET_VOLUME_NAME.
+ * --------------------------------------------------------------------------
+ */
+
+@@ -93,6 +96,7 @@ typedef struct _MSG_RAID_ACTION
+ #define MPI_RAID_ACTION_SET_RESYNC_RATE (0x13)
+ #define MPI_RAID_ACTION_SET_DATA_SCRUB_RATE (0x14)
+ #define MPI_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15)
++#define MPI_RAID_ACTION_SET_VOLUME_NAME (0x16)
+
+ /* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */
+ #define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC (0x00000001)
+@@ -105,6 +109,9 @@ typedef struct _MSG_RAID_ACTION
+ #define MPI_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000)
+ #define MPI_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000002)
+
++/* ActionDataWord defines for use with MPI_RAID_ACTION_DISABLE_VOLUME action */
++#define MPI_RAID_ACTION_ADATA_DISABLE_FULL_REBUILD (0x00000001)
++
+ /* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */
+ #define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL (0x00000001)
+
+--- a/drivers/message/fusion/lsi/mpi_sas.h
++++ b/drivers/message/fusion/lsi/mpi_sas.h
+@@ -1,12 +1,12 @@
+ /*
+- * Copyright (c) 2004-2006 LSI Corporation.
++ * Copyright (c) 2004-2008 LSI Corporation.
+ *
+ *
+ * Name: mpi_sas.h
+ * Title: MPI Serial Attached SCSI structures and definitions
+ * Creation Date: August 19, 2004
+ *
+- * mpi_sas.h Version: 01.05.04
++ * mpi_sas.h Version: 01.05.05
+ *
+ * Version History
+ * ---------------
+@@ -23,6 +23,10 @@
+ * reply.
+ * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO
+ * Unit Control request.
++ * 01-15-08 01.05.05 Added support for MPI_SAS_OP_SET_IOC_PARAMETER,
++ * including adding IOCParameter and IOCParameter value
++ * fields to SAS IO Unit Control Request.
++ * Added MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC define.
+ * --------------------------------------------------------------------------
+ */
+
+@@ -60,6 +64,8 @@
+ * Values for the SAS DeviceInfo field used in SAS Device Status Change Event
+ * data and SAS IO Unit Configuration pages.
+ */
++#define MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC (0xF0000000)
++
+ #define MPI_SAS_DEVICE_INFO_SEP (0x00004000)
+ #define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000)
+ #define MPI_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000)
+@@ -216,7 +222,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R
+ U8 ChainOffset; /* 02h */
+ U8 Function; /* 03h */
+ U16 DevHandle; /* 04h */
+- U8 Reserved3; /* 06h */
++ U8 IOCParameter; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U8 TargetID; /* 0Ch */
+@@ -225,7 +231,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R
+ U8 PrimFlags; /* 0Fh */
+ U32 Primitive; /* 10h */
+ U64 SASAddress; /* 14h */
+- U32 Reserved4; /* 1Ch */
++ U32 IOCParameterValue; /* 1Ch */
+ } MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST,
+ SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t;
+
+@@ -241,6 +247,8 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R
+ #define MPI_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C)
+ #define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D) /* obsolete name */
+ #define MPI_SAS_OP_REMOVE_DEVICE (0x0D)
++#define MPI_SAS_OP_SET_IOC_PARAMETER (0x0E)
++#define MPI_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80)
+
+ /* values for the PrimFlags field */
+ #define MPI_SAS_PRIMFLAGS_SINGLE (0x08)
+@@ -256,7 +264,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R
+ U8 MsgLength; /* 02h */
+ U8 Function; /* 03h */
+ U16 DevHandle; /* 04h */
+- U8 Reserved3; /* 06h */
++ U8 IOCParameter; /* 06h */
+ U8 MsgFlags; /* 07h */
+ U32 MsgContext; /* 08h */
+ U16 Reserved4; /* 0Ch */
+--- a/drivers/message/fusion/lsi/mpi_targ.h
++++ b/drivers/message/fusion/lsi/mpi_targ.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2000-2004 LSI Corporation.
++ * Copyright (c) 2000-2008 LSI Corporation.
+ *
+ *
+ * Name: mpi_targ.h
+--- a/drivers/message/fusion/lsi/mpi_tool.h
++++ b/drivers/message/fusion/lsi/mpi_tool.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2001-2005 LSI Corporation.
++ * Copyright (c) 2001-2008 LSI Corporation.
+ *
+ *
+ * Name: mpi_tool.h
+--- a/drivers/message/fusion/lsi/mpi_type.h
++++ b/drivers/message/fusion/lsi/mpi_type.h
+@@ -1,12 +1,12 @@
+ /*
+- * Copyright (c) 2000-2004 LSI Corporation.
++ * Copyright (c) 2000-2008 LSI Corporation.
+ *
+ *
+ * Name: mpi_type.h
+ * Title: MPI Basic type definitions
+ * Creation Date: June 6, 2000
+ *
+- * mpi_type.h Version: 01.05.01
++ * mpi_type.h Version: 01.05.02
+ *
+ * Version History
+ * ---------------
+@@ -20,6 +20,7 @@
+ * 08-08-01 01.02.01 Original release for v1.2 work.
+ * 05-11-04 01.03.01 Original release for MPI v1.3.
+ * 08-19-04 01.05.01 Original release for MPI v1.5.
++ * 08-30-05 01.05.02 Added PowerPC option to #ifdef's.
+ * --------------------------------------------------------------------------
+ */
+
+@@ -49,8 +50,18 @@ typedef signed short S16;
+ typedef unsigned short U16;
+
+
+-typedef int32_t S32;
+-typedef u_int32_t U32;
++#if defined(unix) || defined(__arm) || defined(ALPHA) || defined(__PPC__) || defined(__ppc)
++
++ typedef signed int S32;
++ typedef unsigned int U32;
++
++#else
++
++ typedef signed long S32;
++ typedef unsigned long U32;
++
++#endif
++
+
+ typedef struct _S64
+ {
+--- a/drivers/message/fusion/Makefile
++++ b/drivers/message/fusion/Makefile
+@@ -1,12 +1,17 @@
+-# Fusion MPT drivers; recognized debug defines...
++#
++# LSI mpt fusion
++#
++
++# csmi ioctls enable
++EXTRA_CFLAGS += -DCPQ_CIM
++EXTRA_CFLAGS += -DDIAG_BUFFER_SUPPORT
++
++EXTRA_CFLAGS += -DCONFIG_FUSION_LOGGING
+
+ # enable verbose logging
+ # CONFIG_FUSION_LOGGING needs to be enabled in Kconfig
+ #EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE
+
+-
+-#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
+-
+ obj-$(CONFIG_FUSION_SPI) += mptbase.o mptscsih.o mptspi.o
+ obj-$(CONFIG_FUSION_FC) += mptbase.o mptscsih.o mptfc.o
+ obj-$(CONFIG_FUSION_SAS) += mptbase.o mptscsih.o mptsas.o
+--- a/drivers/message/fusion/mptbase.c
++++ b/drivers/message/fusion/mptbase.c
+@@ -58,6 +58,7 @@
+ #include <linux/delay.h>
+ #include <linux/interrupt.h> /* needed for in_interrupt() proto */
+ #include <linux/dma-mapping.h>
++#include <linux/sort.h>
+ #include <asm/io.h>
+ #ifdef CONFIG_MTRR
+ #include <asm/mtrr.h>
+@@ -79,19 +80,38 @@ MODULE_VERSION(my_VERSION);
+ /*
+ * cmd line parameters
+ */
+-static int mpt_msi_enable = -1;
+-module_param(mpt_msi_enable, int, 0);
+-MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
++
++static int mpt_msi_enable_spi;
++module_param(mpt_msi_enable_spi, int, 0);
++MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI controllers (default=0)");
++
++static int mpt_msi_enable_fc;
++module_param(mpt_msi_enable_fc, int, 0);
++MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC controllers (default=0)");
++
++static int mpt_msi_enable_sas = 1;
++module_param(mpt_msi_enable_sas, int, 0);
++MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS controllers (default=1)");
++
+
+ static int mpt_channel_mapping;
+ module_param(mpt_channel_mapping, int, 0);
+ MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
+
+-static int mpt_debug_level;
++int mpt_debug_level;
+ static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
+ module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
+ &mpt_debug_level, 0600);
+ MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
++EXPORT_SYMBOL(mpt_debug_level);
++
++int mpt_fwfault_debug;
++module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
++ &mpt_fwfault_debug, 0600);
++MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
++ " and halt Firmware on fault - (default=0)");
++EXPORT_SYMBOL(mpt_fwfault_debug);
++
+
+ #ifdef MFCNT
+ static int mfcounter = 0;
+@@ -102,8 +122,7 @@ static int mfcounter = 0;
+ /*
+ * Public data...
+ */
+-
+-static struct proc_dir_entry *mpt_proc_root_dir;
++struct proc_dir_entry *mpt_proc_root_dir;
+
+ #define WHOINIT_UNKNOWN 0xAA
+
+@@ -125,6 +144,8 @@ static struct mpt_pci_driver *MptDevice
+
+ static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
+
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++
+ /*
+ * Driver Callback Index's
+ */
+@@ -135,8 +156,7 @@ static u8 last_drv_idx;
+ /*
+ * Forward protos...
+ */
+-static irqreturn_t mpt_interrupt(int irq, void *bus_id);
+-static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
++static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+ static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
+ u32 *req, int replyBytes, u16 *u16reply, int maxwait,
+ int sleepFlag);
+@@ -167,9 +187,8 @@ static int mpt_GetScsiPortSettings(MPT_A
+ static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
+ static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
+ static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
+-static void mpt_timer_expired(unsigned long data);
+ static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
+-static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
++static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag);
+ static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
+ static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
+ static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
+@@ -184,7 +203,6 @@ static int procmpt_iocinfo_read(char *bu
+ #endif
+ static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
+
+-//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
+ static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
+ static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
+ static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
+@@ -193,6 +211,7 @@ static void mpt_sas_log_info(MPT_ADAPTER
+ static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
+ static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
+
++
+ /* module entry point */
+ static int __init fusion_init (void);
+ static void __exit fusion_exit (void);
+@@ -223,7 +242,16 @@ pci_enable_io_access(struct pci_dev *pde
+ pci_write_config_word(pdev, PCI_COMMAND, command_reg);
+ }
+
+-static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
++/**
++ * mpt_set_debug_level - global setting of the mpt_debug_level
++ * found via /sys/module/mptbase/parameters/mpt_debug_level
++ * @val:
++ * @kp:
++ *
++ * Returns
++ **/
++static int
++mpt_set_debug_level(const char *val, struct kernel_param *kp)
+ {
+ int ret = param_set_int(val, kp);
+ MPT_ADAPTER *ioc;
+@@ -254,6 +282,56 @@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
+ }
+
+ /**
++ * mpt_is_discovery_complete - determine if discovery has completed
++ * @ioc: per adatper instance
++ *
++ * Returns 1 when discovery completed, else zero.
++ */
++static int
++mpt_is_discovery_complete(MPT_ADAPTER *ioc)
++{
++ ConfigExtendedPageHeader_t hdr;
++ CONFIGPARMS cfg;
++ SasIOUnitPage0_t *buffer;
++ dma_addr_t dma_handle;
++ int rc = 0;
++
++ memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
++ memset(&cfg, 0, sizeof(CONFIGPARMS));
++ hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++
++ if ((mpt_config(ioc, &cfg)))
++ goto out;
++ if (!hdr.ExtPageLength)
++ goto out;
++
++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
++ &dma_handle);
++ if (!buffer)
++ goto out;
++
++ cfg.physAddr = dma_handle;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ if ((mpt_config(ioc, &cfg)))
++ goto out_free_consistent;
++
++ if (!(buffer->PhyData[0].PortFlags &
++ MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
++ rc = 1;
++
++ out_free_consistent:
++ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
++ buffer, dma_handle);
++ out:
++ return rc;
++}
++
++/**
+ * mpt_fault_reset_work - work performed on workq after ioc fault
+ * @work: input argument, used to derive ioc
+ *
+@@ -267,23 +345,29 @@ mpt_fault_reset_work(struct work_struct
+ int rc;
+ unsigned long flags;
+
+- if (ioc->diagPending || !ioc->active)
++ if (ioc->ioc_reset_in_progress || !ioc->active)
+ goto out;
+
+ ioc_raw_state = mpt_GetIocState(ioc, 0);
+ if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+ printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
+- ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
++ ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
+ printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
+- ioc->name, __func__);
++ ioc->name, __FUNCTION__);
+ rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
+ printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
+- __func__, (rc == 0) ? "success" : "failed");
++ __FUNCTION__, (rc == 0) ? "success" : "failed");
+ ioc_raw_state = mpt_GetIocState(ioc, 0);
+ if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
+ printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
+ "reset (%04xh)\n", ioc->name, ioc_raw_state &
+ MPI_DOORBELL_DATA_MASK);
++ } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
++ if ((mpt_is_discovery_complete(ioc))) {
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
++ "discovery_quiesce_io flag\n", ioc->name));
++ ioc->sas_discovery_quiesce_io = 0;
++ }
+ }
+
+ out:
+@@ -294,14 +378,13 @@ mpt_fault_reset_work(struct work_struct
+ ioc = ioc->alt_ioc;
+
+ /* rearm the timer */
+- spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ if (ioc->reset_work_q)
+ queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
+ msecs_to_jiffies(MPT_POLLING_INTERVAL));
+- spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+ }
+
+-
+ /*
+ * Process turbo (context) reply...
+ */
+@@ -354,9 +437,9 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa
+
+ /* Check for (valid) IO callback! */
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
+- MptCallbacks[cb_idx] == NULL) {
++ MptCallbacks[cb_idx] == NULL) {
+ printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
+- __func__, ioc->name, cb_idx);
++ __FUNCTION__, ioc->name, cb_idx);
+ goto out;
+ }
+
+@@ -398,6 +481,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
+
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
+ ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
++
+ DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
+
+ /* Check/log IOC log info
+@@ -413,14 +497,17 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
+ mpt_sas_log_info(ioc, log_info);
+ }
+
++ /* TODO - add shost_attrs, or command line option, and
++ * extend this to SAS/FC
++ */
+ if (ioc_stat & MPI_IOCSTATUS_MASK)
+ mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
+
+ /* Check for (valid) IO callback! */
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
+- MptCallbacks[cb_idx] == NULL) {
++ MptCallbacks[cb_idx] == NULL) {
+ printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
+- __func__, ioc->name, cb_idx);
++ __FUNCTION__, ioc->name, cb_idx);
+ freeme = 0;
+ goto out;
+ }
+@@ -436,11 +523,11 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
+ mb();
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
+ * @irq: irq number (not used)
+ * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
++ * @r: pt_regs pointer (not used)
+ *
+ * This routine is registered via the request_irq() kernel API call,
+ * and handles all interrupts generated from a specific MPT adapter
+@@ -452,7 +539,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
+ * This routine handles register-level access of the adapter but
+ * dispatches (calls) a protocol-specific callback routine to handle
+ * the protocol-specific details of the MPT request completion.
+- */
++ **/
+ static irqreturn_t
+ mpt_interrupt(int irq, void *bus_id)
+ {
+@@ -478,9 +565,9 @@ mpt_interrupt(int irq, void *bus_id)
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+- * mpt_base_reply - MPT base driver's callback routine
++ * mptbase_reply - MPT base driver's callback routine
+ * @ioc: Pointer to MPT_ADAPTER structure
+- * @mf: Pointer to original MPT request frame
++ * @req: Pointer to original MPT request frame
+ * @reply: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ * MPT base driver's callback routine; all base driver
+@@ -491,122 +578,49 @@ mpt_interrupt(int irq, void *bus_id)
+ * should be freed, or 0 if it shouldn't.
+ */
+ static int
+-mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
++mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
+ {
++ EventNotificationReply_t *pEventReply;
++ u8 event;
++ int evHandlers;
+ int freereq = 1;
+- u8 func;
+-
+- dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
+-#ifdef CONFIG_FUSION_LOGGING
+- if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
+- !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
+- dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
+- ioc->name, mf));
+- DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
+- }
+-#endif
+-
+- func = reply->u.hdr.Function;
+- dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
+- ioc->name, func));
+-
+- if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
+- EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
+- int evHandlers = 0;
+- int results;
+-
+- results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
+- if (results != evHandlers) {
+- /* CHECKME! Any special handling needed here? */
+- devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
+- ioc->name, evHandlers, results));
+- }
+
+- /*
+- * Hmmm... It seems that EventNotificationReply is an exception
+- * to the rule of one reply per request.
+- */
+- if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
++ switch (reply->u.hdr.Function) {
++ case MPI_FUNCTION_EVENT_NOTIFICATION:
++ pEventReply = (EventNotificationReply_t *)reply;
++ evHandlers = 0;
++ ProcessEventNotification(ioc, pEventReply, &evHandlers);
++ event = le32_to_cpu(pEventReply->Event) & 0xFF;
++ if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
+ freereq = 0;
+- } else {
+- devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
+- ioc->name, pEvReply));
+- }
+-
+-#ifdef CONFIG_PROC_FS
+-// LogEvent(ioc, pEvReply);
+-#endif
+-
+- } else if (func == MPI_FUNCTION_EVENT_ACK) {
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
+- ioc->name));
+- } else if (func == MPI_FUNCTION_CONFIG) {
+- CONFIGPARMS *pCfg;
+- unsigned long flags;
+-
+- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
+- ioc->name, mf, reply));
+-
+- pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
+-
+- if (pCfg) {
+- /* disable timer and remove from linked list */
+- del_timer(&pCfg->timer);
+-
+- spin_lock_irqsave(&ioc->FreeQlock, flags);
+- list_del(&pCfg->linkage);
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+-
+- /*
+- * If IOC Status is SUCCESS, save the header
+- * and set the status code to GOOD.
+- */
+- pCfg->status = MPT_CONFIG_ERROR;
+- if (reply) {
+- ConfigReply_t *pReply = (ConfigReply_t *)reply;
+- u16 status;
+-
+- status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+- dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+- ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
+-
+- pCfg->status = status;
+- if (status == MPI_IOCSTATUS_SUCCESS) {
+- if ((pReply->Header.PageType &
+- MPI_CONFIG_PAGETYPE_MASK) ==
+- MPI_CONFIG_PAGETYPE_EXTENDED) {
+- pCfg->cfghdr.ehdr->ExtPageLength =
+- le16_to_cpu(pReply->ExtPageLength);
+- pCfg->cfghdr.ehdr->ExtPageType =
+- pReply->ExtPageType;
+- }
+- pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
+-
+- /* If this is a regular header, save PageLength. */
+- /* LMP Do this better so not using a reserved field! */
+- pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
+- pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
+- pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
+- }
+- }
+-
+- /*
+- * Wake up the original calling thread
+- */
+- pCfg->wait_done = 1;
+- wake_up(&mpt_waitq);
+- }
+- } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
+- /* we should be always getting a reply frame */
+- memcpy(ioc->persist_reply_frame, reply,
+- min(MPT_DEFAULT_FRAME_SIZE,
+- 4*reply->u.reply.MsgLength));
+- del_timer(&ioc->persist_timer);
+- ioc->persist_wait_done = 1;
+- wake_up(&mpt_waitq);
+- } else {
+- printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
+- ioc->name, func);
++ if (event != MPI_EVENT_EVENT_CHANGE)
++ break;
++ case MPI_FUNCTION_CONFIG:
++ case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
++ ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
++ if (reply) {
++ ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
++ memcpy(ioc->mptbase_cmds.reply, reply,
++ min(MPT_DEFAULT_FRAME_SIZE,
++ 4 * reply->u.reply.MsgLength));
++ }
++ if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
++ ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
++ complete(&ioc->mptbase_cmds.done);
++ } else
++ freereq = 0;
++ if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
++ freereq = 1;
++ break;
++ case MPI_FUNCTION_EVENT_ACK:
++ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "EventAck reply received\n", ioc->name));
++ break;
++ default:
++ printk(MYIOC_s_ERR_FMT
++ "Unexpected msg function (=%02Xh) reply received!\n",
++ ioc->name, reply->u.hdr.Function);
++ break;
+ }
+
+ /*
+@@ -616,7 +630,6 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRA
+ return freereq;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_register - Register protocol-specific main callback handler.
+ * @cbfunc: callback function pointer
+@@ -635,7 +648,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRA
+ * {N,...,7,6,5,...,1} if successful.
+ * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
+ * considered an error by the caller.
+- */
++ **/
+ u8
+ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
+ {
+@@ -659,14 +672,13 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DR
+ return last_drv_idx;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_deregister - Deregister a protocol drivers resources.
+ * @cb_idx: previously registered callback handle
+ *
+ * Each protocol-specific driver should call this routine when its
+ * module is unloaded.
+- */
++ **/
+ void
+ mpt_deregister(u8 cb_idx)
+ {
+@@ -679,9 +691,9 @@ mpt_deregister(u8 cb_idx)
+ }
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+- * mpt_event_register - Register protocol-specific event callback handler.
++ * mpt_event_register - Register protocol-specific event callback
++ * handler.
+ * @cb_idx: previously registered (via mpt_register) callback handle
+ * @ev_cbfunc: callback function
+ *
+@@ -689,7 +701,7 @@ mpt_deregister(u8 cb_idx)
+ * if/when they choose to be notified of MPT events.
+ *
+ * Returns 0 for success.
+- */
++ **/
+ int
+ mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
+ {
+@@ -700,15 +712,15 @@ mpt_event_register(u8 cb_idx, MPT_EVHAND
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+- * mpt_event_deregister - Deregister protocol-specific event callback handler
++ * mpt_event_deregister - Deregister protocol-specific event callback
++ * handler.
+ * @cb_idx: previously registered callback handle
+ *
+ * Each protocol-specific driver should call this routine
+ * when it does not (or can no longer) handle events,
+ * or when its module is unloaded.
+- */
++ **/
+ void
+ mpt_event_deregister(u8 cb_idx)
+ {
+@@ -718,7 +730,6 @@ mpt_event_deregister(u8 cb_idx)
+ MptEvHandlers[cb_idx] = NULL;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_reset_register - Register protocol-specific IOC reset handler.
+ * @cb_idx: previously registered (via mpt_register) callback handle
+@@ -728,7 +739,7 @@ mpt_event_deregister(u8 cb_idx)
+ * if/when they choose to be notified of IOC resets.
+ *
+ * Returns 0 for success.
+- */
++ **/
+ int
+ mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
+ {
+@@ -739,7 +750,6 @@ mpt_reset_register(u8 cb_idx, MPT_RESETH
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
+ * @cb_idx: previously registered callback handle
+@@ -747,7 +757,7 @@ mpt_reset_register(u8 cb_idx, MPT_RESETH
+ * Each protocol-specific driver should call this routine
+ * when it does not (or can no longer) handle IOC reset handling,
+ * or when its module is unloaded.
+- */
++ **/
+ void
+ mpt_reset_deregister(u8 cb_idx)
+ {
+@@ -757,12 +767,11 @@ mpt_reset_deregister(u8 cb_idx)
+ MptResetHandlers[cb_idx] = NULL;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_device_driver_register - Register device driver hooks
+ * @dd_cbfunc: driver callbacks struct
+ * @cb_idx: MPT protocol driver index
+- */
++ **/
+ int
+ mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
+ {
+@@ -776,20 +785,21 @@ mpt_device_driver_register(struct mpt_pc
+
+ /* call per pci device probe entry point */
+ list_for_each_entry(ioc, &ioc_list, list) {
++ if (!pci_get_drvdata(ioc->pcidev))
++ continue;
+ id = ioc->pcidev->driver ?
+ ioc->pcidev->driver->id_table : NULL;
+ if (dd_cbfunc->probe)
+ dd_cbfunc->probe(ioc->pcidev, id);
+- }
++ }
+
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_device_driver_deregister - DeRegister device driver hooks
+ * @cb_idx: MPT protocol driver index
+- */
++ **/
+ void
+ mpt_device_driver_deregister(u8 cb_idx)
+ {
+@@ -809,19 +819,15 @@ mpt_device_driver_deregister(u8 cb_idx)
+ MptDeviceDriverHandlers[cb_idx] = NULL;
+ }
+
+-
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+- * mpt_get_msg_frame - Obtain an MPT request frame from the pool
++ * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
++ * allocated per MPT adapter.
+ * @cb_idx: Handle of registered MPT protocol driver
+ * @ioc: Pointer to MPT adapter structure
+ *
+- * Obtain an MPT request frame from the pool (of 1024) that are
+- * allocated per MPT adapter.
+- *
+ * Returns pointer to a MPT request frame or %NULL if none are available
+ * or IOC is not active.
+- */
++ **/
+ MPT_FRAME_HDR*
+ mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
+ {
+@@ -851,7 +857,6 @@ mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER
+ mf->u.frame.linkage.arg1 = 0;
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
+ req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
+- /* u16! */
+ req_idx = req_offset / ioc->req_sz;
+ mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
+ mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+@@ -881,16 +886,16 @@ mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER
+ return mf;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+- * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
++ * mpt_put_msg_frame - Send a protocol specific MPT request frame
++ * to a IOC.
+ * @cb_idx: Handle of registered MPT protocol driver
+ * @ioc: Pointer to MPT adapter structure
+ * @mf: Pointer to MPT request frame
+ *
+- * This routine posts an MPT request frame to the request post FIFO of a
++ * This routine posts a MPT request frame to the request post FIFO of a
+ * specific MPT adapter.
+- */
++ **/
+ void
+ mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+ {
+@@ -901,14 +906,14 @@ mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER
+ /* ensure values are reset properly! */
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
+ req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
+- /* u16! */
+ req_idx = req_offset / ioc->req_sz;
+ mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
+ mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+
+ DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
+
+- mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
++ mf_dma_addr = (ioc->req_frames_low_dma + req_offset) |
++ ioc->RequestNB[req_idx];
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
+ "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
+ ioc->RequestNB[req_idx]));
+@@ -916,15 +921,13 @@ mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER
+ }
+
+ /**
+- * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
++ * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame
++ * to a IOC using hi priority request queue.
+ * @cb_idx: Handle of registered MPT protocol driver
+ * @ioc: Pointer to MPT adapter structure
+ * @mf: Pointer to MPT request frame
+ *
+- * Send a protocol-specific MPT request frame to an IOC using
+- * hi-priority request queue.
+- *
+- * This routine posts an MPT request frame to the request post FIFO of a
++ * This routine posts a MPT request frame to the request post FIFO of a
+ * specific MPT adapter.
+ **/
+ void
+@@ -949,7 +952,6 @@ mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_
+ CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
+ * @handle: Handle of registered MPT protocol driver
+@@ -958,7 +960,7 @@ mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_
+ *
+ * This routine places a MPT request frame back on the MPT adapter's
+ * FreeQ.
+- */
++ **/
+ void
+ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+ {
+@@ -966,43 +968,144 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT
+
+ /* Put Request back on FreeQ! */
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
+- mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
++ if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
++ goto out;
++ mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf); /* signature to know if this mf is freed */
+ list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
+ #ifdef MFCNT
+ ioc->mfcnt--;
+ #endif
++ out:
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+- * mpt_add_sge - Place a simple SGE at address pAddr.
++ * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
+ * @pAddr: virtual address for SGE
+ * @flagslength: SGE flags and data transfer length
+ * @dma_addr: Physical address
+ *
+ * This routine places a MPT request frame back on the MPT adapter's
+ * FreeQ.
+- */
+-void
++ **/
++static void
+ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
+ {
+- if (sizeof(dma_addr_t) == sizeof(u64)) {
+- SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+- u32 tmp = dma_addr & 0xFFFFFFFF;
++ SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
++ pSge->FlagsLength = cpu_to_le32(flagslength);
++ pSge->Address = cpu_to_le32(dma_addr);
++}
+
+- pSge->FlagsLength = cpu_to_le32(flagslength);
+- pSge->Address.Low = cpu_to_le32(tmp);
+- tmp = (u32) ((u64)dma_addr >> 32);
+- pSge->Address.High = cpu_to_le32(tmp);
+
+- } else {
+- SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+- pSge->FlagsLength = cpu_to_le32(flagslength);
+- pSge->Address = cpu_to_le32(dma_addr);
++/**
++ * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
++ * @pAddr: virtual address for SGE
++ * @flagslength: SGE flags and data transfer length
++ * @dma_addr: Physical address
++ *
++ * This routine places a MPT request frame back on the MPT adapter's
++ * FreeQ.
++ **/
++static void
++mpt_add_sge_64bit(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
++{
++ SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
++ u32 tmp;
++
++ tmp = dma_addr & 0xFFFFFFFF;
++ pSge->Address.Low = cpu_to_le32(tmp);
++ tmp = (u32) ((u64)dma_addr >> 32);
++ pSge->Address.High = cpu_to_le32(tmp);
++ pSge->FlagsLength = cpu_to_le32(
++ (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
++}
++
++
++/**
++ * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
++ * (1078 workaround).
++ * @pAddr: virtual address for SGE
++ * @flagslength: SGE flags and data transfer length
++ * @dma_addr: Physical address
++ *
++ * This routine places a MPT request frame back on the MPT adapter's
++ * FreeQ.
++ **/
++static void
++mpt_add_sge_64bit_1078(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
++{
++ SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
++ u32 tmp;
++
++ tmp = dma_addr & 0xFFFFFFFF;
++ pSge->Address.Low = cpu_to_le32(tmp);
++ tmp = (u32) ((u64)dma_addr >> 32);
++
++ /*
++ * 1078 errata workaround for the 36GB limitation
++ */
++ if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
++ flagslength |=
++ MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
++ tmp |= (1<<31);
++ if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
++ printk(KERN_DEBUG "1078 P0M2 addressing for "
++ "addr = 0x%llx len = %d\n",
++ (unsigned long long)dma_addr,
++ MPI_SGE_LENGTH(flagslength));
+ }
++
++ pSge->Address.High = cpu_to_le32(tmp);
++ pSge->FlagsLength = cpu_to_le32(
++ (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
++}
++
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++/**
++ * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
++ * @pAddr: virtual address for SGE
++ * @next: nextChainOffset value (u32's)
++ * @length: length of next SGL segment
++ * @dma_addr: Physical address
++ *
++ */
++static void
++mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
++{
++ SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
++ pChain->Length = cpu_to_le16(length);
++ pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
++ pChain->NextChainOffset = next;
++ pChain->Address = cpu_to_le32(dma_addr);
++}
++
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++/**
++ * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
++ * @pAddr: virtual address for SGE
++ * @next: nextChainOffset value (u32's)
++ * @length: length of next SGL segment
++ * @dma_addr: Physical address
++ *
++ */
++static void
++mpt_add_chain_64bit(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
++{
++ SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
++ u32 tmp = dma_addr & 0xFFFFFFFF;
++
++ pChain->Length = cpu_to_le16(length);
++ pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
++ MPI_SGE_FLAGS_64_BIT_ADDRESSING);
++
++ pChain->NextChainOffset = next;
++
++ pChain->Address.Low = cpu_to_le32(tmp);
++ tmp = (u32) ((u64)dma_addr >> 32);
++ pChain->Address.High = cpu_to_le32(tmp);
+ }
+
++
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
+@@ -1019,11 +1122,11 @@ mpt_add_sge(char *pAddr, u32 flagslength
+ * request which are greater than 1 byte in size.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ int
+ mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
+ {
+- int r = 0;
++ int r = 0;
+ u8 *req_as_bytes;
+ int ii;
+
+@@ -1038,7 +1141,7 @@ mpt_send_handshake_request(u8 cb_idx, MP
+ * is in proper (pre-alloc'd) request buffer range...
+ */
+ ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
+- if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
++ if (ii >= 0 && ii < ioc->req_depth) {
+ MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
+ mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
+@@ -1096,7 +1199,6 @@ mpt_send_handshake_request(u8 cb_idx, MP
+ return r;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_host_page_access_control - control the IOC's Host Page Buffer access
+ * @ioc: Pointer to MPT adapter structure
+@@ -1113,8 +1215,7 @@ mpt_send_handshake_request(u8 cb_idx, MP
+ * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
+-
++ **/
+ static int
+ mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
+ {
+@@ -1139,7 +1240,6 @@ mpt_host_page_access_control(MPT_ADAPTER
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_host_page_alloc - allocate system memory for the fw
+ * @ioc: Pointer to pointer to IOC adapter
+@@ -1147,7 +1247,7 @@ mpt_host_page_access_control(MPT_ADAPTER
+ *
+ * If we already allocated memory in past, then resend the same pointer.
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int
+ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
+ {
+@@ -1171,7 +1271,7 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pI
+ host_page_buffer_sz,
+ &ioc->HostPageBuffer_dma)) != NULL) {
+
+- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+ "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
+ ioc->name, ioc->HostPageBuffer,
+ (u32)ioc->HostPageBuffer_dma,
+@@ -1195,21 +1295,16 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pI
+ psge = (char *)&ioc_init->HostPageBufferSGE;
+ flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+- MPI_SGE_FLAGS_32_BIT_ADDRESSING |
+ MPI_SGE_FLAGS_HOST_TO_IOC |
+ MPI_SGE_FLAGS_END_OF_BUFFER;
+- if (sizeof(dma_addr_t) == sizeof(u64)) {
+- flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
+- }
+ flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
+ flags_length |= ioc->HostPageBuffer_sz;
+- mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
++ ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
+ ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
+
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
+ * @iocid: IOC unique identifier (integer)
+@@ -1220,7 +1315,7 @@ return 0;
+ *
+ * Returns iocid and sets iocpp if iocid is found.
+ * Returns -1 if iocid is not found.
+- */
++ **/
+ int
+ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
+ {
+@@ -1493,7 +1588,6 @@ mpt_mapresources(MPT_ADAPTER *ioc)
+ unsigned long port;
+ u32 msize;
+ u32 psize;
+- u8 revision;
+ int r = -ENODEV;
+ struct pci_dev *pdev;
+
+@@ -1509,24 +1603,39 @@ mpt_mapresources(MPT_ADAPTER *ioc)
+ "MEM failed\n", ioc->name);
+ return r;
+ }
++ if (sizeof(dma_addr_t) > 4) {
++ const uint64_t required_mask = dma_get_required_mask(&pdev->dev);
++ if (required_mask > DMA_32BIT_MASK
++ && !pci_set_dma_mask(pdev, DMA_64BIT_MASK)
++ && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
++ ioc->dma_mask = DMA_64BIT_MASK;
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
++ ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
++ ioc->name));
++ } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
++ && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
++ ioc->dma_mask = DMA_32BIT_MASK;
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
++ ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
++ ioc->name));
++ } else {
++ printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
++ ioc->name, pci_name(pdev));
++ return r;
++ }
+
+- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+-
+- if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
+- && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
+- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+- ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
+- ioc->name));
+- } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
+- && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+- ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
+- ioc->name));
+ } else {
+- printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
+- ioc->name, pci_name(pdev));
+- pci_release_selected_regions(pdev, ioc->bars);
+- return r;
++ if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
++ && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
++ ioc->dma_mask = DMA_32BIT_MASK;
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
++ ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
++ ioc->name));
++ } else {
++ printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
++ ioc->name, pci_name(pdev));
++ return r;
++ }
+ }
+
+ mem_phys = msize = 0;
+@@ -1554,7 +1663,7 @@ mpt_mapresources(MPT_ADAPTER *ioc)
+ mem = ioremap(mem_phys, msize);
+ if (mem == NULL) {
+ printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
+- " memory!\n", ioc->name);
++ "memory!\n", ioc->name);
+ return -EINVAL;
+ }
+ ioc->memmap = mem;
+@@ -1565,13 +1674,15 @@ mpt_mapresources(MPT_ADAPTER *ioc)
+ ioc->chip = (SYSIF_REGS __iomem *)mem;
+
+ /* Save Port IO values in case we need to do downloadboot */
+- ioc->pio_mem_phys = port;
+- ioc->pio_chip = (SYSIF_REGS __iomem *)port;
++ {
++ u8 *pmem = (u8*)port;
++ ioc->pio_mem_phys = port;
++ ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
++ }
+
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_attach - Install a PCI intelligent MPT adapter.
+ * @pdev: Pointer to pci_dev structure
+@@ -1588,7 +1699,7 @@ mpt_mapresources(MPT_ADAPTER *ioc)
+ * Returns 0 for success, non-zero for failure.
+ *
+ * TODO: Add support for polled controllers
+- */
++ **/
+ int
+ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+ {
+@@ -1610,6 +1721,7 @@ mpt_attach(struct pci_dev *pdev, const s
+
+ ioc->id = mpt_ids++;
+ sprintf(ioc->name, "ioc%d", ioc->id);
++ dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
+
+ /*
+ * set initial debug level
+@@ -1620,7 +1732,6 @@ mpt_attach(struct pci_dev *pdev, const s
+ if (mpt_debug_level)
+ printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
+
+- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
+
+ ioc->pcidev = pdev;
+ if (mpt_mapresources(ioc)) {
+@@ -1628,14 +1739,34 @@ mpt_attach(struct pci_dev *pdev, const s
+ return r;
+ }
+
++ /*
++ * Setting up proper handlers for scatter gather handling
++ */
++ if (ioc->dma_mask == DMA_64BIT_MASK) {
++ if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
++ ioc->add_sge = &mpt_add_sge_64bit_1078;
++ else
++ ioc->add_sge = &mpt_add_sge_64bit;
++ ioc->add_chain = &mpt_add_chain_64bit;
++ ioc->sg_addr_size = 8;
++ } else {
++ ioc->add_sge = &mpt_add_sge;
++ ioc->add_chain = &mpt_add_chain;
++ ioc->sg_addr_size = 4;
++ }
++ ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
++
+ ioc->alloc_total = sizeof(MPT_ADAPTER);
+ ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
+ ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
+
+- ioc->pcidev = pdev;
+- ioc->diagPending = 0;
+- spin_lock_init(&ioc->diagLock);
+- spin_lock_init(&ioc->initializing_hba_lock);
++ spin_lock_init(&ioc->taskmgmt_lock);
++ mutex_init(&ioc->internal_cmds.mutex);
++ init_completion(&ioc->internal_cmds.done);
++ mutex_init(&ioc->mptbase_cmds.mutex);
++ init_completion(&ioc->mptbase_cmds.done);
++ mutex_init(&ioc->taskmgmt_cmds.mutex);
++ init_completion(&ioc->taskmgmt_cmds.done);
+
+ /* Initialize the event logging.
+ */
+@@ -1648,16 +1779,13 @@ mpt_attach(struct pci_dev *pdev, const s
+ ioc->mfcnt = 0;
+ #endif
+
++ ioc->sh = NULL;
+ ioc->cached_fw = NULL;
+
+ /* Initilize SCSI Config Data structure
+ */
+ memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
+
+- /* Initialize the running configQ head.
+- */
+- INIT_LIST_HEAD(&ioc->configQ);
+-
+ /* Initialize the fc rport list head.
+ */
+ INIT_LIST_HEAD(&ioc->fc_rports);
+@@ -1665,11 +1793,10 @@ mpt_attach(struct pci_dev *pdev, const s
+ /* Find lookup slot. */
+ INIT_LIST_HEAD(&ioc->list);
+
+-
+- /* Initialize workqueue */
++ /* Initialize work */
+ INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
+- spin_lock_init(&ioc->fault_reset_work_lock);
+
++ /* Initialize workqueue */
+ snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
+ "mpt_poll_%d", ioc->id);
+ ioc->reset_work_q =
+@@ -1682,8 +1809,8 @@ mpt_attach(struct pci_dev *pdev, const s
+ return -ENOMEM;
+ }
+
+- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
+- ioc->name, &ioc->facts, &ioc->pfacts[0]));
++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts @ %p, pfacts[0] @ %p\n",
++ ioc->name, &ioc->facts, &ioc->pfacts[0]));
+
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+ mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
+@@ -1703,14 +1830,14 @@ mpt_attach(struct pci_dev *pdev, const s
+ case MPI_MANUFACTPAGE_DEVICEID_FC929X:
+ if (revision < XL_929) {
+ /* 929X Chip Fix. Set Split transactions level
+- * for PCIX. Set MOST bits to zero.
+- */
++ * for PCIX. Set MOST bits to zero.
++ */
+ pci_read_config_byte(pdev, 0x6a, &pcixcmd);
+ pcixcmd &= 0x8F;
+ pci_write_config_byte(pdev, 0x6a, pcixcmd);
+ } else {
+ /* 929XL Chip Fix. Set MMRBC to 0x08.
+- */
++ */
+ pci_read_config_byte(pdev, 0x6a, &pcixcmd);
+ pcixcmd |= 0x08;
+ pci_write_config_byte(pdev, 0x6a, pcixcmd);
+@@ -1728,6 +1855,7 @@ mpt_attach(struct pci_dev *pdev, const s
+ ioc->bus_type = FC;
+ break;
+
++
+ case MPI_MANUFACTPAGE_DEVID_53C1030:
+ /* 1030 Chip Fix. Disable Split transactions
+ * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
+@@ -1745,22 +1873,33 @@ mpt_attach(struct pci_dev *pdev, const s
+ case MPI_MANUFACTPAGE_DEVID_SAS1064:
+ case MPI_MANUFACTPAGE_DEVID_SAS1068:
+ ioc->errata_flag_1064 = 1;
++ ioc->bus_type = SAS;
++ break;
+
+ case MPI_MANUFACTPAGE_DEVID_SAS1064E:
+ case MPI_MANUFACTPAGE_DEVID_SAS1068E:
+ case MPI_MANUFACTPAGE_DEVID_SAS1078:
+ ioc->bus_type = SAS;
++ break;
+ }
+
+- if (mpt_msi_enable == -1) {
+- /* Enable on SAS, disable on FC and SPI */
+- if (ioc->bus_type == SAS)
+- ioc->msi_enable = 1;
+- else
+- ioc->msi_enable = 0;
+- } else
+- /* follow flag: 0 - disable; 1 - enable */
+- ioc->msi_enable = mpt_msi_enable;
++ switch (ioc->bus_type) {
++ case SAS:
++ ioc->msi_enable = mpt_msi_enable_sas;
++ break;
++
++ case SPI:
++ ioc->msi_enable = mpt_msi_enable_spi;
++ break;
++
++ case FC:
++ ioc->msi_enable = mpt_msi_enable_fc;
++ break;
++
++ default:
++ ioc->msi_enable = 0;
++ break;
++ }
+
+ if (ioc->errata_flag_1064)
+ pci_disable_io_access(pdev);
+@@ -1772,9 +1911,6 @@ mpt_attach(struct pci_dev *pdev, const s
+ ioc->active = 0;
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+
+- /* Set IOC ptr in the pcidev's driver data. */
+- pci_set_drvdata(ioc->pcidev, ioc);
+-
+ /* Set lookup ptr. */
+ list_add_tail(&ioc->list, &ioc_list);
+
+@@ -1782,10 +1918,17 @@ mpt_attach(struct pci_dev *pdev, const s
+ */
+ mpt_detect_bound_ports(ioc, pdev);
+
++
++ INIT_LIST_HEAD(&ioc->fw_event_list);
++ spin_lock_init(&ioc->fw_event_lock);
++ snprintf(ioc->fw_event_q_name, sizeof(ioc->fw_event_q_name),
++ "mpt/%d", ioc->id);
++ ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
++
+ if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
+ CAN_SLEEP)) != 0){
+ printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
+- ioc->name, r);
++ ioc->name, r);
+
+ list_del(&ioc->list);
+ if (ioc->alt_ioc)
+@@ -1796,7 +1939,8 @@ mpt_attach(struct pci_dev *pdev, const s
+
+ destroy_workqueue(ioc->reset_work_q);
+ ioc->reset_work_q = NULL;
+-
++ destroy_workqueue(ioc->fw_event_q);
++ ioc->fw_event_q = NULL;
+ kfree(ioc);
+ pci_set_drvdata(pdev, NULL);
+ return r;
+@@ -1832,35 +1976,37 @@ mpt_attach(struct pci_dev *pdev, const s
+ if (!ioc->alt_ioc)
+ queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
+ msecs_to_jiffies(MPT_POLLING_INTERVAL));
+-
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_detach - Remove a PCI intelligent MPT adapter.
+ * @pdev: Pointer to pci_dev structure
+- */
+-
++ **/
+ void
+ mpt_detach(struct pci_dev *pdev)
+ {
+ MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+ char pname[32];
+ u8 cb_idx;
+- unsigned long flags;
++ unsigned long flags;
+ struct workqueue_struct *wq;
+
+ /*
+ * Stop polling ioc for fault condition
+ */
+- spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ wq = ioc->reset_work_q;
+ ioc->reset_work_q = NULL;
+- spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+ cancel_delayed_work(&ioc->fault_reset_work);
+ destroy_workqueue(wq);
+
++ spin_lock_irqsave(&ioc->fw_event_lock, flags);
++ wq = ioc->fw_event_q;
++ ioc->fw_event_q = NULL;
++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
++ destroy_workqueue(wq);
+
+ sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
+ remove_proc_entry(pname, NULL);
+@@ -1877,32 +2023,18 @@ mpt_detach(struct pci_dev *pdev)
+ }
+ }
+
+- /* Disable interrupts! */
+- CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+-
+- ioc->active = 0;
+- synchronize_irq(pdev->irq);
+-
+- /* Clear any lingering interrupt */
+- CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+-
+- CHIPREG_READ32(&ioc->chip->IntStatus);
+-
+- mpt_adapter_dispose(ioc);
+-
+- pci_set_drvdata(pdev, NULL);
+-}
++ mpt_adapter_dispose(ioc);
++}
+
+ /**************************************************************************
+ * Power Management
+ */
+ #ifdef CONFIG_PM
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_suspend - Fusion MPT base driver suspend routine.
+ * @pdev: Pointer to pci_dev structure
+ * @state: new state to enter
+- */
++ **/
+ int
+ mpt_suspend(struct pci_dev *pdev, pm_message_t state)
+ {
+@@ -1923,7 +2055,6 @@ mpt_suspend(struct pci_dev *pdev, pm_mes
+ /* disable interrupts */
+ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+ ioc->active = 0;
+-
+ /* Clear any lingering interrupt */
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+
+@@ -1938,11 +2069,10 @@ mpt_suspend(struct pci_dev *pdev, pm_mes
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_resume - Fusion MPT base driver resume routine.
+ * @pdev: Pointer to pci_dev structure
+- */
++ **/
+ int
+ mpt_resume(struct pci_dev *pdev)
+ {
+@@ -1962,6 +2092,22 @@ mpt_resume(struct pci_dev *pdev)
+ err = mpt_mapresources(ioc);
+ if (err)
+ return err;
++
++ if (ioc->dma_mask == DMA_64BIT_MASK) {
++ if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
++ ioc->add_sge = &mpt_add_sge_64bit_1078;
++ else
++ ioc->add_sge = &mpt_add_sge_64bit;
++ ioc->add_chain = &mpt_add_chain_64bit;
++ ioc->sg_addr_size = 8;
++ } else {
++
++ ioc->add_sge = &mpt_add_sge;
++ ioc->add_chain = &mpt_add_chain;
++ ioc->sg_addr_size = 4;
++ }
++ ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
++
+
+ printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
+ ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
+@@ -1986,9 +2132,7 @@ mpt_resume(struct pci_dev *pdev)
+
+ /* bring ioc to operational state */
+ printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
+- recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
+- CAN_SLEEP);
+- if (recovery_state != 0)
++ if ((recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0)
+ printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
+ "error:[%x]\n", ioc->name, recovery_state);
+ else
+@@ -1996,7 +2140,6 @@ mpt_resume(struct pci_dev *pdev)
+ "pci-resume: success\n", ioc->name);
+ out:
+ return 0;
+-
+ }
+ #endif
+
+@@ -2015,7 +2158,6 @@ mpt_signal_reset(u8 index, MPT_ADAPTER *
+ return (MptResetHandlers[index])(ioc, reset_phase);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
+ * @ioc: Pointer to MPT adapter structure
+@@ -2034,9 +2176,7 @@ mpt_signal_reset(u8 index, MPT_ADAPTER *
+ * -2 if READY but IOCFacts Failed
+ * -3 if READY but PrimeIOCFifos Failed
+ * -4 if READY but IOCInit Failed
+- * -5 if failed to enable_device and/or request_selected_regions
+- * -6 if failed to upload firmware
+- */
++ **/
+ static int
+ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
+ {
+@@ -2045,14 +2185,12 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ int hard;
+ int rc=0;
+ int ii;
+- u8 cb_idx;
+- int handlers;
+ int ret = 0;
+ int reset_alt_ioc_active = 0;
+ int irq_allocated = 0;
+ u8 *a;
+
+- printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
++ printk(MYIOC_s_DEBUG_FMT "Initiating %s\n", ioc->name,
+ reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
+
+ /* Disable reply interrupts (also blocks FreeQ) */
+@@ -2060,7 +2198,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ ioc->active = 0;
+
+ if (ioc->alt_ioc) {
+- if (ioc->alt_ioc->active)
++ if (ioc->alt_ioc->active || reason == MPT_HOSTEVENT_IOC_RECOVER)
+ reset_alt_ioc_active = 1;
+
+ /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
+@@ -2079,16 +2217,17 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+
+ if (reset_alt_ioc_active && ioc->alt_ioc) {
+ /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
+- dprintk(ioc, printk(MYIOC_s_INFO_FMT
+- "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": alt-ioc reply irq re-enabled\n",
++ ioc->alt_ioc->name));
+ CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
+ ioc->alt_ioc->active = 1;
+ }
+
+ } else {
+- printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
++ printk(MYIOC_s_WARN_FMT "NOT READY WARNING!\n", ioc->name);
+ }
+- return -1;
++ ret = -1;
++ goto out;
+ }
+
+ /* hard_reset_done = 0 if a soft reset was performed
+@@ -2098,7 +2237,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
+ alt_ioc_ready = 1;
+ else
+- printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
++ printk(MYIOC_s_WARN_FMT
++ ": alt-ioc Not ready WARNING!\n", ioc->alt_ioc->name);
+ }
+
+ for (ii=0; ii<5; ii++) {
+@@ -2156,23 +2296,28 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ if (ioc->pcidev->irq) {
+ if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
+ printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
+- ioc->name);
++ ioc->name);
+ else
+ ioc->msi_enable = 0;
++
+ rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
+ IRQF_SHARED, ioc->name, ioc);
+ if (rc < 0) {
+ printk(MYIOC_s_ERR_FMT "Unable to allocate "
+- "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
++ "interrupt %d!\n", ioc->name,
++ ioc->pcidev->irq);
+ if (ioc->msi_enable)
+ pci_disable_msi(ioc->pcidev);
+- return -EBUSY;
++ ret = -EBUSY;
++ goto out;
+ }
+ irq_allocated = 1;
+ ioc->pci_irq = ioc->pcidev->irq;
+ pci_set_master(ioc->pcidev); /* ?? */
+- dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
+- "%d\n", ioc->name, ioc->pcidev->irq));
++ pci_set_drvdata(ioc->pcidev, ioc);
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
++ "installed at interrupt %d\n", ioc->name,
++ ioc->pcidev->irq));
+ }
+ }
+
+@@ -2181,18 +2326,22 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ * init as upper addresses are needed for init.
+ * If fails, continue with alt-ioc processing
+ */
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
++ ioc->name));
+ if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
+ ret = -3;
+
+ /* May need to check/upload firmware & data here!
+ * If fails, continue with alt-ioc processing
+ */
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
++ ioc->name));
+ if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
+ ret = -4;
+ // NEW!
+ if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
+- printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
+- ioc->alt_ioc->name, rc);
++ printk(MYIOC_s_WARN_FMT ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
++ ioc->alt_ioc->name, rc);
+ alt_ioc_ready = 0;
+ reset_alt_ioc_active = 0;
+ }
+@@ -2201,15 +2350,16 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
+ alt_ioc_ready = 0;
+ reset_alt_ioc_active = 0;
+- printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
+- ioc->alt_ioc->name, rc);
++ printk(MYIOC_s_WARN_FMT
++ ": alt-ioc: (%d) init failure WARNING!\n",
++ ioc->alt_ioc->name, rc);
+ }
+ }
+
+ if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
+ if (ioc->upload_fw) {
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "firmware upload required!\n", ioc->name));
++ "firmware upload required!\n", ioc->name));
+
+ /* Controller is not operational, cannot do upload
+ */
+@@ -2232,34 +2382,39 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ } else {
+ printk(MYIOC_s_WARN_FMT
+ "firmware upload failure!\n", ioc->name);
+- ret = -6;
++ ret = -5;
+ }
+ }
+ }
+ }
+
++ /* Enable MPT base driver management of EventNotification
++ * and EventAck handling.
++ */
++ if ((ret == 0) && (!ioc->facts.EventState)) {
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendEventNotification\n",
++ ioc->name));
++ ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
++ }
++
++ if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
++ rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
++
+ if (ret == 0) {
+ /* Enable! (reply interrupt) */
+ CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
+ ioc->active = 1;
+ }
+-
+- if (reset_alt_ioc_active && ioc->alt_ioc) {
+- /* (re)Enable alt-IOC! (reply interrupt) */
+- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
+- ioc->alt_ioc->name));
+- CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
+- ioc->alt_ioc->active = 1;
++ if (rc == 0) { /* alt ioc */
++ if (reset_alt_ioc_active && ioc->alt_ioc) {
++ /* (re)Enable alt-IOC! (reply interrupt) */
++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc reply irq re-enabled\n",
++ ioc->alt_ioc->name));
++ CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
++ ioc->alt_ioc->active = 1;
++ }
+ }
+
+- /* Enable MPT base driver management of EventNotification
+- * and EventAck handling.
+- */
+- if ((ret == 0) && (!ioc->facts.EventState))
+- (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
+-
+- if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
+- (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
+
+ /* Add additional "reason" check before call to GetLanConfigPages
+ * (combined with GetIoUnitPage2 call). This prevents a somewhat
+@@ -2272,11 +2427,12 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ /*
+ * Initalize link list for inactive raid volumes.
+ */
+- mutex_init(&ioc->raid_data.inactive_list_mutex);
++ init_MUTEX(&ioc->raid_data.inactive_list_mutex);
+ INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
+
+- if (ioc->bus_type == SAS) {
++ switch (ioc->bus_type) {
+
++ case SAS:
+ /* clear persistency table */
+ if(ioc->facts.IOCExceptions &
+ MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
+@@ -2290,8 +2446,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ */
+ mpt_findImVolumes(ioc);
+
+- } else if (ioc->bus_type == FC) {
+- if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
++ /* Check, and possibly reset, the coalescing value
++ */
++ mpt_read_ioc_pg_1(ioc);
++
++ break;
++
++ case FC:
++ if ((ioc->pfacts[0].ProtocolFlags &
++ MPI_PORTFACTS_PROTOCOL_LAN) &&
+ (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
+ /*
+ * Pre-fetch the ports LAN MAC address!
+@@ -2300,11 +2463,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ (void) GetLanConfigPages(ioc);
+ a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+- ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
+-
++ "LanAddr = %02X:%02X:%02X"
++ ":%02X:%02X:%02X\n",
++ ioc->name, a[5], a[4],
++ a[3], a[2], a[1], a[0]));
+ }
+- } else {
++ break;
++
++ case SPI:
+ /* Get NVRAM and adapter maximums from SPP 0 and 2
+ */
+ mpt_GetScsiPortSettings(ioc, 0);
+@@ -2323,41 +2489,16 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ mpt_read_ioc_pg_1(ioc);
+
+ mpt_read_ioc_pg_4(ioc);
++
++ break;
+ }
+
+ GetIoUnitPage2(ioc);
+ mpt_get_manufacturing_pg_0(ioc);
+ }
+
+- /*
+- * Call each currently registered protocol IOC reset handler
+- * with post-reset indication.
+- * NOTE: If we're doing _IOC_BRINGUP, there can be no
+- * MptResetHandlers[] registered yet.
+- */
+- if (hard_reset_done) {
+- rc = handlers = 0;
+- for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+- if ((ret == 0) && MptResetHandlers[cb_idx]) {
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "Calling IOC post_reset handler #%d\n",
+- ioc->name, cb_idx));
+- rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
+- handlers++;
+- }
+-
+- if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
+- drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "Calling IOC post_reset handler #%d\n",
+- ioc->alt_ioc->name, cb_idx));
+- rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
+- handlers++;
+- }
+- }
+- /* FIXME? Examine results here? */
+- }
+-
+ out:
++
+ if ((ret != 0) && irq_allocated) {
+ free_irq(ioc->pci_irq, ioc);
+ if (ioc->msi_enable)
+@@ -2366,7 +2507,6 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ return ret;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
+ * @ioc: Pointer to MPT adapter structure
+@@ -2378,7 +2518,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3
+ *
+ * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
+ * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
+- */
++ **/
+ static void
+ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
+ {
+@@ -2389,8 +2529,8 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc,
+
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
+ " searching for devfn match on %x or %x\n",
+- ioc->name, pci_name(pdev), pdev->bus->number,
+- pdev->devfn, func-1, func+1));
++ ioc->name, pci_name(pdev), pdev->bus->number,
++ pdev->devfn, func-1, func+1));
+
+ peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
+ if (!peer) {
+@@ -2404,16 +2544,16 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc,
+ if (_pcidev == peer) {
+ /* Paranoia checks */
+ if (ioc->alt_ioc != NULL) {
+- printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
+- ioc->name, ioc->alt_ioc->name);
++ printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n",
++ ioc->name, ioc->name, ioc->alt_ioc->name);
+ break;
+ } else if (ioc_srch->alt_ioc != NULL) {
+- printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
+- ioc_srch->name, ioc_srch->alt_ioc->name);
++ printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n",
++ ioc_srch->name, ioc_srch->name, ioc_srch->alt_ioc->name);
+ break;
+ }
+- dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
+- ioc->name, ioc_srch->name));
++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FOUND! binding %s <==> %s\n",
++ ioc->name, ioc->name, ioc_srch->name));
+ ioc_srch->alt_ioc = ioc;
+ ioc->alt_ioc = ioc_srch;
+ }
+@@ -2421,11 +2561,10 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc,
+ pci_dev_put(peer);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_adapter_disable - Disable misbehaving MPT adapter.
+ * @ioc: Pointer to MPT adapter structure
+- */
++ **/
+ static void
+ mpt_adapter_disable(MPT_ADAPTER *ioc)
+ {
+@@ -2433,26 +2572,43 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
+ int ret;
+
+ if (ioc->cached_fw != NULL) {
+- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
+- "adapter\n", __func__, ioc->name));
++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_adapter_disable: "
++ "Pushing FW onto adapter\n", ioc->name));
+ if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
+ ioc->cached_fw, CAN_SLEEP)) < 0) {
+ printk(MYIOC_s_WARN_FMT
+- ": firmware downloadboot failure (%d)!\n",
+- ioc->name, ret);
++ ": firmware downloadboot failure (%d)!\n", ioc->name, ret);
+ }
+ }
+
++ /*
++ * Put the controller into ready state (if its not already)
++ */
++ if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
++ if(!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
++ CAN_SLEEP)) {
++ if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
++ printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
++ "reset failed to put ioc in ready state!\n",
++ ioc->name, __FUNCTION__);
++ } else
++ printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
++ "failed!\n", ioc->name, __FUNCTION__);
++ }
++
+ /* Disable adapter interrupts! */
++ synchronize_irq(ioc->pcidev->irq);
+ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+ ioc->active = 0;
++
+ /* Clear any lingering interrupt */
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
++ CHIPREG_READ32(&ioc->chip->IntStatus);
+
+ if (ioc->alloc != NULL) {
+ sz = ioc->alloc_sz;
+- dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
+- ioc->name, ioc->alloc, ioc->alloc_sz));
++ dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free @ %p, sz=%d bytes\n",
++ ioc->name, ioc->alloc, ioc->alloc_sz));
+ pci_free_consistent(ioc->pcidev, sz,
+ ioc->alloc, ioc->alloc_dma);
+ ioc->reply_frames = NULL;
+@@ -2482,8 +2638,10 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
+ mpt_inactive_raid_list_free(ioc);
+ kfree(ioc->raid_data.pIocPg2);
+ kfree(ioc->raid_data.pIocPg3);
++ kfree(ioc->raid_data.pIocPg6);
+ ioc->spi_data.nvram = NULL;
+ ioc->raid_data.pIocPg3 = NULL;
++ ioc->raid_data.pIocPg6 = NULL;
+
+ if (ioc->spi_data.pIocPg4 != NULL) {
+ sz = ioc->spi_data.IocPg4Sz;
+@@ -2507,27 +2665,29 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
+ if((ret = mpt_host_page_access_control(ioc,
+ MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
+ printk(MYIOC_s_ERR_FMT
+- "host page buffers free failed (%d)!\n",
+- ioc->name, ret);
++ ": %s: host page buffers free failed (%d)!\n",
++ ioc->name, __FUNCTION__, ret);
+ }
+- dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
++ dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
+ ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
+ pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
+- ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
++ ioc->HostPageBuffer,
++ ioc->HostPageBuffer_dma);
+ ioc->HostPageBuffer = NULL;
+ ioc->HostPageBuffer_sz = 0;
+ ioc->alloc_total -= ioc->HostPageBuffer_sz;
+ }
++
++ pci_set_drvdata(ioc->pcidev, NULL);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_adapter_dispose - Free all resources associated with an MPT adapter
+ * @ioc: Pointer to MPT adapter structure
+ *
+ * This routine unregisters h/w resources and frees all alloc'd memory
+ * associated with a MPT adapter structure.
+- */
++ **/
+ static void
+ mpt_adapter_dispose(MPT_ADAPTER *ioc)
+ {
+@@ -2558,7 +2718,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
+ #if defined(CONFIG_MTRR) && 0
+ if (ioc->mtrr_reg > 0) {
+ mtrr_del(ioc->mtrr_reg, 0, 0);
+- dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region de-registered\n", ioc->name));
+ }
+ #endif
+
+@@ -2566,8 +2726,8 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
+ list_del(&ioc->list);
+
+ sz_last = ioc->alloc_total;
+- dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
+- ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free'd %d of %d bytes\n",
++ ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
+
+ if (ioc->alt_ioc)
+ ioc->alt_ioc->alt_ioc = NULL;
+@@ -2575,11 +2735,10 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
+ kfree(ioc);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * MptDisplayIocCapabilities - Disply IOC's capabilities.
+ * @ioc: Pointer to MPT adapter structure
+- */
++ **/
+ static void
+ MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
+ {
+@@ -2618,7 +2777,6 @@ MptDisplayIocCapabilities(MPT_ADAPTER *i
+ printk("}\n");
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -2632,7 +2790,7 @@ MptDisplayIocCapabilities(MPT_ADAPTER *i
+ * -2 - Msg Unit Reset Failed
+ * -3 - IO Unit Reset Failed
+ * -4 - IOC owned by a PEER
+- */
++ **/
+ static int
+ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
+ {
+@@ -2646,7 +2804,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force
+
+ /* Get current [raw] IOC state */
+ ioc_state = mpt_GetIocState(ioc, 0);
+- dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
++ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MakeIocReady, [raw] state=%08x\n", ioc->name, ioc_state));
+
+ /*
+ * Check to see if IOC got left/stuck in doorbell handshake
+@@ -2659,8 +2817,11 @@ MakeIocReady(MPT_ADAPTER *ioc, int force
+ }
+
+ /* Is it already READY? */
+- if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
++ if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) {
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "IOC is in READY state\n",
++ ioc->name));
+ return 0;
++ }
+
+ /*
+ * Check to see if IOC is in FAULT state.
+@@ -2668,9 +2829,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force
+ if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+ statefault = 2;
+ printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
+- ioc->name);
+- printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
+- ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
++ ioc->name);
++ printk(KERN_WARNING " FAULT code = %04xh\n",
++ ioc_state & MPI_DOORBELL_DATA_MASK);
+ }
+
+ /*
+@@ -2686,7 +2847,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force
+ * Else, fall through to KickStart case
+ */
+ whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
+- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "whoinit 0x%x statefault %d force %d\n",
+ ioc->name, whoinit, statefault, force));
+ if (whoinit == MPI_WHOINIT_PCI_PEER)
+@@ -2733,15 +2894,15 @@ MakeIocReady(MPT_ADAPTER *ioc, int force
+
+ ii++; cntdn--;
+ if (!cntdn) {
+- printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
+- ioc->name, (int)((ii+5)/HZ));
++ printk(MYIOC_s_ERR_FMT "Wait IOC_READY state (0x%x) timeout(%d)!\n",
++ ioc->name, ioc_state, (int)((ii+5)/HZ));
+ return -ETIME;
+ }
+
+ if (sleepFlag == CAN_SLEEP) {
+ msleep(1);
+ } else {
+- mdelay (1); /* 1 msec delay */
++ mdelay(1); /* 1 msec delay */
+ }
+
+ }
+@@ -2755,7 +2916,6 @@ MakeIocReady(MPT_ADAPTER *ioc, int force
+ return hard_reset_done;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_GetIocState - Get the current state of a MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -2763,7 +2923,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force
+ *
+ * Returns all IOC Doorbell register bits if cooked==0, else just the
+ * Doorbell bits in MPI_IOC_STATE_MASK.
+- */
++ **/
+ u32
+ mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
+ {
+@@ -2779,7 +2939,6 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int co
+ return cooked ? sc : s;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * GetIocFacts - Send IOCFacts request to MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -2787,7 +2946,7 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int co
+ * @reason: If recovery, only update facts.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int
+ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
+ {
+@@ -2802,8 +2961,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF
+
+ /* IOC *must* NOT be in RESET state! */
+ if (ioc->last_state == MPI_IOC_STATE_RESET) {
+- printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
+- ioc->name, ioc->last_state );
++ printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
++ ioc->name,
++ ioc->last_state );
+ return -44;
+ }
+
+@@ -2820,7 +2980,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF
+ get_facts.Function = MPI_FUNCTION_IOC_FACTS;
+ /* Assert: All other get_facts fields are zero! */
+
+- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+ "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
+ ioc->name, req_sz, reply_sz));
+
+@@ -2850,6 +3010,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF
+ }
+
+ facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
++ if (facts->MsgVersion == MPI_VERSION_01_05)
++ facts->HeaderVersion = le16_to_cpu(facts->HeaderVersion);
+ facts->MsgContext = le32_to_cpu(facts->MsgContext);
+ facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
+ facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
+@@ -2865,7 +3027,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF
+ * Old: u16{Major(4),Minor(4),SubMinor(8)}
+ * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
+ */
+- if (facts->MsgVersion < 0x0102) {
++ if (facts->MsgVersion < MPI_VERSION_01_02) {
+ /*
+ * Handle old FC f/w style, convert to new...
+ */
+@@ -2877,9 +3039,11 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF
+ facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
+
+ facts->ProductID = le16_to_cpu(facts->ProductID);
++
+ if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
+ > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
+ ioc->ir_firmware = 1;
++
+ facts->CurrentHostMfaHighAddr =
+ le32_to_cpu(facts->CurrentHostMfaHighAddr);
+ facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
+@@ -2895,7 +3059,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF
+ * to 14 in MPI-1.01.0x.
+ */
+ if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
+- facts->MsgVersion > 0x0100) {
++ facts->MsgVersion > MPI_VERSION_01_00) {
+ facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
+ }
+
+@@ -2956,7 +3120,6 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * GetPortFacts - Send PortFacts request to MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -2964,7 +3127,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF
+ * @sleepFlag: Specifies whether the process can sleep
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int
+ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
+ {
+@@ -2977,8 +3140,8 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn
+
+ /* IOC *must* NOT be in RESET state! */
+ if (ioc->last_state == MPI_IOC_STATE_RESET) {
+- printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
+- ioc->name, ioc->last_state );
++ printk(MYIOC_s_ERR_FMT "Can't get PortFacts, "
++ " NOT READY! (%08x)\n", ioc->name, ioc->last_state );
+ return -4;
+ }
+
+@@ -2996,14 +3159,14 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn
+ get_pfacts.PortNumber = portnum;
+ /* Assert: All other get_pfacts fields are zero! */
+
+- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
+- ioc->name, portnum));
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
++ ioc->name, portnum));
+
+ /* No non-zero fields in the get_pfacts request are greater than
+ * 1 byte in size, so we can just fire it off as is.
+ */
+ ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
+- reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
++ reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
+ if (ii != 0)
+ return ii;
+
+@@ -3038,7 +3201,6 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * SendIocInit - Send IOCInit request to MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -3047,7 +3209,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn
+ * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int
+ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
+ {
+@@ -3077,7 +3239,8 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF
+
+ ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
+ ioc_init.MaxBuses = (U8)ioc->number_of_buses;
+- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
++
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
+ ioc->name, ioc->facts.MsgVersion));
+ if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
+ // set MsgVersion and HeaderVersion host driver was built with
+@@ -3091,7 +3254,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF
+ }
+ ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
+
+- if (sizeof(dma_addr_t) == sizeof(u64)) {
++ if (ioc->sg_addr_size == sizeof(u64)) {
+ /* Save the upper 32-bits of the request
+ * (reply) and sense buffers.
+ */
+@@ -3160,7 +3323,6 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF
+ return r;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * SendPortEnable - Send PortEnable request to MPT adapter port.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -3170,7 +3332,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF
+ * Send PortEnable to bring IOC to OPERATIONAL state.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int
+ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
+ {
+@@ -3193,7 +3355,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int por
+ /* port_enable.MsgFlags = 0; */
+ /* port_enable.MsgContext = 0; */
+
+- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
+ ioc->name, portnum, &port_enable));
+
+ /* RAID FW may take a long time to enable
+@@ -3273,7 +3435,6 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc)
+ ioc->cached_fw = NULL;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -3286,7 +3447,7 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc)
+ * on the bound IOC, the second image is discarded
+ * and memory is free'd. Both channels must upload to prevent
+ * IOC from running in degraded mode.
+- */
++ **/
+ static int
+ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
+ {
+@@ -3294,22 +3455,19 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee
+ FWUpload_t *prequest;
+ FWUploadReply_t *preply;
+ FWUploadTCSGE_t *ptcsge;
+- int sgeoffset;
+ u32 flagsLength;
+- int ii, sz, reply_sz;
++ int ii, reply_sz;
+ int cmdStatus;
++ int request_size;
+
+ /* If the image size is 0, we are done.
+ */
+- if ((sz = ioc->facts.FWImageSize) == 0)
++ if (!ioc->facts.FWImageSize)
+ return 0;
+
+ if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
+ return -ENOMEM;
+
+- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
+- ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+-
+ prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
+ kzalloc(ioc->req_sz, GFP_KERNEL);
+ if (!prequest) {
+@@ -3326,49 +3484,47 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee
+
+ prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
+ prequest->Function = MPI_FUNCTION_FW_UPLOAD;
+-
+ ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
+ ptcsge->DetailsLength = 12;
+ ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
+- ptcsge->ImageSize = cpu_to_le32(sz);
++ ptcsge->ImageSize = cpu_to_le32(ioc->facts.FWImageSize);
+ ptcsge++;
+
+- sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
+-
+- flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
+- mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
+-
+- sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
+- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
+- ioc->name, prequest, sgeoffset));
++ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | ioc->facts.FWImageSize;
++ ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
++ request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
++ ioc->SGE_size;
++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
++ " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
++ ioc->facts.FWImageSize, request_size));
+ DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
+
+- ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
+- reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
++ ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32*)prequest,
++ reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
+
+- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
++ "rc=%x \n", ioc->name, ii));
+
+ cmdStatus = -EFAULT;
+ if (ii == 0) {
+ /* Handshake transfer was complete and successful.
+ * Check the Reply Frame.
+ */
+- int status, transfer_sz;
+- status = le16_to_cpu(preply->IOCStatus);
+- if (status == MPI_IOCSTATUS_SUCCESS) {
+- transfer_sz = le32_to_cpu(preply->ActualImageSize);
+- if (transfer_sz == sz)
+- cmdStatus = 0;
+- }
++ int status;
++ status = le16_to_cpu(preply->IOCStatus) &
++ MPI_IOCSTATUS_MASK;
++ if (status == MPI_IOCSTATUS_SUCCESS &&
++ ioc->facts.FWImageSize ==
++ le32_to_cpu(preply->ActualImageSize));
++ cmdStatus = 0;
+ }
+- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
+- ioc->name, cmdStatus));
++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "do_upload cmdStatus=%d \n",
++ ioc->name, cmdStatus));
+
+
+ if (cmdStatus) {
+-
+- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
+- ioc->name));
++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
++ "freeing image \n", ioc->name));
+ mpt_free_fw_memory(ioc);
+ }
+ kfree(prequest);
+@@ -3376,7 +3532,6 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee
+ return cmdStatus;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_downloadboot - DownloadBoot code
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -3389,7 +3544,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee
+ * -1 FW Image size is 0
+ * -2 No valid cached_fw Pointer
+ * <0 for fw upload failure.
+- */
++ **/
+ static int
+ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
+ {
+@@ -3401,10 +3556,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw
+ u32 diagRwData;
+ u32 nextImage;
+ u32 load_addr;
+- u32 ioc_state=0;
++ u32 doorbell;
+
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
+- ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
++ ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
+
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+@@ -3416,11 +3571,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
+
+ /* wait 1 msec */
+- if (sleepFlag == CAN_SLEEP) {
++ if (sleepFlag == CAN_SLEEP)
+ msleep(1);
+- } else {
+- mdelay (1);
+- }
++ else
++ mdelay(1);
+
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
+@@ -3433,11 +3587,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw
+ break;
+ }
+ /* wait .1 sec */
+- if (sleepFlag == CAN_SLEEP) {
++ if (sleepFlag == CAN_SLEEP)
+ msleep (100);
+- } else {
++ else
+ mdelay (100);
+- }
+ }
+
+ if ( count == 30 ) {
+@@ -3455,6 +3608,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+
+ /* Set the DiagRwEn and Disable ARM bits */
++ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
+
+ fwSize = (pFwHeader->ImageSize + 3)/4;
+@@ -3468,13 +3622,12 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw
+
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
+- ioc->name, pFwHeader->LoadStartAddress));
++ ioc->name, pFwHeader->LoadStartAddress));
+
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
+- ioc->name, fwSize*4, ptrFw));
+- while (fwSize--) {
++ ioc->name, fwSize*4, ptrFw));
++ while (fwSize--)
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
+- }
+
+ nextImage = pFwHeader->NextImageHeaderOffset;
+ while (nextImage) {
+@@ -3486,21 +3639,22 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw
+ ptrFw = (u32 *)pExtImage;
+
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
+- ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
++ ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
+
+- while (fwSize--) {
++ while (fwSize--)
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
+- }
+ nextImage = pExtImage->NextImageHeaderOffset;
+ }
+
+ /* Write the IopResetVectorRegAddr */
+- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n",
++ ioc->name, pFwHeader->IopResetRegAddr));
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
+
+ /* Write the IopResetVectorValue */
+- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n",
++ ioc->name, pFwHeader->IopResetVectorValue));
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
+
+ /* Clear the internal flash bad bit - autoincrementing register,
+@@ -3517,75 +3671,75 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
+
+- } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
+- diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+- CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
+- MPI_DIAG_CLEAR_FLASH_BAD_SIG);
+-
+- /* wait 1 msec */
+- if (sleepFlag == CAN_SLEEP) {
+- msleep (1);
+- } else {
+- mdelay (1);
+- }
+ }
+
+ if (ioc->errata_flag_1064)
+ pci_disable_io_access(ioc->pcidev);
+
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
+- "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
+- ioc->name, diag0val));
+- diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
+- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
+- ioc->name, diag0val));
++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "diag0val=%x, turning off"
++ " PREVENT_IOC_BOOT and DISABLE_ARM\n", ioc->name, diag0val));
++ diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM);
++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "diag0val=%x\n",
++ ioc->name, diag0val));
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+
+- /* Write 0xFF to reset the sequencer */
+- CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
++ if (ioc->bus_type == SAS ) {
++ /* wait 1 sec */
++ if (sleepFlag == CAN_SLEEP)
++ msleep(1000);
++ else
++ mdelay(1000);
+
+- if (ioc->bus_type == SAS) {
+- ioc_state = mpt_GetIocState(ioc, 0);
+- if ( (GetIocFacts(ioc, sleepFlag,
+- MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
+- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
+- ioc->name, ioc_state));
+- return -EFAULT;
++ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
++ ddlprintk(ioc, printk (MYIOC_s_DEBUG_FMT
++ "diag0val=%x, turning off RW_ENABLE\n", ioc->name,
++ diag0val));
++ diag0val &= ~(MPI_DIAG_RW_ENABLE);
++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "now diag0val=%x\n", ioc->name, diag0val));
++ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
++
++ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
++ if (diag0val & MPI_DIAG_FLASH_BAD_SIG) {
++ diag0val |= MPI_DIAG_CLEAR_FLASH_BAD_SIG;
++ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
++ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ }
++ diag0val &= ~(MPI_DIAG_DISABLE_ARM);
++ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
++ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
++ CHIPREG_WRITE32(&ioc->chip->DiagRwAddress, 0x3f000004);
+ }
+
+- for (count=0; count<HZ*20; count++) {
+- if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
+- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "downloadboot successful! (count=%d) IocState=%x\n",
+- ioc->name, count, ioc_state));
+- if (ioc->bus_type == SAS) {
++ /* Write 0xFF to reset the sequencer */
++ CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
++
++ for (count = 0; count < 30; count ++) {
++ doorbell = CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_IOC_STATE_MASK;
++ if (doorbell == MPI_IOC_STATE_READY) {
++ if (ioc->bus_type == SAS)
+ return 0;
+- }
+ if ((SendIocInit(ioc, sleepFlag)) != 0) {
+- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "downloadboot: SendIocInit failed\n",
+- ioc->name));
++ ddlprintk(ioc, printk(MYIOC_s_WARN_FMT
++ "SendIocInit failed\n", ioc->name));
+ return -EFAULT;
+ }
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "downloadboot: SendIocInit successful\n",
+- ioc->name));
++ "SendIocInit successful\n", ioc->name));
+ return 0;
+ }
+- if (sleepFlag == CAN_SLEEP) {
+- msleep (10);
+- } else {
+- mdelay (10);
+- }
++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "looking for READY STATE:"
++ " doorbell=%x count=%d\n", ioc->name, doorbell, count));
++ if (sleepFlag == CAN_SLEEP)
++ msleep(1000);
++ else
++ mdelay(1000);
+ }
+- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
++ ddlprintk(ioc, printk(MYIOC_s_WARN_FMT "downloadboot failed! count=%d\n", ioc->name, count));
+ return -EFAULT;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * KickStart - Perform hard reset of MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -3610,7 +3764,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw
+ * OR reset but failed to come READY
+ * -2 - no reset, could not enter DIAG mode
+ * -3 - reset but bad FW bit
+- */
++ **/
+ static int
+ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
+ {
+@@ -3618,7 +3772,7 @@ KickStart(MPT_ADAPTER *ioc, int force, i
+ u32 ioc_state=0;
+ int cnt,cntdn;
+
+- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": KickStart\n", ioc->name));
+ if (ioc->bus_type == SPI) {
+ /* Always issue a Msg Unit Reset first. This will clear some
+ * SCSI bus hang conditions.
+@@ -3636,14 +3790,15 @@ KickStart(MPT_ADAPTER *ioc, int force, i
+ if (hard_reset_done < 0)
+ return hard_reset_done;
+
+- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
+- ioc->name));
++ /* may not have worked but hard_reset_done doesn't always signal failure */
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Diagnostic reset completed!\n",
++ ioc->name));
+
+ cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
+ for (cnt=0; cnt<cntdn; cnt++) {
+ ioc_state = mpt_GetIocState(ioc, 1);
+ if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
+- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
+ ioc->name, cnt));
+ return hard_reset_done;
+ }
+@@ -3655,11 +3810,10 @@ KickStart(MPT_ADAPTER *ioc, int force, i
+ }
+
+ dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
+- ioc->name, mpt_GetIocState(ioc, 0)));
++ ioc->name, mpt_GetIocState(ioc, 0)));
+ return -1;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_diag_reset - Perform hard reset of the adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -3677,30 +3831,46 @@ KickStart(MPT_ADAPTER *ioc, int force, i
+ * 0 no reset performed because reset history bit set
+ * -2 enabling diagnostic mode failed
+ * -3 diagnostic reset failed
+- */
++ **/
+ static int
+ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
+ {
+ u32 diag0val;
+- u32 doorbell;
++ u32 doorbell = 0;
+ int hard_reset_done = 0;
+ int count = 0;
+ u32 diag1val = 0;
+ MpiFwHeader_t *cached_fw; /* Pointer to FW */
++ u8 cb_idx;
+
+ /* Clear any existing interrupts */
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+
+ if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
++
++ if (!ignore)
++ return 0;
++
+ drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
+- "address=%p\n", ioc->name, __func__,
+- &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
++ "address=%p\n", ioc->name, __FUNCTION__, &ioc->chip->Doorbell,
++ &ioc->chip->Reset_1078));
+ CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
+ if (sleepFlag == CAN_SLEEP)
+ msleep(1);
+ else
+ mdelay(1);
+
++ /*
++ * Call each currently registered protocol IOC reset handler
++ * with pre-reset indication.
++ * NOTE: If we're doing _IOC_BRINGUP, there can be no
++ * MptResetHandlers[] registered yet.
++ */
++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
++ if (MptResetHandlers[cb_idx])
++ (*(MptResetHandlers[cb_idx]))(ioc, MPT_IOC_PRE_RESET);
++ }
++
+ for (count = 0; count < 60; count ++) {
+ doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
+ doorbell &= MPI_IOC_STATE_MASK;
+@@ -3709,9 +3879,15 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+ "looking for READY STATE: doorbell=%x"
+ " count=%d\n",
+ ioc->name, doorbell, count));
+- if (doorbell == MPI_IOC_STATE_READY) {
++
++ if (doorbell == MPI_IOC_STATE_READY)
+ return 1;
+- }
++
++ /*
++ * Early out for hard fault
++ */
++ if (count && doorbell == MPI_IOC_STATE_FAULT)
++ break;
+
+ /* wait 1 sec */
+ if (sleepFlag == CAN_SLEEP)
+@@ -3719,16 +3895,20 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+ else
+ mdelay(1000);
+ }
++
++ if (doorbell != MPI_IOC_STATE_READY)
++ printk(MYIOC_s_ERR_FMT "Failed to come READY after "
++ "reset! IocState=%x", ioc->name, doorbell);
+ return -1;
+ }
+
+ /* Use "Diagnostic reset" method! (only thing available!) */
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+
+- if (ioc->debug_level & MPT_DEBUG) {
++ if (ioc->debug_level & MPT_DEBUG_RESET) {
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
+ ioc->name, diag0val, diag1val));
+ }
+
+@@ -3748,11 +3928,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+
+ /* wait 100 msec */
+- if (sleepFlag == CAN_SLEEP) {
++ if (sleepFlag == CAN_SLEEP)
+ msleep (100);
+- } else {
++ else
+ mdelay (100);
+- }
+
+ count++;
+ if (count > 20) {
+@@ -3764,14 +3943,14 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+ ioc->name, diag0val));
+ }
+
+- if (ioc->debug_level & MPT_DEBUG) {
++ if (ioc->debug_level & MPT_DEBUG_RESET) {
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
+ ioc->name, diag0val, diag1val));
+ }
+ /*
+@@ -3787,7 +3966,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+ */
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
+ hard_reset_done = 1;
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
+ ioc->name));
+
+ /*
+@@ -3796,25 +3975,13 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+ * NOTE: If we're doing _IOC_BRINGUP, there can be no
+ * MptResetHandlers[] registered yet.
+ */
+- {
+- u8 cb_idx;
+- int r = 0;
+-
+- for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+- if (MptResetHandlers[cb_idx]) {
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "Calling IOC pre_reset handler #%d\n",
+- ioc->name, cb_idx));
+- r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
+- if (ioc->alt_ioc) {
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "Calling alt-%s pre_reset handler #%d\n",
+- ioc->name, ioc->alt_ioc->name, cb_idx));
+- r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
+- }
++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
++ if (MptResetHandlers[cb_idx]) {
++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
++ if (ioc->alt_ioc) {
++ mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
+ }
+ }
+- /* FIXME? Examine results here? */
+ }
+
+ if (ioc->cached_fw)
+@@ -3834,20 +4001,18 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+ break;
+ }
+
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
+ ioc->name, diag0val, count));
+ /* wait 1 sec */
+- if (sleepFlag == CAN_SLEEP) {
++ if (sleepFlag == CAN_SLEEP)
+ msleep (1000);
+- } else {
++ else
+ mdelay (1000);
+- }
+ }
+ if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
+ printk(MYIOC_s_WARN_FMT
+ "firmware downloadboot failure (%d)!\n", ioc->name, count);
+ }
+-
+ } else {
+ /* Wait for FW to reload and for board
+ * to go to the READY state.
+@@ -3859,25 +4024,38 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+ doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
+ doorbell &= MPI_IOC_STATE_MASK;
+
+- if (doorbell == MPI_IOC_STATE_READY) {
++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "looking for READY STATE: doorbell=%x"
++ " count=%d\n", ioc->name, doorbell, count));
++
++ if (doorbell == MPI_IOC_STATE_READY)
++ break;
++
++ /*
++ * Early out for hard fault
++ */
++ if (count && doorbell == MPI_IOC_STATE_FAULT)
+ break;
+- }
+
+ /* wait 1 sec */
+- if (sleepFlag == CAN_SLEEP) {
++ if (sleepFlag == CAN_SLEEP)
+ msleep (1000);
+- } else {
++ else
+ mdelay (1000);
+- }
+ }
++
++ if (doorbell != MPI_IOC_STATE_READY)
++ printk(MYIOC_s_ERR_FMT "Failed to come READY "
++ "after reset! IocState=%x", ioc->name,
++ doorbell);
+ }
+ }
+
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+- if (ioc->debug_level & MPT_DEBUG) {
++ if (ioc->debug_level & MPT_DEBUG_RESET) {
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
+ ioc->name, diag0val, diag1val));
+ }
+
+@@ -3898,11 +4076,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+
+ /* wait 100 msec */
+- if (sleepFlag == CAN_SLEEP) {
++ if (sleepFlag == CAN_SLEEP)
+ msleep (100);
+- } else {
++ else
+ mdelay (100);
+- }
+
+ count++;
+ if (count > 20) {
+@@ -3933,11 +4110,11 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+ return -3;
+ }
+
+- if (ioc->debug_level & MPT_DEBUG) {
++ if (ioc->debug_level & MPT_DEBUG_RESET) {
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
+- ioc->name, diag0val, diag1val));
++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
++ ioc->name, diag0val, diag1val));
+ }
+
+ /*
+@@ -3951,7 +4128,6 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+ return hard_reset_done;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * SendIocReset - Send IOCReset request to MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -3962,7 +4138,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign
+ * Send IOCReset request to the MPT adapter.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int
+ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
+ {
+@@ -3973,7 +4149,7 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_
+ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
+ ioc->name, reset_type));
+ CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
+- if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
++ if ((r = WaitForDoorbellAck(ioc, 15, sleepFlag)) < 0)
+ return r;
+
+ /* FW ACK'd request, wait for READY state
+@@ -3988,15 +4164,15 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_
+ if (sleepFlag != CAN_SLEEP)
+ count *= 10;
+
+- printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
+- ioc->name, (int)((count+5)/HZ));
++ printk(MYIOC_s_ERR_FMT "Wait IOC_READY state (0x%x) timeout(%d)!\n",
++ ioc->name, state, (int)((count+5)/HZ));
+ return -ETIME;
+ }
+
+ if (sleepFlag == CAN_SLEEP) {
+ msleep(1);
+ } else {
+- mdelay (1); /* 1 msec delay */
++ mdelay(1); /* 1 msec delay */
+ }
+ }
+
+@@ -4010,14 +4186,13 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * initChainBuffers - Allocate memory for and initialize chain buffers
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * Allocates memory for and initializes chain buffers,
+ * chain buffer control arrays and spinlock.
+- */
++ **/
+ static int
+ initChainBuffers(MPT_ADAPTER *ioc)
+ {
+@@ -4059,24 +4234,30 @@ initChainBuffers(MPT_ADAPTER *ioc)
+ * num_sge = num sge in request frame + last chain buffer
+ * scale = num sge per chain buffer if no chain element
+ */
+- scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+- if (sizeof(dma_addr_t) == sizeof(u64))
+- num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
++ scale = ioc->req_sz/ ioc->SGE_size;
++ if (ioc->sg_addr_size == sizeof(u64))
++ num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
+ else
+- num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
++ num_sge = 1+ scale + (ioc->req_sz - 64) / ioc->SGE_size;
+
+- if (sizeof(dma_addr_t) == sizeof(u64)) {
++ if (ioc->sg_addr_size == sizeof(u64)) {
+ numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
+- (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
++ (ioc->req_sz - 60) / ioc->SGE_size;
+ } else {
+ numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
+- (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
++ (ioc->req_sz - 64) / ioc->SGE_size;
+ }
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
+ ioc->name, num_sge, numSGE));
+
+- if ( numSGE > MPT_SCSI_SG_DEPTH )
+- numSGE = MPT_SCSI_SG_DEPTH;
++ if (ioc->bus_type == FC) {
++ if (numSGE > MPT_SCSI_FC_SG_DEPTH)
++ numSGE = MPT_SCSI_FC_SG_DEPTH;
++ }
++ else {
++ if (numSGE > MPT_SCSI_SG_DEPTH)
++ numSGE = MPT_SCSI_SG_DEPTH;
++ }
+
+ num_chain = 1;
+ while (numSGE - num_sge > 0) {
+@@ -4111,7 +4292,6 @@ initChainBuffers(MPT_ADAPTER *ioc)
+ return num_chain;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * PrimeIocFifos - Initialize IOC request and reply FIFOs.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -4121,7 +4301,7 @@ initChainBuffers(MPT_ADAPTER *ioc)
+ * reply frames.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int
+ PrimeIocFifos(MPT_ADAPTER *ioc)
+ {
+@@ -4130,13 +4310,36 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
+ dma_addr_t alloc_dma;
+ u8 *mem;
+ int i, reply_sz, sz, total_size, num_chain;
++ u64 dma_mask;
+
+- /* Prime reply FIFO... */
++ dma_mask = 0;
+
++ /* Prime reply FIFO... */
+ if (ioc->reply_frames == NULL) {
+ if ( (num_chain = initChainBuffers(ioc)) < 0)
+ return -1;
+
++ /*
++ * 1078 errata workaround for the 36GB limitation
++ */
++ if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
++ ioc->dma_mask > MPT_DMA_35BIT_MASK) {
++ if (!pci_set_dma_mask(ioc->pcidev, DMA_32BIT_MASK)
++ && !pci_set_consistent_dma_mask(ioc->pcidev,
++ DMA_32BIT_MASK)) {
++ dma_mask = MPT_DMA_35BIT_MASK;
++ d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "setting 35 bit addressing for "
++ "Request/Reply/Chain and Sense Buffers\n",
++ ioc->name));
++ } else {
++ d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "failed setting 35 bit addressing for "
++ "Request/Reply/Chain and Sense Buffers\n",
++ ioc->name));
++ }
++ }
++
+ total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
+ ioc->name, ioc->reply_sz, ioc->reply_depth));
+@@ -4274,9 +4477,16 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
+ alloc_dma += ioc->reply_sz;
+ }
+
++ if (dma_mask == MPT_DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
++ ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
++ ioc->dma_mask))
++ d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "restoring 64 bit addressing\n", ioc->name));
++
+ return 0;
+
+ out_fail:
++
+ if (ioc->alloc != NULL) {
+ sz = ioc->alloc_sz;
+ pci_free_consistent(ioc->pcidev,
+@@ -4293,10 +4503,16 @@ out_fail:
+ ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
+ ioc->sense_buf_pool = NULL;
+ }
++
++ if (dma_mask == MPT_DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
++ DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(ioc->pcidev,
++ DMA_64BIT_MASK))
++ d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "restoring 64 bit addressing\n", ioc->name));
++
+ return -1;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
+ * from IOC via doorbell handshake method.
+@@ -4314,7 +4530,7 @@ out_fail:
+ * greater than 1 byte in size.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int
+ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
+ int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
+@@ -4408,7 +4624,6 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER
+ return -failcnt;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -4420,7 +4635,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER
+ * bit in its IntStatus register being clear.
+ *
+ * Returns a negative value on failure, else wait loop count.
+- */
++ **/
+ static int
+ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
+ {
+@@ -4459,7 +4674,6 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int
+ return -1;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -4470,7 +4684,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int
+ * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
+ *
+ * Returns a negative value on failure, else wait loop count.
+- */
++ **/
+ static int
+ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
+ {
+@@ -4481,18 +4695,18 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int
+ cntdn = 1000 * howlong;
+ if (sleepFlag == CAN_SLEEP) {
+ while (--cntdn) {
++ msleep(1);
+ intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+ if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+ break;
+- msleep(1);
+ count++;
+ }
+ } else {
+ while (--cntdn) {
++ udelay (1000);
+ intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+ if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+ break;
+- udelay (1000);
+ count++;
+ }
+ }
+@@ -4508,7 +4722,6 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int
+ return -1;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -4520,7 +4733,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int
+ * of 128 bytes of reply data.
+ *
+ * Returns a negative value on failure, else size of reply in WORDS.
+- */
++ **/
+ static int
+ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
+ {
+@@ -4594,7 +4807,6 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i
+ return u16cnt/2;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * GetLanConfigPages - Fetch LANConfig pages.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -4604,7 +4816,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i
+ * -EPERM if not allowed due to ISR context
+ * -EAGAIN if no msg frames currently available
+ * -EFAULT for non-successful reply or no reply (timeout)
+- */
++ **/
+ static int
+ GetLanConfigPages(MPT_ADAPTER *ioc)
+ {
+@@ -4705,7 +4917,6 @@ GetLanConfigPages(MPT_ADAPTER *ioc)
+ return rc;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -4718,9 +4929,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc)
+ * NOTE: Don't use not this function during interrupt time.
+ *
+ * Returns 0 for success, non-zero error
+- */
+-
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++ **/
+ int
+ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
+ {
+@@ -4728,7 +4937,14 @@ mptbase_sas_persist_operation(MPT_ADAPTE
+ SasIoUnitControlReply_t *sasIoUnitCntrReply;
+ MPT_FRAME_HDR *mf = NULL;
+ MPIHeader_t *mpi_hdr;
++ int ret = 0;
++ unsigned long timeleft;
++
++ mutex_lock(&ioc->mptbase_cmds.mutex);
+
++ /* init the internal cmd struct */
++ memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
++ INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
+
+ /* insure garbage is not sent to fw */
+ switch(persist_opcode) {
+@@ -4738,17 +4954,18 @@ mptbase_sas_persist_operation(MPT_ADAPTE
+ break;
+
+ default:
+- return -1;
+- break;
++ ret = -1;
++ goto out;
+ }
+
+- printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
++ printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
+
+ /* Get a MF for this command.
+ */
+ if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
+- printk("%s: no msg frames!\n",__func__);
+- return -1;
++ printk("%s: no msg frames!\n",__FUNCTION__);
++ ret = -1;
++ goto out;
+ }
+
+ mpi_hdr = (MPIHeader_t *) mf;
+@@ -4758,31 +4975,44 @@ mptbase_sas_persist_operation(MPT_ADAPTE
+ sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
+ sasIoUnitCntrReq->Operation = persist_opcode;
+
+- init_timer(&ioc->persist_timer);
+- ioc->persist_timer.data = (unsigned long) ioc;
+- ioc->persist_timer.function = mpt_timer_expired;
+- ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
+- ioc->persist_wait_done=0;
+- add_timer(&ioc->persist_timer);
+ mpt_put_msg_frame(mpt_base_index, ioc, mf);
+- wait_event(mpt_waitq, ioc->persist_wait_done);
++ timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
++ if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ ret = -ETIME;
++ printk("%s: failed\n", __FUNCTION__);
++ if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
++ goto out;
++ if (!timeleft) {
++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
++ ioc->name, __FUNCTION__);
++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
++ mpt_HardResetHandler(ioc, CAN_SLEEP);
++ mpt_free_msg_frame(ioc, mf);
++ }
++ goto out;
++ }
++
++ if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
++ ret = -1;
++ goto out;
++ }
+
+ sasIoUnitCntrReply =
+- (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
++ (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
+ if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
+- printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
+- __func__,
+- sasIoUnitCntrReply->IOCStatus,
+- sasIoUnitCntrReply->IOCLogInfo);
+- return -1;
+- }
++ printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", __FUNCTION__,
++ sasIoUnitCntrReply->IOCStatus, sasIoUnitCntrReply->IOCLogInfo);
++ printk("%s: failed\n",__FUNCTION__);
++ ret = -1;
++ } else
++ printk("%s: success\n",__FUNCTION__);
++ out:
+
+- printk("%s: success\n",__func__);
+- return 0;
++ CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
++ mutex_unlock(&ioc->mptbase_cmds.mutex);
++ return ret;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-
+ static void
+ mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
+ MpiEventDataRaid_t * pRaidEventData)
+@@ -4913,7 +5143,6 @@ mptbase_raid_process_event_data(MPT_ADAP
+ }
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -4923,7 +5152,7 @@ mptbase_raid_process_event_data(MPT_ADAP
+ * -EPERM if not allowed due to ISR context
+ * -EAGAIN if no msg frames currently available
+ * -EFAULT for non-successful reply or no reply (timeout)
+- */
++ **/
+ static int
+ GetIoUnitPage2(MPT_ADAPTER *ioc)
+ {
+@@ -4971,7 +5200,6 @@ GetIoUnitPage2(MPT_ADAPTER *ioc)
+ return rc;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
+ * @ioc: Pointer to a Adapter Strucutre
+@@ -4991,7 +5219,7 @@ GetIoUnitPage2(MPT_ADAPTER *ioc)
+ * Both valid
+ * Return 0
+ * CHECK - what type of locking mechanisms should be used????
+- */
++ **/
+ static int
+ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
+ {
+@@ -5051,8 +5279,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc
+ ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
+ rc = 1;
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "Unable to read PortPage0 minSyncFactor=%x\n",
+- ioc->name, ioc->spi_data.minSyncFactor));
++ "Unable to read PortPage0 minSyncFactor=%x\n",
++ ioc->name, ioc->spi_data.minSyncFactor));
+ } else {
+ /* Save the Port Page 0 data
+ */
+@@ -5062,8 +5290,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc
+
+ if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
+ ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
+- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "noQas due to Capabilities=%x\n",
++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "noQas due to Capabilities=%x\n",
+ ioc->name, pPP0->Capabilities));
+ }
+ ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
+@@ -5072,8 +5299,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc
+ ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
+ data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
+ ioc->spi_data.minSyncFactor = (u8) (data >> 8);
+- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "PortPage0 minSyncFactor=%x\n",
++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PortPage0 minSyncFactor=%x\n",
+ ioc->name, ioc->spi_data.minSyncFactor));
+ } else {
+ ioc->spi_data.maxSyncOffset = 0;
+@@ -5089,8 +5315,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc
+
+ if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
+ ioc->spi_data.minSyncFactor = MPT_ULTRA;
+- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "HVD or SE detected, minSyncFactor=%x\n",
++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HVD or SE detected, minSyncFactor=%x\n",
+ ioc->name, ioc->spi_data.minSyncFactor));
+ }
+ }
+@@ -5195,7 +5420,6 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc
+ return rc;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_readScsiDevicePageHeaders - save version and length of SDP1
+ * @ioc: Pointer to a Adapter Strucutre
+@@ -5203,7 +5427,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc
+ *
+ * Return: -EFAULT if read of config page header fails
+ * or 0 if success.
+- */
++ **/
+ static int
+ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
+ {
+@@ -5246,9 +5470,73 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTE
+ return 0;
+ }
+
++static void
++mpt_read_ioc_pg_6(MPT_ADAPTER *ioc)
++{
++ CONFIGPARMS cfg;
++ ConfigPageHeader_t header;
++ IOCPage6_t *pIoc6=NULL;
++ dma_addr_t ioc6_dma;
++ int iocpage6sz;
++ void *mem;
++
++ /* Free the old page
++ */
++ if (ioc->raid_data.pIocPg6) {
++ kfree(ioc->raid_data.pIocPg6);
++ ioc->raid_data.pIocPg6 = NULL;
++ }
++
++ /* There is at least one physical disk.
++ * Read and save IOC Page 3
++ */
++ header.PageVersion = 0;
++ header.PageLength = 0;
++ header.PageNumber = 6;
++ header.PageType = MPI_CONFIG_PAGETYPE_IOC;
++ cfg.cfghdr.hdr = &header;
++ cfg.physAddr = -1;
++ cfg.pageAddr = 0;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0;
++ cfg.timeout = 0;
++ if (mpt_config(ioc, &cfg) != 0)
++ goto out;
++
++ if (header.PageLength == 0)
++ goto out;
++
++ /* Read Header good, alloc memory
++ */
++ iocpage6sz = header.PageLength * 4;
++ pIoc6 = pci_alloc_consistent(ioc->pcidev, iocpage6sz, &ioc6_dma);
++ if (!pIoc6)
++ goto out;
++
++ /* Read the Page and save the data
++ * into malloc'd memory.
++ */
++ cfg.physAddr = ioc6_dma;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ if (mpt_config(ioc, &cfg) != 0)
++ goto out;
++
++ mem = kmalloc(iocpage6sz, GFP_ATOMIC);
++ if (!mem)
++ goto out;
++
++ memcpy(mem, pIoc6, iocpage6sz);
++ ioc->raid_data.pIocPg6 = mem;
++
++ out:
++ if (pIoc6)
++ pci_free_consistent(ioc->pcidev, iocpage6sz, pIoc6, ioc6_dma);
++}
++
+ /**
+- * mpt_inactive_raid_list_free - This clears this link list.
+- * @ioc : pointer to per adapter structure
++ * mpt_inactive_raid_list_free - This clears this link list.
++ * @ioc : pointer to per adapter structure
++ *
+ **/
+ static void
+ mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
+@@ -5258,21 +5546,23 @@ mpt_inactive_raid_list_free(MPT_ADAPTER
+ if (list_empty(&ioc->raid_data.inactive_list))
+ return;
+
+- mutex_lock(&ioc->raid_data.inactive_list_mutex);
++ down(&ioc->raid_data.inactive_list_mutex);
+ list_for_each_entry_safe(component_info, pNext,
+ &ioc->raid_data.inactive_list, list) {
+ list_del(&component_info->list);
+ kfree(component_info);
+ }
+- mutex_unlock(&ioc->raid_data.inactive_list_mutex);
++ up(&ioc->raid_data.inactive_list_mutex);
+ }
+
+ /**
+- * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume
+- *
+- * @ioc : pointer to per adapter structure
+- * @channel : volume channel
+- * @id : volume target id
++ * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums
++ * for devices belonging in an inactive volume
++ *
++ * @ioc : pointer to per adapter structure
++ * @channel : volume channel
++ * @id : volume target id
++ *
+ **/
+ static void
+ mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
+@@ -5281,10 +5571,12 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i
+ ConfigPageHeader_t hdr;
+ dma_addr_t dma_handle;
+ pRaidVolumePage0_t buffer = NULL;
+- int i;
++ int i, j;
+ RaidPhysDiskPage0_t phys_disk;
++ RaidPhysDiskPage1_t *phys_disk_1;
+ struct inactive_raid_component_info *component_info;
+ int handle_inactive_volumes;
++ int num_paths, device_is_online;
+
+ memset(&cfg, 0 , sizeof(CONFIGPARMS));
+ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+@@ -5323,14 +5615,37 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i
+ if (!handle_inactive_volumes)
+ goto out;
+
+- mutex_lock(&ioc->raid_data.inactive_list_mutex);
++ down(&ioc->raid_data.inactive_list_mutex);
+ for (i = 0; i < buffer->NumPhysDisks; i++) {
+ if(mpt_raid_phys_disk_pg0(ioc,
+ buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
+ continue;
+
++ if (phys_disk.PhysDiskStatus.State !=
++ MPI_PHYSDISK0_STATUS_ONLINE)
++ continue;
++
++ /* check to see if device is online by checking phys_disk_pg1 */
++ device_is_online = 0;
++ num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
++ buffer->PhysDisk[i].PhysDiskNum);
++ if (num_paths < 2)
++ continue;
++ phys_disk_1 = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) +
++ (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
++ if (!phys_disk_1)
++ continue;
++ mpt_raid_phys_disk_pg1(ioc, buffer->PhysDisk[i].PhysDiskNum,
++ phys_disk_1);
++ for (j = 0; j < num_paths && !device_is_online; j++)
++ if (!phys_disk_1->Path[j].Flags)
++ device_is_online = 1;
++ kfree(phys_disk_1);
++ if (!device_is_online)
++ continue;
++
+ if ((component_info = kmalloc(sizeof (*component_info),
+- GFP_KERNEL)) == NULL)
++ GFP_KERNEL)) == NULL)
+ continue;
+
+ component_info->volumeID = id;
+@@ -5343,7 +5658,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i
+ list_add_tail(&component_info->list,
+ &ioc->raid_data.inactive_list);
+ }
+- mutex_unlock(&ioc->raid_data.inactive_list_mutex);
++ up(&ioc->raid_data.inactive_list_mutex);
+
+ out:
+ if (buffer)
+@@ -5363,7 +5678,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i
+ * -ENOMEM if pci_alloc failed
+ **/
+ int
+-mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
++mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, RaidPhysDiskPage0_t *phys_disk)
+ {
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t hdr;
+@@ -5373,7 +5688,9 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc,
+
+ memset(&cfg, 0 , sizeof(CONFIGPARMS));
+ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
++ memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
+
++ hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+ cfg.cfghdr.hdr = &hdr;
+ cfg.physAddr = -1;
+@@ -5420,6 +5737,181 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc,
+ }
+
+ /**
++ * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
++ * @ioc: Pointer to a Adapter Structure
++ * @phys_disk_num: io unit unique phys disk num generated by the ioc
++ *
++ * Return:
++ * returns number paths
++ **/
++int
++mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
++{
++ CONFIGPARMS cfg;
++ ConfigPageHeader_t hdr;
++ dma_addr_t dma_handle;
++ pRaidPhysDiskPage1_t buffer = NULL;
++ int rc;
++
++ memset(&cfg, 0 , sizeof(CONFIGPARMS));
++ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
++
++ hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
++ hdr.PageNumber = 1;
++ cfg.cfghdr.hdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++
++ if (mpt_config(ioc, &cfg) != 0) {
++ rc = 0;
++ goto out;
++ }
++
++ if (!hdr.PageLength) {
++ rc = 0;
++ goto out;
++ }
++
++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
++ &dma_handle);
++
++ if (!buffer) {
++ rc = 0;
++ goto out;
++ }
++
++ cfg.physAddr = dma_handle;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ cfg.pageAddr = phys_disk_num;
++
++ if (mpt_config(ioc, &cfg) != 0) {
++ rc = 0;
++ goto out;
++ }
++
++ rc = buffer->NumPhysDiskPaths;
++ out:
++
++ if (buffer)
++ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
++ dma_handle);
++
++ return rc;
++}
++
++/**
++ * mpt_raid_phys_disk_pg1 - returns phys disk page 1
++ * @ioc: Pointer to a Adapter Structure
++ * @phys_disk_num: io unit unique phys disk num generated by the ioc
++ * @phys_disk: requested payload data returned
++ *
++ * Return:
++ * 0 on success
++ * -EFAULT if read of config page header fails or data pointer not NULL
++ * -ENOMEM if pci_alloc failed
++ **/
++int
++mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, RaidPhysDiskPage1_t *phys_disk)
++{
++ CONFIGPARMS cfg;
++ ConfigPageHeader_t hdr;
++ dma_addr_t dma_handle;
++ pRaidPhysDiskPage1_t buffer = NULL;
++ int rc;
++ int i;
++ __le64 sas_address;
++
++ memset(&cfg, 0 , sizeof(CONFIGPARMS));
++ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
++ rc = 0;
++
++ hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
++ hdr.PageNumber = 1;
++ cfg.cfghdr.hdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++
++ if (mpt_config(ioc, &cfg) != 0) {
++ rc = -EFAULT;
++ goto out;
++ }
++
++ if (!hdr.PageLength) {
++ rc = -EFAULT;
++ goto out;
++ }
++
++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
++ &dma_handle);
++
++ if (!buffer) {
++ rc = -ENOMEM;
++ goto out;
++ }
++
++ cfg.physAddr = dma_handle;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ cfg.pageAddr = phys_disk_num;
++
++ if (mpt_config(ioc, &cfg) != 0) {
++ rc = -EFAULT;
++ goto out;
++ }
++
++ phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
++ phys_disk->PhysDiskNum = phys_disk_num;
++ for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
++ phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
++ phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
++ phys_disk->Path[i].OwnerIdentifier = buffer->Path[i].OwnerIdentifier;
++ phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
++ memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
++ sas_address = le64_to_cpu(sas_address);
++ memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
++ memcpy(&sas_address, &buffer->Path[i].OwnerWWID, sizeof(__le64));
++ sas_address = le64_to_cpu(sas_address);
++ memcpy(&phys_disk->Path[i].OwnerWWID, &sas_address, sizeof(__le64));
++ }
++
++ out:
++
++ if (buffer)
++ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
++ dma_handle);
++
++ return rc;
++}
++
++/**
++ * mpt_sort_ioc_pg2 - compare function for sorting volumes
++ * in ascending order
++ * @a: ioc_pg2 raid volume page
++ * @b: ioc_pg2 raid volume page
++ *
++ * Return:
++ * 0 same, 1 (a is bigger), -1 (b is bigger)
++ **/
++static int
++mpt_sort_ioc_pg2(const void *a, const void *b)
++{
++ ConfigPageIoc2RaidVol_t * volume_a = (ConfigPageIoc2RaidVol_t *)a;
++ ConfigPageIoc2RaidVol_t * volume_b = (ConfigPageIoc2RaidVol_t *)b;
++
++ if (volume_a->VolumeBus == volume_b->VolumeBus) {
++ if (volume_a->VolumeID == volume_b->VolumeID)
++ return 0;
++ if (volume_a->VolumeID < volume_b->VolumeID)
++ return -1;
++ return 1;
++ }
++ if (volume_a->VolumeBus < volume_b->VolumeBus)
++ return -1;
++ return 1;
++}
++
++/**
+ * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
+ * @ioc: Pointer to a Adapter Strucutre
+ * @portnum: IOC port number
+@@ -5482,16 +5974,22 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
+ if (!mem)
+ goto out;
+
++ /*
++ * sort volumes in ascending order
++ */
++ sort(pIoc2->RaidVolume, pIoc2->NumActiveVolumes,
++ sizeof(ConfigPageIoc2RaidVol_t), mpt_sort_ioc_pg2, NULL);
+ memcpy(mem, (u8 *)pIoc2, iocpage2sz);
+ ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
+
+- mpt_read_ioc_pg_3(ioc);
+-
+ for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
+ mpt_inactive_raid_volumes(ioc,
+ pIoc2->RaidVolume[i].VolumeBus,
+ pIoc2->RaidVolume[i].VolumeID);
+
++ mpt_read_ioc_pg_3(ioc);
++ mpt_read_ioc_pg_6(ioc);
++
+ out:
+ pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
+
+@@ -5651,6 +6149,9 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ if (mpt_config(ioc, &cfg) == 0) {
+
++#if defined(CPQ_CIM)
++ ioc->pci_slot_number = pIoc1->PCISlotNum;
++#endif
+ tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
+ if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
+ tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
+@@ -5671,19 +6172,16 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
+
+ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+ if (mpt_config(ioc, &cfg) == 0) {
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "Reset NVRAM Coalescing Timeout to = %d\n",
++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
+ ioc->name, MPT_COALESCING_TIMEOUT));
+ } else {
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "Reset NVRAM Coalescing Timeout Failed\n",
+- ioc->name));
++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset NVRAM Coalescing Timeout Failed\n",
++ ioc->name));
+ }
+
+ } else {
+- dprintk(ioc, printk(MYIOC_s_WARN_FMT
+- "Reset of Current Coalescing Timeout Failed!\n",
+- ioc->name));
++ dprintk(ioc, printk(MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
++ ioc->name));
+ }
+ }
+
+@@ -5740,43 +6238,39 @@ mpt_get_manufacturing_pg_0(MPT_ADAPTER *
+ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * SendEventNotification - Send EventNotification (on or off) request to adapter
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @EvSwitch: Event switch flags
+- */
++ * @sleepFlag: Specifies whether the process can sleep
++ **/
+ static int
+-SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
++SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
+ {
+- EventNotification_t *evnp;
+-
+- evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
+- if (evnp == NULL) {
+- devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
+- ioc->name));
+- return 0;
+- }
+- memset(evnp, 0, sizeof(*evnp));
++ EventNotification_t evn;
++ MPIDefaultReply_t reply_buf;
+
+- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
++ memset(&evn, 0, sizeof(EventNotification_t));
++ memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
+
+- evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
+- evnp->ChainOffset = 0;
+- evnp->MsgFlags = 0;
+- evnp->Switch = EvSwitch;
++ evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
++ evn.Switch = EvSwitch;
++ evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
+
+- mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
++ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "Sending EventNotification (%d) request %p\n",
++ ioc->name, EvSwitch, &evn));
+
+- return 0;
++ return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
++ (u32*)&evn, sizeof(MPIDefaultReply_t), (u16*)&reply_buf, 30,
++ sleepFlag);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * SendEventAck - Send EventAck request to MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @evnp: Pointer to original EventNotification request
+- */
++ **/
+ static int
+ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
+ {
+@@ -5784,7 +6278,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNoti
+
+ if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
+- ioc->name,__func__));
++ ioc->name,__FUNCTION__));
+ return -1;
+ }
+
+@@ -5803,7 +6297,6 @@ SendEventAck(MPT_ADAPTER *ioc, EventNoti
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_config - Generic function to issue config message
+ * @ioc: Pointer to an adapter structure
+@@ -5816,35 +6309,62 @@ SendEventAck(MPT_ADAPTER *ioc, EventNoti
+ * -EPERM if not allowed due to ISR context
+ * -EAGAIN if no msg frames currently available
+ * -EFAULT for non-successful reply or no reply (timeout)
+- */
++ **/
+ int
+ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
+ {
+ Config_t *pReq;
++ ConfigReply_t *pReply;
+ ConfigExtendedPageHeader_t *pExtHdr = NULL;
+ MPT_FRAME_HDR *mf;
+- unsigned long flags;
+- int ii, rc;
++ int ii;
+ int flagsLength;
+- int in_isr;
++ long timeout;
++ int ret;
++ u8 page_type = 0, extend_page;
++ unsigned long timeleft;
++ unsigned long flags;
++ u8 issue_hard_reset = 0;
++ u8 retry_count = 0;
+
+- /* Prevent calling wait_event() (below), if caller happens
+- * to be in ISR context, because that is fatal!
+- */
+- in_isr = in_interrupt();
+- if (in_isr) {
+- dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
+- ioc->name));
++ if (in_interrupt())
+ return -EPERM;
++
++ /* don't send a config page during diag reset */
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
++ if (ioc->ioc_reset_in_progress) {
++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: busy with host reset\n", ioc->name, __FUNCTION__));
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
++ return -EBUSY;
++ }
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
++
++ /* don't send if no chance of success */
++ if (!ioc->active ||
++ mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: ioc not operational, %d, %xh\n",
++ ioc->name, __FUNCTION__, ioc->active,
++ mpt_GetIocState(ioc, 0)));
++ return -EFAULT;
+ }
+
++ retry_config:
++ mutex_lock(&ioc->mptbase_cmds.mutex);
++ /* init the internal cmd struct */
++ memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
++ INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
++
+ /* Get and Populate a free Frame
+ */
+ if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
+- dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
+- ioc->name));
+- return -EAGAIN;
++ dcprintk(ioc, printk(MYIOC_s_WARN_FMT
++ "mpt_config: no msg frames!\n", ioc->name));
++ ret = -EAGAIN;
++ goto out;
+ }
++
+ pReq = (Config_t *)mf;
+ pReq->Action = pCfg->action;
+ pReq->Reserved = 0;
+@@ -5870,7 +6390,9 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS
+ pReq->ExtPageType = pExtHdr->ExtPageType;
+ pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+
+- /* Page Length must be treated as a reserved field for the extended header. */
++ /* Page Length must be treated as a reserved field for the
++ * extended header.
++ */
+ pReq->Header.PageLength = 0;
+ }
+
+@@ -5883,126 +6405,126 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS
+ else
+ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+
+- if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
++ if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
++ MPI_CONFIG_PAGETYPE_EXTENDED) {
+ flagsLength |= pExtHdr->ExtPageLength * 4;
+-
+- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
+- ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
+- }
+- else {
++ page_type = pReq->ExtPageType;
++ extend_page = 1;
++ } else {
+ flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
+-
+- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
+- ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
++ page_type = pReq->Header.PageType;
++ extend_page = 0;
+ }
+
+- mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
++ dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "Sending Config request type 0x%x, page 0x%x and action %d\n",
++ ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
+
+- /* Append pCfg pointer to end of mf
+- */
+- *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
+-
+- /* Initalize the timer
+- */
+- init_timer(&pCfg->timer);
+- pCfg->timer.data = (unsigned long) ioc;
+- pCfg->timer.function = mpt_timer_expired;
+- pCfg->wait_done = 0;
+-
+- /* Set the timer; ensure 10 second minimum */
+- if (pCfg->timeout < 10)
+- pCfg->timer.expires = jiffies + HZ*10;
+- else
+- pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
+-
+- /* Add to end of Q, set timer and then issue this command */
+- spin_lock_irqsave(&ioc->FreeQlock, flags);
+- list_add_tail(&pCfg->linkage, &ioc->configQ);
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+-
+- add_timer(&pCfg->timer);
++ ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
++ timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
+ mpt_put_msg_frame(mpt_base_index, ioc, mf);
+- wait_event(mpt_waitq, pCfg->wait_done);
+-
+- /* mf has been freed - do not access */
+-
+- rc = pCfg->status;
++ timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, timeout);
++ if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ ret = -ETIME;
++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "Failed Sending Config request type 0x%x, page 0x%x,"
++ " action %d, status %xh, time left %ld\n\n",
++ ioc->name, page_type, pReq->Header.PageNumber,
++ pReq->Action, ioc->mptbase_cmds.status, timeleft));
++ if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
++ goto out;
++ if (!timeleft)
++ issue_hard_reset = 1;
++ goto out;
++ }
+
+- return rc;
+-}
++ if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
++ ret = -1;
++ goto out;
++ }
++ pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
++ ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
++ if (ret == MPI_IOCSTATUS_SUCCESS) {
++ if (extend_page) {
++ pCfg->cfghdr.ehdr->ExtPageLength =
++ le16_to_cpu(pReply->ExtPageLength);
++ pCfg->cfghdr.ehdr->ExtPageType =
++ pReply->ExtPageType;
++ }
++ pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
++ pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
++ pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
++ pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/**
+- * mpt_timer_expired - Callback for timer process.
+- * Used only internal config functionality.
+- * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+- */
+-static void
+-mpt_timer_expired(unsigned long data)
+-{
+- MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
++ }
+
+- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
++ if (retry_count)
++ printk(MYIOC_s_INFO_FMT "Retry completed ret=0x%x timeleft=%ld\n",
++ ioc->name, ret, timeleft);
+
+- /* Perform a FW reload */
+- if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
+- printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
++ dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
++ ret, le32_to_cpu(pReply->IOCLogInfo)));
+
+- /* No more processing.
+- * Hard reset clean-up will wake up
+- * process and free all resources.
+- */
+- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
++ out:
+
+- return;
++ CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
++ mutex_unlock(&ioc->mptbase_cmds.mutex);
++ if (issue_hard_reset) {
++ issue_hard_reset = 0;
++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
++ ioc->name, __FUNCTION__);
++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
++ mpt_HardResetHandler(ioc, CAN_SLEEP);
++ mpt_free_msg_frame(ioc, mf);
++ /* attempt one retry for a timed out command */
++ if (!retry_count) {
++ printk(MYIOC_s_INFO_FMT
++ "Attempting Retry Config request type 0x%x, page 0x%x,"
++ " action %d\n", ioc->name, page_type,
++ pCfg->cfghdr.hdr->PageNumber, pCfg->action);
++ retry_count++;
++ goto retry_config;
++ }
++ }
++ return ret;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/**
+- * mpt_ioc_reset - Base cleanup for hard reset
+- * @ioc: Pointer to the adapter structure
+- * @reset_phase: Indicates pre- or post-reset functionality
+- *
+- * Remark: Frees resources with internally generated commands.
+- */
+-static int
+-mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+-{
+- CONFIGPARMS *pCfg;
+- unsigned long flags;
+-
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- ": IOC %s_reset routed to MPT base driver!\n",
+- ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+-
+- if (reset_phase == MPT_IOC_SETUP_RESET) {
+- ;
+- } else if (reset_phase == MPT_IOC_PRE_RESET) {
+- /* If the internal config Q is not empty -
+- * delete timer. MF resources will be freed when
+- * the FIFO's are primed.
+- */
+- spin_lock_irqsave(&ioc->FreeQlock, flags);
+- list_for_each_entry(pCfg, &ioc->configQ, linkage)
+- del_timer(&pCfg->timer);
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+-
+- } else {
+- CONFIGPARMS *pNext;
+-
+- /* Search the configQ for internal commands.
+- * Flush the Q, and wake up all suspended threads.
+- */
+- spin_lock_irqsave(&ioc->FreeQlock, flags);
+- list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
+- list_del(&pCfg->linkage);
+-
+- pCfg->status = MPT_CONFIG_ERROR;
+- pCfg->wait_done = 1;
+- wake_up(&mpt_waitq);
++/**
++ * mpt_ioc_reset - Base cleanup for hard reset
++ * @ioc: Pointer to the adapter structure
++ * @reset_phase: Indicates pre- or post-reset functionality
++ *
++ * Remark: Frees resources with internally generated commands.
++ **/
++static int
++mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
++{
++ switch(reset_phase) {
++ case MPT_IOC_SETUP_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
++ ioc->taskmgmt_quiesce_io = 1;
++ break;
++ case MPT_IOC_PRE_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
++ break;
++ case MPT_IOC_POST_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__));
++/* wake up mptbase_cmds */
++ if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
++ ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
++ complete(&ioc->mptbase_cmds.done);
++ }
++/* wake up taskmgmt_cmds */
++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
++ complete(&ioc->taskmgmt_cmds.done);
+ }
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
++ break;
++ default:
++ break;
+ }
+
+ return 1; /* currently means nothing really */
+@@ -6010,16 +6532,11 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int rese
+
+
+ #ifdef CONFIG_PROC_FS /* { */
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
+- * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
+- */
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int
+ procmpt_create(void)
+ {
+@@ -6040,12 +6557,11 @@ procmpt_create(void)
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static void
+ procmpt_destroy(void)
+ {
+@@ -6054,7 +6570,6 @@ procmpt_destroy(void)
+ remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * procmpt_summary_read - Handle read request of a summary file
+ * @buf: Pointer to area to write information
+@@ -6066,7 +6581,7 @@ procmpt_destroy(void)
+ *
+ * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
+ * Returns number of characters written to process performing the read.
+- */
++ **/
+ static int
+ procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
+ {
+@@ -6098,7 +6613,6 @@ procmpt_summary_read(char *buf, char **s
+ MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * procmpt_version_read - Handle read request from /proc/mpt/version.
+ * @buf: Pointer to area to write information
+@@ -6109,7 +6623,7 @@ procmpt_summary_read(char *buf, char **s
+ * @data: Pointer
+ *
+ * Returns number of characters written to process performing the read.
+- */
++ **/
+ static int
+ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
+ {
+@@ -6154,7 +6668,6 @@ procmpt_version_read(char *buf, char **s
+ MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
+ * @buf: Pointer to area to write information
+@@ -6165,7 +6678,7 @@ procmpt_version_read(char *buf, char **s
+ * @data: Pointer
+ *
+ * Returns number of characters written to process performing the read.
+- */
++ **/
+ static int
+ procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
+ {
+@@ -6251,7 +6764,6 @@ procmpt_iocinfo_read(char *buf, char **s
+
+ #endif /* CONFIG_PROC_FS } */
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ static void
+ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
+ {
+@@ -6267,7 +6779,6 @@ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTE
+ }
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -6278,7 +6789,7 @@ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTE
+ *
+ * This routine writes (english readable) ASCII text, which represents
+ * a summary of IOC information, to a buffer.
+- */
++ **/
+ void
+ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
+ {
+@@ -6319,6 +6830,220 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc,
+ /*
+ * Reset Handling
+ */
++
++/**
++ * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment
++ * @ioc: Pointer to MPT_ADAPTER structure
++ *
++ * Returns 0 for SUCCESS or -1 if FAILED.
++ *
++ * If -1 is return, then it was not possible to set the flags
++ **/
++int
++mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
++{
++ unsigned long flags;
++ int retval;
++
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
++ if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
++ (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
++ retval = -1;
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
++ goto out;
++ }
++ retval = 0;
++ ioc->taskmgmt_in_progress = 1;
++ ioc->taskmgmt_quiesce_io = 1;
++ if (ioc->alt_ioc) {
++ ioc->alt_ioc->taskmgmt_in_progress = 1;
++ ioc->alt_ioc->taskmgmt_quiesce_io = 1;
++ }
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
++
++ out:
++ return retval;
++}
++
++/**
++ * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment
++ * @ioc: Pointer to MPT_ADAPTER structure
++ *
++ **/
++void
++mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
++ ioc->taskmgmt_in_progress = 0;
++ ioc->taskmgmt_quiesce_io = 0;
++ if (ioc->alt_ioc) {
++ ioc->alt_ioc->taskmgmt_in_progress = 0;
++ ioc->alt_ioc->taskmgmt_quiesce_io = 0;
++ }
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
++}
++
++/**
++ * mpt_halt_firmware - Halts the firmware if it is operational and panic
++ * the kernel
++ * @ioc: Pointer to MPT_ADAPTER structure
++ *
++ **/
++void
++mpt_halt_firmware(MPT_ADAPTER *ioc)
++{
++ u32 ioc_raw_state;
++
++ ioc_raw_state = mpt_GetIocState(ioc, 0);
++
++ if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
++ printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
++ ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
++ if(mpt_fwfault_debug == 2)
++ for(;;);
++ else
++ panic("%s: IOC Fault (%04xh)!!!\n",ioc->name,
++ ioc_raw_state & MPI_DOORBELL_DATA_MASK);
++ } else {
++ CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
++ if(mpt_fwfault_debug == 2) {
++ printk("%s: Firmware is halted due to command timeout\n"
++ ,ioc->name);
++ for(;;);
++ }
++ else
++ panic("%s: Firmware is halted due to command timeout\n",
++ ioc->name);
++ }
++}
++
++/**
++ * mpt_SoftResetHandler - Issues a less expensive reset
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @sleepFlag: Indicates if sleep or schedule must be called.
++
++ *
++ * Returns 0 for SUCCESS or -1 if FAILED.
++ *
++ * Message Unit Reset - instructs the IOC to reset the Reply Post and
++ * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
++ * All posted buffers are freed, and event notification is turned off.
++ * IOC doesnt reply to any outstanding request. This will transfer IOC
++ * to READY state.
++ **/
++int
++mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
++{
++ int rc;
++ int ii;
++ u8 cb_idx;
++ unsigned long flags;
++ u32 ioc_state;
++ unsigned long time_count;
++
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n", ioc->name));
++
++ ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
++
++ if(mpt_fwfault_debug)
++ mpt_halt_firmware(ioc);
++
++ if (ioc_state == MPI_IOC_STATE_FAULT || ioc_state == MPI_IOC_STATE_RESET) {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "skipping, either in FAULT or RESET state!\n", ioc->name));
++ return -1;
++ }
++
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
++ if (ioc->ioc_reset_in_progress) {
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
++ return -1;
++ }
++ ioc->ioc_reset_in_progress = 1;
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
++
++ rc = -1;
++
++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
++ if (MptResetHandlers[cb_idx])
++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
++ }
++
++ /* Disable reply interrupts (also blocks FreeQ) */
++ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
++ ioc->active = 0;
++ time_count = jiffies;
++
++ rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
++
++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
++ if (MptResetHandlers[cb_idx])
++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
++ }
++
++ if (rc)
++ goto out;
++
++ ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
++ if (ioc_state != MPI_IOC_STATE_READY)
++ goto out;
++
++ for (ii = 0; ii < 5; ii++) {
++ /* Get IOC facts! Allow 5 retries */
++ if ((rc = GetIocFacts(ioc, sleepFlag,
++ MPT_HOSTEVENT_IOC_RECOVER)) == 0)
++ break;
++ if (sleepFlag == CAN_SLEEP) {
++ msleep(100);
++ } else {
++ mdelay(100);
++ }
++ }
++ if (ii == 5)
++ goto out;
++
++ if ((rc = PrimeIocFifos(ioc)) != 0)
++ goto out;
++
++ if ((rc = SendIocInit(ioc, sleepFlag)) != 0)
++ goto out;
++
++ if ((rc = SendEventNotification(ioc, 1, sleepFlag)) != 0)
++ goto out;
++
++ if (ioc->hard_resets < -1)
++ ioc->hard_resets++;
++
++ /*
++ * At this point, we know soft reset succeeded.
++ */
++
++ ioc->active = 1;
++ CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
++
++ out:
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
++ ioc->ioc_reset_in_progress = 0;
++ ioc->taskmgmt_quiesce_io = 0;
++ ioc->taskmgmt_in_progress = 0;
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
++
++ if (ioc->active) { /* otherwise, hard reset coming */
++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
++ if (MptResetHandlers[cb_idx])
++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
++ }
++ }
++
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler: completed (%d seconds): %s\n",
++ ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
++ ((rc == 0) ? "SUCCESS" : "FAILED")));
++
++ return rc;
++}
++
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_HardResetHandler - Generic reset handler
+@@ -6335,12 +7060,14 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc,
+ * FW reload/initialization failed.
+ *
+ * Returns 0 for SUCCESS or -1 if FAILED.
+- */
++ **/
+ int
+ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
+ {
+- int rc;
++ int rc;
++ u8 cb_idx;
+ unsigned long flags;
++ unsigned long time_count;
+
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
+ #ifdef MFCNT
+@@ -6348,67 +7075,82 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i
+ printk("MF count 0x%x !\n", ioc->mfcnt);
+ #endif
+
++ if(mpt_fwfault_debug)
++ mpt_halt_firmware(ioc);
++
+ /* Reset the adapter. Prevent more than 1 call to
+ * mpt_do_ioc_recovery at any instant in time.
+ */
+- spin_lock_irqsave(&ioc->diagLock, flags);
+- if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
+- spin_unlock_irqrestore(&ioc->diagLock, flags);
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
++ if (ioc->ioc_reset_in_progress) {
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+ return 0;
+- } else {
+- ioc->diagPending = 1;
+ }
+- spin_unlock_irqrestore(&ioc->diagLock, flags);
++ ioc->ioc_reset_in_progress = 1;
++ if (ioc->alt_ioc)
++ ioc->alt_ioc->ioc_reset_in_progress = 1;
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+- /* FIXME: If do_ioc_recovery fails, repeat....
+- */
+
+ /* The SCSI driver needs to adjust timeouts on all current
+ * commands prior to the diagnostic reset being issued.
+ * Prevents timeouts occurring during a diagnostic reset...very bad.
+ * For all other protocol drivers, this is a no-op.
+ */
+- {
+- u8 cb_idx;
+- int r = 0;
+-
+- for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+- if (MptResetHandlers[cb_idx]) {
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
+- ioc->name, cb_idx));
+- r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
+- if (ioc->alt_ioc) {
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
+- ioc->name, ioc->alt_ioc->name, cb_idx));
+- r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
+- }
+- }
++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
++ if (MptResetHandlers[cb_idx]) {
++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
++ if (ioc->alt_ioc)
++ mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
+ }
+ }
+
++ time_count = jiffies;
+ if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
+- printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
++ printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
++ rc, ioc->name);
++ } else {
++ if (ioc->hard_resets < -1)
++ ioc->hard_resets++;
+ }
+- ioc->reload_fw = 0;
+- if (ioc->alt_ioc)
+- ioc->alt_ioc->reload_fw = 0;
+
+- spin_lock_irqsave(&ioc->diagLock, flags);
+- ioc->diagPending = 0;
+- if (ioc->alt_ioc)
+- ioc->alt_ioc->diagPending = 0;
+- spin_unlock_irqrestore(&ioc->diagLock, flags);
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
++ ioc->ioc_reset_in_progress = 0;
++ ioc->taskmgmt_quiesce_io = 0;
++ ioc->taskmgmt_in_progress = 0;
++ if (ioc->alt_ioc) {
++ ioc->alt_ioc->ioc_reset_in_progress = 0;
++ ioc->alt_ioc->taskmgmt_quiesce_io = 0;
++ ioc->alt_ioc->taskmgmt_in_progress = 0;
++ }
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
++ if (MptResetHandlers[cb_idx]) {
++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
++ if (ioc->alt_ioc)
++ mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
++ }
++ }
+
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler: completed (%d seconds): %s\n",
++ ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
++ ((rc == 0) ? "SUCCESS" : "FAILED")));
+ return rc;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++#ifdef CONFIG_FUSION_LOGGING
+ static void
+-EventDescriptionStr(u8 event, u32 evData0, char *evStr)
++mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
+ {
+ char *ds = NULL;
++ u32 evData0;
++ int ii;
++ u8 event;
++ char *evStr = ioc->evStr;
++
++ event = le32_to_cpu(pEventReply->Event) & 0xFF;
++ evData0 = le32_to_cpu(pEventReply->Data[0]);
+
+ switch(event) {
+ case MPI_EVENT_NONE:
+@@ -6442,9 +7184,9 @@ EventDescriptionStr(u8 event, u32 evData
+ if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
+ ds = "Loop State(LIP) Change";
+ else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
+- ds = "Loop State(LPE) Change"; /* ??? */
++ ds = "Loop State(LPE) Change";
+ else
+- ds = "Loop State(LPB) Change"; /* ??? */
++ ds = "Loop State(LPB) Change";
+ break;
+ case MPI_EVENT_LOGOUT:
+ ds = "Logout";
+@@ -6540,6 +7282,11 @@ EventDescriptionStr(u8 event, u32 evData
+ "SAS Device Status Change: Internal Device "
+ "Reset : id=%d channel=%d", id, channel);
+ break;
++ case MPI_EVENT_SAS_DEV_STAT_RC_CMPL_INTERNAL_DEV_RESET:
++ snprintf(evStr, EVENT_DESCR_STR_SZ,
++ "SAS Device Status Change: Internal Device "
++ "Reset Completed: id=%d channel=%d", id, channel);
++ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Internal Task "
+@@ -6560,6 +7307,11 @@ EventDescriptionStr(u8 event, u32 evData
+ "SAS Device Status Change: Internal Query "
+ "Task : id=%d channel=%d", id, channel);
+ break;
++ case MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
++ snprintf(evStr, EVENT_DESCR_STR_SZ,
++ "SAS Device Status Change: Async Notification "
++ "Task : id=%d channel=%d", id, channel);
++ break;
+ default:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Unknown: "
+@@ -6644,28 +7396,65 @@ EventDescriptionStr(u8 event, u32 evData
+ }
+ case MPI_EVENT_IR2:
+ {
++ u8 id = (u8)(evData0);
++ u8 channel = (u8)(evData0 >> 8);
++ u8 phys_num = (u8)(evData0 >> 24);
+ u8 ReasonCode = (u8)(evData0 >> 16);
++
+ switch (ReasonCode) {
+ case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
+- ds = "IR2: LD State Changed";
++ snprintf(evStr, EVENT_DESCR_STR_SZ,
++ "IR2: LD State Changed: "
++ "id=%d channel=%d phys_num=%d",
++ id, channel, phys_num);
+ break;
+ case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
+- ds = "IR2: PD State Changed";
++ snprintf(evStr, EVENT_DESCR_STR_SZ,
++ "IR2: PD State Changed "
++ "id=%d channel=%d phys_num=%d",
++ id, channel, phys_num);
+ break;
+ case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
+- ds = "IR2: Bad Block Table Full";
++ snprintf(evStr, EVENT_DESCR_STR_SZ,
++ "IR2: Bad Block Table Full: "
++ "id=%d channel=%d phys_num=%d",
++ id, channel, phys_num);
+ break;
+ case MPI_EVENT_IR2_RC_PD_INSERTED:
+- ds = "IR2: PD Inserted";
++ snprintf(evStr, EVENT_DESCR_STR_SZ,
++ "IR2: PD Inserted: "
++ "id=%d channel=%d phys_num=%d",
++ id, channel, phys_num);
+ break;
+ case MPI_EVENT_IR2_RC_PD_REMOVED:
+- ds = "IR2: PD Removed";
++ snprintf(evStr, EVENT_DESCR_STR_SZ,
++ "IR2: PD Removed: "
++ "id=%d channel=%d phys_num=%d",
++ id, channel, phys_num);
+ break;
+ case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
+- ds = "IR2: Foreign CFG Detected";
++ snprintf(evStr, EVENT_DESCR_STR_SZ,
++ "IR2: Foreign CFG Detected: "
++ "id=%d channel=%d phys_num=%d",
++ id, channel, phys_num);
+ break;
+ case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
+- ds = "IR2: Rebuild Medium Error";
++ snprintf(evStr, EVENT_DESCR_STR_SZ,
++ "IR2: Rebuild Medium Error: "
++ "id=%d channel=%d phys_num=%d",
++ id, channel, phys_num);
++ break;
++ case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
++ snprintf(evStr, EVENT_DESCR_STR_SZ,
++ "IR2: Dual Port Added: "
++ "id=%d channel=%d phys_num=%d",
++ id, channel, phys_num);
++ break;
++ case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
++ snprintf(evStr, EVENT_DESCR_STR_SZ,
++ "IR2: Dual Port Removed: "
++ "id=%d channel=%d phys_num=%d",
++ id, channel, phys_num);
+ break;
+ default:
+ ds = "IR2";
+@@ -6689,25 +7478,46 @@ EventDescriptionStr(u8 event, u32 evData
+ {
+ u8 phy_num = (u8)(evData0);
+ u8 port_num = (u8)(evData0 >> 8);
+- u8 port_width = (u8)(evData0 >> 16);
++ u8 num_phys = (u8)(evData0 >> 16);
+ u8 primative = (u8)(evData0 >> 24);
++ char *primative_str = NULL;
++
++ switch (primative) {
++ case MPI_EVENT_PRIMITIVE_CHANGE:
++ primative_str = "change";
++ break;
++ case MPI_EVENT_PRIMITIVE_EXPANDER:
++ primative_str = "expander";
++ break;
++ case MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT:
++ primative_str = "asyn event";
++ break;
++ default:
++ primative_str = "reserved";
++ break;
++ }
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+- "SAS Broadcase Primative: phy=%d port=%d "
+- "width=%d primative=0x%02x",
+- phy_num, port_num, port_width, primative);
++ "SAS Broadcast Primative: phy=%d port=%d "
++ "num_phys=%d primative=%s (0x%02x)",
++ phy_num, port_num, num_phys, primative_str, primative);
+ break;
+ }
+
+ case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
+ {
+ u8 reason = (u8)(evData0);
+- u8 port_num = (u8)(evData0 >> 8);
+- u16 handle = le16_to_cpu(evData0 >> 16);
+
+- snprintf(evStr, EVENT_DESCR_STR_SZ,
+- "SAS Initiator Device Status Change: reason=0x%02x "
+- "port=%d handle=0x%04x",
+- reason, port_num, handle);
++ switch (reason) {
++ case MPI_EVENT_SAS_INIT_RC_ADDED:
++ ds = "SAS Initiator Status Change: Added";
++ break;
++ case MPI_EVENT_SAS_INIT_RC_REMOVED:
++ ds = "SAS Initiator Status Change: Deleted";
++ break;
++ default:
++ ds = "SAS Initiator Status Change";
++ break;
++ }
+ break;
+ }
+
+@@ -6755,6 +7565,24 @@ EventDescriptionStr(u8 event, u32 evData
+ break;
+ }
+
++ case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
++ {
++ u8 reason = (u8)(evData0);
++
++ switch (reason) {
++ case MPI_EVENT_SAS_EXP_RC_ADDED:
++ ds = "Expander Status Change: Added";
++ break;
++ case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
++ ds = "Expander Status Change: Deleted";
++ break;
++ default:
++ ds = "Expander Status Change";
++ break;
++ }
++ break;
++ }
++
+ /*
+ * MPT base "custom" events may be added here...
+ */
+@@ -6764,9 +7592,21 @@ EventDescriptionStr(u8 event, u32 evData
+ }
+ if (ds)
+ strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
++
++
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "MPT event:(%02Xh) : %s\n",
++ ioc->name, event, evStr));
++
++ devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
++ ": Event data:\n"));
++ for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
++ devtverboseprintk(ioc, printk(" %08x",
++ le32_to_cpu(pEventReply->Data[ii])));
++ devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
+ }
++#endif
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * ProcessEventNotification - Route EventNotificationReply to all event handlers
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -6776,43 +7616,30 @@ EventDescriptionStr(u8 event, u32 evData
+ * Routes a received EventNotificationReply to all currently registered
+ * event handlers.
+ * Returns sum of event handlers return values.
+- */
++ **/
+ static int
+ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
+ {
+ u16 evDataLen;
+ u32 evData0 = 0;
+-// u32 evCtx;
+ int ii;
+ u8 cb_idx;
+ int r = 0;
+ int handlers = 0;
+- char evStr[EVENT_DESCR_STR_SZ];
+ u8 event;
+
++
+ /*
+ * Do platform normalization of values
+ */
+ event = le32_to_cpu(pEventReply->Event) & 0xFF;
+-// evCtx = le32_to_cpu(pEventReply->EventContext);
+ evDataLen = le16_to_cpu(pEventReply->EventDataLength);
+- if (evDataLen) {
++ if (evDataLen)
+ evData0 = le32_to_cpu(pEventReply->Data[0]);
+- }
+-
+- EventDescriptionStr(event, evData0, evStr);
+- devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
+- ioc->name,
+- event,
+- evStr));
+
+ #ifdef CONFIG_FUSION_LOGGING
+- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- ": Event data:\n", ioc->name));
+- for (ii = 0; ii < evDataLen; ii++)
+- devtverboseprintk(ioc, printk(" %08x",
+- le32_to_cpu(pEventReply->Data[ii])));
+- devtverboseprintk(ioc, printk("\n"));
++ if (evDataLen)
++ mpt_display_event_info(ioc, pEventReply);
+ #endif
+
+ /*
+@@ -6867,8 +7694,8 @@ ProcessEventNotification(MPT_ADAPTER *io
+ */
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptEvHandlers[cb_idx]) {
+- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
+- ioc->name, cb_idx));
++ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "Routing Event to event handler #%d\n", ioc->name, cb_idx));
+ r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
+ handlers++;
+ }
+@@ -6935,7 +7762,6 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 lo
+ ioc->name, log_info, desc, (log_info & 0xFFFFFF));
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -6943,7 +7769,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 lo
+ * @log_info: U32 LogInfo word from the IOC
+ *
+ * Refer to lsi/sp_log.h.
+- */
++ **/
+ static void
+ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
+ {
+@@ -6953,8 +7779,6 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l
+ switch (info) {
+ case 0x00010000:
+ desc = "bug! MID not found";
+- if (ioc->reload_fw == 0)
+- ioc->reload_fw++;
+ break;
+
+ case 0x00020000:
+@@ -7149,7 +7973,6 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l
+ "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
+ };
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_sas_log_info - Log information returned from SAS IOC.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -7229,7 +8052,6 @@ union loginfo_type {
+ sas_loginfo.dw.code, sas_loginfo.dw.subcode);
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mpt_iocstatus_info_config - IOCSTATUS information for config pages
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -7531,8 +8353,7 @@ mpt_iocstatus_info(MPT_ADAPTER *ioc, u32
+ if (!desc)
+ return;
+
+- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
+- ioc->name, status, desc));
++ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc));
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+@@ -7543,6 +8364,7 @@ EXPORT_SYMBOL(mpt_resume);
+ EXPORT_SYMBOL(mpt_suspend);
+ #endif
+ EXPORT_SYMBOL(ioc_list);
++EXPORT_SYMBOL(mpt_proc_root_dir);
+ EXPORT_SYMBOL(mpt_register);
+ EXPORT_SYMBOL(mpt_deregister);
+ EXPORT_SYMBOL(mpt_event_register);
+@@ -7555,25 +8377,29 @@ EXPORT_SYMBOL(mpt_get_msg_frame);
+ EXPORT_SYMBOL(mpt_put_msg_frame);
+ EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
+ EXPORT_SYMBOL(mpt_free_msg_frame);
+-EXPORT_SYMBOL(mpt_add_sge);
+ EXPORT_SYMBOL(mpt_send_handshake_request);
+ EXPORT_SYMBOL(mpt_verify_adapter);
+ EXPORT_SYMBOL(mpt_GetIocState);
+ EXPORT_SYMBOL(mpt_print_ioc_summary);
+ EXPORT_SYMBOL(mpt_HardResetHandler);
++EXPORT_SYMBOL(mpt_SoftResetHandler);
+ EXPORT_SYMBOL(mpt_config);
+ EXPORT_SYMBOL(mpt_findImVolumes);
+ EXPORT_SYMBOL(mpt_alloc_fw_memory);
+ EXPORT_SYMBOL(mpt_free_fw_memory);
+ EXPORT_SYMBOL(mptbase_sas_persist_operation);
+ EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
++EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
++EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
++EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
++EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
++EXPORT_SYMBOL(mpt_halt_firmware);
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * fusion_init - Fusion MPT base driver initialization routine.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int __init
+ fusion_init(void)
+ {
+@@ -7592,7 +8418,7 @@ fusion_init(void)
+ /* Register ourselves (mptbase) in order to facilitate
+ * EventNotification handling.
+ */
+- mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
++ mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
+
+ /* Register for hard reset handling callbacks.
+ */
+@@ -7604,17 +8430,15 @@ fusion_init(void)
+ return 0;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * fusion_exit - Perform driver unload cleanup.
+ *
+ * This routine frees all resources associated with each MPT adapter
+ * and removes all %MPT_PROCFS_MPTBASEDIR entries.
+- */
++ **/
+ static void __exit
+ fusion_exit(void)
+ {
+-
+ mpt_reset_deregister(mpt_base_index);
+
+ #ifdef CONFIG_PROC_FS
+--- a/drivers/message/fusion/mptbase.h
++++ b/drivers/message/fusion/mptbase.h
+@@ -49,10 +49,6 @@
+ #define MPTBASE_H_INCLUDED
+ /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+-#include <linux/kernel.h>
+-#include <linux/pci.h>
+-#include <linux/mutex.h>
+-
+ #include "lsi/mpi_type.h"
+ #include "lsi/mpi.h" /* Fusion MPI(nterface) basic defs */
+ #include "lsi/mpi_ioc.h" /* Fusion MPT IOC(ontroller) defs */
+@@ -76,9 +72,13 @@
+ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR
+ #endif
+
+-#define MPT_LINUX_VERSION_COMMON "3.04.07"
+-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.07"
++#define MPT_LINUX_VERSION_COMMON "4.00.43.00"
++#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-4.00.43.00"
+ #define WHAT_MAGIC_STRING "@" "(" "#" ")"
++#define MPT_LINUX_MAJOR_VERSION 4
++#define MPT_LINUX_MINOR_VERSION 00
++#define MPT_LINUX_BUILD_VERSION 43
++#define MPT_LINUX_RELEASE_VERSION 00
+
+ #define show_mptmod_ver(s,ver) \
+ printk(KERN_INFO "%s %s\n", s, ver);
+@@ -87,6 +87,8 @@
+ /*
+ * Fusion MPT(linux) driver configurable stuff...
+ */
++#define MPT_POLLING_INTERVAL 1000 /* in milliseconds */
++
+ #define MPT_MAX_ADAPTERS 18
+ #define MPT_MAX_PROTOCOL_DRIVERS 16
+ #define MPT_MAX_BUS 1 /* Do not change */
+@@ -134,6 +136,8 @@
+
+ #define MPT_COALESCING_TIMEOUT 0x10
+
++#define MPT_DMA_35BIT_MASK 0x00000007ffffffffULL
++
+ /*
+ * SCSI transfer rate defines.
+ */
+@@ -173,10 +177,21 @@
+ #define MPT_SCSI_SG_DEPTH 40
+ #endif
+
++#ifdef CONFIG_FUSION_MAX_FC_SGE
++#if CONFIG_FUSION_MAX_FC_SGE < 16
++#define MPT_SCSI_FC_SG_DEPTH 16
++#elif CONFIG_FUSION_MAX_FC_SGE > 256
++#define MPT_SCSI_FC_SG_DEPTH 256
++#else
++#define MPT_SCSI_FC_SG_DEPTH CONFIG_FUSION_MAX_FC_SGE
++#endif
++#else
++#define MPT_SCSI_FC_SG_DEPTH 40
++#endif
++
+ /* debug print string length used for events and iocstatus */
+-# define EVENT_DESCR_STR_SZ 100
++# define EVENT_DESCR_STR_SZ 100
+
+-#define MPT_POLLING_INTERVAL 1000 /* in milliseconds */
+
+ #ifdef __KERNEL__ /* { */
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+@@ -224,7 +239,6 @@ typedef struct _ATTO_CONFIG_PAGE_SCSI_PO
+ } fATTO_CONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_ATTO_CONFIG_PAGE_SCSI_PORT_2,
+ ATTO_SCSIPortPage2_t, MPI_POINTER pATTO_SCSIPortPage2_t;
+
+-
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /*
+ * MPT protocol driver defs...
+@@ -372,8 +386,8 @@ typedef struct _VirtTarget {
+ struct scsi_target *starget;
+ u8 tflags;
+ u8 ioc_id;
+- u8 id;
+- u8 channel;
++ u8 id; /* logical target id */
++ u8 channel; /* logical channel number */
+ u8 minSyncFactor; /* 0xFF is async */
+ u8 maxOffset; /* 0 if async */
+ u8 maxWidth; /* 0 if narrow, 1 if wide */
+@@ -381,7 +395,7 @@ typedef struct _VirtTarget {
+ u8 raidVolume; /* set, if RAID Volume */
+ u8 type; /* byte 0 of Inquiry data */
+ u8 deleted; /* target in process of being removed */
+- u32 num_luns;
++ int num_luns;
+ } VirtTarget;
+
+ typedef struct _VirtDevice {
+@@ -427,42 +441,33 @@ do { \
+ } while (0)
+
+
+-/*
+- * IOCTL structure and associated defines
+- */
+-
+-#define MPT_IOCTL_STATUS_DID_IOCRESET 0x01 /* IOC Reset occurred on the current*/
+-#define MPT_IOCTL_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */
+-#define MPT_IOCTL_STATUS_TIMER_ACTIVE 0x04 /* The timer is running */
+-#define MPT_IOCTL_STATUS_SENSE_VALID 0x08 /* Sense data is valid */
+-#define MPT_IOCTL_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */
+-#define MPT_IOCTL_STATUS_TMTIMER_ACTIVE 0x20 /* The TM timer is running */
+-#define MPT_IOCTL_STATUS_TM_FAILED 0x40 /* User TM request failed */
+-
+-#define MPTCTL_RESET_OK 0x01 /* Issue Bus Reset */
+-
+-typedef struct _MPT_IOCTL {
+- struct _MPT_ADAPTER *ioc;
+- u8 ReplyFrame[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */
+- u8 sense[MPT_SENSE_BUFFER_ALLOC];
+- int wait_done; /* wake-up value for this ioc */
+- u8 rsvd;
+- u8 status; /* current command status */
+- u8 reset; /* 1 if bus reset allowed */
+- u8 id; /* target for reset */
+- struct mutex ioctl_mutex;
+-} MPT_IOCTL;
+-
+-#define MPT_SAS_MGMT_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */
+-#define MPT_SAS_MGMT_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */
+-#define MPT_SAS_MGMT_STATUS_TM_FAILED 0x40 /* User TM request failed */
++#define MPT_MGMT_STATUS_RF_VALID 0x01 /* The Reply Frame is VALID */
++#define MPT_MGMT_STATUS_COMMAND_GOOD 0x02 /* Command Status GOOD */
++#define MPT_MGMT_STATUS_PENDING 0x04 /* command is pending */
++#define MPT_MGMT_STATUS_DID_IOCRESET 0x08 /* IOC Reset occurred on the current*/
++#define MPT_MGMT_STATUS_SENSE_VALID 0x10 /* valid sense info */
++#define MPT_MGMT_STATUS_TIMER_ACTIVE 0x20 /* obsolete */
++#define MPT_MGMT_STATUS_FREE_MF 0x40 /* free the mf from complete routine */
++
++
++#define INITIALIZE_MGMT_STATUS(status) \
++ status = MPT_MGMT_STATUS_PENDING;
++#define CLEAR_MGMT_STATUS(status) \
++ status = 0;
++#define CLEAR_MGMT_PENDING_STATUS(status) \
++ status &= ~MPT_MGMT_STATUS_PENDING;
++#define SET_MGMT_MSG_CONTEXT(msg_context, value) \
++ msg_context = value;
+
+-typedef struct _MPT_SAS_MGMT {
++typedef struct _MPT_MGMT {
+ struct mutex mutex;
+ struct completion done;
+ u8 reply[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */
++ u8 sense[MPT_SENSE_BUFFER_ALLOC];
+ u8 status; /* current command status */
+-}MPT_SAS_MGMT;
++ int completion_code;
++ u32 msg_context;
++}MPT_MGMT;
+
+ /*
+ * Event Structure and define
+@@ -534,7 +539,8 @@ struct inactive_raid_component_info {
+ typedef struct _RaidCfgData {
+ IOCPage2_t *pIocPg2; /* table of Raid Volumes */
+ IOCPage3_t *pIocPg3; /* table of physical disks */
+- struct mutex inactive_list_mutex;
++ IOCPage6_t *pIocPg6; /* table of IR static data */
++ struct semaphore inactive_list_mutex;
+ struct list_head inactive_list; /* link list for physical
+ disk that belong in
+ inactive volumes */
+@@ -564,6 +570,9 @@ struct mptfc_rport_info
+ u8 flags;
+ };
+
++typedef void (*MPT_ADD_SGE)(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
++typedef void (*MPT_ADD_CHAIN)(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr);
++
+ /*
+ * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
+ */
+@@ -573,6 +582,9 @@ typedef struct _MPT_ADAPTER
+ int pci_irq; /* This irq */
+ char name[MPT_NAME_LENGTH]; /* "iocN" */
+ char prod_name[MPT_NAME_LENGTH]; /* "LSIFC9x9" */
++#ifdef CONFIG_FUSION_LOGGING
++ char evStr[EVENT_DESCR_STR_SZ]; /* used in mpt_display_event_info */
++#endif
+ char board_name[16];
+ char board_assembly[16];
+ char board_tracer[16];
+@@ -584,8 +596,8 @@ typedef struct _MPT_ADAPTER
+ SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */
+ SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */
+ u8 bus_type;
+- u32 mem_phys; /* == f4020000 (mmap) */
+- u32 pio_mem_phys; /* Programmed IO (downloadboot) */
++ unsigned long mem_phys; /* == f4020000 (mmap) */
++ unsigned long pio_mem_phys; /* Programmed IO (downloadboot) */
+ int mem_size; /* mmap memory size */
+ int number_of_buses;
+ int devices_per_bus;
+@@ -600,6 +612,8 @@ typedef struct _MPT_ADAPTER
+ int reply_depth; /* Num Allocated reply frames */
+ int reply_sz; /* Reply frame size */
+ int num_chain; /* Number of chain buffers */
++ MPT_ADD_SGE add_sge; /* Pointer to add_sge function */
++ MPT_ADD_CHAIN add_chain; /* Pointer to add_chain function */
+ /* Pool of buffers for chaining. ReqToChain
+ * and ChainToChain track index of chain buffers.
+ * ChainBuffer (DMA) virt/phys addresses.
+@@ -628,31 +642,27 @@ typedef struct _MPT_ADAPTER
+ dma_addr_t sense_buf_pool_dma;
+ u32 sense_buf_low_dma;
+ u8 *HostPageBuffer; /* SAS - host page buffer support */
+- u32 HostPageBuffer_sz;
+- dma_addr_t HostPageBuffer_dma;
++ u32 HostPageBuffer_sz;
++ dma_addr_t HostPageBuffer_dma;
+ int mtrr_reg;
+ struct pci_dev *pcidev; /* struct pci_dev pointer */
+- int bars; /* bitmask of BAR's that must be configured */
+- int msi_enable;
++ int bars; /* bitmask of BAR's that must be configured */
++ int msi_enable;
+ u8 __iomem *memmap; /* mmap address */
+ struct Scsi_Host *sh; /* Scsi Host pointer */
+- SpiCfgData spi_data; /* Scsi config. data */
+- RaidCfgData raid_data; /* Raid config. data */
+- SasCfgData sas_data; /* Sas config. data */
+- FcCfgData fc_data; /* Fc config. data */
+- MPT_IOCTL *ioctl; /* ioctl data pointer */
++ SpiCfgData spi_data; /* Scsi config. data */
++ RaidCfgData raid_data; /* Raid config. data */
++ SasCfgData sas_data; /* Sas config. data */
++ FcCfgData fc_data; /* Fc config. data */
+ struct proc_dir_entry *ioc_dentry;
+ struct _MPT_ADAPTER *alt_ioc; /* ptr to 929 bound adapter port */
+- spinlock_t diagLock; /* diagnostic reset lock */
+- int diagPending;
+ u32 biosVersion; /* BIOS version from IO Unit Page 2 */
+ int eventTypes; /* Event logging parameters */
+ int eventContext; /* Next event context */
+ int eventLogSize; /* Max number of cached events */
+ struct _mpt_ioctl_events *events; /* pointer to event log */
+ u8 *cached_fw; /* Pointer to FW */
+- dma_addr_t cached_fw_dma;
+- struct list_head configQ; /* linked list of config. requests */
++ dma_addr_t cached_fw_dma;
+ int hs_reply_idx;
+ #ifndef MFCNT
+ u32 pad0;
+@@ -665,13 +675,16 @@ typedef struct _MPT_ADAPTER
+ IOCFactsReply_t facts;
+ PortFactsReply_t pfacts[2];
+ FCPortPage0_t fc_port_page0[2];
+- struct timer_list persist_timer; /* persist table timer */
+- int persist_wait_done; /* persist completion flag */
+- u8 persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */
+ LANPage0_t lan_cnfg_page0;
+ LANPage1_t lan_cnfg_page1;
++#if defined(CPQ_CIM)
++ u32 csmi_change_count; /* count to track all IR
++ events for CSMI */
++ u8 pci_slot_number; /* ioc page 1 - pci slot number */
++#endif
+
+ u8 ir_firmware; /* =1 if IR firmware detected */
++
+ /*
+ * Description: errata_flag_1064
+ * If a PCIX read occurs within 1 or 2 cycles after the chip receives
+@@ -682,25 +695,46 @@ typedef struct _MPT_ADAPTER
+ int aen_event_read_flag; /* flag to indicate event log was read*/
+ u8 FirstWhoInit;
+ u8 upload_fw; /* If set, do a fw upload */
+- u8 reload_fw; /* Force a FW Reload on next reset */
+ u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */
+- u8 pad1[4];
+ u8 DoneCtx;
+ u8 TaskCtx;
+ u8 InternalCtx;
+- spinlock_t initializing_hba_lock;
+- int initializing_hba_lock_flag;
+ struct list_head list;
+ struct net_device *netdev;
+ struct list_head sas_topology;
+ struct mutex sas_topology_mutex;
+- struct mutex sas_discovery_mutex;
+- u8 sas_discovery_runtime;
+- u8 sas_discovery_ignore_events;
++ u8 disable_hotplug_remove;
++
++ struct workqueue_struct *fw_event_q;
++ struct list_head fw_event_list;
++ spinlock_t fw_event_lock;
++ u8 fw_events_off; /* if '1', then ignore events */
++ char fw_event_q_name[20];
++
++ struct mptsas_portinfo *hba_port_info; /* port_info object for the host */
++ u64 hba_port_sas_addr;
++ u16 hba_port_num_phy;
++ struct list_head sas_device_info_list;
++ struct semaphore sas_device_info_mutex;
++ u8 old_sas_discovery_protocal;
++ u8 sas_discovery_quiesce_io;
+ int sas_index; /* index refrencing */
+- MPT_SAS_MGMT sas_mgmt;
+- struct work_struct sas_persist_task;
++ MPT_MGMT sas_mgmt;
++ MPT_MGMT internal_cmds;
++ MPT_MGMT mptbase_cmds; /* for sending config pages */
++ MPT_MGMT taskmgmt_cmds;
++ MPT_MGMT ioctl_cmds; /* ioctl data pointer */
++ spinlock_t taskmgmt_lock; /* diagnostic reset lock */
++ int taskmgmt_in_progress;
++ u8 taskmgmt_quiesce_io;
++ u8 ioc_reset_in_progress;
++#if defined(CPQ_CIM)
++ u8 num_ports;
++#endif
+
++ char reset_work_q_name[20];
++ struct workqueue_struct *reset_work_q;
++ struct delayed_work fault_reset_work;
+ struct work_struct fc_setup_reset_work;
+ struct list_head fc_rports;
+ struct work_struct fc_lsc_work;
+@@ -709,14 +743,27 @@ typedef struct _MPT_ADAPTER
+ struct work_struct fc_rescan_work;
+ char fc_rescan_work_q_name[20];
+ struct workqueue_struct *fc_rescan_work_q;
++ unsigned long hard_resets; /* driver forced bus resets count */
++ unsigned long soft_resets; /* fw/external bus resets count */
++ unsigned long timeouts; /* cmd timeouts */
+ struct scsi_cmnd **ScsiLookup;
+ spinlock_t scsi_lookup_lock;
+-
+- char reset_work_q_name[20];
+- struct workqueue_struct *reset_work_q;
+- struct delayed_work fault_reset_work;
+- spinlock_t fault_reset_work_lock;
+-
++ int sdev_queue_depth; /* sdev queue depth */
++ u64 dma_mask;
++ u32 broadcast_aen_busy;
++#if defined(DIAG_BUFFER_SUPPORT)
++ u8 *DiagBuffer[MPI_DIAG_BUF_TYPE_COUNT];
++ u32 DataSize[MPI_DIAG_BUF_TYPE_COUNT];
++ u32 DiagBuffer_sz[MPI_DIAG_BUF_TYPE_COUNT];
++ dma_addr_t DiagBuffer_dma[MPI_DIAG_BUF_TYPE_COUNT];
++ u8 TraceLevel[MPI_DIAG_BUF_TYPE_COUNT];
++ u8 DiagBuffer_Status[MPI_DIAG_BUF_TYPE_COUNT];
++ u32 UniqueId[MPI_DIAG_BUF_TYPE_COUNT];
++ u32 ExtendedType[MPI_DIAG_BUF_TYPE_COUNT];
++ u32 ProductSpecific[MPI_DIAG_BUF_TYPE_COUNT][4];
++#endif
++ u8 sg_addr_size;
++ u8 SGE_size;
+ } MPT_ADAPTER;
+
+ /*
+@@ -753,13 +800,12 @@ typedef struct _mpt_sge {
+ dma_addr_t Address;
+ } MptSge_t;
+
+-#define mpt_addr_size() \
+- ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \
+- MPI_SGE_FLAGS_32_BIT_ADDRESSING)
+-
+-#define mpt_msg_flags() \
+- ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \
+- MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32)
++#define mpt_msg_flags(ioc) \
++ (ioc->sg_addr_size == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \
++ MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32
++
++#define MPT_SGE_FLAGS_64_BIT_ADDRESSING \
++ (MPI_SGE_FLAGS_64_BIT_ADDRESSING << MPI_SGE_FLAGS_SHIFT)
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /*
+@@ -778,26 +824,10 @@ typedef struct _mpt_sge {
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+-#define SCSI_STD_SENSE_BYTES 18
+-#define SCSI_STD_INQUIRY_BYTES 36
+-#define SCSI_MAX_INQUIRY_BYTES 96
+-
+ /*
+ * MPT_SCSI_HOST defines - Used by the IOCTL and the SCSI drivers
+ * Private to the driver.
+ */
+-/* LOCAL structure and fields used when processing
+- * internally generated commands. These include:
+- * bus scan, dv and config requests.
+- */
+-typedef struct _MPT_LOCAL_REPLY {
+- ConfigPageHeader_t header;
+- int completion;
+- u8 sense[SCSI_STD_SENSE_BYTES];
+- u8 scsiStatus;
+- u8 skip;
+- u32 pad;
+-} MPT_LOCAL_REPLY;
+
+ #define MPT_HOST_BUS_UNKNOWN (0xFF)
+ #define MPT_HOST_TOO_MANY_TM (0x05)
+@@ -813,13 +843,6 @@ typedef struct _MPT_LOCAL_REPLY {
+ #define MPT_NVRAM_WIDE_DISABLE (0x00100000)
+ #define MPT_NVRAM_BOOT_CHOICE (0x00200000)
+
+-/* The TM_STATE variable is used to provide strict single threading of TM
+- * requests as well as communicate TM error conditions.
+- */
+-#define TM_STATE_NONE (0)
+-#define TM_STATE_IN_PROGRESS (1)
+-#define TM_STATE_ERROR (2)
+-
+ typedef enum {
+ FC,
+ SPI,
+@@ -828,63 +851,28 @@ typedef enum {
+
+ typedef struct _MPT_SCSI_HOST {
+ MPT_ADAPTER *ioc;
+- int port;
+- u32 pad0;
+- MPT_LOCAL_REPLY *pLocal; /* used for internal commands */
+- struct timer_list timer;
+- /* Pool of memory for holding SCpnts before doing
+- * OS callbacks. freeQ is the free pool.
+- */
+- u8 tmPending;
+- u8 resetPending;
+- u8 negoNvram; /* DV disabled, nego NVRAM */
+- u8 pad1;
+- u8 tmState;
+- u8 rsvd[2];
+- MPT_FRAME_HDR *cmdPtr; /* Ptr to nonOS request */
+- struct scsi_cmnd *abortSCpnt;
+- MPT_LOCAL_REPLY localReply; /* internal cmd reply struct */
+- unsigned long hard_resets; /* driver forced bus resets count */
+- unsigned long soft_resets; /* fw/external bus resets count */
+- unsigned long timeouts; /* cmd timeouts */
+ ushort sel_timeout[MPT_MAX_FC_DEVICES];
+ char *info_kbuf;
+- wait_queue_head_t scandv_waitq;
+- int scandv_wait_done;
+ long last_queue_full;
+- u16 tm_iocstatus;
+ u16 spi_pending;
+ struct list_head target_reset_list;
+ } MPT_SCSI_HOST;
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /*
+- * More Dynamic Multi-Pathing stuff...
+- */
+-
+-/* Forward decl, a strange C thing, to prevent gcc compiler warnings */
+-struct scsi_cmnd;
+-
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
+ * Generic structure passed to the base mpt_config function.
+ */
+ typedef struct _x_config_parms {
+- struct list_head linkage; /* linked list */
+- struct timer_list timer; /* timer function for this request */
+ union {
+ ConfigExtendedPageHeader_t *ehdr;
+ ConfigPageHeader_t *hdr;
+ } cfghdr;
+ dma_addr_t physAddr;
+- int wait_done; /* wait for this request */
+ u32 pageAddr; /* properly formatted */
++ u16 status;
+ u8 action;
+ u8 dir;
+ u8 timeout; /* seconds */
+- u8 pad1;
+- u16 status;
+- u16 pad2;
+ } CONFIGPARMS;
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+@@ -909,29 +897,37 @@ extern MPT_FRAME_HDR *mpt_get_msg_frame(
+ extern void mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
+ extern void mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
+ extern void mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
+-extern void mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
+-
+ extern int mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag);
+ extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
+ extern u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
+ extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
+ extern int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
++extern int mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
+ extern int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
+ extern int mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
+ extern void mpt_free_fw_memory(MPT_ADAPTER *ioc);
+ extern int mpt_findImVolumes(MPT_ADAPTER *ioc);
+ extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
+ extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk);
++extern int mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage1_t phys_disk);
++extern int mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num);
++
++extern int mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
++extern void mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
++extern void mpt_halt_firmware(MPT_ADAPTER *ioc);
+
+ /*
+ * Public data decl's...
+ */
+ extern struct list_head ioc_list;
++extern struct proc_dir_entry *mpt_proc_root_dir;
++extern int mpt_debug_level;
++extern int mpt_fwfault_debug;
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ #endif /* } __KERNEL__ */
+
+-#ifdef CONFIG_64BIT
++#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__) || defined(__powerpc64__)
+ #define CAST_U32_TO_PTR(x) ((void *)(u64)x)
+ #define CAST_PTR_TO_U32(x) ((u32)(u64)x)
+ #else
+@@ -956,7 +952,6 @@ extern struct list_head ioc_list;
+ #define MPT_SGE_FLAGS_END_OF_BUFFER (0x40000000)
+ #define MPT_SGE_FLAGS_LOCAL_ADDRESS (0x08000000)
+ #define MPT_SGE_FLAGS_DIRECTION (0x04000000)
+-#define MPT_SGE_FLAGS_ADDRESSING (mpt_addr_size() << MPI_SGE_FLAGS_SHIFT)
+ #define MPT_SGE_FLAGS_END_OF_LIST (0x01000000)
+
+ #define MPT_SGE_FLAGS_TRANSACTION_ELEMENT (0x00000000)
+@@ -969,14 +964,12 @@ extern struct list_head ioc_list;
+ MPT_SGE_FLAGS_END_OF_BUFFER | \
+ MPT_SGE_FLAGS_END_OF_LIST | \
+ MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
+- MPT_SGE_FLAGS_ADDRESSING | \
+ MPT_TRANSFER_IOC_TO_HOST)
+ #define MPT_SGE_FLAGS_SSIMPLE_WRITE \
+ (MPT_SGE_FLAGS_LAST_ELEMENT | \
+ MPT_SGE_FLAGS_END_OF_BUFFER | \
+ MPT_SGE_FLAGS_END_OF_LIST | \
+ MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
+- MPT_SGE_FLAGS_ADDRESSING | \
+ MPT_TRANSFER_HOST_TO_IOC)
+
+ /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+--- a/drivers/message/fusion/mptctl.c
++++ b/drivers/message/fusion/mptctl.c
+@@ -45,6 +45,7 @@
+ */
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
++#include <linux/version.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/errno.h>
+@@ -71,6 +72,15 @@
+ #include "mptbase.h"
+ #include "mptctl.h"
+
++#if defined(CPQ_CIM)
++#include "mptsas.h"
++#include "csmi/csmisas.h"
++#endif // CPQ_CIM
++
++#if defined(DIAG_BUFFER_SUPPORT)
++#include "rejected_ioctls/diag_buffer.h"
++#endif
++
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ #define my_NAME "Fusion MPT misc device (ioctl) driver"
+ #define my_VERSION MPT_LINUX_VERSION_COMMON
+@@ -84,6 +94,7 @@ MODULE_VERSION(my_VERSION);
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+ static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS;
++static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS;
+
+ static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
+
+@@ -112,6 +123,42 @@ static int mptctl_do_reset(unsigned long
+ static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd);
+ static int mptctl_hp_targetinfo(unsigned long arg);
+
++#if defined(CPQ_CIM)
++/* csmisas proto's*/
++static int csmisas_get_driver_info(unsigned long arg);
++static int csmisas_get_cntlr_status(unsigned long arg);
++static int csmisas_get_cntlr_config(unsigned long arg);
++static int csmisas_get_phy_info(unsigned long arg);
++static int csmisas_get_scsi_address(unsigned long arg);
++static int csmisas_get_link_errors(unsigned long arg);
++static int csmisas_smp_passthru(unsigned long arg);
++static int csmisas_firmware_download(unsigned long arg);
++static int csmisas_get_raid_info(unsigned long arg);
++static int csmisas_get_raid_config(unsigned long arg);
++static int csmisas_get_raid_features(unsigned long arg);
++static int csmisas_set_raid_control(unsigned long arg);
++static int csmisas_get_raid_element(unsigned long arg);
++static int csmisas_set_raid_operation(unsigned long arg);
++static int csmisas_set_phy_info(unsigned long arg);
++static int csmisas_ssp_passthru(unsigned long arg);
++static int csmisas_stp_passthru(unsigned long arg);
++static int csmisas_get_sata_signature(unsigned long arg);
++static int csmisas_get_device_address(unsigned long arg);
++static int csmisas_task_managment(unsigned long arg);
++static int csmisas_phy_control(unsigned long arg);
++static int csmisas_get_connector_info(unsigned long arg);
++static int csmisas_get_location(unsigned long arg);
++#endif // CPQ_CIM
++
++#if defined(DIAG_BUFFER_SUPPORT)
++/* diag_buffer proto's */
++static int mptctl_register_diag_buffer(unsigned long arg);
++static int mptctl_release_diag_buffer(unsigned long arg);
++static int mptctl_unregister_diag_buffer(unsigned long arg);
++static int mptctl_query_diag_buffer(unsigned long arg);
++static int mptctl_read_diag_buffer(unsigned long arg);
++#endif // DIAG_BUFFER_SUPPORT
++
+ static int mptctl_probe(struct pci_dev *, const struct pci_device_id *);
+ static void mptctl_remove(struct pci_dev *);
+
+@@ -127,10 +174,6 @@ static MptSge_t *kbuf_alloc_2_sgl(int by
+ struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
+ static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
+ struct buflist *buflist, MPT_ADAPTER *ioc);
+-static void mptctl_timeout_expired (MPT_IOCTL *ioctl);
+-static int mptctl_bus_reset(MPT_IOCTL *ioctl);
+-static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd);
+-static void mptctl_free_tm_flags(MPT_ADAPTER *ioc);
+
+ /*
+ * Reset Handler cleanup function
+@@ -183,10 +226,10 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, in
+ int rc = 0;
+
+ if (nonblock) {
+- if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
++ if (!mutex_trylock(&ioc->ioctl_cmds.mutex))
+ rc = -EAGAIN;
+ } else {
+- if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
++ if (mutex_lock_interruptible(&ioc->ioctl_cmds.mutex))
+ rc = -ERESTARTSYS;
+ }
+ return rc;
+@@ -202,131 +245,104 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, in
+ static int
+ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
+ {
+- char *sense_data;
+- int sz, req_index;
+- u16 iocStatus;
+- u8 cmd;
+-
+- if (req)
+- cmd = req->u.hdr.Function;
+- else
+- return 1;
+- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tcompleting mpi function (0x%02X), req=%p, "
+- "reply=%p\n", ioc->name, req->u.hdr.Function, req, reply));
+-
+- if (ioc->ioctl) {
++ char *sense_data;
++ int req_index;
++ int sz;
+
+- if (reply==NULL) {
++ if (!req)
++ return 0;
+
+- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_reply() NULL Reply "
+- "Function=%x!\n", ioc->name, cmd));
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "completing mpi function "
++ "(0x%02X), req=%p, reply=%p\n", ioc->name, req->u.hdr.Function,
++ req, reply));
+
+- ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+- ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
++ /*
++ * Handling continuation of the same reply. Processing the first
++ * reply, and eating the other replys that come later.
++ */
++ if (ioc->ioctl_cmds.msg_context != req->u.hdr.MsgContext)
++ goto out_continuation;
+
+- /* We are done, issue wake up
+- */
+- ioc->ioctl->wait_done = 1;
+- wake_up (&mptctl_wait);
+- return 1;
++ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+
+- }
++ if (!reply)
++ goto out;
+
+- /* Copy the reply frame (which much exist
+- * for non-SCSI I/O) to the IOC structure.
+- */
+- memcpy(ioc->ioctl->ReplyFrame, reply,
+- min(ioc->reply_sz, 4*reply->u.reply.MsgLength));
+- ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
++ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
++ sz = min(ioc->reply_sz, 4*reply->u.reply.MsgLength);
++ memcpy(ioc->ioctl_cmds.reply, reply, sz);
+
+- /* Set the command status to GOOD if IOC Status is GOOD
+- * OR if SCSI I/O cmd and data underrun or recovered error.
+- */
+- iocStatus = le16_to_cpu(reply->u.reply.IOCStatus) & MPI_IOCSTATUS_MASK;
+- if (iocStatus == MPI_IOCSTATUS_SUCCESS)
+- ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+-
+- if (iocStatus || reply->u.reply.IOCLogInfo)
+- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tiocstatus (0x%04X), "
+- "loginfo (0x%08X)\n", ioc->name,
+- iocStatus,
+- le32_to_cpu(reply->u.reply.IOCLogInfo)));
+-
+- if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+- (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+-
+- if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
+- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "\tscsi_status (0x%02x), scsi_state (0x%02x), "
+- "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
+- reply->u.sreply.SCSIStatus,
+- reply->u.sreply.SCSIState,
+- le16_to_cpu(reply->u.sreply.TaskTag),
+- le32_to_cpu(reply->u.sreply.TransferCount)));
+-
+- ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
+-
+- if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) ||
+- (iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) {
+- ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+- }
+- }
++ if (reply->u.reply.IOCStatus || reply->u.reply.IOCLogInfo)
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "iocstatus (0x%04X), loginfo (0x%08X)\n", ioc->name,
++ le16_to_cpu(reply->u.reply.IOCStatus),
++ le32_to_cpu(reply->u.reply.IOCLogInfo)));
++
++ if ((req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
++ (req->u.hdr.Function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
++
++ if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "scsi_status (0x%02x), scsi_state (0x%02x), "
++ "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
++ reply->u.sreply.SCSIStatus,
++ reply->u.sreply.SCSIState,
++ le16_to_cpu(reply->u.sreply.TaskTag),
++ le32_to_cpu(reply->u.sreply.TransferCount)));
+
+- /* Copy the sense data - if present
+- */
+- if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) &&
+- (reply->u.sreply.SCSIState &
+- MPI_SCSI_STATE_AUTOSENSE_VALID)){
++ if (reply->u.sreply.SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+ sz = req->u.scsireq.SenseBufferLength;
+ req_index =
+ le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
+- sense_data =
+- ((u8 *)ioc->sense_buf_pool +
++ sense_data = ((u8 *)ioc->sense_buf_pool +
+ (req_index * MPT_SENSE_BUFFER_ALLOC));
+- memcpy(ioc->ioctl->sense, sense_data, sz);
+- ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID;
++ memcpy(ioc->ioctl_cmds.sense, sense_data, sz);
++ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_SENSE_VALID;
+ }
++ }
+
+- if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT)
+- mptctl_free_tm_flags(ioc);
+-
+- /* We are done, issue wake up
+- */
+- ioc->ioctl->wait_done = 1;
+- wake_up (&mptctl_wait);
++ out:
++ /* We are done, issue wake up
++ */
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
++ if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT)
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
++ complete(&ioc->ioctl_cmds.done);
+ }
++
++ out_continuation:
++ if (reply && (reply->u.reply.MsgFlags &
++ MPI_MSGFLAGS_CONTINUATION_REPLY))
++ return 0;
+ return 1;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/* mptctl_timeout_expired
+- *
+- * Expecting an interrupt, however timed out.
+- *
+- */
+-static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
++static int
++mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+ {
+- int rc = 1;
++ if (!mf)
++ return 0;
+
+- dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n",
+- ioctl->ioc->name, ioctl->ioc->id));
+- if (ioctl == NULL)
+- return;
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n",
++ ioc->name, mf, mr));
+
+- ioctl->wait_done = 0;
+- if (ioctl->reset & MPTCTL_RESET_OK)
+- rc = mptctl_bus_reset(ioctl);
+-
+- if (rc) {
+- /* Issue a reset for this device.
+- * The IOC is not responding.
+- */
+- dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
+- ioctl->ioc->name));
+- mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP);
+- }
+- return;
++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
++
++ if (!mr)
++ goto out;
+
++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
++ memcpy(ioc->taskmgmt_cmds.reply, mr,
++ min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
++ out:
++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
++ complete(&ioc->taskmgmt_cmds.done);
++ return 1;
++ }
++ return 0;
+ }
+
+ /* mptctl_bus_reset
+@@ -334,132 +350,181 @@ static void mptctl_timeout_expired (MPT_
+ * Bus reset code.
+ *
+ */
+-static int mptctl_bus_reset(MPT_IOCTL *ioctl)
++static int
++mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
+ {
+ MPT_FRAME_HDR *mf;
+ SCSITaskMgmt_t *pScsiTm;
+- MPT_SCSI_HOST *hd;
++ SCSITaskMgmtReply_t *pScsiTmReply;
+ int ii;
+- int retval=0;
+-
+-
+- ioctl->reset &= ~MPTCTL_RESET_OK;
+-
+- if (ioctl->ioc->sh == NULL)
++ int retval;
++ unsigned long timeout;
++ unsigned long time_count;
++ u16 iocstatus;
++
++ /* bus reset is only good for SCSI IO, RAID PASSTHRU */
++ if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) ||
++ (function == MPI_FUNCTION_SCSI_IO_REQUEST)) {
++ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, not SCSI_IO!!\n",
++ ioc->name));
+ return -EPERM;
++ }
+
+- hd = shost_priv(ioctl->ioc->sh);
+- if (hd == NULL)
++ mutex_lock(&ioc->taskmgmt_cmds.mutex);
++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+ return -EPERM;
++ }
+
+- /* Single threading ....
+- */
+- if (mptctl_set_tm_flags(hd) != 0)
+- return -EPERM;
++ retval = 0;
+
+ /* Send request
+ */
+- if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) {
+- dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt, no msg frames!!\n",
+- ioctl->ioc->name));
+-
+- mptctl_free_tm_flags(ioctl->ioc);
+- return -ENOMEM;
++ if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) {
++ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
++ ioc->name));
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ retval = -ENOMEM;
++ goto mptctl_bus_reset_done;
+ }
+
+- dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
+- ioctl->ioc->name, mf));
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
++ ioc->name, mf));
+
+ pScsiTm = (SCSITaskMgmt_t *) mf;
+- pScsiTm->TargetID = ioctl->id;
+- pScsiTm->Bus = hd->port; /* 0 */
+- pScsiTm->ChainOffset = 0;
++ memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
+ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+- pScsiTm->Reserved = 0;
+ pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+- pScsiTm->Reserved1 = 0;
+ pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+-
++ pScsiTm->TargetID = 0;
++ pScsiTm->Bus = 0;
++ pScsiTm->ChainOffset = 0;
++ pScsiTm->Reserved = 0;
++ pScsiTm->Reserved1 = 0;
++ pScsiTm->TaskMsgContext = 0;
+ for (ii= 0; ii < 8; ii++)
+ pScsiTm->LUN[ii] = 0;
+-
+ for (ii=0; ii < 7; ii++)
+ pScsiTm->Reserved2[ii] = 0;
+
+- pScsiTm->TaskMsgContext = 0;
+- dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT
+- "mptctl_bus_reset: issued.\n", ioctl->ioc->name));
+-
+- DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf);
++ switch (ioc->bus_type) {
++ case FC:
++ timeout = 40;
++ break;
++ case SAS:
++ timeout = 30;
++ break;
++ case SPI:
++ default:
++ timeout = 2;
++ break;
++ }
+
+- ioctl->wait_done=0;
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
++ ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
+
+- if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+- (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+- mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf);
++ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
++ time_count = jiffies;
++ if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
++ (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
++ mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf);
+ else {
+- retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
+- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
++ retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,
++ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+ if (retval != 0) {
+- dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
+- " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
+- hd->ioc, mf));
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt send_handshake FAILED!"
++ " (ioc %p, mf %p, rc=%d) \n", ioc->name,
++ ioc, mf, retval));
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ goto mptctl_bus_reset_done;
+ }
+ }
+
+ /* Now wait for the command to complete */
+- ii = wait_event_timeout(mptctl_wait,
+- ioctl->wait_done == 1,
+- HZ*5 /* 5 second timeout */);
+-
+- if(ii <=0 && (ioctl->wait_done != 1 )) {
+- mpt_free_msg_frame(hd->ioc, mf);
+- ioctl->wait_done = 0;
+- retval = -1; /* return failure */
++ ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt failed\n", ioc->name));
++ mpt_free_msg_frame(ioc, mf);
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
++ retval = 0;
++ else
++ retval = -1; /* return failure */
++ goto mptctl_bus_reset_done;
+ }
+
+-mptctl_bus_reset_done:
+-
+- mptctl_free_tm_flags(ioctl->ioc);
+- return retval;
+-}
+-
+-static int
+-mptctl_set_tm_flags(MPT_SCSI_HOST *hd) {
+- unsigned long flags;
+-
+- spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt failed\n", ioc->name));
++ retval = -1; /* return failure */
++ goto mptctl_bus_reset_done;
++ }
+
+- if (hd->tmState == TM_STATE_NONE) {
+- hd->tmState = TM_STATE_IN_PROGRESS;
+- hd->tmPending = 1;
+- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+- } else {
+- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+- return -EBUSY;
++ pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, "
++ "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, "
++ "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus,
++ pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
++ le16_to_cpu(pScsiTmReply->IOCStatus),
++ le32_to_cpu(pScsiTmReply->IOCLogInfo),
++ pScsiTmReply->ResponseCode,
++ le32_to_cpu(pScsiTmReply->TerminationCount)));
++
++ iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
++
++ if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
++ iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED ||
++ iocstatus == MPI_IOCSTATUS_SUCCESS)
++ retval = 0;
++ else {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt failed\n", ioc->name));
++ retval = -1; /* return failure */
+ }
+
+- return 0;
++
++ mptctl_bus_reset_done:
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
++ return retval;
+ }
+
+ static void
+-mptctl_free_tm_flags(MPT_ADAPTER *ioc)
++mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+ {
+- MPT_SCSI_HOST * hd;
+ unsigned long flags;
+
+- hd = shost_priv(ioc->sh);
+- if (hd == NULL)
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
++ ioc->name, __FUNCTION__));
++
++ if(mpt_fwfault_debug)
++ mpt_halt_firmware(ioc);
++
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
++ if (ioc->ioc_reset_in_progress) {
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
++ CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
++ mpt_free_msg_frame(ioc, mf);
+ return;
++ }
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+- spin_lock_irqsave(&ioc->FreeQlock, flags);
+
+- hd->tmState = TM_STATE_NONE;
+- hd->tmPending = 0;
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
++ if (!mptctl_bus_reset(ioc, mf->u.hdr.Function))
++ return;
+
+- return;
++ /* Issue a reset for this device.
++ * The IOC is not responding.
++ */
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
++ ioc->name));
++ CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
++ mpt_HardResetHandler(ioc, CAN_SLEEP);
++ mpt_free_msg_frame(ioc, mf);
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+@@ -472,22 +537,23 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc)
+ static int
+ mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+ {
+- MPT_IOCTL *ioctl = ioc->ioctl;
+- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name,
+- reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+-
+- if(ioctl == NULL)
+- return 1;
+-
+ switch(reset_phase) {
+ case MPT_IOC_SETUP_RESET:
+- ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET;
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
++ break;
++ case MPT_IOC_PRE_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
+ break;
+ case MPT_IOC_POST_RESET:
+- ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET;
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__));
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
++ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
++ complete(&ioc->ioctl_cmds.done);
++ }
+ break;
+- case MPT_IOC_PRE_RESET:
+ default:
+ break;
+ }
+@@ -505,7 +571,7 @@ mptctl_event_process(MPT_ADAPTER *ioc, E
+ event = le32_to_cpu(pEvReply->Event) & 0xFF;
+
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n",
+- ioc->name, __func__));
++ ioc->name, __FUNCTION__));
+ if(async_queue == NULL)
+ return 1;
+
+@@ -548,15 +614,11 @@ static int
+ mptctl_fasync(int fd, struct file *filep, int mode)
+ {
+ MPT_ADAPTER *ioc;
+- int ret;
+
+- lock_kernel();
+ list_for_each_entry(ioc, &ioc_list, list)
+ ioc->aen_event_read_flag=0;
+
+- ret = fasync_helper(fd, filep, mode, &async_queue);
+- unlock_kernel();
+- return ret;
++ return fasync_helper(fd, filep, mode, &async_queue);
+ }
+
+ static int
+@@ -582,6 +644,7 @@ __mptctl_ioctl(struct file *file, unsign
+ int ret;
+ MPT_ADAPTER *iocp = NULL;
+
++
+ if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
+ printk(KERN_ERR MYNAM "%s::mptctl_ioctl() @%d - "
+ "Unable to copy mpt_ioctl_header data @ %p\n",
+@@ -596,17 +659,12 @@ __mptctl_ioctl(struct file *file, unsign
+ iocnumX = khdr.iocnum & 0xFF;
+ if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+ (iocp == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnumX);
+ return -ENODEV;
+ }
+
+- if (!iocp->active) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n",
+- __FILE__, __LINE__);
+- return -EFAULT;
+- }
+-
+ /* Handle those commands that are just returning
+ * information stored in the driver.
+ * These commands should never time out and are unaffected
+@@ -626,6 +684,25 @@ __mptctl_ioctl(struct file *file, unsign
+ return mptctl_eventreport(arg);
+ } else if (cmd == MPTFWREPLACE) {
+ return mptctl_replace_fw(arg);
++#if defined(DIAG_BUFFER_SUPPORT)
++/* diag_buffer static data calls*/
++ } else if (cmd == MPTDIAGQUERY) {
++ return mptctl_query_diag_buffer(arg);
++ } else if (cmd == MPTDIAGUNREGISTER) {
++ return mptctl_unregister_diag_buffer(arg);
++#endif
++
++#if defined(CPQ_CIM)
++/* csmisas static data calls*/
++ } else if (cmd == CC_CSMI_SAS_GET_DRIVER_INFO) {
++ return csmisas_get_driver_info(arg);
++ } else if (cmd == CC_CSMI_SAS_GET_CNTLR_STATUS) {
++ return csmisas_get_cntlr_status(arg);
++ } else if (cmd == CC_CSMI_SAS_GET_SCSI_ADDRESS) {
++ return csmisas_get_scsi_address(arg);
++ } else if (cmd == CC_CSMI_SAS_GET_DEVICE_ADDRESS){
++ return csmisas_get_device_address(arg);
++#endif // CPQ_CIM
+ }
+
+ /* All of these commands require an interrupt or
+@@ -634,6 +711,8 @@ __mptctl_ioctl(struct file *file, unsign
+ if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+ return ret;
+
++// dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT ": mptctl_ioctl()\n", iocp->name));
++
+ if (cmd == MPTFWDOWNLOAD)
+ ret = mptctl_fw_download(arg);
+ else if (cmd == MPTCOMMAND)
+@@ -644,10 +723,61 @@ __mptctl_ioctl(struct file *file, unsign
+ ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd));
+ else if (cmd == HP_GETTARGETINFO)
+ ret = mptctl_hp_targetinfo(arg);
++#if defined(CPQ_CIM)
++/* csmisas requiring fw calls*/
++ else if (cmd == CC_CSMI_SAS_GET_CNTLR_CONFIG)
++ ret = csmisas_get_cntlr_config(arg);
++ else if (cmd == CC_CSMI_SAS_GET_PHY_INFO)
++ ret = csmisas_get_phy_info(arg);
++ else if (cmd == CC_CSMI_SAS_GET_SATA_SIGNATURE)
++ ret = csmisas_get_sata_signature(arg);
++ else if (cmd == CC_CSMI_SAS_GET_LINK_ERRORS)
++ ret = csmisas_get_link_errors(arg);
++ else if (cmd == CC_CSMI_SAS_SMP_PASSTHRU)
++ ret = csmisas_smp_passthru(arg);
++ else if (cmd == CC_CSMI_SAS_SSP_PASSTHRU)
++ ret = csmisas_ssp_passthru(arg);
++ else if (cmd == CC_CSMI_SAS_FIRMWARE_DOWNLOAD)
++ ret = csmisas_firmware_download(arg);
++ else if (cmd == CC_CSMI_SAS_GET_RAID_INFO)
++ ret = csmisas_get_raid_info(arg);
++ else if (cmd == CC_CSMI_SAS_GET_RAID_CONFIG)
++ ret = csmisas_get_raid_config(arg);
++ else if (cmd == CC_CSMI_SAS_GET_RAID_FEATURES)
++ ret = csmisas_get_raid_features(arg);
++ else if (cmd == CC_CSMI_SAS_SET_RAID_CONTROL)
++ ret = csmisas_set_raid_control(arg);
++ else if (cmd == CC_CSMI_SAS_GET_RAID_ELEMENT)
++ ret = csmisas_get_raid_element(arg);
++ else if (cmd == CC_CSMI_SAS_SET_RAID_OPERATION)
++ ret = csmisas_set_raid_operation(arg);
++ else if (cmd == CC_CSMI_SAS_SET_PHY_INFO)
++ ret = csmisas_set_phy_info(arg);
++ else if (cmd == CC_CSMI_SAS_STP_PASSTHRU)
++ ret = csmisas_stp_passthru(arg);
++ else if (cmd == CC_CSMI_SAS_TASK_MANAGEMENT)
++ ret = csmisas_task_managment(arg);
++ else if (cmd == CC_CSMI_SAS_PHY_CONTROL)
++ ret = csmisas_phy_control(arg);
++ else if (cmd == CC_CSMI_SAS_GET_CONNECTOR_INFO)
++ ret = csmisas_get_connector_info(arg);
++ else if (cmd == CC_CSMI_SAS_GET_LOCATION)
++ ret = csmisas_get_location(arg);
++#endif // CPQ_CIM
++
++#if defined(DIAG_BUFFER_SUPPORT)
++/* diag_buffer requiring fw calls*/
++ else if (cmd == MPTDIAGREGISTER)
++ ret = mptctl_register_diag_buffer(arg);
++ else if (cmd == MPTDIAGRELEASE)
++ ret = mptctl_release_diag_buffer(arg);
++ else if (cmd == MPTDIAGREADBUFFER)
++ ret = mptctl_read_diag_buffer(arg);
++#endif // DIAG_BUFFER_SUPPORT
+ else
+ ret = -EINVAL;
+
+- mutex_unlock(&iocp->ioctl->ioctl_mutex);
++ mutex_unlock(&iocp->ioctl_cmds.mutex);
+
+ return ret;
+ }
+@@ -676,6 +806,7 @@ static int mptctl_do_reset(unsigned long
+ }
+
+ if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+ __FILE__, __LINE__, krinfo.hdr.iocnum);
+ return -ENODEV; /* (-6) No such device or address */
+@@ -763,10 +894,11 @@ mptctl_do_fw_download(int ioc, char __us
+ int sge_offset = 0;
+ u16 iocstat;
+ pFWDownloadReply_t ReplyMsg = NULL;
++ unsigned long timeleft;
+
+ if (mpt_verify_adapter(ioc, &iocp) < 0) {
+- printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n",
+- ioc);
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
++ printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n", ioc);
+ return -ENODEV; /* (-6) No such device or address */
+ } else {
+
+@@ -847,10 +979,10 @@ mptctl_do_fw_download(int ioc, char __us
+ * 64 4
+ */
+ maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t))
+- / (sizeof(dma_addr_t) + sizeof(u32));
++ / iocp->SGE_size;
+ if (numfrags > maxfrags) {
+ ret = -EMLINK;
+- goto fwdl_out;
++ goto fwdl_out;
+ }
+
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: sgl buffer = %p, sgfrags = %d\n",
+@@ -875,19 +1007,19 @@ mptctl_do_fw_download(int ioc, char __us
+ if (nib == 0 || nib == 3) {
+ ;
+ } else if (sgIn->Address) {
+- mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
++ iocp->add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
+ n++;
+ if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
+ printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
+- "Unable to copy f/w buffer hunk#%d @ %p\n",
+- iocp->name, __FILE__, __LINE__, n, ufwbuf);
++ "Unable to copy f/w buffer hunk#%d @ %p\n",
++ iocp->name, __FILE__, __LINE__, n, ufwbuf);
+ goto fwdl_out;
+ }
+ fw_bytes_copied += bl->len;
+ }
+ sgIn++;
+ bl++;
+- sgOut += (sizeof(dma_addr_t) + sizeof(u32));
++ sgOut += iocp->SGE_size;
+ }
+
+ DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags);
+@@ -896,16 +1028,27 @@ mptctl_do_fw_download(int ioc, char __us
+ * Finally, perform firmware download.
+ */
+ ReplyMsg = NULL;
++ SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, dlmsg->MsgContext);
++ INITIALIZE_MGMT_STATUS(iocp->ioctl_cmds.status)
+ mpt_put_msg_frame(mptctl_id, iocp, mf);
+
+ /* Now wait for the command to complete */
+- ret = wait_event_timeout(mptctl_wait,
+- iocp->ioctl->wait_done == 1,
+- HZ*60);
+-
+- if(ret <=0 && (iocp->ioctl->wait_done != 1 )) {
+- /* Now we need to reset the board */
+- mptctl_timeout_expired(iocp->ioctl);
++ timeleft = wait_for_completion_timeout(&iocp->ioctl_cmds.done, HZ*60);
++ if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ ret = -ETIME;
++ printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __FUNCTION__);
++ if (iocp->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
++ mpt_free_msg_frame(iocp, mf);
++ goto fwdl_out;
++ }
++ if (!timeleft)
++ mptctl_timeout_expired(iocp, mf);
++ goto fwdl_out;
++ }
++
++ if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
++ printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __FUNCTION__);
++ mpt_free_msg_frame(iocp, mf);
+ ret = -ENODATA;
+ goto fwdl_out;
+ }
+@@ -913,31 +1056,34 @@ mptctl_do_fw_download(int ioc, char __us
+ if (sgl)
+ kfree_sgl(sgl, sgl_dma, buflist, iocp);
+
+- ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame;
++ ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply;
+ iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
+ if (iocstat == MPI_IOCSTATUS_SUCCESS) {
+- printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name);
++ printk(MYIOC_s_INFO_FMT ": F/W update successfully sent!\n", iocp->name);
+ return 0;
+ } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
+- printk(MYIOC_s_WARN_FMT "Hmmm... F/W download not supported!?!\n",
+- iocp->name);
++ printk(MYIOC_s_WARN_FMT "Hmmm... doesn't support F/W download?\n",
++ iocp->name);
+ printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n",
+- iocp->name);
++ iocp->name);
+ return -EBADRQC;
+ } else if (iocstat == MPI_IOCSTATUS_BUSY) {
+ printk(MYIOC_s_WARN_FMT "IOC_BUSY!\n", iocp->name);
+ printk(MYIOC_s_WARN_FMT "(try again later?)\n", iocp->name);
+ return -EBUSY;
+ } else {
+- printk(MYIOC_s_WARN_FMT "ioctl_fwdl() returned [bad] status = %04xh\n",
+- iocp->name, iocstat);
++ printk(MYIOC_s_WARN_FMT "returned [bad] status = %04xh\n",
++ iocp->name, iocstat);
+ printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name);
+ return -ENOMSG;
+ }
+ return 0;
+
+ fwdl_out:
+- kfree_sgl(sgl, sgl_dma, buflist, iocp);
++
++ CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status);
++ SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0);
++ kfree_sgl(sgl, sgl_dma, buflist, iocp);
+ return ret;
+ }
+
+@@ -1008,7 +1154,7 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i
+ *
+ */
+ sgl = sglbuf;
+- sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1;
++ sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1;
+ while (bytes_allocd < bytes) {
+ this_alloc = min(alloc_sz, bytes-bytes_allocd);
+ buflist[buflist_ent].len = this_alloc;
+@@ -1019,9 +1165,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i
+ alloc_sz = alloc_sz / 2;
+ if (alloc_sz == 0) {
+ printk(MYIOC_s_WARN_FMT "-SG: No can do - "
+- "not enough memory! :-(\n", ioc->name);
++ "not enough memory! :-(\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
+- ioc->name, numfrags);
++ ioc->name, numfrags);
+ goto free_and_fail;
+ }
+ continue;
+@@ -1029,7 +1175,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i
+ dma_addr_t dma_addr;
+
+ bytes_allocd += this_alloc;
+- sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc);
++ sgl->FlagsLength = (0x10000000|sgdir|this_alloc);
++ if (ioc->sg_addr_size == sizeof(u64))
++ sgl->FlagsLength |= MPT_SGE_FLAGS_64_BIT_ADDRESSING;
+ dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
+ sgl->Address = dma_addr;
+
+@@ -1044,8 +1192,8 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i
+
+ /* Need to chain? */
+ if (fragcnt == sg_spill) {
+- printk(MYIOC_s_WARN_FMT
+- "-SG: No can do - " "Chain required! :-(\n", ioc->name);
++ printk(MYIOC_s_WARN_FMT "-SG: No can do - "
++ "Chain required! :-(\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT "(freeing %d frags)\n", ioc->name, numfrags);
+ goto free_and_fail;
+ }
+@@ -1054,9 +1202,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i
+ if (numfrags*8 > MAX_SGL_BYTES){
+ /* GRRRRR... */
+ printk(MYIOC_s_WARN_FMT "-SG: No can do - "
+- "too many SG frags! :-(\n", ioc->name);
++ "too many SG frags! :-(\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
+- ioc->name, numfrags);
++ ioc->name, numfrags);
+ goto free_and_fail;
+ }
+ }
+@@ -1213,6 +1361,7 @@ mptctl_getiocinfo (unsigned long arg, un
+
+ if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
+ (ioc == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
+ kfree(karg);
+@@ -1222,8 +1371,8 @@ mptctl_getiocinfo (unsigned long arg, un
+ /* Verify the data transfer size is correct. */
+ if (karg->hdr.maxDataSize != data_size) {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
+- "Structure size mismatch. Command not completed.\n",
+- ioc->name, __FILE__, __LINE__);
++ "Structure size mismatch. Command not completed.\n",
++ ioc->name, __FILE__, __LINE__);
+ kfree(karg);
+ return -EFAULT;
+ }
+@@ -1275,6 +1424,8 @@ mptctl_getiocinfo (unsigned long arg, un
+ if (ioc->sh) {
+ shost_for_each_device(sdev, ioc->sh) {
+ vdevice = sdev->hostdata;
++ if (vdevice == NULL || vdevice->vtarget == NULL)
++ continue;
+ if (vdevice->vtarget->tflags &
+ MPT_TARGET_FLAGS_RAID_COMPONENT)
+ continue;
+@@ -1346,6 +1497,7 @@ mptctl_gettargetinfo (unsigned long arg)
+
+ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+ (ioc == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
+ return -ENODEV;
+@@ -1362,8 +1514,8 @@ mptctl_gettargetinfo (unsigned long arg)
+ port = karg.hdr.port;
+
+ if (maxWordsLeft <= 0) {
+- printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
+- ioc->name, __FILE__, __LINE__);
++ printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
++ ioc->name, __FILE__, __LINE__);
+ return -ENOMEM;
+ }
+
+@@ -1383,8 +1535,8 @@ mptctl_gettargetinfo (unsigned long arg)
+ */
+ pmem = kzalloc(numBytes, GFP_KERNEL);
+ if (!pmem) {
+- printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
+- ioc->name, __FILE__, __LINE__);
++ printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
++ ioc->name, __FILE__, __LINE__);
+ return -ENOMEM;
+ }
+ pdata = (int *) pmem;
+@@ -1396,6 +1548,8 @@ mptctl_gettargetinfo (unsigned long arg)
+ if (!maxWordsLeft)
+ continue;
+ vdevice = sdev->hostdata;
++ if (vdevice == NULL || vdevice->vtarget == NULL)
++ continue;
+ if (vdevice->vtarget->tflags &
+ MPT_TARGET_FLAGS_RAID_COMPONENT)
+ continue;
+@@ -1460,6 +1614,7 @@ mptctl_readtest (unsigned long arg)
+
+ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+ (ioc == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
+ return -ENODEV;
+@@ -1521,6 +1676,7 @@ mptctl_eventquery (unsigned long arg)
+
+ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+ (ioc == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
+ return -ENODEV;
+@@ -1560,6 +1716,7 @@ mptctl_eventenable (unsigned long arg)
+
+ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+ (ioc == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
+ return -ENODEV;
+@@ -1573,8 +1730,7 @@ mptctl_eventenable (unsigned long arg)
+ int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
+ ioc->events = kzalloc(sz, GFP_KERNEL);
+ if (!ioc->events) {
+- printk(MYIOC_s_ERR_FMT
+- ": ERROR - Insufficient memory to add adapter!\n",
++ printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
+ ioc->name);
+ return -ENOMEM;
+ }
+@@ -1609,13 +1765,14 @@ mptctl_eventreport (unsigned long arg)
+
+ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+ (ioc == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
+ return -ENODEV;
+ }
++
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n",
+ ioc->name));
+-
+ numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
+ maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
+
+@@ -1663,6 +1820,7 @@ mptctl_replace_fw (unsigned long arg)
+
+ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+ (ioc == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
+ return -ENODEV;
+@@ -1694,8 +1852,8 @@ mptctl_replace_fw (unsigned long arg)
+ */
+ if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - "
+- "Unable to read in mpt_ioctl_replace_fw image "
+- "@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
++ "Unable to read in mpt_ioctl_replace_fw image "
++ "@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
+ mpt_free_fw_memory(ioc);
+ return -EFAULT;
+ }
+@@ -1712,7 +1870,7 @@ mptctl_replace_fw (unsigned long arg)
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+- * -EBUSY if previous command timeout and IOC reset is not complete.
++ * -EBUSY if previous command timout and IOC reset is not complete.
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ * -ETIME if timer expires
+@@ -1737,6 +1895,7 @@ mptctl_mpt_command (unsigned long arg)
+
+ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+ (ioc == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
+ return -ENODEV;
+@@ -1752,7 +1911,7 @@ mptctl_mpt_command (unsigned long arg)
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+- * -EBUSY if previous command timeout and IOC reset is not complete.
++ * -EBUSY if previous command timout and IOC reset is not complete.
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ * -ETIME if timer expires
+@@ -1775,8 +1934,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ int sz, rc = 0;
+ int msgContext;
+ u16 req_idx;
+- ulong timeout;
++ unsigned long timeout;
++ unsigned long timeleft;
+ struct scsi_device *sdev;
++ unsigned long flags;
++ u8 function;
+
+ /* bufIn and bufOut are used for user to kernel space transfers
+ */
+@@ -1785,28 +1947,28 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+
+ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+ (ioc == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+- if (!ioc->ioctl) {
+- printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
+- "No memory available during driver init.\n",
+- __FILE__, __LINE__);
+- return -ENOMEM;
+- } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
++
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
++ if (ioc->ioc_reset_in_progress) {
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
+- "Busy with IOC Reset \n", __FILE__, __LINE__);
++ "Busy with diagnostic reset\n", __FILE__, __LINE__);
+ return -EBUSY;
+ }
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+ /* Verify that the final request frame will not be too large.
+ */
+ sz = karg.dataSgeOffset * 4;
+ if (karg.dataInSize > 0)
+- sz += sizeof(dma_addr_t) + sizeof(u32);
++ sz += ioc->SGE_size;
+ if (karg.dataOutSize > 0)
+- sz += sizeof(dma_addr_t) + sizeof(u32);
++ sz += ioc->SGE_size;
+
+ if (sz > ioc->req_sz) {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
+@@ -1832,18 +1994,19 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
+ "Unable to read MF from mpt_ioctl_command struct @ %p\n",
+ ioc->name, __FILE__, __LINE__, mfPtr);
++ function = -1;
+ rc = -EFAULT;
+ goto done_free_mem;
+ }
+ hdr->MsgContext = cpu_to_le32(msgContext);
+-
++ function = hdr->Function;
+
+ /* Verify that this request is allowed.
+ */
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n",
+- ioc->name, hdr->Function, mf));
++ ioc->name, function, mf));
+
+- switch (hdr->Function) {
++ switch (function) {
+ case MPI_FUNCTION_IOC_FACTS:
+ case MPI_FUNCTION_PORT_FACTS:
+ karg.dataOutSize = karg.dataInSize = 0;
+@@ -1898,7 +2061,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ }
+
+ pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
+- pScsiReq->MsgFlags |= mpt_msg_flags();
++ pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
+
+
+ /* verify that app has not requested
+@@ -1920,6 +2083,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ struct scsi_target *starget = scsi_target(sdev);
+ VirtTarget *vtarget = starget->hostdata;
+
++ if (vtarget == NULL)
++ continue;
+ if ((pScsiReq->TargetID == vtarget->id) &&
+ (pScsiReq->Bus == vtarget->channel) &&
+ (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+@@ -1940,9 +2105,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ pScsiReq->Control = cpu_to_le32(scsidir | qtag);
+ pScsiReq->DataLength = cpu_to_le32(dataSize);
+
+- ioc->ioctl->reset = MPTCTL_RESET_OK;
+- ioc->ioctl->id = pScsiReq->TargetID;
+-
+ } else {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
+ "SCSI driver is not loaded. \n",
+@@ -1955,7 +2117,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ case MPI_FUNCTION_SMP_PASSTHROUGH:
+ /* Check mf->PassthruFlags to determine if
+ * transfer is ImmediateMode or not.
+- * Immediate mode returns data in the ReplyFrame.
++ * Immediate mode returns data in the reply.
+ * Else, we are sending request and response data
+ * in two SGLs at the end of the mf.
+ */
+@@ -1984,7 +2146,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ int dataSize;
+
+ pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
+- pScsiReq->MsgFlags |= mpt_msg_flags();
++ pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
+
+
+ /* verify that app has not requested
+@@ -2019,8 +2181,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ pScsiReq->Control = cpu_to_le32(scsidir | qtag);
+ pScsiReq->DataLength = cpu_to_le32(dataSize);
+
+- ioc->ioctl->reset = MPTCTL_RESET_OK;
+- ioc->ioctl->id = pScsiReq->TargetID;
+ } else {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
+ "SCSI driver is not loaded. \n",
+@@ -2031,20 +2191,15 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ break;
+
+ case MPI_FUNCTION_SCSI_TASK_MGMT:
+- {
+- MPT_SCSI_HOST *hd = NULL;
+- if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) {
+- printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
+- "SCSI driver not loaded or SCSI host not found. \n",
+- ioc->name, __FILE__, __LINE__);
+- rc = -EFAULT;
+- goto done_free_mem;
+- } else if (mptctl_set_tm_flags(hd) != 0) {
+- rc = -EPERM;
+- goto done_free_mem;
+- }
+- }
++ {
++ SCSITaskMgmt_t *pScsiTm;
++ pScsiTm = (SCSITaskMgmt_t *)mf;
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tTaskType=0x%x MsgFlags=0x%x "
++ "TaskMsgContext=0x%x id=%d channel=%d\n", ioc->name, pScsiTm->TaskType,
++ le32_to_cpu(pScsiTm->TaskMsgContext), pScsiTm->MsgFlags,
++ pScsiTm->TargetID, pScsiTm->Bus));
+ break;
++ }
+
+ case MPI_FUNCTION_IOC_INIT:
+ {
+@@ -2054,7 +2209,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ /* Verify that all entries in the IOC INIT match
+ * existing setup (and in LE format).
+ */
+- if (sizeof(dma_addr_t) == sizeof(u64)) {
++ if (ioc->sg_addr_size == sizeof(u64)) {
+ high_addr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32));
+ sense_high= cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
+ } else {
+@@ -2062,6 +2217,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ sense_high= 0;
+ }
+
++ if (!pInit->MaxDevices && !pInit->MaxBuses) {
++ pInit->MaxDevices = ioc->facts.MaxDevices;
++ pInit->MaxBuses = ioc->facts.MaxBuses;
++ }
++
+ if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) ||
+ (pInit->MaxBuses != ioc->facts.MaxBuses) ||
+ (pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) ||
+@@ -2102,7 +2262,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
+ "Illegal request (function 0x%x) \n",
+- ioc->name, __FILE__, __LINE__, hdr->Function);
++ ioc->name, __FILE__, __LINE__, function);
+ rc = -EFAULT;
+ goto done_free_mem;
+ }
+@@ -2128,8 +2288,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ if (karg.dataInSize > 0) {
+ flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_END_OF_BUFFER |
+- MPI_SGE_FLAGS_DIRECTION |
+- mpt_addr_size() )
++ MPI_SGE_FLAGS_DIRECTION )
+ << MPI_SGE_FLAGS_SHIFT;
+ } else {
+ flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
+@@ -2146,8 +2305,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ /* Set up this SGE.
+ * Copy to MF and to sglbuf
+ */
+- mpt_add_sge(psge, flagsLength, dma_addr_out);
+- psge += (sizeof(u32) + sizeof(dma_addr_t));
++ ioc->add_sge(psge, flagsLength, dma_addr_out);
++ psge += ioc->SGE_size;
+
+ /* Copy user data to kernel space.
+ */
+@@ -2180,17 +2339,24 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ /* Set up this SGE
+ * Copy to MF and to sglbuf
+ */
+- mpt_add_sge(psge, flagsLength, dma_addr_in);
++ ioc->add_sge(psge, flagsLength, dma_addr_in);
+ }
+ }
+ } else {
+ /* Add a NULL SGE
+ */
+- mpt_add_sge(psge, flagsLength, (dma_addr_t) -1);
++ ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
+ }
+
+- ioc->ioctl->wait_done = 0;
+- if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext);
++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
++ if (function == MPI_FUNCTION_SCSI_TASK_MGMT) {
++
++ mutex_lock(&ioc->taskmgmt_cmds.mutex);
++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++ goto done_free_mem;
++ }
+
+ DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
+
+@@ -2198,53 +2364,57 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+ mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf);
+ else {
+- rc =mpt_send_handshake_request(mptctl_id, ioc,
+- sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
++ rc = mpt_send_handshake_request(mptctl_id, ioc,
++ sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
+ if (rc != 0) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "_send_handshake FAILED! (ioc %p, mf %p)\n",
++ "send_handshake FAILED! (ioc %p, mf %p)\n",
+ ioc->name, ioc, mf));
+- mptctl_free_tm_flags(ioc);
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ rc = -ENODATA;
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+ goto done_free_mem;
+ }
+ }
+-
+ } else
+ mpt_put_msg_frame(mptctl_id, ioc, mf);
+
+ /* Now wait for the command to complete */
+ timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT;
+- timeout = wait_event_timeout(mptctl_wait,
+- ioc->ioctl->wait_done == 1,
+- HZ*timeout);
+-
+- if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) {
+- /* Now we need to reset the board */
+-
+- if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT)
+- mptctl_free_tm_flags(ioc);
+-
+- mptctl_timeout_expired(ioc->ioctl);
+- rc = -ENODATA;
++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*timeout);
++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ rc = -ETIME;
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n",
++ ioc->name, __FUNCTION__));
++ if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
++ goto done_free_mem;
++ }
++ if (!timeleft) {
++ mptctl_timeout_expired(ioc, mf);
++ mf = NULL;
++ }
+ goto done_free_mem;
+ }
+
++ if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++
+ mf = NULL;
+
+ /* If a valid reply frame, copy to the user.
+ * Offset 2: reply length in U32's
+ */
+- if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) {
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
+ if (karg.maxReplyBytes < ioc->reply_sz) {
+- sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
++ sz = min(karg.maxReplyBytes, 4*ioc->ioctl_cmds.reply[2]);
+ } else {
+- sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
++ sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]);
+ }
+-
+ if (sz > 0) {
+ if (copy_to_user(karg.replyFrameBufPtr,
+- &ioc->ioctl->ReplyFrame, sz)){
++ ioc->ioctl_cmds.reply, sz)){
+ printk(MYIOC_s_ERR_FMT
+ "%s@%d::mptctl_do_mpt_command - "
+ "Unable to write out reply frame %p\n",
+@@ -2257,10 +2427,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+
+ /* If valid sense data, copy to user.
+ */
+- if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) {
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) {
+ sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
+ if (sz > 0) {
+- if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) {
++ if (copy_to_user(karg.senseDataPtr, ioc->ioctl_cmds.sense, sz)) {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
+ "Unable to write sense data to user %p\n",
+ ioc->name, __FILE__, __LINE__,
+@@ -2274,9 +2444,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ /* If the overall status is _GOOD and data in, copy data
+ * to user.
+ */
+- if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) &&
+- (karg.dataInSize > 0) && (bufIn.kptr)) {
+-
++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) &&
++ (karg.dataInSize > 0) && (bufIn.kptr)) {
+ if (copy_to_user(karg.dataInBufPtr,
+ bufIn.kptr, karg.dataInSize)) {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
+@@ -2289,9 +2458,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+
+ done_free_mem:
+
+- ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_COMMAND_GOOD |
+- MPT_IOCTL_STATUS_SENSE_VALID |
+- MPT_IOCTL_STATUS_RF_VALID );
++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
+
+ /* Free the allocated memory.
+ */
+@@ -2320,7 +2488,7 @@ done_free_mem:
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+- * -EBUSY if previous command timeout and IOC reset is not complete.
++ * -EBUSY if previous command timout and IOC reset is not complete.
+ * -ENODEV if no such device/adapter
+ * -ETIME if timer expires
+ * -ENOMEM if memory allocation error
+@@ -2331,16 +2499,17 @@ mptctl_hp_hostinfo(unsigned long arg, un
+ hp_host_info_t __user *uarg = (void __user *) arg;
+ MPT_ADAPTER *ioc;
+ struct pci_dev *pdev;
+- char *pbuf=NULL;
++ char *pbuf=NULL;
+ dma_addr_t buf_dma;
+ hp_host_info_t karg;
+- CONFIGPARMS cfg;
+- ConfigPageHeader_t hdr;
+ int iocnum;
+- int rc, cim_rev;
++ int cim_rev;
+ ToolboxIstwiReadWriteRequest_t *IstwiRWRequest;
+ MPT_FRAME_HDR *mf = NULL;
+ MPIHeader_t *mpi_hdr;
++ unsigned long timeleft;
++ int retval;
++ u32 MsgContext;
+
+ /* Reset long to int. Should affect IA64 and SPARC only
+ */
+@@ -2360,13 +2529,14 @@ mptctl_hp_hostinfo(unsigned long arg, un
+
+ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+ (ioc == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
+ return -ENODEV;
+ }
++
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n",
+ ioc->name));
+-
+ /* Fill in the data and return the structure to the calling
+ * program
+ */
+@@ -2406,42 +2576,9 @@ mptctl_hp_hostinfo(unsigned long arg, un
+ karg.fw_version[10] = (ioc->facts.FWVersion.Struct.Dev % 10 ) + '0';
+ karg.fw_version[11] = '\0';
+
+- /* Issue a config request to get the device serial number
+- */
+- hdr.PageVersion = 0;
+- hdr.PageLength = 0;
+- hdr.PageNumber = 0;
+- hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
+- cfg.cfghdr.hdr = &hdr;
+- cfg.physAddr = -1;
+- cfg.pageAddr = 0;
+- cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+- cfg.dir = 0; /* read */
+- cfg.timeout = 10;
++ strncpy(karg.serial_number, ioc->board_tracer, 16);
+
+- strncpy(karg.serial_number, " ", 24);
+- if (mpt_config(ioc, &cfg) == 0) {
+- if (cfg.cfghdr.hdr->PageLength > 0) {
+- /* Issue the second config page request */
+- cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+-
+- pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
+- if (pbuf) {
+- cfg.physAddr = buf_dma;
+- if (mpt_config(ioc, &cfg) == 0) {
+- ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
+- if (strlen(pdata->BoardTracerNumber) > 1) {
+- strncpy(karg.serial_number, pdata->BoardTracerNumber, 24);
+- karg.serial_number[24-1]='\0';
+- }
+- }
+- pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
+- pbuf = NULL;
+- }
+- }
+- }
+- rc = mpt_GetIocState(ioc, 1);
+- switch (rc) {
++ switch (mpt_GetIocState(ioc, 1)) {
+ case MPI_IOC_STATE_OPERATIONAL:
+ karg.ioc_status = HP_STATUS_OK;
+ break;
+@@ -2468,12 +2605,12 @@ mptctl_hp_hostinfo(unsigned long arg, un
+ karg.soft_resets = 0;
+ karg.timeouts = 0;
+ if (ioc->sh != NULL) {
+- MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
++ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+
+ if (hd && (cim_rev == 1)) {
+- karg.hard_resets = hd->hard_resets;
+- karg.soft_resets = hd->soft_resets;
+- karg.timeouts = hd->timeouts;
++ karg.hard_resets = ioc->hard_resets;
++ karg.soft_resets = ioc->soft_resets;
++ karg.timeouts = ioc->timeouts;
+ }
+ }
+
+@@ -2482,16 +2619,18 @@ mptctl_hp_hostinfo(unsigned long arg, un
+ */
+ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
+- ioc->name,__func__));
++ ioc->name,__FUNCTION__));
++ retval = -ENOMEM;
+ goto out;
+ }
+
+ IstwiRWRequest = (ToolboxIstwiReadWriteRequest_t *)mf;
+ mpi_hdr = (MPIHeader_t *) mf;
++ MsgContext = mpi_hdr->MsgContext;
+ memset(IstwiRWRequest,0,sizeof(ToolboxIstwiReadWriteRequest_t));
+ IstwiRWRequest->Function = MPI_FUNCTION_TOOLBOX;
+ IstwiRWRequest->Tool = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL;
+- IstwiRWRequest->MsgContext = mpi_hdr->MsgContext;
++ IstwiRWRequest->MsgContext = MsgContext;
+ IstwiRWRequest->Flags = MPI_TB_ISTWI_FLAGS_READ;
+ IstwiRWRequest->NumAddressBytes = 0x01;
+ IstwiRWRequest->DataLength = cpu_to_le16(0x04);
+@@ -2501,28 +2640,30 @@ mptctl_hp_hostinfo(unsigned long arg, un
+ IstwiRWRequest->DeviceAddr = 0xB0;
+
+ pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma);
+- if (!pbuf)
++ if (!pbuf) {
++ retval = -ENOMEM;
+ goto out;
+- mpt_add_sge((char *)&IstwiRWRequest->SGL,
+- (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);
++ }
++ ioc->add_sge((char *)&IstwiRWRequest->SGL, (MPT_SGE_FLAGS_SSIMPLE_READ|4),buf_dma);
+
+- ioc->ioctl->wait_done = 0;
++ retval = 0;
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, IstwiRWRequest->MsgContext);
++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
+ mpt_put_msg_frame(mptctl_id, ioc, mf);
+-
+- rc = wait_event_timeout(mptctl_wait,
+- ioc->ioctl->wait_done == 1,
+- HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */);
+-
+- if(rc <=0 && (ioc->ioctl->wait_done != 1 )) {
+- /*
+- * Now we need to reset the board
+- */
+- mpt_free_msg_frame(ioc, mf);
+- mptctl_timeout_expired(ioc->ioctl);
++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*MPT_IOCTL_DEFAULT_TIMEOUT);
++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ retval = -ETIME;
++ printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __FUNCTION__);
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
++ mpt_free_msg_frame(ioc, mf);
++ goto out;
++ }
++ if (!timeleft)
++ mptctl_timeout_expired(ioc, mf);
+ goto out;
+ }
+
+- /*
++ /*
+ *ISTWI Data Definition
+ * pbuf[0] = FW_VERSION = 0x4
+ * pbuf[1] = Bay Count = 6 or 4 or 2, depending on
+@@ -2531,10 +2672,13 @@ mptctl_hp_hostinfo(unsigned long arg, un
+ * bays have drives in them
+ * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3)
+ */
+- if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID)
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)
+ karg.rsvd = *(u32 *)pbuf;
+
+ out:
++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
++
+ if (pbuf)
+ pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma);
+
+@@ -2547,7 +2691,7 @@ mptctl_hp_hostinfo(unsigned long arg, un
+ return -EFAULT;
+ }
+
+- return 0;
++ return retval;
+
+ }
+
+@@ -2557,7 +2701,7 @@ mptctl_hp_hostinfo(unsigned long arg, un
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+- * -EBUSY if previous command timeout and IOC reset is not complete.
++ * -EBUSY if previous command timout and IOC reset is not complete.
+ * -ENODEV if no such device/adapter
+ * -ETIME if timer expires
+ * -ENOMEM if memory allocation error
+@@ -2587,13 +2731,14 @@ mptctl_hp_targetinfo(unsigned long arg)
+
+ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+ (ioc == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
+- ioc->name));
+
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_targetinfo called.\n",
++ ioc->name));
+ /* There is nothing to do for FCP parts.
+ */
+ if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
+@@ -2685,7 +2830,7 @@ mptctl_hp_targetinfo(unsigned long arg)
+ pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma);
+ }
+ }
+- hd = shost_priv(ioc->sh);
++ hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+ if (hd != NULL)
+ karg.select_timeouts = hd->sel_timeout[karg.hdr.id];
+
+@@ -2703,7 +2848,7 @@ mptctl_hp_targetinfo(unsigned long arg)
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+-static const struct file_operations mptctl_fops = {
++static struct file_operations mptctl_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .release = mptctl_release,
+@@ -2743,8 +2888,9 @@ compat_mptfwxfer_ioctl(struct file *filp
+ iocnumX = kfw32.iocnum & 0xFF;
+ if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+ (iocp == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+- __LINE__, iocnumX);
++ __LINE__, iocnumX);
+ return -ENODEV;
+ }
+
+@@ -2759,7 +2905,7 @@ compat_mptfwxfer_ioctl(struct file *filp
+
+ ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
+
+- mutex_unlock(&iocp->ioctl->ioctl_mutex);
++ mutex_unlock(&iocp->ioctl_cmds.mutex);
+
+ return ret;
+ }
+@@ -2783,8 +2929,9 @@ compat_mpt_command(struct file *filp, un
+ iocnumX = karg32.hdr.iocnum & 0xFF;
+ if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+ (iocp == NULL)) {
++ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
+- __LINE__, iocnumX);
++ __LINE__, iocnumX);
+ return -ENODEV;
+ }
+
+@@ -2813,7 +2960,7 @@ compat_mpt_command(struct file *filp, un
+ */
+ ret = mptctl_do_mpt_command (karg, &uarg->MF);
+
+- mutex_unlock(&iocp->ioctl->ioctl_mutex);
++ mutex_unlock(&iocp->ioctl_cmds.mutex);
+
+ return ret;
+ }
+@@ -2833,6 +2980,31 @@ static long compat_mpctl_ioctl(struct fi
+ case MPTHARDRESET:
+ case HP_GETHOSTINFO:
+ case HP_GETTARGETINFO:
++#if defined(CPQ_CIM)
++ case CC_CSMI_SAS_GET_DRIVER_INFO:
++ case CC_CSMI_SAS_GET_CNTLR_CONFIG:
++ case CC_CSMI_SAS_GET_CNTLR_STATUS:
++ case CC_CSMI_SAS_GET_SCSI_ADDRESS:
++ case CC_CSMI_SAS_GET_DEVICE_ADDRESS:
++ case CC_CSMI_SAS_GET_PHY_INFO:
++ case CC_CSMI_SAS_GET_SATA_SIGNATURE:
++ case CC_CSMI_SAS_GET_LINK_ERRORS:
++ case CC_CSMI_SAS_SMP_PASSTHRU:
++ case CC_CSMI_SAS_SSP_PASSTHRU:
++ case CC_CSMI_SAS_FIRMWARE_DOWNLOAD:
++ case CC_CSMI_SAS_GET_RAID_INFO:
++ case CC_CSMI_SAS_GET_RAID_CONFIG:
++ case CC_CSMI_SAS_GET_RAID_FEATURES:
++ case CC_CSMI_SAS_SET_RAID_CONTROL:
++ case CC_CSMI_SAS_GET_RAID_ELEMENT:
++ case CC_CSMI_SAS_SET_RAID_OPERATION:
++ case CC_CSMI_SAS_SET_PHY_INFO:
++ case CC_CSMI_SAS_STP_PASSTHRU:
++ case CC_CSMI_SAS_TASK_MANAGEMENT:
++ case CC_CSMI_SAS_PHY_CONTROL:
++ case CC_CSMI_SAS_GET_CONNECTOR_INFO:
++ case CC_CSMI_SAS_GET_LOCATION:
++#endif /* CPQ_CIM */
+ case MPTTEST:
+ ret = __mptctl_ioctl(f, cmd, arg);
+ break;
+@@ -2865,21 +3037,11 @@ static long compat_mpctl_ioctl(struct fi
+ static int
+ mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ {
+- MPT_IOCTL *mem;
+ MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+
+- /*
+- * Allocate and inite a MPT_IOCTL structure
+- */
+- mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL);
+- if (!mem) {
+- mptctl_remove(pdev);
+- return -ENOMEM;
+- }
++ mutex_init(&ioc->ioctl_cmds.mutex);
++ init_completion(&ioc->ioctl_cmds.done);
+
+- ioc->ioctl = mem;
+- ioc->ioctl->ioc = ioc;
+- mutex_init(&ioc->ioctl->ioctl_mutex);
+ return 0;
+ }
+
+@@ -2893,9 +3055,22 @@ mptctl_probe(struct pci_dev *pdev, const
+ static void
+ mptctl_remove(struct pci_dev *pdev)
+ {
++#if defined(DIAG_BUFFER_SUPPORT)
+ MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
++ int i;
+
+- kfree ( ioc->ioctl );
++ /*
++ * Cleanup diag buffer allocated memory
++ */
++ for (i = 0; i < MPI_DIAG_BUF_TYPE_COUNT; i++) {
++ if (ioc->DiagBuffer[i] == NULL)
++ continue;
++ pci_free_consistent(ioc->pcidev, ioc->DiagBuffer_sz[i],
++ ioc->DiagBuffer[i], ioc->DiagBuffer_dma[i]);
++ ioc->DiagBuffer[i] = NULL;
++ ioc->DiagBuffer_Status[i] = 0;
++ }
++#endif
+ }
+
+ static struct mpt_pci_driver mptctl_driver = {
+@@ -2935,6 +3110,7 @@ static int __init mptctl_init(void)
+ goto out_fail;
+ }
+
++ mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
+ mpt_reset_register(mptctl_id, mptctl_ioc_reset);
+ mpt_event_register(mptctl_id, mptctl_event_process);
+
+@@ -2956,15 +3132,23 @@ static void mptctl_exit(void)
+
+ /* De-register reset handler from base module */
+ mpt_reset_deregister(mptctl_id);
++ mpt_reset_deregister(mptctl_taskmgmt_id);
+
+ /* De-register callback handler from base module */
+ mpt_deregister(mptctl_id);
+
+ mpt_device_driver_deregister(MPTCTL_DRIVER);
+-
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
++#if defined(CPQ_CIM)
++#include "csmi/csmisas.c"
++#endif // CPQ_CIM
++
++#if defined(DIAG_BUFFER_SUPPORT)
++#include "rejected_ioctls/diag_buffer.c"
++#endif
++
+ module_init(mptctl_init);
+ module_exit(mptctl_exit);
+--- a/drivers/message/fusion/mptctl.h
++++ b/drivers/message/fusion/mptctl.h
+@@ -1,5 +1,5 @@
+ /*
+- * linux/drivers/message/fusion/mptioctl.h
++ * linux/drivers/message/fusion/mptctl.h
+ * Fusion MPT misc device (ioctl) driver.
+ * For use with PCI chip/adapter(s):
+ * LSIFC9xx/LSI409xx Fibre Channel
+@@ -460,8 +460,5 @@ typedef struct _hp_target_info {
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+-
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-
+ #endif
+
+--- a/drivers/message/fusion/mptdebug.h
++++ b/drivers/message/fusion/mptdebug.h
+@@ -17,6 +17,10 @@
+ *
+ * Example: (programming for MPT_DEBUG_EVENTS on host 5)
+ *
++ * global setting:
++ * echo 8 > /sys/module/mptbase/parameters/mpt_debug_level
++ *
++ * per host setting:
+ * echo 8 > /sys/class/scsi_host/host5/debug_level
+ *
+ * --------------------------------------------------------
+@@ -55,9 +59,11 @@
+ #define MPT_DEBUG_RESET 0x00008000
+ #define MPT_DEBUG_SCSI 0x00010000
+ #define MPT_DEBUG_IOCTL 0x00020000
++#define MPT_DEBUG_CSMISAS 0x00040000
+ #define MPT_DEBUG_FC 0x00080000
+ #define MPT_DEBUG_SAS 0x00100000
+ #define MPT_DEBUG_SAS_WIDE 0x00200000
++#define MPT_DEBUG_36GB_MEM 0x00400000
+
+ /*
+ * CONFIG_FUSION_LOGGING - enabled in Kconfig
+@@ -126,6 +132,9 @@
+ #define dctlprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL)
+
++#define dcsmisasprintk(IOC, CMD) \
++ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CSMISAS)
++
+ #define dfcprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FC)
+
+@@ -135,7 +144,8 @@
+ #define dsaswideprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE)
+
+-
++#define d36memprintk(IOC, CMD) \
++ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_36GB_MEM)
+
+ /*
+ * Verbose logging
+--- a/drivers/message/fusion/mptfc.c
++++ b/drivers/message/fusion/mptfc.c
+@@ -43,6 +43,7 @@
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+@@ -52,8 +53,10 @@
+ #include <linux/delay.h> /* for mdelay */
+ #include <linux/interrupt.h> /* needed for in_interrupt() proto */
+ #include <linux/reboot.h> /* notifier code */
++#include <linux/sched.h>
+ #include <linux/workqueue.h>
+ #include <linux/sort.h>
++#include <linux/pci.h>
+
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -84,6 +87,14 @@ MODULE_PARM_DESC(mptfc_dev_loss_tmo, " I
+ " return following a device loss event."
+ " Default=60.");
+
++static int mpt_sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
++static int mptfc_set_sdev_queue_depth(const char *val, struct kernel_param *kp);
++module_param_call(mpt_sdev_queue_depth, mptfc_set_sdev_queue_depth,
++ param_get_int, &mpt_sdev_queue_depth, 0600);
++MODULE_PARM_DESC(mpt_sdev_queue_depth,
++ " Max Device Queue Depth (default="
++ __MODULE_STRING(MPT_SCSI_CMD_PER_DEV_HIGH) ")");
++
+ /* scsi-mid layer global parmeter is max_report_luns, which is 511 */
+ #define MPTFC_MAX_LUN (16895)
+ static int max_lun = MPTFC_MAX_LUN;
+@@ -183,6 +194,34 @@ static struct fc_function_template mptfc
+ .show_host_symbolic_name = 1,
+ };
+
++/**
++ * mptfc_set_sdev_queue_depth - global setting of the mpt_sdev_queue_depth
++ * found via /sys/module/mptfc/parameters/mpt_sdev_queue_depth
++ * @val:
++ * @kp:
++ *
++ * Returns
++ **/
++static int
++mptfc_set_sdev_queue_depth(const char *val, struct kernel_param *kp)
++{
++ int ret = param_set_int(val, kp);
++ MPT_ADAPTER *ioc;
++ struct scsi_device *sdev;
++
++ if (ret)
++ return ret;
++
++ list_for_each_entry(ioc, &ioc_list, list) {
++ if (ioc->bus_type != FC)
++ continue;
++ shost_for_each_device(sdev, ioc->sh)
++ mptscsih_change_queue_depth(sdev, mpt_sdev_queue_depth);
++ ioc->sdev_queue_depth = mpt_sdev_queue_depth;
++ }
++ return 0;
++}
++
+ static int
+ mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
+ int (*func)(struct scsi_cmnd *SCpnt),
+@@ -194,7 +233,7 @@ mptfc_block_error_handler(struct scsi_cm
+ struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
+ unsigned long flags;
+ int ready;
+- MPT_ADAPTER *ioc;
++ MPT_ADAPTER *ioc;
+
+ hd = shost_priv(SCpnt->device->host);
+ ioc = hd->ioc;
+@@ -231,28 +270,28 @@ static int
+ mptfc_abort(struct scsi_cmnd *SCpnt)
+ {
+ return
+- mptfc_block_error_handler(SCpnt, mptscsih_abort, __func__);
++ mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
+ }
+
+ static int
+ mptfc_dev_reset(struct scsi_cmnd *SCpnt)
+ {
+ return
+- mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __func__);
++ mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
+ }
+
+ static int
+ mptfc_bus_reset(struct scsi_cmnd *SCpnt)
+ {
+ return
+- mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __func__);
++ mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
+ }
+
+ static int
+ mptfc_host_reset(struct scsi_cmnd *SCpnt)
+ {
+ return
+- mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __func__);
++ mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
+ }
+
+ static void
+@@ -476,6 +515,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int
+ if (vtarget) {
+ vtarget->id = pg0->CurrentTargetID;
+ vtarget->channel = pg0->CurrentBus;
++ vtarget->deleted = 0;
+ }
+ }
+ *((struct mptfc_rport_info **)rport->dd_data) = ri;
+@@ -513,6 +553,7 @@ mptfc_target_destroy(struct scsi_target
+ struct fc_rport *rport;
+ struct mptfc_rport_info *ri;
+
++ printk("%s - starget=%p\n", __FUNCTION__, starget);
+ rport = starget_to_rport(starget);
+ if (rport) {
+ ri = *((struct mptfc_rport_info **)rport->dd_data);
+@@ -560,6 +601,7 @@ mptfc_target_alloc(struct scsi_target *s
+
+ return rc;
+ }
++
+ /*
+ * mptfc_dump_lun_info
+ * @ioc
+@@ -589,7 +631,6 @@ mptfc_dump_lun_info(MPT_ADAPTER *ioc, st
+ (unsigned long long)nn));
+ }
+
+-
+ /*
+ * OS entry point to allow host driver to alloc memory
+ * for each scsi device. Called once per device the bus scan.
+@@ -604,7 +645,7 @@ mptfc_slave_alloc(struct scsi_device *sd
+ VirtDevice *vdevice;
+ struct scsi_target *starget;
+ struct fc_rport *rport;
+- MPT_ADAPTER *ioc;
++ MPT_ADAPTER *ioc;
+
+ starget = scsi_target(sdev);
+ rport = starget_to_rport(starget);
+@@ -614,11 +655,10 @@ mptfc_slave_alloc(struct scsi_device *sd
+
+ hd = shost_priv(sdev->host);
+ ioc = hd->ioc;
+-
+ vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+ if (!vdevice) {
+ printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
+- ioc->name, sizeof(VirtDevice));
++ ioc->name, sizeof(VirtDevice));
+ return -ENOMEM;
+ }
+
+@@ -635,10 +675,7 @@ mptfc_slave_alloc(struct scsi_device *sd
+ vdevice->lun = sdev->lun;
+
+ vtarget->num_luns++;
+-
+-
+ mptfc_dump_lun_info(ioc, rport, sdev, vtarget);
+-
+ return 0;
+ }
+
+@@ -944,11 +981,12 @@ start_over:
+ return rc;
+ }
+
+-static void
++static int
+ mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
+ {
+ int ii;
+ FCPortPage1_t *pp1;
++ int rc;
+
+ #define MPTFC_FW_DEVICE_TIMEOUT (1)
+ #define MPTFC_FW_IO_PEND_TIMEOUT (1)
+@@ -956,8 +994,8 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTE
+ #define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS)
+
+ for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
+- if (mptfc_GetFcPortPage1(ioc, ii) != 0)
+- continue;
++ if ((rc = mptfc_GetFcPortPage1(ioc, ii)) < 0)
++ return rc;
+ pp1 = ioc->fc_data.fc_port_page1[ii].data;
+ if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT)
+ && (pp1->InitiatorIoPendTimeout == MPTFC_FW_IO_PEND_TIMEOUT)
+@@ -968,8 +1006,10 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTE
+ pp1->InitiatorIoPendTimeout = MPTFC_FW_IO_PEND_TIMEOUT;
+ pp1->Flags &= ~OFF_FLAGS;
+ pp1->Flags |= ON_FLAGS;
+- mptfc_WriteFcPortPage1(ioc, ii);
++ if ((rc = mptfc_WriteFcPortPage1(ioc, ii)) < 0)
++ return rc;
+ }
++ return 0;
+ }
+
+
+@@ -1082,10 +1122,13 @@ mptfc_link_status_change(struct work_str
+ static void
+ mptfc_setup_reset(struct work_struct *work)
+ {
+- MPT_ADAPTER *ioc =
++ MPT_ADAPTER *ioc =
+ container_of(work, MPT_ADAPTER, fc_setup_reset_work);
+ u64 pn;
+ struct mptfc_rport_info *ri;
++ struct scsi_target *starget;
++ VirtTarget *vtarget;
++
+
+ /* reset about to happen, delete (block) all rports */
+ list_for_each_entry(ri, &ioc->fc_rports, list) {
+@@ -1093,6 +1136,12 @@ mptfc_setup_reset(struct work_struct *wo
+ ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
+ fc_remote_port_delete(ri->rport); /* won't sleep */
+ ri->rport = NULL;
++ starget = ri->starget;
++ if (starget) {
++ vtarget = starget->hostdata;
++ if (vtarget)
++ vtarget->deleted = 1;
++ }
+
+ pn = (u64)ri->pg0.WWPN.High << 32 |
+ (u64)ri->pg0.WWPN.Low;
+@@ -1111,8 +1160,22 @@ mptfc_rescan_devices(struct work_struct
+ MPT_ADAPTER *ioc =
+ container_of(work, MPT_ADAPTER, fc_rescan_work);
+ int ii;
++ int rc;
+ u64 pn;
+ struct mptfc_rport_info *ri;
++ struct scsi_target *starget;
++ VirtTarget *vtarget;
++
++ /*
++ * if cannot set defaults, something's really wrong, bail out
++ */
++
++ if ((rc = mptfc_SetFcPortPage1_defaults(ioc)) < 0) {
++ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
++ "mptfc_rescan.%d: unable to set PP1 defaults, rc %d.\n",
++ ioc->name, ioc->sh->host_no, rc));
++ return;
++ }
+
+ /* start by tagging all ports as missing */
+ list_for_each_entry(ri, &ioc->fc_rports, list) {
+@@ -1140,6 +1203,12 @@ mptfc_rescan_devices(struct work_struct
+ MPT_RPORT_INFO_FLAGS_MISSING);
+ fc_remote_port_delete(ri->rport); /* won't sleep */
+ ri->rport = NULL;
++ starget = ri->starget;
++ if (starget) {
++ vtarget = starget->hostdata;
++ if (vtarget)
++ vtarget->deleted = 1;
++ }
+
+ pn = (u64)ri->pg0.WWPN.High << 32 |
+ (u64)ri->pg0.WWPN.Low;
+@@ -1238,6 +1307,10 @@ mptfc_probe(struct pci_dev *pdev, const
+ sh->max_id = ioc->pfacts->MaxDevices;
+ sh->max_lun = max_lun;
+
++ sh->this_id = ioc->pfacts[0].PortSCSIID;
++
++ ioc->sdev_queue_depth = mpt_sdev_queue_depth;
++
+ /* Required entry.
+ */
+ sh->unique_id = ioc->id;
+@@ -1251,17 +1324,15 @@ mptfc_probe(struct pci_dev *pdev, const
+ * A slightly different algorithm is required for
+ * 64bit SGEs.
+ */
+- scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+- if (sizeof(dma_addr_t) == sizeof(u64)) {
++ scale = ioc->req_sz/ioc->SGE_size;
++ if (ioc->sg_addr_size == sizeof(u64)) {
+ numSGE = (scale - 1) *
+ (ioc->facts.MaxChainDepth-1) + scale +
+- (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
+- sizeof(u32));
++ (ioc->req_sz - 60) / ioc->SGE_size;
+ } else {
+ numSGE = 1 + (scale - 1) *
+ (ioc->facts.MaxChainDepth-1) + scale +
+- (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
+- sizeof(u32));
++ (ioc->req_sz - 64) / ioc->SGE_size;
+ }
+
+ if (numSGE < sh->sg_tablesize) {
+@@ -1290,30 +1361,6 @@ mptfc_probe(struct pci_dev *pdev, const
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
+ ioc->name, ioc->ScsiLookup));
+
+- /* Clear the TM flags
+- */
+- hd->tmPending = 0;
+- hd->tmState = TM_STATE_NONE;
+- hd->resetPending = 0;
+- hd->abortSCpnt = NULL;
+-
+- /* Clear the pointer used to store
+- * single-threaded commands, i.e., those
+- * issued during a bus scan, dv and
+- * configuration pages.
+- */
+- hd->cmdPtr = NULL;
+-
+- /* Initialize this SCSI Hosts' timers
+- * To use, set the timer expires field
+- * and add_timer
+- */
+- init_timer(&hd->timer);
+- hd->timer.data = (unsigned long) hd;
+- hd->timer.function = mptscsih_timer_expired;
+-
+- init_waitqueue_head(&hd->scandv_waitq);
+- hd->scandv_wait_done = 0;
+ hd->last_queue_full = 0;
+
+ sh->transportt = mptfc_transport_template;
+@@ -1326,8 +1373,8 @@ mptfc_probe(struct pci_dev *pdev, const
+
+ /* initialize workqueue */
+
+- snprintf(ioc->fc_rescan_work_q_name, sizeof(ioc->fc_rescan_work_q_name),
+- "mptfc_wq_%d", sh->host_no);
++ snprintf(ioc->fc_rescan_work_q_name, sizeof(ioc->fc_rescan_work_q_name), "mptfc_wq_%d",
++ sh->host_no);
+ ioc->fc_rescan_work_q =
+ create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
+ if (!ioc->fc_rescan_work_q)
+@@ -1340,7 +1387,6 @@ mptfc_probe(struct pci_dev *pdev, const
+ for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+ (void) mptfc_GetFcPortPage0(ioc, ii);
+ }
+- mptfc_SetFcPortPage1_defaults(ioc);
+
+ /*
+ * scan for rports -
+@@ -1378,9 +1424,6 @@ mptfc_event_process(MPT_ADAPTER *ioc, Ev
+ unsigned long flags;
+ int rc=1;
+
+- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
+- ioc->name, event));
+-
+ if (ioc->sh == NULL ||
+ ((hd = shost_priv(ioc->sh)) == NULL))
+ return 1;
+@@ -1416,45 +1459,45 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int re
+ unsigned long flags;
+
+ rc = mptscsih_ioc_reset(ioc,reset_phase);
+- if (rc == 0)
++ if ((ioc->bus_type != FC) || (!rc))
+ return rc;
+
+-
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- ": IOC %s_reset routed to FC host driver!\n",ioc->name,
+- reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+-
+- if (reset_phase == MPT_IOC_SETUP_RESET) {
++ switch(reset_phase) {
++ case MPT_IOC_SETUP_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
+ spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+ if (ioc->fc_rescan_work_q) {
+ queue_work(ioc->fc_rescan_work_q,
+ &ioc->fc_setup_reset_work);
+ }
+ spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+- }
+-
+- else if (reset_phase == MPT_IOC_PRE_RESET) {
+- }
+-
+- else { /* MPT_IOC_POST_RESET */
+- mptfc_SetFcPortPage1_defaults(ioc);
++ break;
++ case MPT_IOC_PRE_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
++ break;
++ case MPT_IOC_POST_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__));
+ spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+ if (ioc->fc_rescan_work_q) {
+ queue_work(ioc->fc_rescan_work_q,
+ &ioc->fc_rescan_work);
+ }
+ spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
++ break;
++ default:
++ break;
+ }
+ return 1;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int __init
+ mptfc_init(void)
+ {
+@@ -1486,12 +1529,11 @@ mptfc_init(void)
+ return error;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mptfc_remove - Remove fc infrastructure for devices
+ * @pdev: Pointer to pci_dev structure
+ *
+- */
++ **/
+ static void __devexit
+ mptfc_remove(struct pci_dev *pdev)
+ {
+@@ -1501,6 +1543,8 @@ mptfc_remove(struct pci_dev *pdev)
+ unsigned long flags;
+ int ii;
+
++ printk("%s -pdev=%p\n", __FUNCTION__, pdev);
++
+ /* destroy workqueue */
+ if ((work_q=ioc->fc_rescan_work_q)) {
+ spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+@@ -1543,7 +1587,6 @@ mptfc_exit(void)
+
+ mpt_reset_deregister(mptfcDoneCtx);
+ mpt_event_deregister(mptfcDoneCtx);
+-
+ mpt_deregister(mptfcInternalCtx);
+ mpt_deregister(mptfcTaskCtx);
+ mpt_deregister(mptfcDoneCtx);
+--- a/drivers/message/fusion/mptlan.c
++++ b/drivers/message/fusion/mptlan.c
+@@ -6,7 +6,6 @@
+ *
+ * Copyright (c) 2000-2008 LSI Corporation
+ * (mailto:DL-MPTFusionLinux@lsi.com)
+- *
+ */
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /*
+@@ -165,6 +164,11 @@ DEFINE_RWLOCK(bad_naa_lock);
+ #endif
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++/*
++ * Fusion MPT LAN external data
++ */
++
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * lan_reply - Handle all data sent from the hardware.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -190,8 +194,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_H
+ u32 tmsg = CAST_PTR_TO_U32(reply);
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @lan_reply, tmsg %08x\n",
+- IOC_AND_NETDEV_NAMES_s_s(dev),
+- tmsg));
++ IOC_AND_NETDEV_NAMES_s_s(dev), tmsg));
+
+ switch (GET_LAN_FORM(tmsg)) {
+
+@@ -440,6 +443,7 @@ mpt_lan_open(struct net_device *dev)
+ dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
+
+ mpt_lan_post_receive_buckets(priv);
++
+ printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev));
+
+@@ -610,7 +614,7 @@ mpt_lan_send_turbo(struct net_device *de
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+- __func__, sent));
++ __FUNCTION__, sent));
+
+ priv->SendCtl[ctx].skb = NULL;
+ pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
+@@ -676,7 +680,7 @@ mpt_lan_send_reply(struct net_device *de
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+- __func__, sent));
++ __FUNCTION__, sent));
+
+ priv->SendCtl[ctx].skb = NULL;
+ pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
+@@ -715,7 +719,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s
+ u16 cur_naa = 0x1000;
+
+ dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
+- __func__, skb));
++ __FUNCTION__, skb));
+
+ spin_lock_irqsave(&priv->txfidx_lock, flags);
+ if (priv->mpt_txfidx_tail < 0) {
+@@ -723,7 +727,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+ printk (KERN_ERR "%s: no tx context available: %u\n",
+- __func__, priv->mpt_txfidx_tail);
++ __FUNCTION__, priv->mpt_txfidx_tail);
+ return 1;
+ }
+
+@@ -733,7 +737,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+ printk (KERN_ERR "%s: Unable to alloc request frame\n",
+- __func__);
++ __FUNCTION__);
+ return 1;
+ }
+
+@@ -780,6 +784,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s
+ // ctx, skb, skb->data));
+
+ mac = skb_mac_header(skb);
++
+ #ifdef QLOGIC_NAA_WORKAROUND
+ {
+ struct NAA_Hosed *nh;
+@@ -805,6 +810,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s
+ }
+ #endif
+
++
+ pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) |
+ (mac[0] << 8) |
+ (mac[1] << 0));
+@@ -828,7 +834,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s
+ MPI_SGE_FLAGS_END_OF_LIST) << MPI_SGE_FLAGS_SHIFT) |
+ skb->len);
+ pSimple->Address.Low = cpu_to_le32((u32) dma);
+- if (sizeof(dma_addr_t) > sizeof(u32))
++ if (mpt_dev->sg_addr_size > sizeof(u32))
+ pSimple->Address.High = cpu_to_le32((u32) ((u64) dma >> 32));
+ else
+ pSimple->Address.High = 0;
+@@ -1117,7 +1123,6 @@ mpt_lan_receive_post_reply(struct net_de
+ PCI_DMA_FROMDEVICE);
+
+ skb_copy_from_linear_data(old_skb, skb_put(skb, len), len);
+-
+ pci_dma_sync_single_for_device(mpt_dev->pcidev,
+ priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len,
+@@ -1208,7 +1213,7 @@ mpt_lan_post_receive_buckets(struct mpt_
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+- __func__, buckets, curr));
++ __FUNCTION__, buckets, curr));
+
+ max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
+ (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
+@@ -1217,9 +1222,9 @@ mpt_lan_post_receive_buckets(struct mpt_
+ mf = mpt_get_msg_frame(LanCtx, mpt_dev);
+ if (mf == NULL) {
+ printk (KERN_ERR "%s: Unable to alloc request frame\n",
+- __func__);
++ __FUNCTION__);
+ dioprintk((KERN_ERR "%s: %u buckets remaining\n",
+- __func__, buckets));
++ __FUNCTION__, buckets));
+ goto out;
+ }
+ pRecvReq = (LANReceivePostRequest_t *) mf;
+@@ -1244,7 +1249,7 @@ mpt_lan_post_receive_buckets(struct mpt_
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ if (priv->mpt_rxfidx_tail < 0) {
+ printk (KERN_ERR "%s: Can't alloc context\n",
+- __func__);
++ __FUNCTION__);
+ spin_unlock_irqrestore(&priv->rxfidx_lock,
+ flags);
+ break;
+@@ -1267,7 +1272,7 @@ mpt_lan_post_receive_buckets(struct mpt_
+ if (skb == NULL) {
+ printk (KERN_WARNING
+ MYNAM "/%s: Can't alloc skb\n",
+- __func__);
++ __FUNCTION__);
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+ break;
+@@ -1295,7 +1300,7 @@ mpt_lan_post_receive_buckets(struct mpt_
+ MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_64_BIT_ADDRESSING) << MPI_SGE_FLAGS_SHIFT) | len);
+ pSimple->Address.Low = cpu_to_le32((u32) priv->RcvCtl[ctx].dma);
+- if (sizeof(dma_addr_t) > sizeof(u32))
++ if (mpt_dev->sg_addr_size > sizeof(u32))
+ pSimple->Address.High = cpu_to_le32((u32) ((u64) priv->RcvCtl[ctx].dma >> 32));
+ else
+ pSimple->Address.High = 0;
+@@ -1305,7 +1310,7 @@ mpt_lan_post_receive_buckets(struct mpt_
+
+ if (pSimple == NULL) {
+ /**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
+-/**/ __func__);
++/**/ __FUNCTION__);
+ mpt_free_msg_frame(mpt_dev, mf);
+ goto out;
+ }
+@@ -1329,9 +1334,9 @@ mpt_lan_post_receive_buckets(struct mpt_
+
+ out:
+ dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
+- __func__, buckets, atomic_read(&priv->buckets_out)));
++ __FUNCTION__, buckets, atomic_read(&priv->buckets_out)));
+ dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
+- __func__, priv->total_posted, priv->total_received));
++ __FUNCTION__, priv->total_posted, priv->total_received));
+
+ clear_bit(0, &priv->post_buckets_active);
+ }
+@@ -1340,18 +1345,17 @@ static void
+ mpt_lan_post_receive_buckets_work(struct work_struct *work)
+ {
+ mpt_lan_post_receive_buckets(container_of(work, struct mpt_lan_priv,
+- post_buckets_task.work));
++ post_buckets_task.work));
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ static struct net_device *
+ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
+ {
+- struct net_device *dev;
+- struct mpt_lan_priv *priv;
++ struct net_device *dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
++ struct mpt_lan_priv *priv = NULL;
+ u8 HWaddr[FC_ALEN], *a;
+
+- dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
+ if (!dev)
+ return NULL;
+
+@@ -1363,8 +1367,9 @@ mpt_register_lan_device (MPT_ADAPTER *mp
+ priv->mpt_dev = mpt_dev;
+ priv->pnum = pnum;
+
++ memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task));
+ INIT_DELAYED_WORK(&priv->post_buckets_task,
+- mpt_lan_post_receive_buckets_work);
++ mpt_lan_post_receive_buckets_work);
+ priv->post_buckets_active = 0;
+
+ dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
+@@ -1387,6 +1392,8 @@ mpt_register_lan_device (MPT_ADAPTER *mp
+ spin_lock_init(&priv->txfidx_lock);
+ spin_lock_init(&priv->rxfidx_lock);
+
++ memset(&priv->stats, 0, sizeof(priv->stats));
++
+ /* Grab pre-fetched LANPage1 stuff. :-) */
+ a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow;
+
+@@ -1421,6 +1428,7 @@ mpt_register_lan_device (MPT_ADAPTER *mp
+ dlprintk((KERN_INFO MYNAM ": Finished registering dev "
+ "and setting initial values\n"));
+
++
+ if (register_netdev(dev) != 0) {
+ free_netdev(dev);
+ dev = NULL;
+--- a/drivers/message/fusion/mptlan.h
++++ b/drivers/message/fusion/mptlan.h
+@@ -6,7 +6,6 @@
+ *
+ * Copyright (c) 2000-2008 LSI Corporation
+ * (mailto:DL-MPTFusionLinux@lsi.com)
+- *
+ */
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /*
+@@ -55,6 +54,7 @@
+ #include <linux/module.h>
+ #endif
+
++#include <linux/version.h>
+ #include <linux/netdevice.h>
+ #include <linux/errno.h>
+ // #include <linux/etherdevice.h>
+@@ -73,6 +73,7 @@
+
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
++#include <linux/pci.h>
+
+ /* Override mptbase.h by pre-defining these! */
+ #define MODULEAUTHOR "LSI Corporation"
+--- a/drivers/message/fusion/mptsas.c
++++ b/drivers/message/fusion/mptsas.c
+@@ -47,9 +47,11 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/errno.h>
+-#include <linux/jiffies.h>
++#include <linux/sched.h>
+ #include <linux/workqueue.h>
++#include <linux/interrupt.h>
+ #include <linux/delay.h> /* for mdelay */
++#include <linux/pci.h>
+
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -62,7 +64,6 @@
+ #include "mptscsih.h"
+ #include "mptsas.h"
+
+-
+ #define my_NAME "Fusion MPT SAS Host driver"
+ #define my_VERSION MPT_LINUX_VERSION_COMMON
+ #define MYNAM "mptsas"
+@@ -72,6 +73,8 @@
+ */
+ #define MPTSAS_RAID_CHANNEL 1
+
++#define SAS_CONFIG_PAGE_TIMEOUT 30
++
+ MODULE_AUTHOR(MODULEAUTHOR);
+ MODULE_DESCRIPTION(my_NAME);
+ MODULE_LICENSE("GPL");
+@@ -83,6 +86,25 @@ MODULE_PARM_DESC(mpt_pt_clear,
+ " Clear persistency table: enable=1 "
+ "(default=MPTSCSIH_PT_CLEAR=0)");
+
++static int mpt_cmd_retry_count = 144;
++module_param(mpt_cmd_retry_count, int, 0);
++MODULE_PARM_DESC(mpt_cmd_retry_count,
++ " Device discovery TUR command retry count: default=144");
++
++static int mpt_disable_hotplug_remove = 0;
++module_param(mpt_disable_hotplug_remove, int, 0);
++MODULE_PARM_DESC(mpt_disable_hotplug_remove,
++ " Disable hotpug remove events: default=0");
++
++static int mpt_sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
++static int mptsas_set_sdev_queue_depth(const char *val,
++ struct kernel_param *kp);
++module_param_call(mpt_sdev_queue_depth, mptsas_set_sdev_queue_depth,
++ param_get_int, &mpt_sdev_queue_depth, 0600);
++MODULE_PARM_DESC(mpt_sdev_queue_depth,
++ " Max Device Queue Depth (default="
++ __MODULE_STRING(MPT_SCSI_CMD_PER_DEV_HIGH) ")");
++
+ /* scsi-mid layer global parmeter is max_report_luns, which is 511 */
+ #define MPTSAS_MAX_LUN (16895)
+ static int max_lun = MPTSAS_MAX_LUN;
+@@ -93,8 +115,53 @@ static u8 mptsasDoneCtx = MPT_MAX_PROTOC
+ static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
+ static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
+ static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
++static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
++
++static inline void mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
++static struct mptsas_phyinfo * mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc,
++ u64 sas_address);
++static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
++ u32 form, u32 form_specific);
++static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
++ u32 form, u32 form_specific);
++
++static int mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info);
++static void mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info);
++static void mptsas_expander_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info);
++static int mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
++ u32 form, u32 form_specific);
++static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
++static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
++
++static void mptsas_firmware_event_work(struct work_struct *work);
++
++/**
++ * mptsas_set_sdev_queue_depth - global setting of the mpt_sdev_queue_depth
++ * found via /sys/module/mptsas/parameters/mpt_sdev_queue_depth
++ * @val:
++ * @kp:
++ *
++ * Returns
++ **/
++static int
++mptsas_set_sdev_queue_depth(const char *val, struct kernel_param *kp)
++{
++ int ret = param_set_int(val, kp);
++ MPT_ADAPTER *ioc;
++ struct scsi_device *sdev;
+
+-static void mptsas_hotplug_work(struct work_struct *work);
++ if (ret)
++ return ret;
++
++ list_for_each_entry(ioc, &ioc_list, list) {
++ if (ioc->bus_type != SAS)
++ continue;
++ shost_for_each_device(sdev, ioc->sh)
++ mptscsih_change_queue_depth(sdev, mpt_sdev_queue_depth);
++ ioc->sdev_queue_depth = mpt_sdev_queue_depth;
++ }
++ return 0;
++}
+
+ static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
+ MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
+@@ -218,37 +285,183 @@ static void mptsas_print_expander_pg1(MP
+ le16_to_cpu(pg1->AttachedDevHandle)));
+ }
+
+-static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
++/* inhibit sas firmware event handling */
++static void
++mptsas_fw_event_off(MPT_ADAPTER *ioc)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioc->fw_event_lock, flags);
++ ioc->fw_events_off = 1;
++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
++
++}
++
++/* enable sas firmware event handling */
++static void
++mptsas_fw_event_on(MPT_ADAPTER *ioc)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioc->fw_event_lock, flags);
++ ioc->fw_events_off = 0;
++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
++}
++
++/* queue a sas firmware event */
++static void
++mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
++ unsigned long delay)
++{
++ unsigned long flags;
++
++#if defined(CPQ_CIM)
++ ioc->csmi_change_count++;
++#endif
++
++ spin_lock_irqsave(&ioc->fw_event_lock, flags);
++ list_add_tail(&fw_event->list, &ioc->fw_event_list);
++ INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: add (fw_event=0x%p)\n",
++ ioc->name,__FUNCTION__, fw_event));
++ queue_delayed_work(ioc->fw_event_q, &fw_event->work,
++ msecs_to_jiffies(delay));
++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
++}
++
++/* requeue a sas firmware event */
++static void
++mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
++ unsigned long delay)
++{
++ unsigned long flags;
++ spin_lock_irqsave(&ioc->fw_event_lock, flags);
++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: reschedule task "
++ "(fw_event=0x%p)\n", ioc->name,__FUNCTION__, fw_event));
++ fw_event->retries++;
++ queue_delayed_work(ioc->fw_event_q, &fw_event->work,
++ msecs_to_jiffies(delay));
++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
++}
++
++/* free memory assoicated to a sas firmware event */
++static void
++mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ioc->fw_event_lock, flags);
++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: kfree (fw_event=0x%p)\n",
++ ioc->name,__FUNCTION__, fw_event));
++ list_del(&fw_event->list);
++ kfree(fw_event);
++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
++}
++
++/* walk the firmware event queue, and either stop or wait for outstanding events to complete */
++static void
++mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
++{
++ struct fw_event_work *fw_event, *next;
++ struct mptsas_target_reset_event *target_reset_list, *n;
++ u8 flush_q;
++ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
++
++ /* flush the target_reset_list */
++ if (!list_empty(&hd->target_reset_list)) {
++ list_for_each_entry_safe(target_reset_list, n,
++ &hd->target_reset_list, list) {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: removing target reset for id=%d\n",
++ ioc->name, __FUNCTION__,
++ target_reset_list->sas_event_data.TargetID));
++ list_del(&target_reset_list->list);
++ kfree(target_reset_list);
++ }
++ }
++
++ if (list_empty(&ioc->fw_event_list) ||
++ !ioc->fw_event_q || in_interrupt())
++ return;
++
++ flush_q = 0;
++ list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
++ if (cancel_delayed_work(&fw_event->work))
++ mptsas_free_fw_event(ioc, fw_event);
++ else
++ flush_q = 1;
++ }
++ if (flush_q)
++ flush_workqueue(ioc->fw_event_q);
++}
++
++
++/**
++ * phy_to_ioc -
++ * @phy:
++ *
++ *
++ **/
++static inline MPT_ADAPTER *
++phy_to_ioc(struct sas_phy *phy)
+ {
+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+ return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
+ }
+
+-static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
++/**
++ * rphy_to_ioc -
++ * @rphy:
++ *
++ *
++ **/
++static inline MPT_ADAPTER *
++rphy_to_ioc(struct sas_rphy *rphy)
+ {
+ struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
+ return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
+ }
+
++/**
++ * mptsas_find_portinfo_by_sas_address -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @handle:
++ *
++ * This function should be called with the sas_topology_mutex already held
++ *
++ **/
+ static struct mptsas_portinfo *
+-mptsas_get_hba_portinfo(MPT_ADAPTER *ioc)
++mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
+ {
+- struct list_head *head = &ioc->sas_topology;
+- struct mptsas_portinfo *pi = NULL;
+-
+- /* always the first entry on sas_topology list */
+-
+- if (!list_empty(head))
+- pi = list_entry(head->next, struct mptsas_portinfo, list);
++ struct mptsas_portinfo *port_info, *rc=NULL;
++ int i;
++
++ if (sas_address >= ioc->hba_port_sas_addr &&
++ sas_address < (ioc->hba_port_sas_addr +
++ ioc->hba_port_num_phy))
++ return ioc->hba_port_info;
+
+- return pi;
++ mutex_lock(&ioc->sas_topology_mutex);
++ list_for_each_entry(port_info, &ioc->sas_topology, list)
++ for (i = 0; i < port_info->num_phys; i++)
++ if (port_info->phy_info[i].identify.sas_address ==
++ sas_address) {
++ rc = port_info;
++ goto out;
++ }
++ out:
++ mutex_unlock(&ioc->sas_topology_mutex);
++ return rc;
+ }
+
+-/*
+- * mptsas_find_portinfo_by_handle
++/**
++ * mptsas_find_portinfo_by_handle -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @handle:
+ *
+- * This function should be called with the sas_topology_mutex already held
+- */
++ * This function should be called with the sas_topology_mutex already held
++ *
++ **/
+ static struct mptsas_portinfo *
+ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
+ {
+@@ -265,9 +478,12 @@ mptsas_find_portinfo_by_handle(MPT_ADAPT
+ return rc;
+ }
+
+-/*
+- * Returns true if there is a scsi end device
+- */
++/**
++ * mptsas_is_end_device -
++ * @attached:
++ *
++ * Returns true if there is a scsi end device
++ **/
+ static inline int
+ mptsas_is_end_device(struct mptsas_devinfo * attached)
+ {
+@@ -285,7 +501,14 @@ mptsas_is_end_device(struct mptsas_devin
+ return 0;
+ }
+
+-/* no mutex */
++/**
++ * mptsas_port_delete -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @port_details:
++ *
++ * (no mutex)
++ *
++ **/
+ static void
+ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
+ {
+@@ -300,7 +523,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, str
+ phy_info = port_info->phy_info;
+
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
+- "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
++ "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details,
+ port_details->num_phys, (unsigned long long)
+ port_details->phy_bitmask));
+
+@@ -308,11 +531,17 @@ mptsas_port_delete(MPT_ADAPTER *ioc, str
+ if(phy_info->port_details != port_details)
+ continue;
+ memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
++ mptsas_set_rphy(ioc, phy_info, NULL);
+ phy_info->port_details = NULL;
+ }
+ kfree(port_details);
+ }
+
++/**
++ * mptsas_get_rphy -
++ * @phy_info:
++ *
++ **/
+ static inline struct sas_rphy *
+ mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
+ {
+@@ -322,13 +551,20 @@ mptsas_get_rphy(struct mptsas_phyinfo *p
+ return NULL;
+ }
+
++/**
++ * mptsas_set_rphy -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @phy_info:
++ * @rphy:
++ *
++ **/
+ static inline void
+ mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
+ {
+ if (phy_info->port_details) {
+ phy_info->port_details->rphy = rphy;
+- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
+- ioc->name, rphy));
++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "sas_rphy_add: rphy=%p\n", ioc->name, rphy));
+ }
+
+ if (rphy) {
+@@ -339,6 +575,11 @@ mptsas_set_rphy(MPT_ADAPTER *ioc, struct
+ }
+ }
+
++/**
++ * mptsas_get_port -
++ * @phy_info:
++ *
++ **/
+ static inline struct sas_port *
+ mptsas_get_port(struct mptsas_phyinfo *phy_info)
+ {
+@@ -348,6 +589,13 @@ mptsas_get_port(struct mptsas_phyinfo *p
+ return NULL;
+ }
+
++/**
++ * mptsas_set_port -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @phy_info:
++ * @port:
++ *
++ **/
+ static inline void
+ mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
+ {
+@@ -362,6 +610,11 @@ mptsas_set_port(MPT_ADAPTER *ioc, struct
+ }
+ }
+
++/**
++ * mptsas_get_starget -
++ * @phy_info:
++ *
++ **/
+ static inline struct scsi_target *
+ mptsas_get_starget(struct mptsas_phyinfo *phy_info)
+ {
+@@ -371,6 +624,12 @@ mptsas_get_starget(struct mptsas_phyinfo
+ return NULL;
+ }
+
++/**
++ * mptsas_set_starget -
++ * @phy_info:
++ * @starget:
++ *
++ **/
+ static inline void
+ mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
+ starget)
+@@ -379,714 +638,787 @@ starget)
+ phy_info->port_details->starget = starget;
+ }
+
+-
+-/*
+- * mptsas_setup_wide_ports
++/**
++ * mptsas_add_device_component -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @channel: fw mapped id's
++ * @id:
++ * @sas_address:
++ * @device_info:
+ *
+- * Updates for new and existing narrow/wide port configuration
+- * in the sas_topology
+- */
++ **/
+ static void
+-mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
++mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
++ u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
+ {
+- struct mptsas_portinfo_details * port_details;
+- struct mptsas_phyinfo *phy_info, *phy_info_cmp;
+- u64 sas_address;
+- int i, j;
+-
+- mutex_lock(&ioc->sas_topology_mutex);
+-
+- phy_info = port_info->phy_info;
+- for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
+- if (phy_info->attached.handle)
+- continue;
+- port_details = phy_info->port_details;
+- if (!port_details)
+- continue;
+- if (port_details->num_phys < 2)
+- continue;
+- /*
+- * Removing a phy from a port, letting the last
+- * phy be removed by firmware events.
+- */
+- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "%s: [%p]: deleting phy = %d\n",
+- ioc->name, __func__, port_details, i));
+- port_details->num_phys--;
+- port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
+- memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
+- sas_port_delete_phy(port_details->port, phy_info->phy);
+- phy_info->port_details = NULL;
++ struct sas_device_info *sas_info, *next;
++ struct scsi_device *sdev;
++ struct scsi_target *starget;
++ struct sas_rphy *rphy;
++
++ /*
++ * Delete all matching devices out of the list
++ */
++ down(&ioc->sas_device_info_mutex);
++ list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
++ list) {
++ if (!sas_info->is_logical_volume &&
++ (sas_info->sas_address == sas_address ||
++ (sas_info->fw.channel == channel &&
++ sas_info->fw.id == id))) {
++ list_del(&sas_info->list);
++ kfree(sas_info);
++ }
+ }
+
++ if (!(sas_info = kzalloc(sizeof(struct sas_device_info), GFP_KERNEL)))
++ goto out;
++
+ /*
+- * Populate and refresh the tree
++ * Set Firmware mapping
+ */
+- phy_info = port_info->phy_info;
+- for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
+- sas_address = phy_info->attached.sas_address;
+- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
+- ioc->name, i, (unsigned long long)sas_address));
+- if (!sas_address)
+- continue;
+- port_details = phy_info->port_details;
+- /*
+- * Forming a port
+- */
+- if (!port_details) {
+- port_details = kzalloc(sizeof(*port_details),
+- GFP_KERNEL);
+- if (!port_details)
+- goto out;
+- port_details->num_phys = 1;
+- port_details->port_info = port_info;
+- if (phy_info->phy_id < 64 )
+- port_details->phy_bitmask |=
+- (1 << phy_info->phy_id);
+- phy_info->sas_port_add_phy=1;
+- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
+- "phy_id=%d sas_address=0x%018llX\n",
+- ioc->name, i, (unsigned long long)sas_address));
+- phy_info->port_details = port_details;
+- }
++ sas_info->fw.id = id;
++ sas_info->fw.channel = channel;
+
+- if (i == port_info->num_phys - 1)
+- continue;
+- phy_info_cmp = &port_info->phy_info[i + 1];
+- for (j = i + 1 ; j < port_info->num_phys ; j++,
+- phy_info_cmp++) {
+- if (!phy_info_cmp->attached.sas_address)
+- continue;
+- if (sas_address != phy_info_cmp->attached.sas_address)
+- continue;
+- if (phy_info_cmp->port_details == port_details )
+- continue;
+- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "\t\tphy_id=%d sas_address=0x%018llX\n",
+- ioc->name, j, (unsigned long long)
+- phy_info_cmp->attached.sas_address));
+- if (phy_info_cmp->port_details) {
+- port_details->rphy =
+- mptsas_get_rphy(phy_info_cmp);
+- port_details->port =
+- mptsas_get_port(phy_info_cmp);
+- port_details->starget =
+- mptsas_get_starget(phy_info_cmp);
+- port_details->num_phys =
+- phy_info_cmp->port_details->num_phys;
+- if (!phy_info_cmp->port_details->num_phys)
+- kfree(phy_info_cmp->port_details);
+- } else
+- phy_info_cmp->sas_port_add_phy=1;
+- /*
+- * Adding a phy to a port
+- */
+- phy_info_cmp->port_details = port_details;
+- if (phy_info_cmp->phy_id < 64 )
+- port_details->phy_bitmask |=
+- (1 << phy_info_cmp->phy_id);
+- port_details->num_phys++;
++ sas_info->sas_address = sas_address;
++ sas_info->device_info = device_info;
++ sas_info->slot = slot;
++ sas_info->enclosure_logical_id = enclosure_logical_id;
++ INIT_LIST_HEAD(&sas_info->list);
++ list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
++
++ /*
++ * Set OS mapping
++ */
++ shost_for_each_device(sdev, ioc->sh) {
++ starget = scsi_target(sdev);
++ rphy = dev_to_rphy(starget->dev.parent);
++ if (rphy->identify.sas_address == sas_address) {
++ sas_info->os.id = starget->id;
++ sas_info->os.channel = starget->channel;
+ }
+ }
+
+ out:
+-
+- for (i = 0; i < port_info->num_phys; i++) {
+- port_details = port_info->phy_info[i].port_details;
+- if (!port_details)
+- continue;
+- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "%s: [%p]: phy_id=%02d num_phys=%02d "
+- "bitmask=0x%016llX\n", ioc->name, __func__,
+- port_details, i, port_details->num_phys,
+- (unsigned long long)port_details->phy_bitmask));
+- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
+- ioc->name, port_details->port, port_details->rphy));
+- }
+- dsaswideprintk(ioc, printk("\n"));
+- mutex_unlock(&ioc->sas_topology_mutex);
++ up(&ioc->sas_device_info_mutex);
++ return;
+ }
+
+ /**
+- * csmisas_find_vtarget
+- *
+- * @ioc
+- * @volume_id
+- * @volume_bus
++ * mptsas_add_device_component_by_fw -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @channel: fw mapped id's
++ * @id:
+ *
+ **/
+-static VirtTarget *
+-mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
++static void
++mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
+ {
+- struct scsi_device *sdev;
+- VirtDevice *vdevice;
+- VirtTarget *vtarget = NULL;
++ struct mptsas_devinfo sas_device;
++ struct mptsas_enclosure enclosure_info;
++ int rc;
+
+- shost_for_each_device(sdev, ioc->sh) {
+- if ((vdevice = sdev->hostdata) == NULL)
+- continue;
+- if (vdevice->vtarget->id == id &&
+- vdevice->vtarget->channel == channel)
+- vtarget = vdevice->vtarget;
+- }
+- return vtarget;
++ rc = mptsas_sas_device_pg0(ioc, &sas_device,
++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
++ (channel << 8) + id);
++ if (rc)
++ return;
++
++ memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
++ mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
++ (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
++ MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
++ sas_device.handle_enclosure);
++
++ mptsas_add_device_component(ioc, sas_device.channel,
++ sas_device.id, sas_device.sas_address, sas_device.device_info,
++ sas_device.slot, enclosure_info.enclosure_logical_id);
+ }
+
+ /**
+- * mptsas_target_reset
+- *
+- * Issues TARGET_RESET to end device using handshaking method
+- *
+- * @ioc
+- * @channel
+- * @id
+- *
+- * Returns (1) success
+- * (0) failure
+- *
+- **/
+-static int
+-mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
+-{
+- MPT_FRAME_HDR *mf;
+- SCSITaskMgmt_t *pScsiTm;
+-
+- if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
+- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
+- ioc->name,__func__, __LINE__));
+- return 0;
+- }
+-
+- /* Format the Request
+- */
+- pScsiTm = (SCSITaskMgmt_t *) mf;
+- memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
+- pScsiTm->TargetID = id;
+- pScsiTm->Bus = channel;
+- pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+- pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+- pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+-
+- DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
+-
+- mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
+-
+- return 1;
+-}
+-
+-/**
+- * mptsas_target_reset_queue
+- *
+- * Receive request for TARGET_RESET after recieving an firmware
+- * event NOT_RESPONDING_EVENT, then put command in link list
+- * and queue if task_queue already in use.
+- *
+- * @ioc
+- * @sas_event_data
++ * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding
++ * each individual device to list
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @channel: fw mapped id's
++ * @id:
+ *
+ **/
+ static void
+-mptsas_target_reset_queue(MPT_ADAPTER *ioc,
+- EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
++mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, struct scsi_target *starget)
+ {
+- MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+- VirtTarget *vtarget = NULL;
+- struct mptsas_target_reset_event *target_reset_list;
+- u8 id, channel;
++ CONFIGPARMS cfg;
++ ConfigPageHeader_t hdr;
++ dma_addr_t dma_handle;
++ pRaidVolumePage0_t buffer = NULL;
++ int i;
++ RaidPhysDiskPage0_t phys_disk;
++ struct sas_device_info *sas_info, *next;
+
+- id = sas_event_data->TargetID;
+- channel = sas_event_data->Bus;
++ memset(&cfg, 0 , sizeof(CONFIGPARMS));
++ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
++ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
++ /* assumption that all volumes on channel = 0 */
++ cfg.pageAddr = starget->id;
++ cfg.cfghdr.hdr = &hdr;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
+
+- if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
+- return;
++ if (mpt_config(ioc, &cfg) != 0)
++ goto out;
+
+- vtarget->deleted = 1; /* block IO */
++ if (!hdr.PageLength)
++ goto out;
+
+- target_reset_list = kzalloc(sizeof(*target_reset_list),
+- GFP_ATOMIC);
+- if (!target_reset_list) {
+- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
+- ioc->name,__func__, __LINE__));
+- return;
+- }
++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
++ &dma_handle);
+
+- memcpy(&target_reset_list->sas_event_data, sas_event_data,
+- sizeof(*sas_event_data));
+- list_add_tail(&target_reset_list->list, &hd->target_reset_list);
++ if (!buffer)
++ goto out;
+
+- if (hd->resetPending)
+- return;
++ cfg.physAddr = dma_handle;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+- if (mptsas_target_reset(ioc, channel, id)) {
+- target_reset_list->target_reset_issued = 1;
+- hd->resetPending = 1;
+- }
+-}
++ if (mpt_config(ioc, &cfg) != 0)
++ goto out;
+
+-/**
+- * mptsas_dev_reset_complete
+- *
+- * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
+- * enable work queue to finish off removing device from upper layers.
+- * then send next TARGET_RESET in the queue.
+- *
+- * @ioc
+- *
+- **/
+-static void
+-mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
+-{
+- MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+- struct list_head *head = &hd->target_reset_list;
+- struct mptsas_target_reset_event *target_reset_list;
+- struct mptsas_hotplug_event *ev;
+- EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
+- u8 id, channel;
+- __le64 sas_address;
++ if (!buffer->NumPhysDisks)
++ goto out;
+
+- if (list_empty(head))
+- return;
++ /*
++ * Adding entry for hidden components
++ */
++ for (i = 0; i < buffer->NumPhysDisks; i++) {
+
+- target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
++ if(mpt_raid_phys_disk_pg0(ioc,
++ buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
++ continue;
+
+- sas_event_data = &target_reset_list->sas_event_data;
+- id = sas_event_data->TargetID;
+- channel = sas_event_data->Bus;
+- hd->resetPending = 0;
++ mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
++ phys_disk.PhysDiskID);
+
+- /*
+- * retry target reset
+- */
+- if (!target_reset_list->target_reset_issued) {
+- if (mptsas_target_reset(ioc, channel, id)) {
+- target_reset_list->target_reset_issued = 1;
+- hd->resetPending = 1;
++ down(&ioc->sas_device_info_mutex);
++ list_for_each_entry(sas_info, &ioc->sas_device_info_list,
++ list) {
++ if (!sas_info->is_logical_volume &&
++ (sas_info->fw.channel == phys_disk.PhysDiskBus &&
++ sas_info->fw.id == phys_disk.PhysDiskID)) {
++ sas_info->is_hidden_raid_component = 1;
++ sas_info->volume_id = starget->id;
++ }
+ }
+- return;
++ up(&ioc->sas_device_info_mutex);
+ }
+
+ /*
+- * enable work queue to remove device from upper layers
++ * Delete all matching devices out of the list
+ */
+- list_del(&target_reset_list->list);
++ down(&ioc->sas_device_info_mutex);
++ list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
++ list) {
++ if (sas_info->is_logical_volume && sas_info->fw.id ==
++ starget->id) {
++ list_del(&sas_info->list);
++ kfree(sas_info);
++ }
++ }
+
+- ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+- if (!ev) {
+- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
+- ioc->name,__func__, __LINE__));
+- return;
++ sas_info = kzalloc(sizeof(struct sas_device_info), GFP_KERNEL);
++ if (sas_info) {
++ sas_info->fw.id = starget->id;
++ sas_info->os.id = starget->id;
++ sas_info->os.channel = starget->channel;
++ sas_info->is_logical_volume = 1;
++ INIT_LIST_HEAD(&sas_info->list);
++ list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
+ }
++ up(&ioc->sas_device_info_mutex);
+
+- INIT_WORK(&ev->work, mptsas_hotplug_work);
+- ev->ioc = ioc;
+- ev->handle = le16_to_cpu(sas_event_data->DevHandle);
+- ev->parent_handle =
+- le16_to_cpu(sas_event_data->ParentDevHandle);
+- ev->channel = channel;
+- ev->id =id;
+- ev->phy_id = sas_event_data->PhyNum;
+- memcpy(&sas_address, &sas_event_data->SASAddress,
+- sizeof(__le64));
+- ev->sas_address = le64_to_cpu(sas_address);
+- ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
+- ev->event_type = MPTSAS_DEL_DEVICE;
+- schedule_work(&ev->work);
+- kfree(target_reset_list);
++ out:
++ if (buffer)
++ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
++ dma_handle);
++}
+
+- /*
+- * issue target reset to next device in the queue
+- */
++/**
++ * mptsas_add_device_component_starget -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @starget:
++ *
++ **/
++static void
++mptsas_add_device_component_starget(MPT_ADAPTER *ioc, struct scsi_target *starget)
++{
++ VirtTarget *vtarget;
++ struct sas_rphy *rphy;
++ struct mptsas_phyinfo *phy_info = NULL;
++ struct mptsas_enclosure enclosure_info;
+
+- head = &hd->target_reset_list;
+- if (list_empty(head))
++ rphy = dev_to_rphy(starget->dev.parent);
++ vtarget = starget->hostdata;
++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
++ rphy->identify.sas_address);
++ if (!phy_info)
+ return;
+
+- target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
+- list);
+-
+- sas_event_data = &target_reset_list->sas_event_data;
+- id = sas_event_data->TargetID;
+- channel = sas_event_data->Bus;
+-
+- if (mptsas_target_reset(ioc, channel, id)) {
+- target_reset_list->target_reset_issued = 1;
+- hd->resetPending = 1;
+- }
++ memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
++ mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
++ (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
++ MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
++ phy_info->attached.handle_enclosure);
++
++ mptsas_add_device_component(ioc, phy_info->attached.channel,
++ phy_info->attached.id, phy_info->attached.sas_address,
++ phy_info->attached.device_info,
++ phy_info->attached.slot, enclosure_info.enclosure_logical_id);
+ }
+
+ /**
+- * mptsas_taskmgmt_complete
+- *
+- * @ioc
+- * @mf
+- * @mr
++ * mptsas_del_device_component_by_os - Once a device has been removed, we
++ * mark the entry in the list as being cached
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @channel: os mapped id's
++ * @id:
+ *
+ **/
+-static int
+-mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
++static void
++mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
+ {
+- mptsas_dev_reset_complete(ioc);
+- return mptscsih_taskmgmt_complete(ioc, mf, mr);
++ struct sas_device_info *sas_info, *next;
++
++ /*
++ * Set is_cached flag
++ */
++ list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
++ list) {
++ if (sas_info->os.channel == channel && sas_info->os.id == id)
++ sas_info->is_cached = 1;
++ }
+ }
+
+ /**
+- * mptscsih_ioc_reset
+- *
+- * @ioc
+- * @reset_phase
++ * mptsas_del_device_components - Cleaning the list
++ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+-static int
+-mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
++static void
++mptsas_del_device_components(MPT_ADAPTER *ioc)
+ {
+- MPT_SCSI_HOST *hd;
+- struct mptsas_target_reset_event *target_reset_list, *n;
+- int rc;
+-
+- rc = mptscsih_ioc_reset(ioc, reset_phase);
+-
+- if (ioc->bus_type != SAS)
+- goto out;
+-
+- if (reset_phase != MPT_IOC_POST_RESET)
+- goto out;
++ struct sas_device_info *sas_info, *next;
+
+- if (!ioc->sh || !ioc->sh->hostdata)
+- goto out;
+- hd = shost_priv(ioc->sh);
+- if (!hd->ioc)
+- goto out;
+-
+- if (list_empty(&hd->target_reset_list))
+- goto out;
+-
+- /* flush the target_reset_list */
+- list_for_each_entry_safe(target_reset_list, n,
+- &hd->target_reset_list, list) {
+- list_del(&target_reset_list->list);
+- kfree(target_reset_list);
++ down(&ioc->sas_device_info_mutex);
++ list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
++ list) {
++ list_del(&sas_info->list);
++ kfree(sas_info);
+ }
+-
+- out:
+- return rc;
++ up(&ioc->sas_device_info_mutex);
+ }
+
+-static int
+-mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
+- u32 form, u32 form_specific)
++/**
++ * mptsas_setup_wide_ports - Updates for new and existing narrow/wide port
++ * configuration
++ * in the sas_topology
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @port_info:
++ *
++ */
++static void
++mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
+ {
+- ConfigExtendedPageHeader_t hdr;
+- CONFIGPARMS cfg;
+- SasEnclosurePage0_t *buffer;
+- dma_addr_t dma_handle;
+- int error;
+- __le64 le_identifier;
+-
+- memset(&hdr, 0, sizeof(hdr));
+- hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
+- hdr.PageNumber = 0;
+- hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+- hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
++ struct mptsas_portinfo_details * port_details;
++ struct mptsas_phyinfo *phy_info, *phy_info_cmp;
++ u64 sas_address;
++ int i, j;
+
+- cfg.cfghdr.ehdr = &hdr;
+- cfg.physAddr = -1;
+- cfg.pageAddr = form + form_specific;
+- cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+- cfg.dir = 0; /* read */
+- cfg.timeout = 10;
++ mutex_lock(&ioc->sas_topology_mutex);
+
+- error = mpt_config(ioc, &cfg);
+- if (error)
+- goto out;
+- if (!hdr.ExtPageLength) {
+- error = -ENXIO;
+- goto out;
+- }
++ phy_info = port_info->phy_info;
++ for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
++ if (phy_info->attached.handle)
++ continue;
++ port_details = phy_info->port_details;
++ if (!port_details)
++ continue;
++ if (port_details->num_phys < 2)
++ continue;
+
+- buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+- &dma_handle);
+- if (!buffer) {
+- error = -ENOMEM;
+- goto out;
++ /*
++ * Removing a phy from a port, letting the last
++ * phy be removed by firmware events.
++ */
++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: [%p]: deleting phy = %d\n",
++ ioc->name, __FUNCTION__, port_details, i));
++ port_details->num_phys--;
++ port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
++ memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
++ devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
++ MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
++ phy_info->phy_id, phy_info->phy));
++ sas_port_delete_phy(port_details->port, phy_info->phy);
++ phy_info->port_details = NULL;
+ }
+
+- cfg.physAddr = dma_handle;
+- cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+-
+- error = mpt_config(ioc, &cfg);
+- if (error)
+- goto out_free_consistent;
+-
+- /* save config data */
+- memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
+- enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
+- enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
+- enclosure->flags = le16_to_cpu(buffer->Flags);
+- enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
+- enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
+- enclosure->start_id = buffer->StartTargetID;
+- enclosure->start_channel = buffer->StartBus;
+- enclosure->sep_id = buffer->SEPTargetID;
+- enclosure->sep_channel = buffer->SEPBus;
++ /*
++ * Populate and refresh the tree
++ */
++ phy_info = port_info->phy_info;
++ for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
++ sas_address = phy_info->attached.sas_address;
++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
++ ioc->name, i, (unsigned long long)sas_address));
++ if (!sas_address)
++ continue;
++ port_details = phy_info->port_details;
++ /*
++ * Forming a port
++ */
++ if (!port_details) {
++ port_details = kzalloc(sizeof(struct mptsas_portinfo_details),
++ GFP_KERNEL);
++ if (!port_details)
++ goto out;
++ port_details->num_phys = 1;
++ port_details->port_info = port_info;
++ if (phy_info->phy_id < 64 )
++ port_details->phy_bitmask |=
++ (1 << phy_info->phy_id);
++ phy_info->sas_port_add_phy=1;
++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
++ "phy_id=%d sas_address=0x%018llX\n", ioc->name, i,
++ (unsigned long long) sas_address));
++ phy_info->port_details = port_details;
++ }
++
++ if (i == port_info->num_phys - 1)
++ continue;
++ phy_info_cmp = &port_info->phy_info[i + 1];
++ for (j = i + 1 ; j < port_info->num_phys ; j++,
++ phy_info_cmp++) {
++ if (!phy_info_cmp->attached.sas_address)
++ continue;
++ if (sas_address != phy_info_cmp->attached.sas_address)
++ continue;
++ if (phy_info_cmp->port_details == port_details )
++ continue;
++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "\t\tphy_id=%d sas_address=0x%018llX\n",
++ ioc->name, j, (unsigned long long)
++ phy_info_cmp->attached.sas_address));
++ if (phy_info_cmp->port_details) {
++ port_details->rphy =
++ mptsas_get_rphy(phy_info_cmp);
++ port_details->port =
++ mptsas_get_port(phy_info_cmp);
++ port_details->starget =
++ mptsas_get_starget(phy_info_cmp);
++ port_details->num_phys =
++ phy_info_cmp->port_details->num_phys;
++ if (!phy_info_cmp->port_details->num_phys)
++ kfree(phy_info_cmp->port_details);
++ } else
++ phy_info_cmp->sas_port_add_phy=1;
++ /*
++ * Adding a phy to a port
++ */
++ phy_info_cmp->port_details = port_details;
++ if (phy_info_cmp->phy_id < 64 )
++ port_details->phy_bitmask |=
++ (1 << phy_info_cmp->phy_id);
++ port_details->num_phys++;
++ }
++ }
+
+- out_free_consistent:
+- pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+- buffer, dma_handle);
+ out:
+- return error;
++
++ for (i = 0; i < port_info->num_phys; i++) {
++ port_details = port_info->phy_info[i].port_details;
++ if (!port_details)
++ continue;
++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: [%p]: phy_id=%02d num_phys=%02d "
++ "bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
++ port_details, i, port_details->num_phys,
++ (unsigned long long)port_details->phy_bitmask));
++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
++ ioc->name, port_details->port, port_details->rphy));
++ }
++ dsaswideprintk(ioc, printk("\n"));
++ mutex_unlock(&ioc->sas_topology_mutex);
+ }
+
+-static int
+-mptsas_slave_configure(struct scsi_device *sdev)
++/**
++ * mptsas_find_vtarget - obtain vtarget object for non-raid devices
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @channel:
++ * @id:
++ *
++ **/
++static VirtTarget *
++mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
++{
++ struct scsi_device *sdev;
++ VirtDevice *vdevice;
++ VirtTarget *vtarget = NULL;
++
++ shost_for_each_device(sdev, ioc->sh) {
++ if ((vdevice = sdev->hostdata) == NULL ||
++ (vdevice->vtarget == NULL))
++ continue;
++ if ((vdevice->vtarget->tflags &
++ MPT_TARGET_FLAGS_RAID_COMPONENT ||
++ vdevice->vtarget->raidVolume))
++ continue;
++ if (vdevice->vtarget->id == id &&
++ vdevice->vtarget->channel == channel)
++ vtarget = vdevice->vtarget;
++ }
++ return vtarget;
++}
++
++static void
++mptsas_queue_device_delete(MPT_ADAPTER *ioc,
++ MpiEventDataSasDeviceStatusChange_t *sas_event_data)
+ {
++ struct fw_event_work *fw_event;
++ int sz;
+
+- if (sdev->channel == MPTSAS_RAID_CHANNEL)
+- goto out;
++ sz = offsetof(struct fw_event_work, event_data) +
++ sizeof(MpiEventDataSasDeviceStatusChange_t);
++ fw_event = kzalloc(sz, GFP_ATOMIC);
++ if (!fw_event) {
++ printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
++ ioc->name, __FUNCTION__, __LINE__);
++ return;
++ }
++ memcpy(fw_event->event_data, sas_event_data,
++ sizeof(MpiEventDataSasDeviceStatusChange_t));
++ fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
++ fw_event->ioc = ioc;
++ mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
++}
+
+- sas_read_port_mode_page(sdev);
++static void
++mptsas_queue_rescan(MPT_ADAPTER *ioc)
++{
++ struct fw_event_work *fw_event;
++ int sz;
+
+- out:
+- return mptscsih_slave_configure(sdev);
++ sz = offsetof(struct fw_event_work, event_data);
++ fw_event = kzalloc(sz, GFP_ATOMIC);
++ if (!fw_event) {
++ printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
++ ioc->name, __FUNCTION__, __LINE__);
++ return;
++ }
++ fw_event->event = -1;
++ fw_event->ioc = ioc;
++ mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
+ }
+
++
++/**
++ * mptsas_target_reset - Issues TARGET_RESET to end device using
++ * handshaking method
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @channel:
++ * @id:
++ *
++ * Returns (1) success
++ * (0) failure
++ *
++ **/
+ static int
+-mptsas_target_alloc(struct scsi_target *starget)
++mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
+ {
+- struct Scsi_Host *host = dev_to_shost(&starget->dev);
+- MPT_SCSI_HOST *hd = shost_priv(host);
+- VirtTarget *vtarget;
+- u8 id, channel;
+- struct sas_rphy *rphy;
+- struct mptsas_portinfo *p;
+- int i;
+- MPT_ADAPTER *ioc = hd->ioc;
++ MPT_FRAME_HDR *mf;
++ SCSITaskMgmt_t *pScsiTm;
+
+- vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
+- if (!vtarget)
+- return -ENOMEM;
++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
++ return 0;
+
+- vtarget->starget = starget;
+- vtarget->ioc_id = ioc->id;
+- vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
+- id = starget->id;
+- channel = 0;
++ if ((mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc)) == NULL) {
++ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
++ ioc->name,__FUNCTION__, __LINE__));
++ goto out_fail;
++ }
+
+- /*
+- * RAID volumes placed beyond the last expected port.
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
++ ioc->name, mf));
++
++ /* Format the Request
+ */
+- if (starget->channel == MPTSAS_RAID_CHANNEL) {
+- for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
+- if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
+- channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
+- goto out;
+- }
++ pScsiTm = (SCSITaskMgmt_t *) mf;
++ memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
++ pScsiTm->TargetID = id;
++ pScsiTm->Bus = channel;
++ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
++ pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
++ pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+
+- rphy = dev_to_rphy(starget->dev.parent);
+- mutex_lock(&ioc->sas_topology_mutex);
+- list_for_each_entry(p, &ioc->sas_topology, list) {
+- for (i = 0; i < p->num_phys; i++) {
+- if (p->phy_info[i].attached.sas_address !=
+- rphy->identify.sas_address)
+- continue;
+- id = p->phy_info[i].attached.id;
+- channel = p->phy_info[i].attached.channel;
+- mptsas_set_starget(&p->phy_info[i], starget);
++ DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
+
+- /*
+- * Exposing hidden raid components
+- */
+- if (mptscsih_is_phys_disk(ioc, channel, id)) {
+- id = mptscsih_raid_id_to_num(ioc,
+- channel, id);
+- vtarget->tflags |=
+- MPT_TARGET_FLAGS_RAID_COMPONENT;
+- p->phy_info[i].attached.phys_disk_num = id;
+- }
+- mutex_unlock(&ioc->sas_topology_mutex);
+- goto out;
+- }
+- }
+- mutex_unlock(&ioc->sas_topology_mutex);
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
++ ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
+
+- kfree(vtarget);
+- return -ENXIO;
++ mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
+
+- out:
+- vtarget->id = id;
+- vtarget->channel = channel;
+- starget->hostdata = vtarget;
++ return 1;
++
++ out_fail:
++
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ return 0;
+ }
+-
++/**
++ * mptsas_target_reset_queue -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @sas_event_data:
++ *
++ * Receive request for TARGET_RESET after
++ * recieving an firmware event NOT_RESPONDING_EVENT, then put command in
++ * link list and queue if task_queue already in use.
++ **/
+ static void
+-mptsas_target_destroy(struct scsi_target *starget)
++mptsas_target_reset_queue(MPT_ADAPTER *ioc,
++ EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
+ {
+- struct Scsi_Host *host = dev_to_shost(&starget->dev);
+- MPT_SCSI_HOST *hd = shost_priv(host);
+- struct sas_rphy *rphy;
+- struct mptsas_portinfo *p;
+- int i;
+- MPT_ADAPTER *ioc = hd->ioc;
++ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
++ VirtTarget *vtarget = NULL;
++ struct mptsas_target_reset_event *target_reset_list;
++ u8 id, channel;
+
+- if (!starget->hostdata)
+- return;
++ id = sas_event_data->TargetID;
++ channel = sas_event_data->Bus;
+
+- if (starget->channel == MPTSAS_RAID_CHANNEL)
+- goto out;
++ if ((vtarget = mptsas_find_vtarget(ioc, channel, id))) {
++ if (!ioc->disable_hotplug_remove)
++ vtarget->deleted = 1; /* block IO */
++ }
+
+- rphy = dev_to_rphy(starget->dev.parent);
+- list_for_each_entry(p, &ioc->sas_topology, list) {
+- for (i = 0; i < p->num_phys; i++) {
+- if (p->phy_info[i].attached.sas_address !=
+- rphy->identify.sas_address)
+- continue;
+- mptsas_set_starget(&p->phy_info[i], NULL);
+- goto out;
+- }
++ target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
++ GFP_ATOMIC);
++ if (!target_reset_list) {
++ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
++ ioc->name,__FUNCTION__, __LINE__));
++ return;
+ }
+
+- out:
+- kfree(starget->hostdata);
+- starget->hostdata = NULL;
+-}
++ memcpy(&target_reset_list->sas_event_data, sas_event_data,
++ sizeof(*sas_event_data));
++ list_add_tail(&target_reset_list->list, &hd->target_reset_list);
++
++ target_reset_list->time_count = jiffies;
+
++ if (mptsas_target_reset(ioc, channel, id))
++ target_reset_list->target_reset_issued = 1;
++}
+
++/**
++ * mptsas_taskmgmt_complete - Completion for TARGET_RESET after
++ * NOT_RESPONDING_EVENT, enable work queue to finish off removing device
++ * from upper layers. then send next TARGET_RESET in the queue.
++ * @ioc: Pointer to MPT_ADAPTER structure
++ *
++ **/
+ static int
+-mptsas_slave_alloc(struct scsi_device *sdev)
++mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+ {
+- struct Scsi_Host *host = sdev->host;
+- MPT_SCSI_HOST *hd = shost_priv(host);
+- struct sas_rphy *rphy;
+- struct mptsas_portinfo *p;
+- VirtDevice *vdevice;
+- struct scsi_target *starget;
+- int i;
+- MPT_ADAPTER *ioc = hd->ioc;
++ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
++ struct list_head *head = &hd->target_reset_list;
++ struct mptsas_target_reset_event *target_reset_list;
++ u8 id, channel;
++ SCSITaskMgmtReply_t *pScsiTmReply;
+
+- vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+- if (!vdevice) {
+- printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
+- ioc->name, sizeof(VirtDevice));
+- return -ENOMEM;
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
++ "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
++
++ pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
++ if (pScsiTmReply) {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
++ "\ttask_type = 0x%02X, iocstatus = 0x%04X "
++ "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
++ "term_cmnds = %d\n", ioc->name,
++ pScsiTmReply->Bus, pScsiTmReply->TargetID,
++ pScsiTmReply->TaskType,
++ le16_to_cpu(pScsiTmReply->IOCStatus),
++ le32_to_cpu(pScsiTmReply->IOCLogInfo),
++ pScsiTmReply->ResponseCode,
++ le32_to_cpu(pScsiTmReply->TerminationCount)));
++
++ if (pScsiTmReply->ResponseCode)
++ mptscsih_taskmgmt_response_code(ioc,
++ pScsiTmReply->ResponseCode);
++ }
++
++ if (pScsiTmReply && (pScsiTmReply->TaskType ==
++ MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
++ MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
++ memcpy(ioc->taskmgmt_cmds.reply, mr,
++ min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
++ ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
++ complete(&ioc->taskmgmt_cmds.done);
++ return 1;
++ }
++ return 0;
+ }
+- starget = scsi_target(sdev);
+- vdevice->vtarget = starget->hostdata;
+
+- if (sdev->channel == MPTSAS_RAID_CHANNEL)
+- goto out;
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
+
+- rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
+- mutex_lock(&ioc->sas_topology_mutex);
+- list_for_each_entry(p, &ioc->sas_topology, list) {
+- for (i = 0; i < p->num_phys; i++) {
+- if (p->phy_info[i].attached.sas_address !=
+- rphy->identify.sas_address)
+- continue;
+- vdevice->lun = sdev->lun;
+- /*
+- * Exposing hidden raid components
+- */
+- if (mptscsih_is_phys_disk(ioc,
+- p->phy_info[i].attached.channel,
+- p->phy_info[i].attached.id))
+- sdev->no_uld_attach = 1;
+- mutex_unlock(&ioc->sas_topology_mutex);
+- goto out;
+- }
++ if (list_empty(head))
++ return 1;
++
++ target_reset_list = list_entry(head->next,
++ struct mptsas_target_reset_event, list);
++
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt: completed (%d seconds)\n",
++ ioc->name, jiffies_to_msecs(jiffies -
++ target_reset_list->time_count)/1000));
++
++ id = pScsiTmReply->TargetID;
++ channel = pScsiTmReply->Bus;
++ target_reset_list->time_count = jiffies;
++
++ /*
++ * retry target reset
++ */
++ if (!target_reset_list->target_reset_issued) {
++ if (mptsas_target_reset(ioc, channel, id))
++ target_reset_list->target_reset_issued = 1;
++ return 1;
+ }
+- mutex_unlock(&ioc->sas_topology_mutex);
+
+- kfree(vdevice);
+- return -ENXIO;
++ /*
++ * enable work queue to remove device from upper layers
++ */
++ list_del(&target_reset_list->list);
++ if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
++ mptsas_queue_device_delete(ioc, &target_reset_list->sas_event_data);
+
+- out:
+- vdevice->vtarget->num_luns++;
+- sdev->hostdata = vdevice;
+- return 0;
++
++ /*
++ * issue target reset to next device in the queue
++ */
++
++ head = &hd->target_reset_list;
++ if (list_empty(head))
++ return 1;
++
++ target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
++ list);
++
++ id = target_reset_list->sas_event_data.TargetID;
++ channel = target_reset_list->sas_event_data.Bus;
++ target_reset_list->time_count = jiffies;
++
++ if (mptsas_target_reset(ioc, channel, id))
++ target_reset_list->target_reset_issued = 1;
++
++ return 1;
+ }
+
++/**
++ * mptsas_ioc_reset -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @reset_phase:
++ *
++ **/
+ static int
+-mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
++mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+ {
+- VirtDevice *vdevice = SCpnt->device->hostdata;
+-
+- if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
+- SCpnt->result = DID_NO_CONNECT << 16;
+- done(SCpnt);
+- return 0;
+- }
++ MPT_SCSI_HOST *hd;
++ int rc;
+
+-// scsi_print_command(SCpnt);
++ rc = mptscsih_ioc_reset(ioc, reset_phase);
++ if ((ioc->bus_type != SAS) || (!rc))
++ return rc;
+
+- return mptscsih_qcmd(SCpnt,done);
+-}
++ hd = shost_priv(ioc->sh);
++ if (!hd->ioc)
++ goto out;
+
++ switch(reset_phase) {
++ case MPT_IOC_SETUP_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
++ mptsas_fw_event_off(ioc);
++ break;
++ case MPT_IOC_PRE_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
++ break;
++ case MPT_IOC_POST_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__));
++ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
++ ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
++ complete(&ioc->sas_mgmt.done);
++ }
++ mptsas_cleanup_fw_event_q(ioc);
++ mptsas_queue_rescan(ioc);
++ mptsas_fw_event_on(ioc);
++ break;
++ default:
++ break;
++ }
+
+-static struct scsi_host_template mptsas_driver_template = {
+- .module = THIS_MODULE,
+- .proc_name = "mptsas",
+- .proc_info = mptscsih_proc_info,
+- .name = "MPT SPI Host",
+- .info = mptscsih_info,
+- .queuecommand = mptsas_qcmd,
+- .target_alloc = mptsas_target_alloc,
+- .slave_alloc = mptsas_slave_alloc,
+- .slave_configure = mptsas_slave_configure,
+- .target_destroy = mptsas_target_destroy,
+- .slave_destroy = mptscsih_slave_destroy,
+- .change_queue_depth = mptscsih_change_queue_depth,
+- .eh_abort_handler = mptscsih_abort,
+- .eh_device_reset_handler = mptscsih_dev_reset,
+- .eh_bus_reset_handler = mptscsih_bus_reset,
+- .eh_host_reset_handler = mptscsih_host_reset,
+- .bios_param = mptscsih_bios_param,
+- .can_queue = MPT_FC_CAN_QUEUE,
+- .this_id = -1,
+- .sg_tablesize = MPT_SCSI_SG_DEPTH,
+- .max_sectors = 8192,
+- .cmd_per_lun = 7,
+- .use_clustering = ENABLE_CLUSTERING,
+- .shost_attrs = mptscsih_host_attrs,
+-};
++ out:
++ return rc;
++}
+
+-static int mptsas_get_linkerrors(struct sas_phy *phy)
++/**
++ * mptsas_sas_enclosure_pg0 -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @enclosure:
++ * @form:
++ * @form_specific:
++ *
++ **/
++static int
++mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
++ u32 form, u32 form_specific)
+ {
+- MPT_ADAPTER *ioc = phy_to_ioc(phy);
+ ConfigExtendedPageHeader_t hdr;
+ CONFIGPARMS cfg;
+- SasPhyPage1_t *buffer;
++ SasEnclosurePage0_t *buffer;
+ dma_addr_t dma_handle;
+ int error;
++ __le64 le_identifier;
+
+- /* FIXME: only have link errors on local phys */
+- if (!scsi_is_sas_phy_local(phy))
+- return -EINVAL;
+-
+- hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
+- hdr.ExtPageLength = 0;
+- hdr.PageNumber = 1 /* page number 1*/;
+- hdr.Reserved1 = 0;
+- hdr.Reserved2 = 0;
++ memset(&hdr, 0, sizeof(hdr));
++ hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
++ hdr.PageNumber = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+- hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.physAddr = -1;
+- cfg.pageAddr = phy->identify.phy_identifier;
++ cfg.pageAddr = form + form_specific;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+- cfg.dir = 0; /* read */
+- cfg.timeout = 10;
++ cfg.dir = 0; /* read */
++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
+
+ error = mpt_config(ioc, &cfg);
+ if (error)
+- return error;
+- if (!hdr.ExtPageLength)
+- return -ENXIO;
++ goto out;
++ if (!hdr.ExtPageLength) {
++ error = -ENXIO;
++ goto out;
++ }
+
+ buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+- &dma_handle);
+- if (!buffer)
+- return -ENOMEM;
++ &dma_handle);
++ if (!buffer) {
++ error = -ENOMEM;
++ goto out;
++ }
+
+ cfg.physAddr = dma_handle;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+@@ -1095,289 +1427,852 @@ static int mptsas_get_linkerrors(struct
+ if (error)
+ goto out_free_consistent;
+
+- mptsas_print_phy_pg1(ioc, buffer);
+-
+- phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
+- phy->running_disparity_error_count =
+- le32_to_cpu(buffer->RunningDisparityErrorCount);
+- phy->loss_of_dword_sync_count =
+- le32_to_cpu(buffer->LossDwordSynchCount);
+- phy->phy_reset_problem_count =
+- le32_to_cpu(buffer->PhyResetProblemCount);
++ /* save config data */
++ memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
++ enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
++ enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
++ enclosure->flags = le16_to_cpu(buffer->Flags);
++ enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
++ enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
++ enclosure->start_id = buffer->StartTargetID;
++ enclosure->start_channel = buffer->StartBus;
++ enclosure->sep_id = buffer->SEPTargetID;
++ enclosure->sep_channel = buffer->SEPBus;
+
+ out_free_consistent:
+ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+ buffer, dma_handle);
++ out:
+ return error;
+ }
+
+-static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
+- MPT_FRAME_HDR *reply)
++/**
++ * mptsas_get_lun_number - returns the first entry in report_luns table
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @channel:
++ * @id:
++ * @lun:
++ *
++ */
++static int
++mptsas_get_lun_number(MPT_ADAPTER *ioc, u8 channel, u8 id, int *lun)
+ {
+- ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
+- if (reply != NULL) {
+- ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
+- memcpy(ioc->sas_mgmt.reply, reply,
+- min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
+- }
+- complete(&ioc->sas_mgmt.done);
+- return 1;
+-}
++ INTERNAL_CMD *iocmd;
++ struct scsi_lun *lun_data;
++ dma_addr_t lun_data_dma;
++ u32 lun_data_len;
++ u8 *data;
++ MPT_SCSI_HOST *hd;
++ int rc;
++ u32 length, num_luns;
+
+-static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
+-{
+- MPT_ADAPTER *ioc = phy_to_ioc(phy);
+- SasIoUnitControlRequest_t *req;
+- SasIoUnitControlReply_t *reply;
+- MPT_FRAME_HDR *mf;
+- MPIHeader_t *hdr;
+- unsigned long timeleft;
+- int error = -ERESTARTSYS;
++ iocmd = NULL;
++ hd = shost_priv(ioc->sh);
++ lun_data_len = (255 * sizeof(struct scsi_lun));
++ lun_data = pci_alloc_consistent(ioc->pcidev, lun_data_len,
++ &lun_data_dma);
++ if (!lun_data) {
++ printk(MYIOC_s_ERR_FMT "%s: pci_alloc_consistent(%d) FAILED!\n",
++ ioc->name, __FUNCTION__, lun_data_len);
++ rc = -ENOMEM;
++ goto out;
++ }
+
+- /* FIXME: fusion doesn't allow non-local phy reset */
+- if (!scsi_is_sas_phy_local(phy))
+- return -EINVAL;
++ iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL);
++ if (!iocmd) {
++ printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n",
++ ioc->name, __FUNCTION__, sizeof(INTERNAL_CMD));
++ rc = -ENOMEM;
++ goto out;
++ }
+
+- /* not implemented for expanders */
+- if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
+- return -ENXIO;
++ /*
++ * Report Luns
++ */
++ iocmd->cmd = REPORT_LUNS;
++ iocmd->data_dma = lun_data_dma;
++ iocmd->data = (u8 *)lun_data;
++ iocmd->size = lun_data_len;
++ iocmd->channel = channel;
++ iocmd->id = id;
+
+- if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
++ if ((rc = mptscsih_do_cmd(hd, iocmd)) < 0) {
++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
++ "report_luns failed due to rc=0x%x\n", ioc->name,
++ __FUNCTION__, channel, id, rc);
+ goto out;
++ }
+
+- mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
+- if (!mf) {
+- error = -ENOMEM;
+- goto out_unlock;
++ if (rc != MPT_SCANDV_GOOD) {
++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
++ "report_luns failed due to rc=0x%x\n", ioc->name,
++ __FUNCTION__, channel, id, rc);
++ rc = -rc;
++ goto out;
+ }
+
+- hdr = (MPIHeader_t *) mf;
+- req = (SasIoUnitControlRequest_t *)mf;
+- memset(req, 0, sizeof(SasIoUnitControlRequest_t));
+- req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
+- req->MsgContext = hdr->MsgContext;
+- req->Operation = hard_reset ?
+- MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
+- req->PhyNum = phy->identify.phy_identifier;
++ data = (u8 *)lun_data;
++ length = ((data[0] << 24) | (data[1] << 16) |
++ (data[2] << 8) | (data[3] << 0));
+
+- mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
++ num_luns = (length / sizeof(struct scsi_lun));
++ if (!num_luns)
++ goto out;
++ /* return 1st lun in the list */
++ *lun = scsilun_to_int(&lun_data[1]);
+
+- timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
+- 10 * HZ);
+- if (!timeleft) {
+- /* On timeout reset the board */
+- mpt_free_msg_frame(ioc, mf);
+- mpt_HardResetHandler(ioc, CAN_SLEEP);
+- error = -ETIMEDOUT;
+- goto out_unlock;
++#if 0
++ /* some debugging, left commented out */
++ {
++ struct scsi_lun *lunp;
++ for (lunp = &lun_data[1]; lunp <= &lun_data[num_luns]; lunp++)
++ printk("%x\n", scsilun_to_int(lunp));
+ }
++#endif
+
+- /* a reply frame is expected */
+- if ((ioc->sas_mgmt.status &
+- MPT_IOCTL_STATUS_RF_VALID) == 0) {
+- error = -ENXIO;
+- goto out_unlock;
+- }
++ out:
++ if (lun_data)
++ pci_free_consistent(ioc->pcidev, lun_data_len, lun_data,
++ lun_data_dma);
++ kfree(iocmd);
++ return rc;
++}
+
+- /* process the completed Reply Message Frame */
+- reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
+- if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
+- printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
+- ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
+- error = -ENXIO;
+- goto out_unlock;
++/**
++ * enum device_state -
++ * @DEVICE_RETRY: need to retry the TUR
++ * @DEVICE_ERROR: TUR return error, don't add device
++ * @DEVICE_READY: device can be added
++ *
++ */
++enum device_state{
++ DEVICE_RETRY,
++ DEVICE_ERROR,
++ DEVICE_READY,
++};
++
++/**
++ * mptsas_test_unit_ready -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @channel:
++ * @id:
++ * @count: retry count
++ *
++ */
++enum device_state
++mptsas_test_unit_ready(MPT_ADAPTER *ioc, u8 channel, u8 id, u16 count)
++{
++ INTERNAL_CMD *iocmd;
++ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
++ enum device_state state;
++ int rc;
++ u8 skey, asc, ascq;
++ u8 retry_ua;
++
++ if (count >= mpt_cmd_retry_count)
++ return DEVICE_ERROR;
++
++ retry_ua = 0;
++ iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL);
++ if (!iocmd) {
++ printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n",
++ __FUNCTION__, ioc->name, sizeof(INTERNAL_CMD));
++ return DEVICE_ERROR;
++ }
++
++ state = DEVICE_ERROR;
++ iocmd->cmd = TEST_UNIT_READY;
++ iocmd->data_dma = -1;
++ iocmd->data = NULL;
++
++ if (mptscsih_is_phys_disk(ioc, channel, id)) {
++ iocmd->flags |= MPT_ICFLAG_PHYS_DISK;
++ iocmd->physDiskNum = mptscsih_raid_id_to_num(ioc, channel, id);
++ iocmd->id = id;
++ }
++ iocmd->channel = channel;
++ iocmd->id = id;
++
++ retry:
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_channel=%d "
++ "fw_id=%d retry=%d\n", ioc->name, __FUNCTION__, channel, id, count));
++ rc = mptscsih_do_cmd(hd, iocmd);
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rc=0x%02x\n",
++ ioc->name, __FUNCTION__, rc));
++ if (rc < 0) {
++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
++ "tur failed due to timeout\n", ioc->name,
++ __FUNCTION__, channel, id);
++ goto tur_done;
++ }
++
++ switch(rc) {
++ case MPT_SCANDV_GOOD:
++ state = DEVICE_READY;
++ goto tur_done;
++ case MPT_SCANDV_BUSY:
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: "
++ "fw_channel=%d fw_id=%d : device busy\n",
++ ioc->name, __FUNCTION__, channel, id));
++ state = DEVICE_RETRY;
++ break;
++ case MPT_SCANDV_DID_RESET:
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: "
++ "fw_channel=%d fw_id=%d : did reset\n",
++ ioc->name, __FUNCTION__, channel, id));
++ state = DEVICE_RETRY;
++ break;
++ case MPT_SCANDV_SENSE:
++ skey = ioc->internal_cmds.sense[2] & 0x0F;
++ asc = ioc->internal_cmds.sense[12];
++ ascq = ioc->internal_cmds.sense[13];
++
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: "
++ "fw_channel=%d fw_id=%d : [sense_key,asc,"
++ "ascq]: [0x%02x,0x%02x,0x%02x]\n", ioc->name,
++ __FUNCTION__, channel, id, skey, asc, ascq));
++
++ if (skey == UNIT_ATTENTION) {
++ if (!retry_ua) {
++ retry_ua++;
++ goto retry;
++ }
++ } else if (skey == NOT_READY) {
++ /*
++ * medium isn't present
++ */
++ if (asc == 0x3a) {
++ state = DEVICE_READY;
++ goto tur_done;
++ }
++ /*
++ * LU becoming ready, or
++ * LU hasn't self-configured yet
++ */
++ if ((asc == 0x04 && ascq == 0x01) ||
++ (asc == 0x04 && ascq == 0x11) ||
++ asc == 0x3e) {
++ state = DEVICE_RETRY;
++ break;
++ }
++ } else if (skey == ILLEGAL_REQUEST) {
++ /* try sending a tur to a non-zero lun number */
++ if (!iocmd->lun && !mptsas_get_lun_number(ioc,
++ channel, id, &iocmd->lun) && iocmd->lun)
++ goto retry;
++ }
++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d : "
++ "tur failed due to [sense_key,asc,ascq]: "
++ "[0x%02x,0x%02x,0x%02x]\n", ioc->name,
++ __FUNCTION__, channel, id, skey, asc, ascq);
++ goto tur_done;
++ case MPT_SCANDV_SELECTION_TIMEOUT:
++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
++ "tur failed due to no device\n", ioc->name,
++ __FUNCTION__, channel,
++ id);
++ goto tur_done;
++ case MPT_SCANDV_SOME_ERROR:
++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
++ "tur failed due to some error\n", ioc->name,
++ __FUNCTION__,
++ channel, id);
++ goto tur_done;
++ default:
++ printk(MYIOC_s_ERR_FMT
++ "%s: fw_channel=%d fw_id=%d: tur failed due to "
++ "unknown rc=0x%02x\n", ioc->name, __FUNCTION__,
++ channel, id, rc );
++ goto tur_done;
++ }
++ tur_done:
++ kfree(iocmd);
++ return state;
++}
++
++/**
++ * mptsas_issue_tlr - Enabling Transport Layer Retries
++ * @hd:
++ * @sdev:
++ *
++ **/
++static void
++mptsas_issue_tlr(MPT_SCSI_HOST *hd, struct scsi_device *sdev)
++{
++ INTERNAL_CMD *iocmd;
++ VirtDevice *vdevice = sdev->hostdata;
++ u8 retries;
++ u8 rc;
++ MPT_ADAPTER *ioc = hd->ioc;
++
++ if ( sdev->inquiry[8] == 'H' &&
++ sdev->inquiry[9] == 'P' &&
++ sdev->inquiry[10] == ' ' &&
++ sdev->inquiry[11] == ' ' &&
++ sdev->inquiry[12] == ' ' &&
++ sdev->inquiry[13] == ' ' &&
++ sdev->inquiry[14] == ' ' &&
++ sdev->inquiry[15] == ' ' ) {
++
++ iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL);
++ if (!iocmd) {
++ printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n",
++ __FUNCTION__, ioc->name, sizeof(INTERNAL_CMD));
++ return;
++ }
++ iocmd->id = vdevice->vtarget->id;
++ iocmd->channel = vdevice->vtarget->channel;
++ iocmd->lun = vdevice->lun;
++ iocmd->physDiskNum = -1;
++ iocmd->cmd = TRANSPORT_LAYER_RETRIES;
++ iocmd->data_dma = -1;
++ for (retries = 0, rc = -1; retries < 3; retries++) {
++ rc = mptscsih_do_cmd(hd, iocmd);
++ if (!rc)
++ break;
++ }
++ if (rc != 0)
++ printk(MYIOC_s_DEBUG_FMT "unable to enable TLR on"
++ " fw_channel %d, fw_id %d, lun=%d\n",
++ ioc->name, vdevice->vtarget->channel,
++ vdevice->vtarget->id, sdev->lun);
++ kfree(iocmd);
+ }
++}
+
+- error = 0;
++/**
++ * mptsas_slave_configure -
++ * @sdev:
++ *
++ **/
++static int
++mptsas_slave_configure(struct scsi_device *sdev)
++{
++ struct Scsi_Host *host = sdev->host;
++ MPT_SCSI_HOST *hd = shost_priv(host);
++ MPT_ADAPTER *ioc = hd->ioc;
++ VirtDevice *vdevice = sdev->hostdata;
++
++
++ if (vdevice->vtarget->deleted) {
++ sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
++ vdevice->vtarget->deleted = 0;
++ }
+
+- out_unlock:
+- mutex_unlock(&ioc->sas_mgmt.mutex);
++ /*
++ * RAID volumes placed beyond the last expected port.
++ * Ignore sending sas mode pages in that case..
++ */
++ if (sdev->channel == MPTSAS_RAID_CHANNEL) {
++ mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
++ goto out;
++ }
++
++ sas_read_port_mode_page(sdev);
++
++ mptsas_add_device_component_starget(ioc, scsi_target(sdev));
++
++ if (sdev->type == TYPE_TAPE &&
++ (ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_TLR ))
++ mptsas_issue_tlr(hd, sdev);
+ out:
+- return error;
++
++ return mptscsih_slave_configure(sdev);
+ }
+
++/**
++ * mptsas_target_alloc -
++ * @starget:
++ *
++ **/
+ static int
+-mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
++mptsas_target_alloc(struct scsi_target *starget)
+ {
+- MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
+- int i, error;
+- struct mptsas_portinfo *p;
+- struct mptsas_enclosure enclosure_info;
+- u64 enclosure_handle;
++ struct Scsi_Host *host = dev_to_shost(&starget->dev);
++ MPT_SCSI_HOST *hd = shost_priv(host);
++ VirtTarget *vtarget;
++ u8 id, channel;
++ struct sas_rphy *rphy;
++ struct mptsas_portinfo *p;
++ int i;
++ MPT_ADAPTER *ioc = hd->ioc;
++
++ vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
++ if (!vtarget)
++ return -ENOMEM;
++
++ vtarget->starget = starget;
++ vtarget->ioc_id = ioc->id;
++ vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
++ id = starget->id;
++ channel = 0;
++
++ /*
++ * RAID volumes placed beyond the last expected port.
++ */
++ if (starget->channel == MPTSAS_RAID_CHANNEL) {
++ if (!ioc->raid_data.pIocPg2) {
++ kfree(vtarget);
++ return -ENXIO;
++ }
++ for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
++ if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
++ channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
++ vtarget->raidVolume = 1;
++ goto out;
++ }
+
++ rphy = dev_to_rphy(starget->dev.parent);
+ mutex_lock(&ioc->sas_topology_mutex);
+ list_for_each_entry(p, &ioc->sas_topology, list) {
+ for (i = 0; i < p->num_phys; i++) {
+- if (p->phy_info[i].attached.sas_address ==
+- rphy->identify.sas_address) {
+- enclosure_handle = p->phy_info[i].
+- attached.handle_enclosure;
+- goto found_info;
++ if (p->phy_info[i].attached.sas_address !=
++ rphy->identify.sas_address)
++ continue;
++ id = p->phy_info[i].attached.id;
++ channel = p->phy_info[i].attached.channel;
++ mptsas_set_starget(&p->phy_info[i], starget);
++
++ starget_printk(KERN_INFO, starget, MYIOC_s_FMT
++ "add device: fw_channel %d, fw_id %d, phy %d, sas_addr 0x%llx\n",
++ ioc->name, p->phy_info[i].attached.channel,
++ p->phy_info[i].attached.id, p->phy_info[i].attached.phy_id,
++ (unsigned long long)p->phy_info[i].attached.sas_address);
++
++ /*
++ * Exposing hidden raid components
++ */
++ if (mptscsih_is_phys_disk(ioc, channel, id)) {
++ id = mptscsih_raid_id_to_num(ioc,
++ channel, id);
++ vtarget->tflags |=
++ MPT_TARGET_FLAGS_RAID_COMPONENT;
++ p->phy_info[i].attached.phys_disk_num = id;
+ }
++ mutex_unlock(&ioc->sas_topology_mutex);
++ goto out;
+ }
+ }
+ mutex_unlock(&ioc->sas_topology_mutex);
++
++ kfree(vtarget);
+ return -ENXIO;
+
+- found_info:
+- mutex_unlock(&ioc->sas_topology_mutex);
+- memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
+- error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
+- (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
+- MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
+- if (!error)
+- *identifier = enclosure_info.enclosure_logical_id;
+- return error;
++ out:
++ vtarget->id = id;
++ vtarget->channel = channel;
++ starget->hostdata = vtarget;
++ return 0;
+ }
+
+-static int
+-mptsas_get_bay_identifier(struct sas_rphy *rphy)
++/**
++ * mptsas_target_destroy -
++ * @starget:
++ *
++ **/
++static void
++mptsas_target_destroy(struct scsi_target *starget)
+ {
+- MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
+- struct mptsas_portinfo *p;
+- int i, rc;
++ struct Scsi_Host *host = dev_to_shost(&starget->dev);
++ MPT_SCSI_HOST *hd = shost_priv(host);
++ struct sas_rphy *rphy;
++ struct mptsas_portinfo *p;
++ int i;
++ MPT_ADAPTER *ioc = hd->ioc;
+
+- mutex_lock(&ioc->sas_topology_mutex);
++ if (!starget->hostdata)
++ return;
++
++ mptsas_del_device_component_by_os(ioc, starget->channel,
++ starget->id);
++
++ if (starget->channel == MPTSAS_RAID_CHANNEL)
++ goto out;
++
++ rphy = dev_to_rphy(starget->dev.parent);
+ list_for_each_entry(p, &ioc->sas_topology, list) {
+ for (i = 0; i < p->num_phys; i++) {
+- if (p->phy_info[i].attached.sas_address ==
+- rphy->identify.sas_address) {
+- rc = p->phy_info[i].attached.slot;
+- goto out;
+- }
++ if (p->phy_info[i].attached.sas_address !=
++ rphy->identify.sas_address)
++ continue;
++
++ starget_printk(KERN_INFO, starget, MYIOC_s_FMT
++ "delete device: fw_channel %d, fw_id %d, phy %d, "
++ "sas_addr 0x%llx\n", ioc->name,
++ p->phy_info[i].attached.channel,
++ p->phy_info[i].attached.id,
++ p->phy_info[i].attached.phy_id, (unsigned long long)
++ p->phy_info[i].attached.sas_address);
++
++ mptsas_port_delete(ioc, p->phy_info[i].port_details);
+ }
+ }
+- rc = -ENXIO;
++
+ out:
+- mutex_unlock(&ioc->sas_topology_mutex);
+- return rc;
++ kfree(starget->hostdata);
++ starget->hostdata = NULL;
+ }
+
+-static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+- struct request *req)
++/**
++ * mptsas_slave_alloc -
++ * @sdev:
++ *
++ **/
++static int
++mptsas_slave_alloc(struct scsi_device *sdev)
+ {
+- MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
+- MPT_FRAME_HDR *mf;
+- SmpPassthroughRequest_t *smpreq;
+- struct request *rsp = req->next_rq;
+- int ret;
+- int flagsLength;
+- unsigned long timeleft;
+- char *psge;
+- dma_addr_t dma_addr_in = 0;
+- dma_addr_t dma_addr_out = 0;
+- u64 sas_address = 0;
+-
+- if (!rsp) {
+- printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
+- ioc->name, __func__);
+- return -EINVAL;
+- }
++ struct Scsi_Host *host = sdev->host;
++ MPT_SCSI_HOST *hd = shost_priv(host);
++ struct sas_rphy *rphy;
++ struct mptsas_portinfo *p;
++ VirtDevice *vdevice;
++ struct scsi_target *starget;
++ int i;
++ MPT_ADAPTER *ioc = hd->ioc;
+
+- /* do we need to support multiple segments? */
+- if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
+- printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
+- ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
+- rsp->bio->bi_vcnt, rsp->data_len);
+- return -EINVAL;
++ vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
++ if (!vdevice) {
++ printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
++ ioc->name, sizeof(VirtDevice));
++ return -ENOMEM;
+ }
++ starget = scsi_target(sdev);
++ vdevice->vtarget = starget->hostdata;
+
+- ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
+- if (ret)
++ /*
++ * RAID volumes placed beyond the last expected port.
++ */
++ if (sdev->channel == MPTSAS_RAID_CHANNEL)
+ goto out;
+
+- mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
+- if (!mf) {
+- ret = -ENOMEM;
+- goto out_unlock;
++ rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
++ mutex_lock(&ioc->sas_topology_mutex);
++ list_for_each_entry(p, &ioc->sas_topology, list) {
++ for (i = 0; i < p->num_phys; i++) {
++ if (p->phy_info[i].attached.sas_address !=
++ rphy->identify.sas_address)
++ continue;
++ vdevice->lun = sdev->lun;
++ /*
++ * Exposing hidden raid components
++ */
++ if (mptscsih_is_phys_disk(ioc,
++ p->phy_info[i].attached.channel,
++ p->phy_info[i].attached.id))
++ sdev->no_uld_attach = 1;
++ mutex_unlock(&ioc->sas_topology_mutex);
++ goto out;
++ }
+ }
++ mutex_unlock(&ioc->sas_topology_mutex);
+
+- smpreq = (SmpPassthroughRequest_t *)mf;
+- memset(smpreq, 0, sizeof(*smpreq));
++ kfree(vdevice);
++ return -ENXIO;
+
+- smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
+- smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
++ out:
++ vdevice->vtarget->num_luns++;
++ sdev->hostdata = vdevice;
++ return 0;
++}
+
+- if (rphy)
+- sas_address = rphy->identify.sas_address;
+- else {
+- struct mptsas_portinfo *port_info;
++/**
++ * mptsas_qcmd -
++ * @SCpnt:
++ * @done:
++ *
++ **/
++static int
++mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
++{
++ MPT_SCSI_HOST *hd;
++ MPT_ADAPTER *ioc;
++ VirtDevice *vdevice = SCpnt->device->hostdata;
+
+- mutex_lock(&ioc->sas_topology_mutex);
+- port_info = mptsas_get_hba_portinfo(ioc);
+- if (port_info && port_info->phy_info)
+- sas_address =
+- port_info->phy_info[0].phy->identify.sas_address;
+- mutex_unlock(&ioc->sas_topology_mutex);
++ if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
++ SCpnt->result = DID_NO_CONNECT << 16;
++ done(SCpnt);
++ return 0;
+ }
+
+- *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
++ hd = shost_priv(SCpnt->device->host);
++ ioc = hd->ioc;
+
+- psge = (char *)
+- (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
++ if (ioc->sas_discovery_quiesce_io)
++ return SCSI_MLQUEUE_HOST_BUSY;
+
+- /* request */
+- flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+- MPI_SGE_FLAGS_END_OF_BUFFER |
+- MPI_SGE_FLAGS_DIRECTION |
+- mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
+- flagsLength |= (req->data_len - 4);
+-
+- dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
+- req->data_len, PCI_DMA_BIDIRECTIONAL);
+- if (!dma_addr_out)
+- goto put_mf;
+- mpt_add_sge(psge, flagsLength, dma_addr_out);
+- psge += (sizeof(u32) + sizeof(dma_addr_t));
+-
+- /* response */
+- flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+- flagsLength |= rsp->data_len + 4;
+- dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
+- rsp->data_len, PCI_DMA_BIDIRECTIONAL);
+- if (!dma_addr_in)
+- goto unmap;
+- mpt_add_sge(psge, flagsLength, dma_addr_in);
++// scsi_print_command(SCpnt);
++ return mptscsih_qcmd(SCpnt,done);
++}
+
+- mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
+
+- timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
+- if (!timeleft) {
+- printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
+- /* On timeout reset the board */
+- mpt_HardResetHandler(ioc, CAN_SLEEP);
+- ret = -ETIMEDOUT;
+- goto unmap;
+- }
+- mf = NULL;
+-
+- if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
+- SmpPassthroughReply_t *smprep;
+-
+- smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
+- memcpy(req->sense, smprep, sizeof(*smprep));
+- req->sense_len = sizeof(*smprep);
+- req->data_len = 0;
+- rsp->data_len -= smprep->ResponseDataLength;
+- } else {
+- printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
+- ioc->name, __func__);
+- ret = -ENXIO;
+- }
+-unmap:
+- if (dma_addr_out)
+- pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
+- PCI_DMA_BIDIRECTIONAL);
+- if (dma_addr_in)
+- pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
+- PCI_DMA_BIDIRECTIONAL);
+-put_mf:
+- if (mf)
++static struct scsi_host_template mptsas_driver_template = {
++ .module = THIS_MODULE,
++ .proc_name = "mptsas",
++ .proc_info = mptscsih_proc_info,
++ .name = "MPT SPI Host",
++ .info = mptscsih_info,
++ .queuecommand = mptsas_qcmd,
++ .target_alloc = mptsas_target_alloc,
++ .slave_alloc = mptsas_slave_alloc,
++ .slave_configure = mptsas_slave_configure,
++ .target_destroy = mptsas_target_destroy,
++ .slave_destroy = mptscsih_slave_destroy,
++ .change_queue_depth = mptscsih_change_queue_depth,
++ .eh_abort_handler = mptscsih_abort,
++ .eh_device_reset_handler = mptscsih_dev_reset,
++ .eh_bus_reset_handler = mptscsih_bus_reset,
++ .eh_host_reset_handler = mptscsih_host_reset,
++ .bios_param = mptscsih_bios_param,
++ .can_queue = MPT_FC_CAN_QUEUE,
++ .this_id = -1,
++ .sg_tablesize = MPT_SCSI_SG_DEPTH,
++ .max_sectors = 8192,
++ .cmd_per_lun = 7,
++ .use_clustering = ENABLE_CLUSTERING,
++ .shost_attrs = mptscsih_host_attrs,
++};
++
++/**
++ * mptsas_get_linkerrors -
++ * @phy:
++ *
++ **/
++static int mptsas_get_linkerrors(struct sas_phy *phy)
++{
++ MPT_ADAPTER *ioc = phy_to_ioc(phy);
++ ConfigExtendedPageHeader_t hdr;
++ CONFIGPARMS cfg;
++ SasPhyPage1_t *buffer;
++ dma_addr_t dma_handle;
++ int error;
++
++ /* FIXME: only have link errors on local phys */
++ if (!scsi_is_sas_phy_local(phy))
++ return -EINVAL;
++
++ hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
++ hdr.ExtPageLength = 0;
++ hdr.PageNumber = 1 /* page number 1*/;
++ hdr.Reserved1 = 0;
++ hdr.Reserved2 = 0;
++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
++
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.pageAddr = phy->identify.phy_identifier;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
++
++ error = mpt_config(ioc, &cfg);
++ if (error)
++ return error;
++ if (!hdr.ExtPageLength)
++ return -ENXIO;
++
++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
++ &dma_handle);
++ if (!buffer)
++ return -ENOMEM;
++
++ cfg.physAddr = dma_handle;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ error = mpt_config(ioc, &cfg);
++ if (error)
++ goto out_free_consistent;
++
++ mptsas_print_phy_pg1(ioc, buffer);
++
++ phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
++ phy->running_disparity_error_count =
++ le32_to_cpu(buffer->RunningDisparityErrorCount);
++ phy->loss_of_dword_sync_count =
++ le32_to_cpu(buffer->LossDwordSynchCount);
++ phy->phy_reset_problem_count =
++ le32_to_cpu(buffer->PhyResetProblemCount);
++
++ out_free_consistent:
++ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
++ buffer, dma_handle);
++ return error;
++}
++
++/**
++ * mptsas_mgmt_done -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @req:
++ * @reply:
++ *
++ **/
++static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
++ MPT_FRAME_HDR *reply)
++{
++ ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
++ if (reply != NULL) {
++ ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
++ memcpy(ioc->sas_mgmt.reply, reply,
++ min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
++ }
++
++ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
++ ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
++ complete(&ioc->sas_mgmt.done);
++ return 1;
++ }
++ return 0;
++}
++
++/**
++ * mptsas_phy_reset -
++ * @phy:
++ * @hard_reset:
++ *
++ **/
++static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
++{
++ MPT_ADAPTER *ioc = phy_to_ioc(phy);
++ SasIoUnitControlRequest_t *req;
++ SasIoUnitControlReply_t *reply;
++ MPT_FRAME_HDR *mf;
++ MPIHeader_t *hdr;
++ unsigned long timeleft;
++ int error = -ERESTARTSYS;
++
++ /* FIXME: fusion doesn't allow non-local phy reset */
++ if (!scsi_is_sas_phy_local(phy))
++ return -EINVAL;
++
++ /* not implemented for expanders */
++ if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
++ return -ENXIO;
++
++ if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
++ goto out;
++
++ mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
++ if (!mf) {
++ error = -ENOMEM;
++ goto out_unlock;
++ }
++
++ hdr = (MPIHeader_t *) mf;
++ req = (SasIoUnitControlRequest_t *)mf;
++ memset(req, 0, sizeof(SasIoUnitControlRequest_t));
++ req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
++ req->MsgContext = hdr->MsgContext;
++ req->Operation = hard_reset ?
++ MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
++ req->PhyNum = phy->identify.phy_identifier;
++
++ INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
++ mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
++ timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10*HZ);
++ if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ error = -ETIME;
+ mpt_free_msg_frame(ioc, mf);
+-out_unlock:
++ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
++ goto out;
++ if (!timeleft) {
++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
++ mpt_HardResetHandler(ioc, CAN_SLEEP);
++ }
++ goto out_unlock;
++ }
++
++ /* a reply frame is expected */
++ if ((ioc->sas_mgmt.status &
++ MPT_MGMT_STATUS_RF_VALID) == 0) {
++ error = -ENXIO;
++ goto out_unlock;
++ }
++
++ /* process the completed Reply Message Frame */
++ reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
++ if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
++ printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
++ ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo);
++ error = -ENXIO;
++ goto out_unlock;
++ }
++
++ error = 0;
++
++ out_unlock:
++ CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
+ mutex_unlock(&ioc->sas_mgmt.mutex);
+-out:
+- return ret;
++ out:
++ return error;
++}
++
++/**
++ * mptsas_get_enclosure_identifier -
++ * @rphy:
++ * @identifier:
++ *
++ **/
++static int
++mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
++{
++ MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
++ int i, error;
++ struct mptsas_portinfo *p;
++ struct mptsas_enclosure enclosure_info;
++ u64 enclosure_handle;
++
++ mutex_lock(&ioc->sas_topology_mutex);
++ list_for_each_entry(p, &ioc->sas_topology, list) {
++ for (i = 0; i < p->num_phys; i++) {
++ if (p->phy_info[i].attached.sas_address ==
++ rphy->identify.sas_address) {
++ enclosure_handle = p->phy_info[i].
++ attached.handle_enclosure;
++ goto found_info;
++ }
++ }
++ }
++ mutex_unlock(&ioc->sas_topology_mutex);
++ return -ENXIO;
++
++ found_info:
++ mutex_unlock(&ioc->sas_topology_mutex);
++ memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
++ error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
++ (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
++ MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
++ enclosure_handle);
++ if (!error)
++ *identifier = enclosure_info.enclosure_logical_id;
++ return error;
++}
++
++/**
++ * mptsas_get_bay_identifier -
++ * @rphy:
++ *
++ **/
++static int
++mptsas_get_bay_identifier(struct sas_rphy *rphy)
++{
++ MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
++ struct mptsas_portinfo *p;
++ int i, rc;
++
++ mutex_lock(&ioc->sas_topology_mutex);
++ list_for_each_entry(p, &ioc->sas_topology, list) {
++ for (i = 0; i < p->num_phys; i++) {
++ if (p->phy_info[i].attached.sas_address ==
++ rphy->identify.sas_address) {
++ rc = p->phy_info[i].attached.slot;
++ goto out;
++ }
++ }
++ }
++ rc = -ENXIO;
++ out:
++ mutex_unlock(&ioc->sas_topology_mutex);
++ return rc;
+ }
+
+ static struct sas_function_template mptsas_transport_functions = {
+@@ -1385,11 +2280,16 @@ static struct sas_function_template mpts
+ .get_enclosure_identifier = mptsas_get_enclosure_identifier,
+ .get_bay_identifier = mptsas_get_bay_identifier,
+ .phy_reset = mptsas_phy_reset,
+- .smp_handler = mptsas_smp_handler,
+ };
+
+ static struct scsi_transport_template *mptsas_transport_template;
+
++/**
++ * mptsas_sas_io_unit_pg0 -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @port_info:
++ *
++ **/
+ static int
+ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
+ {
+@@ -1412,7 +2312,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc,
+ cfg.pageAddr = 0;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+- cfg.timeout = 10;
++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
+
+ error = mpt_config(ioc, &cfg);
+ if (error)
+@@ -1438,7 +2338,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc,
+
+ port_info->num_phys = buffer->NumPhys;
+ port_info->phy_info = kcalloc(port_info->num_phys,
+- sizeof(*port_info->phy_info),GFP_KERNEL);
++ sizeof(struct mptsas_phyinfo),GFP_KERNEL);
+ if (!port_info->phy_info) {
+ error = -ENOMEM;
+ goto out_free_consistent;
+@@ -1459,6 +2359,8 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc,
+ port_info->phy_info[i].portinfo = port_info;
+ port_info->phy_info[i].handle =
+ le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
++ port_info->phy_info[i].port_flags =
++ buffer->PhyData[i].PortFlags;
+ }
+
+ out_free_consistent:
+@@ -1468,6 +2370,11 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc,
+ return error;
+ }
+
++/**
++ * mptsas_sas_io_unit_pg1 -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ *
++ **/
+ static int
+ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
+ {
+@@ -1483,11 +2390,11 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+- cfg.timeout = 10;
+ cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+ cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
+ cfg.cfghdr.ehdr->PageNumber = 1;
++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
+
+ error = mpt_config(ioc, &cfg);
+ if (error)
+@@ -1525,6 +2432,14 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
+ return error;
+ }
+
++/**
++ * mptsas_sas_phy_pg0 -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @phy_info:
++ * @form:
++ * @form_specific:
++ *
++ **/
+ static int
+ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
+ u32 form, u32 form_specific)
+@@ -1545,12 +2460,12 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, str
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.dir = 0; /* read */
+- cfg.timeout = 10;
+
+ /* Get Phy Pg 0 for each Phy. */
+ cfg.physAddr = -1;
+ cfg.pageAddr = form + form_specific;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
+
+ error = mpt_config(ioc, &cfg);
+ if (error)
+@@ -1581,6 +2496,8 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, str
+ phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
+ phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
+ phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
++ phy_info->change_count = buffer->ChangeCount;
++ phy_info->phy_info = le32_to_cpu(buffer->PhyInfo);
+
+ out_free_consistent:
+ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+@@ -1589,6 +2506,14 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, str
+ return error;
+ }
+
++/**
++ * mptsas_sas_device_pg0 -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @device_info:
++ * @form:
++ * @form_specific:
++ *
++ **/
+ static int
+ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
+ u32 form, u32 form_specific)
+@@ -1600,10 +2525,6 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
+ __le64 sas_address;
+ int error=0;
+
+- if (ioc->sas_discovery_runtime &&
+- mptsas_is_end_device(device_info))
+- goto out;
+-
+ hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 0;
+@@ -1617,9 +2538,8 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+- cfg.timeout = 10;
++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
+
+- memset(device_info, 0, sizeof(struct mptsas_devinfo));
+ error = mpt_config(ioc, &cfg);
+ if (error)
+ goto out;
+@@ -1639,11 +2559,18 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ error = mpt_config(ioc, &cfg);
++
++ if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
++ error = -ENODEV;
++ goto out_free_consistent;
++ }
++
+ if (error)
+ goto out_free_consistent;
+
+ mptsas_print_device_pg0(ioc, buffer);
+
++ memset(device_info, 0, sizeof(struct mptsas_devinfo));
+ device_info->handle = le16_to_cpu(buffer->DevHandle);
+ device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
+ device_info->handle_enclosure =
+@@ -1666,6 +2593,14 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
+ return error;
+ }
+
++/**
++ * mptsas_sas_expander_pg0 -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @port_info:
++ * @form:
++ * @form_specific:
++ *
++ **/
+ static int
+ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
+ u32 form, u32 form_specific)
+@@ -1675,7 +2610,9 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc
+ SasExpanderPage0_t *buffer;
+ dma_addr_t dma_handle;
+ int i, error;
++ __le64 sas_address;
+
++ memset(port_info, 0, sizeof(struct mptsas_portinfo));
+ hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 0;
+@@ -1689,9 +2626,8 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc
+ cfg.pageAddr = form + form_specific;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+- cfg.timeout = 10;
++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
+
+- memset(port_info, 0, sizeof(struct mptsas_portinfo));
+ error = mpt_config(ioc, &cfg);
+ if (error)
+ goto out;
+@@ -1712,27 +2648,32 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ error = mpt_config(ioc, &cfg);
+- if (error)
+- goto out_free_consistent;
+-
+- if (!buffer->NumPhys) {
++ if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
+ error = -ENODEV;
+ goto out_free_consistent;
+ }
+
++ if (error)
++ goto out_free_consistent;
++
+ /* save config data */
+- port_info->num_phys = buffer->NumPhys;
++ port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
+ port_info->phy_info = kcalloc(port_info->num_phys,
+- sizeof(*port_info->phy_info),GFP_KERNEL);
++ sizeof(struct mptsas_phyinfo),GFP_KERNEL);
+ if (!port_info->phy_info) {
+ error = -ENOMEM;
+ goto out_free_consistent;
+ }
+
++ memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
+ for (i = 0; i < port_info->num_phys; i++) {
+ port_info->phy_info[i].portinfo = port_info;
+ port_info->phy_info[i].handle =
+ le16_to_cpu(buffer->DevHandle);
++ port_info->phy_info[i].identify.sas_address =
++ le64_to_cpu(sas_address);
++ port_info->phy_info[i].identify.handle_parent =
++ le16_to_cpu(buffer->ParentDevHandle);
+ }
+
+ out_free_consistent:
+@@ -1742,6 +2683,14 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc
+ return error;
+ }
+
++/**
++ * mptsas_sas_expander_pg1 -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @phy_info:
++ * @form:
++ * @form_specific:
++ *
++ **/
+ static int
+ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
+ u32 form, u32 form_specific)
+@@ -1752,11 +2701,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc
+ dma_addr_t dma_handle;
+ int error=0;
+
+- if (ioc->sas_discovery_runtime &&
+- mptsas_is_end_device(&phy_info->attached))
+- goto out;
+-
+- hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
++ hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 1;
+ hdr.Reserved1 = 0;
+@@ -1764,1352 +2709,2349 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
+
+- cfg.cfghdr.ehdr = &hdr;
+- cfg.physAddr = -1;
+- cfg.pageAddr = form + form_specific;
++ cfg.cfghdr.ehdr = &hdr;
++ cfg.physAddr = -1;
++ cfg.pageAddr = form + form_specific;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ cfg.dir = 0; /* read */
++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
++
++ error = mpt_config(ioc, &cfg);
++ if (error)
++ goto out;
++
++ if (!hdr.ExtPageLength) {
++ error = -ENXIO;
++ goto out;
++ }
++
++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
++ &dma_handle);
++ if (!buffer) {
++ error = -ENOMEM;
++ goto out;
++ }
++
++ cfg.physAddr = dma_handle;
++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++
++ error = mpt_config(ioc, &cfg);
++ if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
++ error = -ENODEV;
++ goto out;
++ }
++
++ if (error)
++ goto out_free_consistent;
++
++
++ mptsas_print_expander_pg1(ioc, buffer);
++
++ /* save config data */
++ phy_info->phy_id = buffer->PhyIdentifier;
++ phy_info->port_id = buffer->PhysicalPort;
++ phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
++ phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
++ phy_info->hw_link_rate = buffer->HwLinkRate;
++ phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
++ phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
++ phy_info->change_count = buffer->ChangeCount;
++ phy_info->phy_info = le32_to_cpu(buffer->PhyInfo);
++
++ out_free_consistent:
++ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
++ buffer, dma_handle);
++ out:
++ return error;
++}
++
++/**
++ * mptsas_parse_device_info -
++ * @identify:
++ * @device_info:
++ *
++ **/
++static void
++mptsas_parse_device_info(struct sas_identify *identify,
++ struct mptsas_devinfo *device_info)
++{
++ u16 protocols;
++
++ identify->sas_address = device_info->sas_address;
++ identify->phy_identifier = device_info->phy_id;
++
++ /*
++ * Fill in Phy Initiator Port Protocol.
++ * Bits 6:3, more than one bit can be set, fall through cases.
++ */
++ protocols = device_info->device_info & 0x78;
++ identify->initiator_port_protocols = 0;
++ if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
++ identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
++ if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
++ identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
++ if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
++ identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
++ if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
++ identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
++
++ /*
++ * Fill in Phy Target Port Protocol.
++ * Bits 10:7, more than one bit can be set, fall through cases.
++ */
++ protocols = device_info->device_info & 0x780;
++ identify->target_port_protocols = 0;
++ if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
++ identify->target_port_protocols |= SAS_PROTOCOL_SSP;
++ if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
++ identify->target_port_protocols |= SAS_PROTOCOL_STP;
++ if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
++ identify->target_port_protocols |= SAS_PROTOCOL_SMP;
++ if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
++ identify->target_port_protocols |= SAS_PROTOCOL_SATA;
++
++ /*
++ * Fill in Attached device type.
++ */
++ switch (device_info->device_info &
++ MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
++ case MPI_SAS_DEVICE_INFO_NO_DEVICE:
++ identify->device_type = SAS_PHY_UNUSED;
++ break;
++ case MPI_SAS_DEVICE_INFO_END_DEVICE:
++ identify->device_type = SAS_END_DEVICE;
++ break;
++ case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
++ identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
++ break;
++ case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
++ identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
++ break;
++ }
++}
++
++/**
++ * mptsas_probe_one_phy -
++ * @dev:
++ * @phy_info:
++ * @local:
++ *
++ **/
++static int mptsas_probe_one_phy(struct device *dev,
++ struct mptsas_phyinfo *phy_info, int index, int local)
++{
++ MPT_ADAPTER *ioc;
++ struct sas_phy *phy;
++ struct sas_port *port;
++ int error = 0;
++
++ if (!dev) {
++ error = -ENODEV;
++ goto out;
++ }
++
++ if (!phy_info->phy) {
++ phy = sas_phy_alloc(dev, index);
++ if (!phy) {
++ error = -ENOMEM;
++ goto out;
++ }
++ } else
++ phy = phy_info->phy;
++
++ mptsas_parse_device_info(&phy->identify, &phy_info->identify);
++
++ /*
++ * Set Negotiated link rate.
++ */
++ switch (phy_info->negotiated_link_rate) {
++ case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
++ phy->negotiated_linkrate = SAS_PHY_DISABLED;
++ break;
++ case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
++ phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
++ break;
++ case MPI_SAS_IOUNIT0_RATE_1_5:
++ phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
++ break;
++ case MPI_SAS_IOUNIT0_RATE_3_0:
++ phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
++ break;
++ case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
++ case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
++ default:
++ phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
++ break;
++ }
++
++ /*
++ * Set Max hardware link rate.
++ */
++ switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
++ case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
++ phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
++ break;
++ case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
++ phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
++ break;
++ default:
++ break;
++ }
++
++ /*
++ * Set Max programmed link rate.
++ */
++ switch (phy_info->programmed_link_rate &
++ MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
++ case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
++ phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
++ break;
++ case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
++ phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
++ break;
++ default:
++ break;
++ }
++
++ /*
++ * Set Min hardware link rate.
++ */
++ switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
++ case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
++ phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
++ break;
++ case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
++ phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
++ break;
++ default:
++ break;
++ }
++
++ /*
++ * Set Min programmed link rate.
++ */
++ switch (phy_info->programmed_link_rate &
++ MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
++ case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
++ phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
++ break;
++ case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
++ phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
++ break;
++ default:
++ break;
++ }
++
++ if (!phy_info->phy) {
++
++ error = sas_phy_add(phy);
++ if (error) {
++ sas_phy_free(phy);
++ goto out;
++ }
++ phy_info->phy = phy;
++ }
++
++ if (!phy_info->attached.handle ||
++ !phy_info->port_details)
++ goto out;
++
++ port = mptsas_get_port(phy_info);
++ ioc = phy_to_ioc(phy_info->phy);
++
++ if (phy_info->sas_port_add_phy) {
++ if (!port) {
++ port = sas_port_alloc_num(dev);
++ if (!port) {
++ error = -ENOMEM;
++ goto out;
++ }
++ error = sas_port_add(port);
++ if (error) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: exit at line=%d\n", ioc->name,
++ __FUNCTION__, __LINE__));
++ goto out;
++ }
++ mptsas_set_port(ioc, phy_info, port);
++ devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
++ MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
++ ioc->name, port->port_identifier,
++ (unsigned long long)phy_info->attached.sas_address));
++ }
++ sas_port_add_phy(port, phy_info->phy);
++ phy_info->sas_port_add_phy = 0;
++ devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
++ MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
++ phy_info->phy_id, phy_info->phy));
++ }
++
++ if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
++
++ struct sas_rphy *rphy;
++ struct device *parent;
++ struct sas_identify identify;
++
++ parent = dev->parent->parent;
++
++ if (mptsas_is_end_device(&phy_info->attached) &&
++ phy_info->attached.handle_parent) {
++ goto out;
++ }
++
++ mptsas_parse_device_info(&identify, &phy_info->attached);
++ if (scsi_is_host_device(parent)) {
++ struct mptsas_portinfo *port_info;
++ int i;
++
++ port_info = ioc->hba_port_info;
++ for (i = 0; i < port_info->num_phys; i++)
++ if (port_info->phy_info[i].identify.sas_address ==
++ identify.sas_address) {
++ sas_port_mark_backlink(port);
++ goto out;
++ }
++
++ } else if (scsi_is_sas_rphy(parent)) {
++ struct sas_rphy *parent_rphy = dev_to_rphy(parent);
++ if (identify.sas_address ==
++ parent_rphy->identify.sas_address) {
++ sas_port_mark_backlink(port);
++ goto out;
++ }
++ }
++
++ switch (identify.device_type) {
++ case SAS_END_DEVICE:
++ rphy = sas_end_device_alloc(port);
++ break;
++ case SAS_EDGE_EXPANDER_DEVICE:
++ case SAS_FANOUT_EXPANDER_DEVICE:
++ rphy = sas_expander_alloc(port, identify.device_type);
++ break;
++ default:
++ rphy = NULL;
++ break;
++ }
++ if (!rphy) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: exit at line=%d\n", ioc->name,
++ __FUNCTION__, __LINE__));
++ goto out;
++ }
++
++ rphy->identify = identify;
++ error = sas_rphy_add(rphy);
++ if (error) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: exit at line=%d\n", ioc->name,
++ __FUNCTION__, __LINE__));
++ sas_rphy_free(rphy);
++ goto out;
++ }
++ mptsas_set_rphy(ioc, phy_info, rphy);
++ }
++
++ out:
++ return error;
++}
++
++/**
++ * mptsas_probe_hba_phys -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @handle:
++ *
++ **/
++static int
++mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
++{
++ struct mptsas_portinfo *port_info, *hba;
++ int error = -ENOMEM, i;
++
++ hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
++ if (! hba)
++ goto out;
++
++ error = mptsas_sas_io_unit_pg0(ioc, hba);
++ if (error)
++ goto out_free_port_info;
++
++ mptsas_sas_io_unit_pg1(ioc);
++ mutex_lock(&ioc->sas_topology_mutex);
++ port_info = ioc->hba_port_info;
++ if (!port_info) {
++ ioc->hba_port_info = port_info = hba;
++ ioc->hba_port_num_phy = port_info->num_phys;
++ list_add_tail(&port_info->list, &ioc->sas_topology);
++ } else {
++ for (i = 0; i < hba->num_phys; i++) {
++ port_info->phy_info[i].negotiated_link_rate =
++ hba->phy_info[i].negotiated_link_rate;
++ port_info->phy_info[i].handle =
++ hba->phy_info[i].handle;
++ port_info->phy_info[i].port_id =
++ hba->phy_info[i].port_id;
++ port_info->phy_info[i].port_flags =
++ hba->phy_info[i].port_flags;
++ }
++ kfree(hba->phy_info);
++ kfree(hba);
++ hba = NULL;
++ }
++ mutex_unlock(&ioc->sas_topology_mutex);
++#if defined(CPQ_CIM)
++ ioc->num_ports = port_info->num_phys;
++#endif
++ for (i = 0; i < port_info->num_phys; i++) {
++ mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
++ (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
++ MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
++ port_info->phy_info[i].identify.handle =
++ port_info->phy_info[i].handle;
++ mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
++ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
++ port_info->phy_info[i].identify.handle);
++ if (!ioc->hba_port_sas_addr)
++ ioc->hba_port_sas_addr =
++ port_info->phy_info[i].identify.sas_address;
++ port_info->phy_info[i].identify.phy_id =
++ port_info->phy_info[i].phy_id = i;
++ if (port_info->phy_info[i].attached.handle)
++ mptsas_sas_device_pg0(ioc,
++ &port_info->phy_info[i].attached,
++ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
++ port_info->phy_info[i].attached.handle);
++ }
++
++ mptsas_setup_wide_ports(ioc, port_info);
++
++ for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
++ mptsas_probe_one_phy(&ioc->sh->shost_gendev,
++ &port_info->phy_info[i], ioc->sas_index, 1);
++
++ return 0;
++
++ out_free_port_info:
++ kfree(hba);
++ out:
++ return error;
++}
++
++/**
++ * mptsas_find_phyinfo_by_sas_address -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @sas_address:
++ *
++ **/
++static struct mptsas_phyinfo *
++mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
++{
++ struct mptsas_portinfo *port_info;
++ struct mptsas_phyinfo *phy_info = NULL;
++ int i;
++
++ mutex_lock(&ioc->sas_topology_mutex);
++ list_for_each_entry(port_info, &ioc->sas_topology, list) {
++ for (i = 0; i < port_info->num_phys; i++) {
++ if (!mptsas_is_end_device(
++ &port_info->phy_info[i].attached))
++ continue;
++ if (port_info->phy_info[i].attached.sas_address
++ != sas_address)
++ continue;
++ phy_info = &port_info->phy_info[i];
++ break;
++ }
++ }
++ mutex_unlock(&ioc->sas_topology_mutex);
++ return phy_info;
++}
++
++/**
++ * mptsas_find_phyinfo_by_phys_disk_num -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @phys_disk_num:
++ * @channel:
++ * @id:
++ *
++ **/
++static struct mptsas_phyinfo *
++mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
++ u8 channel, u8 id)
++{
++ struct mptsas_phyinfo *phy_info;
++ struct mptsas_portinfo *port_info;
++ RaidPhysDiskPage1_t *phys_disk = NULL;
++ int num_paths;
++ u64 sas_address = 0;
++ int i;
++
++ phy_info = NULL;
++ if (!ioc->raid_data.pIocPg3)
++ return NULL;
++ /* dual port support */
++ num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
++ if (!num_paths)
++ goto out;
++ phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) +
++ (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
++ if (!phys_disk)
++ goto out;
++ mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
++ for (i = 0; i < num_paths; i++) {
++ if ((phys_disk->Path[i].Flags & 1) != 0)
++ /* entry no longer valid */
++ continue;
++ if ((id == phys_disk->Path[i].PhysDiskID) &&
++ (channel == phys_disk->Path[i].PhysDiskBus)) {
++ memcpy(&sas_address, &phys_disk->Path[i].WWID,
++ sizeof(u64));
++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc, sas_address);
++ goto out;
++ }
++ }
++
++ out:
++ kfree(phys_disk);
++ if (phy_info)
++ return phy_info;
++
++ /*
++ * Extra code to handle RAID0 case, where the sas_address is not updated
++ * in phys_disk_page_1 when hotswapped
++ */
++ mutex_lock(&ioc->sas_topology_mutex);
++ list_for_each_entry(port_info, &ioc->sas_topology, list) {
++ for (i = 0; i < port_info->num_phys && !phy_info; i++) {
++ if (!mptsas_is_end_device(
++ &port_info->phy_info[i].attached))
++ continue;
++ if (port_info->phy_info[i].attached.phys_disk_num == ~0)
++ continue;
++ if (port_info->phy_info[i].attached.phys_disk_num == phys_disk_num &&
++ port_info->phy_info[i].attached.id == id &&
++ port_info->phy_info[i].attached.channel == channel)
++ phy_info = &port_info->phy_info[i];
++ }
++ }
++ mutex_unlock(&ioc->sas_topology_mutex);
++ return phy_info;
++}
++
++/**
++ * mptsas_reprobe_lun -
++ * @sdev:
++ * @data:
++ *
++ **/
++static void
++mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
++{
++ int rc;
++
++ sdev->no_uld_attach = data ? 1 : 0;
++ rc = scsi_device_reprobe(sdev);
++}
++
++/**
++ * mptsas_reprobe_target -
++ * @starget:
++ * @uld_attach:
++ *
++ **/
++static void
++mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
++{
++ starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
++ mptsas_reprobe_lun);
++}
++
++/**
++ * mptsas_adding_inactive_raid_components -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @channel:
++ * @id:
++ *
++ *
++ * TODO: check for hotspares
++ **/
++static void
++mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
++{
++ CONFIGPARMS cfg;
++ ConfigPageHeader_t hdr;
++ dma_addr_t dma_handle;
++ pRaidVolumePage0_t buffer = NULL;
++ RaidPhysDiskPage0_t phys_disk;
++ int i;
++ struct mptsas_phyinfo *phy_info;
++ struct mptsas_devinfo sas_device;
++
++ memset(&cfg, 0 , sizeof(CONFIGPARMS));
++ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
++ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
++ cfg.pageAddr = (channel << 8) + id;
++ cfg.cfghdr.hdr = &hdr;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+- cfg.dir = 0; /* read */
+- cfg.timeout = 10;
++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
+
+- error = mpt_config(ioc, &cfg);
+- if (error)
++ if (mpt_config(ioc, &cfg) != 0)
+ goto out;
+
+- if (!hdr.ExtPageLength) {
+- error = -ENXIO;
++ if (!hdr.PageLength)
+ goto out;
+- }
+
+- buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+- &dma_handle);
+- if (!buffer) {
+- error = -ENOMEM;
++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
++ &dma_handle);
++
++ if (!buffer)
+ goto out;
+- }
+
+ cfg.physAddr = dma_handle;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+- error = mpt_config(ioc, &cfg);
+- if (error)
+- goto out_free_consistent;
+-
+-
+- mptsas_print_expander_pg1(ioc, buffer);
+-
+- /* save config data */
+- phy_info->phy_id = buffer->PhyIdentifier;
+- phy_info->port_id = buffer->PhysicalPort;
+- phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
+- phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
+- phy_info->hw_link_rate = buffer->HwLinkRate;
+- phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
+- phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
++ if (mpt_config(ioc, &cfg) != 0)
++ goto out;
+
+- out_free_consistent:
+- pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+- buffer, dma_handle);
+- out:
+- return error;
+-}
++ if (!(buffer->VolumeStatus.Flags &
++ MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
++ goto out;
+
+-static void
+-mptsas_parse_device_info(struct sas_identify *identify,
+- struct mptsas_devinfo *device_info)
+-{
+- u16 protocols;
++ if (!buffer->NumPhysDisks)
++ goto out;
+
+- identify->sas_address = device_info->sas_address;
+- identify->phy_identifier = device_info->phy_id;
++ for (i = 0; i < buffer->NumPhysDisks; i++) {
+
+- /*
+- * Fill in Phy Initiator Port Protocol.
+- * Bits 6:3, more than one bit can be set, fall through cases.
+- */
+- protocols = device_info->device_info & 0x78;
+- identify->initiator_port_protocols = 0;
+- if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
+- identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
+- if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
+- identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
+- if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
+- identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
+- if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
+- identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
++ if (mpt_raid_phys_disk_pg0(ioc,
++ buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
++ continue;
+
+- /*
+- * Fill in Phy Target Port Protocol.
+- * Bits 10:7, more than one bit can be set, fall through cases.
+- */
+- protocols = device_info->device_info & 0x780;
+- identify->target_port_protocols = 0;
+- if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
+- identify->target_port_protocols |= SAS_PROTOCOL_SSP;
+- if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
+- identify->target_port_protocols |= SAS_PROTOCOL_STP;
+- if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
+- identify->target_port_protocols |= SAS_PROTOCOL_SMP;
+- if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+- identify->target_port_protocols |= SAS_PROTOCOL_SATA;
++ if (mptsas_sas_device_pg0(ioc, &sas_device,
++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
++ (phys_disk.PhysDiskBus << 8) +
++ phys_disk.PhysDiskID))
++ continue;
+
+- /*
+- * Fill in Attached device type.
+- */
+- switch (device_info->device_info &
+- MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
+- case MPI_SAS_DEVICE_INFO_NO_DEVICE:
+- identify->device_type = SAS_PHY_UNUSED;
+- break;
+- case MPI_SAS_DEVICE_INFO_END_DEVICE:
+- identify->device_type = SAS_END_DEVICE;
+- break;
+- case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
+- identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
+- break;
+- case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
+- identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
+- break;
++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
++ sas_device.sas_address);
++ mptsas_add_end_device(ioc, phy_info);
+ }
++
++ out:
++ if (buffer)
++ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
++ dma_handle);
+ }
+
+-static int mptsas_probe_one_phy(struct device *dev,
+- struct mptsas_phyinfo *phy_info, int index, int local)
++/**
++ * mptsas_add_end_device - report a new end device to sas transport layer
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @phy_info: decribes attached device
++ *
++ * return (0) success (1) failure
++ *
++ **/
++static int
++mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
+ {
+- MPT_ADAPTER *ioc;
+- struct sas_phy *phy;
++ struct sas_rphy *rphy;
+ struct sas_port *port;
+- int error = 0;
++ struct sas_identify identify;
++ char *ds = NULL;
++ u8 fw_id;
+
+- if (!dev) {
+- error = -ENODEV;
+- goto out;
++ if (!phy_info){
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: exit at line=%d\n", ioc->name,
++ __FUNCTION__, __LINE__));
++ return 1;
+ }
+
+- if (!phy_info->phy) {
+- phy = sas_phy_alloc(dev, index);
+- if (!phy) {
+- error = -ENOMEM;
+- goto out;
+- }
+- } else
+- phy = phy_info->phy;
+-
+- mptsas_parse_device_info(&phy->identify, &phy_info->identify);
+-
+- /*
+- * Set Negotiated link rate.
+- */
+- switch (phy_info->negotiated_link_rate) {
+- case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
+- phy->negotiated_linkrate = SAS_PHY_DISABLED;
+- break;
+- case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
+- phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
+- break;
+- case MPI_SAS_IOUNIT0_RATE_1_5:
+- phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
+- break;
+- case MPI_SAS_IOUNIT0_RATE_3_0:
+- phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
+- break;
+- case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
+- case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
+- default:
+- phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
+- break;
+- }
++ fw_id = phy_info->attached.id;
+
+- /*
+- * Set Max hardware link rate.
+- */
+- switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
+- case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
+- phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+- break;
+- case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
+- phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
+- break;
+- default:
+- break;
++ if (mptsas_get_rphy(phy_info)) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, fw_id, __LINE__));
++ return 2;
+ }
+
+- /*
+- * Set Max programmed link rate.
+- */
+- switch (phy_info->programmed_link_rate &
+- MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
+- case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
+- phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+- break;
+- case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
+- phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
+- break;
+- default:
+- break;
++ port = mptsas_get_port(phy_info);
++ if (!port) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, fw_id, __LINE__));
++ return 3;
++ }
++
++ if (phy_info->attached.device_info &
++ MPI_SAS_DEVICE_INFO_SSP_TARGET)
++ ds = "ssp";
++ if (phy_info->attached.device_info &
++ MPI_SAS_DEVICE_INFO_STP_TARGET)
++ ds = "stp";
++ if (phy_info->attached.device_info &
++ MPI_SAS_DEVICE_INFO_SATA_DEVICE)
++ ds = "sata";
++
++ printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
++ " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
++ phy_info->attached.channel, phy_info->attached.id,
++ phy_info->attached.phy_id, (unsigned long long)
++ phy_info->attached.sas_address);
++
++ mptsas_parse_device_info(&identify, &phy_info->attached);
++ rphy = sas_end_device_alloc(port);
++ if (!rphy) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, fw_id, __LINE__));
++ return 5; /* non-fatal: an rphy can be added later */
++ }
++
++ rphy->identify = identify;
++ if (sas_rphy_add(rphy)) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, fw_id, __LINE__));
++ sas_rphy_free(rphy);
++ return 6;
+ }
++ mptsas_set_rphy(ioc, phy_info, rphy);
++ return 0;
++}
+
+- /*
+- * Set Min hardware link rate.
+- */
+- switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
+- case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
+- phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+- break;
+- case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
+- phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
+- break;
+- default:
+- break;
+- }
++/**
++ * mptsas_del_end_device - report a deleted end device to sas transport
++ * layer
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @phy_info: decribes attached device
++ *
++ **/
++static void
++mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
++{
++ struct sas_rphy *rphy;
++ struct sas_port *port;
++ struct mptsas_portinfo *port_info;
++ struct mptsas_phyinfo *phy_info_parent;
++ int i;
++ struct scsi_target * starget;
++ char *ds = NULL;
++ u8 fw_id;
++ u64 sas_address;
+
+- /*
+- * Set Min programmed link rate.
+- */
+- switch (phy_info->programmed_link_rate &
+- MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
+- case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
+- phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+- break;
+- case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
+- phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
+- break;
+- default:
+- break;
+- }
++ if (!phy_info)
++ return;
+
+- if (!phy_info->phy) {
++ fw_id = phy_info->attached.id;
++ sas_address = phy_info->attached.sas_address;
+
+- error = sas_phy_add(phy);
+- if (error) {
+- sas_phy_free(phy);
+- goto out;
+- }
+- phy_info->phy = phy;
++ if (!phy_info->port_details) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, fw_id, __LINE__));
++ return;
+ }
+-
+- if (!phy_info->attached.handle ||
+- !phy_info->port_details)
+- goto out;
++ rphy = mptsas_get_rphy(phy_info);
++ if (!rphy) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, fw_id, __LINE__));
++ return;
++ }
++ if (phy_info->attached.device_info &
++ MPI_SAS_DEVICE_INFO_SSP_TARGET)
++ ds = "ssp";
++ if (phy_info->attached.device_info &
++ MPI_SAS_DEVICE_INFO_STP_TARGET)
++ ds = "stp";
++ if (phy_info->attached.device_info &
++ MPI_SAS_DEVICE_INFO_SATA_DEVICE)
++ ds = "sata";
++
++ starget = mptsas_get_starget(phy_info);
++
++ printk(MYIOC_s_INFO_FMT "removing %s device: fw_channel %d,"
++ " fw_id %d, phy %d, sas_addr 0x%llx\n", ioc->name, ds,
++ phy_info->attached.channel, phy_info->attached.id,
++ phy_info->attached.phy_id, (unsigned long long)
++ sas_address);
+
+ port = mptsas_get_port(phy_info);
+- ioc = phy_to_ioc(phy_info->phy);
++ if (!port) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, fw_id, __LINE__));
++ return;
++ }
++ port_info = phy_info->portinfo;
++ phy_info_parent = port_info->phy_info;
++ for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
++ if(!phy_info_parent->phy)
++ continue;
++ if (phy_info_parent->attached.sas_address !=
++ sas_address)
++ continue;
++ dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
++ MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
++ ioc->name, phy_info_parent->phy_id,
++ phy_info_parent->phy);
++ sas_port_delete_phy(port, phy_info_parent->phy);
++ }
++
++ dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
++ "delete port %d, sas_addr (0x%llx)\n", ioc->name,
++ port->port_identifier, (unsigned long long)sas_address);
++ sas_port_delete(port);
++// mptsas_port_delete(ioc, phy_info->port_details);
++}
+
+- if (phy_info->sas_port_add_phy) {
++struct mptsas_phyinfo *
++mptsas_refreshing_device_handles(MPT_ADAPTER *ioc, struct mptsas_devinfo *sas_device)
++{
++ struct mptsas_phyinfo *phy_info;
++ struct mptsas_portinfo *port_info;
++ int i;
+
+- if (!port) {
+- port = sas_port_alloc_num(dev);
+- if (!port) {
+- error = -ENOMEM;
+- goto out;
+- }
+- error = sas_port_add(port);
+- if (error) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- goto out;
+- }
+- mptsas_set_port(ioc, phy_info, port);
+- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "sas_port_alloc: port=%p dev=%p port_id=%d\n",
+- ioc->name, port, dev, port->port_identifier));
+- }
+- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
+- ioc->name, phy_info->phy_id));
+- sas_port_add_phy(port, phy_info->phy);
+- phy_info->sas_port_add_phy = 0;
++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
++ sas_device->sas_address);
++ if (!phy_info)
++ goto out;
++ port_info = phy_info->portinfo;
++ if (!port_info)
++ goto out;
++ mutex_lock(&ioc->sas_topology_mutex);
++ for (i = 0; i < port_info->num_phys; i++) {
++ if(port_info->phy_info[i].attached.sas_address !=
++ sas_device->sas_address)
++ continue;
++ port_info->phy_info[i].attached.channel = sas_device->channel;
++ port_info->phy_info[i].attached.id = sas_device->id;
++ port_info->phy_info[i].attached.sas_address =
++ sas_device->sas_address;
++ port_info->phy_info[i].attached.handle = sas_device->handle;
++ port_info->phy_info[i].attached.handle_parent =
++ sas_device->handle_parent;
++ port_info->phy_info[i].attached.handle_enclosure =
++ sas_device->handle_enclosure;
+ }
++ mutex_unlock(&ioc->sas_topology_mutex);
++ out:
++ return phy_info;
++}
+
+- if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
+-
+- struct sas_rphy *rphy;
+- struct device *parent;
+- struct sas_identify identify;
+
+- parent = dev->parent->parent;
+- /*
+- * Let the hotplug_work thread handle processing
+- * the adding/removing of devices that occur
+- * after start of day.
+- */
+- if (ioc->sas_discovery_runtime &&
+- mptsas_is_end_device(&phy_info->attached))
+- goto out;
++/**
++ * mptsas_hotplug_work - Work queue thread to handle SAS hotplug events
++ *
++ *
++ **/
++static void
++mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
++ struct mptsas_hotplug_event *hot_plug_info)
++{
++ struct mptsas_phyinfo *phy_info;
++ struct scsi_target * starget;
++ struct mptsas_devinfo sas_device;
++ VirtTarget *vtarget;
++ enum device_state state;
++ int i;
+
+- mptsas_parse_device_info(&identify, &phy_info->attached);
+- if (scsi_is_host_device(parent)) {
+- struct mptsas_portinfo *port_info;
+- int i;
++ switch (hot_plug_info->event_type) {
+
+- mutex_lock(&ioc->sas_topology_mutex);
+- port_info = mptsas_get_hba_portinfo(ioc);
+- mutex_unlock(&ioc->sas_topology_mutex);
++ case MPTSAS_ADD_PHYSDISK:
+
+- for (i = 0; i < port_info->num_phys; i++)
+- if (port_info->phy_info[i].identify.sas_address ==
+- identify.sas_address) {
+- sas_port_mark_backlink(port);
+- goto out;
+- }
++ if (!ioc->raid_data.pIocPg2)
++ break;
+
+- } else if (scsi_is_sas_rphy(parent)) {
+- struct sas_rphy *parent_rphy = dev_to_rphy(parent);
+- if (identify.sas_address ==
+- parent_rphy->identify.sas_address) {
+- sas_port_mark_backlink(port);
+- goto out;
++ for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
++ if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
++ hot_plug_info->id) {
++ printk(MYIOC_s_WARN_FMT "firmware bug: unable "
++ "to add hidden disk - target_id matchs "
++ "volume_id\n", ioc->name);
++ mptsas_free_fw_event(ioc, fw_event);
++ return;
+ }
+ }
+
+- switch (identify.device_type) {
+- case SAS_END_DEVICE:
+- rphy = sas_end_device_alloc(port);
+- break;
+- case SAS_EDGE_EXPANDER_DEVICE:
+- case SAS_FANOUT_EXPANDER_DEVICE:
+- rphy = sas_expander_alloc(port, identify.device_type);
++ case MPTSAS_ADD_DEVICE:
++ memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
++ mptsas_sas_device_pg0(ioc, &sas_device,
++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
++ (hot_plug_info->channel << 8) +
++ hot_plug_info->id);
++
++ if (!sas_device.handle)
++ return;
++
++ phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
++ if (!phy_info)
+ break;
+- default:
+- rphy = NULL;
++
++ if (mptsas_get_rphy(phy_info))
+ break;
+- }
+- if (!rphy) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- goto out;
+- }
+
+- rphy->identify = identify;
+- error = sas_rphy_add(rphy);
+- if (error) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- sas_rphy_free(rphy);
+- goto out;
++ state = mptsas_test_unit_ready(ioc, phy_info->attached.channel,
++ phy_info->attached.id, fw_event->retries);
++
++ if (state == DEVICE_RETRY && !ioc->fw_events_off) {
++ mptsas_requeue_fw_event(ioc, fw_event, 1000);
++ return;
+ }
+- mptsas_set_rphy(ioc, phy_info, rphy);
+- }
+
+- out:
+- return error;
+-}
++ if (state == DEVICE_READY)
++ mptsas_add_end_device(ioc, phy_info);
++ break;
+
+-static int
+-mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
+-{
+- struct mptsas_portinfo *port_info, *hba;
+- int error = -ENOMEM, i;
++ case MPTSAS_DEL_DEVICE:
+
+- hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
+- if (! hba)
+- goto out;
++ if (!ioc->disable_hotplug_remove) {
++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
++ hot_plug_info->sas_address);
++ mptsas_del_end_device(ioc, phy_info);
++ }
++ break;
+
+- error = mptsas_sas_io_unit_pg0(ioc, hba);
+- if (error)
+- goto out_free_port_info;
++ case MPTSAS_DEL_PHYSDISK:
+
+- mptsas_sas_io_unit_pg1(ioc);
+- mutex_lock(&ioc->sas_topology_mutex);
+- port_info = mptsas_get_hba_portinfo(ioc);
+- if (!port_info) {
+- port_info = hba;
+- list_add_tail(&port_info->list, &ioc->sas_topology);
+- } else {
+- for (i = 0; i < hba->num_phys; i++) {
+- port_info->phy_info[i].negotiated_link_rate =
+- hba->phy_info[i].negotiated_link_rate;
+- port_info->phy_info[i].handle =
+- hba->phy_info[i].handle;
+- port_info->phy_info[i].port_id =
+- hba->phy_info[i].port_id;
+- }
+- kfree(hba->phy_info);
+- kfree(hba);
+- hba = NULL;
+- }
+- mutex_unlock(&ioc->sas_topology_mutex);
+- for (i = 0; i < port_info->num_phys; i++) {
+- mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
+- (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
+- MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
++ mpt_findImVolumes(ioc);
+
+- mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
+- (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+- MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+- port_info->phy_info[i].handle);
+- port_info->phy_info[i].identify.phy_id =
+- port_info->phy_info[i].phy_id = i;
+- if (port_info->phy_info[i].attached.handle)
+- mptsas_sas_device_pg0(ioc,
+- &port_info->phy_info[i].attached,
+- (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+- MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+- port_info->phy_info[i].attached.handle);
+- }
++ phy_info = mptsas_find_phyinfo_by_phys_disk_num(
++ ioc, hot_plug_info->phys_disk_num, hot_plug_info->channel,
++ hot_plug_info->id);
++ mptsas_del_end_device(ioc, phy_info);
++ break;
+
+- mptsas_setup_wide_ports(ioc, port_info);
++ case MPTSAS_ADD_PHYSDISK_REPROBE:
+
+- for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
+- mptsas_probe_one_phy(&ioc->sh->shost_gendev,
+- &port_info->phy_info[i], ioc->sas_index, 1);
++ if (mptsas_sas_device_pg0(ioc, &sas_device,
++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
++ (hot_plug_info->channel << 8) + hot_plug_info->id)) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, hot_plug_info->id, __LINE__));
++ break;
++ }
+
+- return 0;
++ phy_info = mptsas_find_phyinfo_by_sas_address(
++ ioc, sas_device.sas_address);
+
+- out_free_port_info:
+- kfree(hba);
+- out:
+- return error;
+-}
++ if (!phy_info){
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, hot_plug_info->id, __LINE__));
++ break;
++ }
+
+-static int
+-mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
+-{
+- struct mptsas_portinfo *port_info, *p, *ex;
+- struct device *parent;
+- struct sas_rphy *rphy;
+- int error = -ENOMEM, i, j;
++ starget = mptsas_get_starget(phy_info);
++ if (!starget) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, hot_plug_info->id, __LINE__));
++ break;
++ }
+
+- ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
+- if (!ex)
+- goto out;
++ vtarget = starget->hostdata;
++ if (!vtarget) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, hot_plug_info->id, __LINE__));
++ break;
++ }
+
+- error = mptsas_sas_expander_pg0(ioc, ex,
+- (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
+- MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
+- if (error)
+- goto out_free_port_info;
++ mpt_findImVolumes(ioc);
+
+- *handle = ex->phy_info[0].handle;
++ starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
++ "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
++ ioc->name, hot_plug_info->channel, hot_plug_info->id,
++ hot_plug_info->phys_disk_num, (unsigned long long)
++ sas_device.sas_address);
++
++ vtarget->id = hot_plug_info->phys_disk_num;
++ vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
++ phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
++ mptsas_reprobe_target(starget, 1);
++ break;
+
+- mutex_lock(&ioc->sas_topology_mutex);
+- port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
+- if (!port_info) {
+- port_info = ex;
+- list_add_tail(&port_info->list, &ioc->sas_topology);
+- } else {
+- for (i = 0; i < ex->num_phys; i++) {
+- port_info->phy_info[i].handle =
+- ex->phy_info[i].handle;
+- port_info->phy_info[i].port_id =
+- ex->phy_info[i].port_id;
++ case MPTSAS_DEL_PHYSDISK_REPROBE:
++
++ if (mptsas_sas_device_pg0(ioc, &sas_device,
++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
++ (hot_plug_info->channel << 8) + hot_plug_info->id)) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n",
++ ioc->name, __FUNCTION__,
++ hot_plug_info->id, __LINE__));
++ break;
+ }
+- kfree(ex->phy_info);
+- kfree(ex);
+- ex = NULL;
+- }
+- mutex_unlock(&ioc->sas_topology_mutex);
+
+- for (i = 0; i < port_info->num_phys; i++) {
+- mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
+- (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
+- MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
++ sas_device.sas_address);
++ if (!phy_info) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, hot_plug_info->id, __LINE__));
++ break;
++ }
+
+- if (port_info->phy_info[i].identify.handle) {
+- mptsas_sas_device_pg0(ioc,
+- &port_info->phy_info[i].identify,
+- (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+- MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+- port_info->phy_info[i].identify.handle);
+- port_info->phy_info[i].identify.phy_id =
+- port_info->phy_info[i].phy_id;
++ starget = mptsas_get_starget(phy_info);
++ if (!starget) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, hot_plug_info->id, __LINE__));
++ break;
+ }
+
+- if (port_info->phy_info[i].attached.handle) {
+- mptsas_sas_device_pg0(ioc,
+- &port_info->phy_info[i].attached,
+- (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+- MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+- port_info->phy_info[i].attached.handle);
+- port_info->phy_info[i].attached.phy_id =
+- port_info->phy_info[i].phy_id;
++ vtarget = starget->hostdata;
++ if (!vtarget) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, hot_plug_info->id, __LINE__));
++ break;
+ }
+- }
+
+- parent = &ioc->sh->shost_gendev;
+- for (i = 0; i < port_info->num_phys; i++) {
+- mutex_lock(&ioc->sas_topology_mutex);
+- list_for_each_entry(p, &ioc->sas_topology, list) {
+- for (j = 0; j < p->num_phys; j++) {
+- if (port_info->phy_info[i].identify.handle !=
+- p->phy_info[j].attached.handle)
+- continue;
+- rphy = mptsas_get_rphy(&p->phy_info[j]);
+- parent = &rphy->dev;
+- }
++ if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: fw_id=%d exit at line=%d\n", ioc->name,
++ __FUNCTION__, hot_plug_info->id, __LINE__));
++ break;
+ }
+- mutex_unlock(&ioc->sas_topology_mutex);
+- }
+
+- mptsas_setup_wide_ports(ioc, port_info);
++ mpt_findImVolumes(ioc);
++
++ starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
++ " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
++ ioc->name, hot_plug_info->channel, hot_plug_info->id,
++ hot_plug_info->phys_disk_num, (unsigned long long)
++ sas_device.sas_address);
++
++ vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
++ vtarget->id = hot_plug_info->id;
++ phy_info->attached.phys_disk_num = ~0;
++ mptsas_reprobe_target(starget, 0);
++ mptsas_add_device_component_by_fw(ioc,
++ hot_plug_info->channel, hot_plug_info->id);
++ break;
++
++ case MPTSAS_ADD_RAID:
++
++ mpt_findImVolumes(ioc);
++ printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
++ "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
++ hot_plug_info->id);
++ scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
++ hot_plug_info->id, 0);
++ break;
++
++ case MPTSAS_DEL_RAID:
++
++ mpt_findImVolumes(ioc);
++ printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
++ "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
++ hot_plug_info->id);
++ scsi_remove_device(hot_plug_info->sdev);
++ scsi_device_put(hot_plug_info->sdev);
++ break;
+
+- for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
+- mptsas_probe_one_phy(parent, &port_info->phy_info[i],
+- ioc->sas_index, 0);
++ case MPTSAS_ADD_INACTIVE_VOLUME:
+
+- return 0;
++ mpt_findImVolumes(ioc);
++ mptsas_adding_inactive_raid_components(ioc,
++ hot_plug_info->channel, hot_plug_info->id);
++ break;
+
+- out_free_port_info:
+- if (ex) {
+- kfree(ex->phy_info);
+- kfree(ex);
++ default:
++ break;
+ }
+- out:
+- return error;
++
++ mptsas_free_fw_event(ioc, fw_event);
+ }
+
+-/*
+- * mptsas_delete_expander_phys
++/**
++ * mptsas_send_sas_event
+ *
+ *
+- * This will traverse topology, and remove expanders
+- * that are no longer present
+- */
++ * @ioc
++ * @sas_event_data
++ *
++ **/
+ static void
+-mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
++mptsas_send_sas_event(struct fw_event_work *fw_event)
+ {
+- struct mptsas_portinfo buffer;
+- struct mptsas_portinfo *port_info, *n, *parent;
+- struct mptsas_phyinfo *phy_info;
+- struct sas_port * port;
+- int i;
+- u64 expander_sas_address;
++ MPT_ADAPTER *ioc;
++ struct mptsas_hotplug_event hot_plug_info;
++ EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
++ u32 device_info;
++ u64 sas_address;
+
+- mutex_lock(&ioc->sas_topology_mutex);
+- list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
++ ioc = fw_event->ioc;
++ sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
++ fw_event->event_data;
++ device_info = le32_to_cpu(sas_event_data->DeviceInfo);
+
+- if (port_info->phy_info &&
+- (!(port_info->phy_info[0].identify.device_info &
+- MPI_SAS_DEVICE_INFO_SMP_TARGET)))
+- continue;
++ if ((device_info &
++ (MPI_SAS_DEVICE_INFO_SSP_TARGET |
++ MPI_SAS_DEVICE_INFO_STP_TARGET |
++ MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) {
++ mptsas_free_fw_event(ioc, fw_event);
++ return;
++ }
+
+- if (mptsas_sas_expander_pg0(ioc, &buffer,
+- (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
+- MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
+- port_info->phy_info[0].handle)) {
++ if (sas_event_data->ReasonCode ==
++ MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
++ mptbase_sas_persist_operation(ioc,
++ MPI_SAS_OP_CLEAR_NOT_PRESENT);
++ mptsas_free_fw_event(ioc, fw_event);
++ return;
++ }
+
+- /*
+- * Obtain the port_info instance to the parent port
+- */
+- parent = mptsas_find_portinfo_by_handle(ioc,
+- port_info->phy_info[0].identify.handle_parent);
++ switch (sas_event_data->ReasonCode) {
++ case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
++ case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
++ memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
++ hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
++ hot_plug_info.channel = sas_event_data->Bus;
++ hot_plug_info.id = sas_event_data->TargetID;
++ hot_plug_info.phy_id = sas_event_data->PhyNum;
++ memcpy(&sas_address, &sas_event_data->SASAddress,
++ sizeof(u64));
++ hot_plug_info.sas_address = le64_to_cpu(sas_address);
++ hot_plug_info.device_info = device_info;
++ if (sas_event_data->ReasonCode &
++ MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
++ hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
++ else
++ hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
++ mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
++ break;
++
++ case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
++ mptbase_sas_persist_operation(ioc,
++ MPI_SAS_OP_CLEAR_NOT_PRESENT);
++ mptsas_free_fw_event(ioc, fw_event);
++ break;
+
+- if (!parent)
+- goto next_port;
++ case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
++ /* TODO */
++ case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
++ /* TODO */
++ default:
++ mptsas_free_fw_event(ioc, fw_event);
++ break;
++ }
++}
+
+- expander_sas_address =
+- port_info->phy_info[0].identify.sas_address;
+
+- /*
+- * Delete rphys in the parent that point
+- * to this expander. The transport layer will
+- * cleanup all the children.
+- */
+- phy_info = parent->phy_info;
+- for (i = 0; i < parent->num_phys; i++, phy_info++) {
+- port = mptsas_get_port(phy_info);
+- if (!port)
+- continue;
+- if (phy_info->attached.sas_address !=
+- expander_sas_address)
+- continue;
+- dsaswideprintk(ioc,
+- dev_printk(KERN_DEBUG, &port->dev,
+- MYIOC_s_FMT "delete port (%d)\n", ioc->name,
+- port->port_identifier));
+- sas_port_delete(port);
+- mptsas_port_delete(ioc, phy_info->port_details);
+- }
+- next_port:
+-
+- phy_info = port_info->phy_info;
+- for (i = 0; i < port_info->num_phys; i++, phy_info++)
+- mptsas_port_delete(ioc, phy_info->port_details);
+-
+- list_del(&port_info->list);
+- kfree(port_info->phy_info);
+- kfree(port_info);
++/**
++ * mptsas_send_raid_event
++ *
++ *
++ * @ioc
++ * @raid_event_data
++ *
++ **/
++static void
++mptsas_send_raid_event(struct fw_event_work *fw_event)
++{
++ MPT_ADAPTER *ioc;
++ EVENT_DATA_RAID *raid_event_data;
++ struct mptsas_hotplug_event hot_plug_info;
++ int status;
++ int state;
++ struct scsi_device *sdev = NULL;
++ VirtDevice *vdevice = NULL;
++ RaidPhysDiskPage0_t phys_disk;
++
++ ioc = fw_event->ioc;
++ raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
++ status = le32_to_cpu(raid_event_data->SettingsStatus);
++ state = (status >> 8) & 0xff;
++
++ memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
++ hot_plug_info.id = raid_event_data->VolumeID;
++ hot_plug_info.channel = raid_event_data->VolumeBus;
++ hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
++
++ if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
++ raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
++ raid_event_data->ReasonCode ==
++ MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
++ sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
++ hot_plug_info.id, 0);
++ hot_plug_info.sdev = sdev;
++ if (sdev)
++ vdevice = sdev->hostdata;
++ }
++
++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "Entering %s: "
++ "ReasonCode=%02x\n", ioc->name, __FUNCTION__,
++ raid_event_data->ReasonCode));
++
++ switch (raid_event_data->ReasonCode) {
++ case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
++ hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
++ break;
++ case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
++ hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
++ break;
++ case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
++ switch (state) {
++ case MPI_PD_STATE_ONLINE:
++ case MPI_PD_STATE_NOT_COMPATIBLE:
++ mpt_raid_phys_disk_pg0(ioc,
++ raid_event_data->PhysDiskNum, &phys_disk);
++ hot_plug_info.id = phys_disk.PhysDiskID;
++ hot_plug_info.channel = phys_disk.PhysDiskBus;
++ hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
++ break;
++ case MPI_PD_STATE_FAILED:
++ case MPI_PD_STATE_MISSING:
++ case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
++ case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
++ case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
++ hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
++ break;
++ default:
++ break;
+ }
+- /*
+- * Free this memory allocated from inside
+- * mptsas_sas_expander_pg0
+- */
+- kfree(buffer.phy_info);
++ break;
++ case MPI_EVENT_RAID_RC_VOLUME_DELETED:
++ if (!sdev)
++ break;
++ vdevice->vtarget->deleted = 1; /* block IO */
++ hot_plug_info.event_type = MPTSAS_DEL_RAID;
++ break;
++ case MPI_EVENT_RAID_RC_VOLUME_CREATED:
++ if (sdev) {
++ scsi_device_put(sdev);
++ break;
++ }
++ hot_plug_info.event_type = MPTSAS_ADD_RAID;
++ break;
++ case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
++ if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
++ if (!sdev)
++ break;
++ vdevice->vtarget->deleted = 1; /* block IO */
++ hot_plug_info.event_type = MPTSAS_DEL_RAID;
++ break;
++ }
++ switch (state) {
++ case MPI_RAIDVOL0_STATUS_STATE_FAILED:
++ case MPI_RAIDVOL0_STATUS_STATE_MISSING:
++ if (!sdev)
++ break;
++ vdevice->vtarget->deleted = 1; /* block IO */
++ hot_plug_info.event_type = MPTSAS_DEL_RAID;
++ break;
++ case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
++ case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
++ if (sdev) {
++ scsi_device_put(sdev);
++ break;
++ }
++ hot_plug_info.event_type = MPTSAS_ADD_RAID;
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ break;
+ }
+- mutex_unlock(&ioc->sas_topology_mutex);
++
++ if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
++ mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
++ else
++ mptsas_free_fw_event(ioc, fw_event);
+ }
+
+-/*
+- * Start of day discovery
+- */
+-static void
+-mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
++/**
++ * mptsas_issue_tm - send mptsas internal tm request
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @type
++ * @channel
++ * @id
++ * @lun
++ * @task_context
++ * @timeout
++ *
++ * return:
++ *
++ **/
++static int
++mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, int task_context, ulong timeout,
++ u8 *issue_reset)
+ {
+- u32 handle = 0xFFFF;
+- int i;
++ MPT_FRAME_HDR *mf;
++ SCSITaskMgmt_t *pScsiTm;
++ int retval;
++ unsigned long timeleft;
+
+- mutex_lock(&ioc->sas_discovery_mutex);
+- mptsas_probe_hba_phys(ioc);
+- while (!mptsas_probe_expander_phys(ioc, &handle))
+- ;
+- /*
+- Reporting RAID volumes.
+- */
+- if (!ioc->ir_firmware)
++ *issue_reset = 0;
++ if ((mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc)) == NULL) {
++ retval = -1; /* return failure */
++ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
++ "msg frames!!\n", ioc->name));
+ goto out;
+- if (!ioc->raid_data.pIocPg2)
++ }
++
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
++ "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
++ "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
++ type, timeout, channel, id, (unsigned long long)lun,
++ task_context));
++
++ pScsiTm = (SCSITaskMgmt_t *) mf;
++ memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
++ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
++ pScsiTm->TaskType = type;
++ pScsiTm->MsgFlags = 0;
++ pScsiTm->TargetID = id;
++ pScsiTm->Bus = channel;
++ pScsiTm->ChainOffset = 0;
++ pScsiTm->Reserved = 0;
++ pScsiTm->Reserved1 = 0;
++ pScsiTm->TaskMsgContext = task_context;
++ int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
++
++ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
++ CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
++ retval = 0;
++ mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
++
++ /* Now wait for the command to complete */
++ timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
++ timeout*HZ);
++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ retval = -1; /* return failure */
++ dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
++ mpt_free_msg_frame(ioc, mf);
++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
++ goto out;
++ *issue_reset = 1;
+ goto out;
+- if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
++ }
++
++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
++ retval = -1; /* return failure */
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt request: failed with no reply\n", ioc->name));
+ goto out;
+- for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+- scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
+- ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
+ }
++
+ out:
+- mutex_unlock(&ioc->sas_discovery_mutex);
++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
++ return retval;
+ }
+
+-/*
+- * Work queue thread to handle Runtime discovery
+- * Mere purpose is the hot add/delete of expanders
+- *(Mutex UNLOCKED)
+- */
++/**
++ * mptsas_broadcast_primative_work - Work queue thread to handle
++ * broadcast primitive events
++ * @work: work queue payload containing info describing the event
++ *
++ **/
+ static void
+-__mptsas_discovery_work(MPT_ADAPTER *ioc)
++mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
+ {
+- u32 handle = 0xFFFF;
++ MPT_ADAPTER *ioc = fw_event->ioc;
++ MPT_FRAME_HDR *mf;
++ VirtDevice *vdevice;
++ int ii;
++ struct scsi_cmnd *sc;
++ SCSITaskMgmtReply_t * pScsiTmReply;
++ u8 issue_reset;
++ int task_context;
++ u8 channel, id;
++ int lun;
++ u32 termination_count;
++ u32 query_count;
++
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s - enter\n", ioc->name, __FUNCTION__));
++
++ mutex_lock(&ioc->taskmgmt_cmds.mutex);
++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++ mptsas_requeue_fw_event(ioc, fw_event, 1000);
++ return;
++ }
+
+- ioc->sas_discovery_runtime=1;
+- mptsas_delete_expander_phys(ioc);
+- mptsas_probe_hba_phys(ioc);
+- while (!mptsas_probe_expander_phys(ioc, &handle))
+- ;
+- ioc->sas_discovery_runtime=0;
++ issue_reset = 0;
++ termination_count = 0;
++ query_count = 0;
++ mpt_findImVolumes(ioc);
++ pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
++
++ for (ii = 0; ii < ioc->req_depth; ii++) {
++ sc = mptscsih_get_scsi_lookup(ioc, ii);
++ if (!sc)
++ continue;
++ mf = MPT_INDEX_2_MFPTR(ioc, ii);
++ if (!mf)
++ continue;
++ task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
++ vdevice = sc->device->hostdata;
++ if (!vdevice || !vdevice->vtarget)
++ continue;
++ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
++ continue; /* skip hidden raid components */
++ if (vdevice->vtarget->raidVolume)
++ continue; /* skip hidden raid components */
++ channel = vdevice->vtarget->channel;
++ id = vdevice->vtarget->id;
++ lun = vdevice->lun;
++ if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
++ channel, id, (u64)lun, task_context, 30, &issue_reset))
++ goto out;
++ query_count++;
++ termination_count +=
++ le32_to_cpu(pScsiTmReply->TerminationCount);
++ if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
++ (pScsiTmReply->ResponseCode ==
++ MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
++ pScsiTmReply->ResponseCode ==
++ MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
++ continue;
++ if (mptsas_issue_tm(ioc,
++ MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
++ channel, id, (u64)lun, 0, 30, &issue_reset))
++ goto out;
++ termination_count +=
++ le32_to_cpu(pScsiTmReply->TerminationCount);
++ }
++
++ out:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s - exit, query_count = %d termination_count = %d\n",
++ ioc->name, __FUNCTION__, query_count, termination_count));
++
++ ioc->broadcast_aen_busy = 0;
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++
++ if (issue_reset) {
++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
++ ioc->name, __FUNCTION__);
++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP))
++ mpt_HardResetHandler(ioc, CAN_SLEEP);
++ }
++ mptsas_free_fw_event(ioc, fw_event);
+ }
+
+-/*
+- * Work queue thread to handle Runtime discovery
+- * Mere purpose is the hot add/delete of expanders
+- *(Mutex LOCKED)
+- */
++/**
++ * mptsas_send_ir2_event - handle exposing hidden disk when an inactive raid volume is added
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @ir2_data:
++ *
++ **/
+ static void
+-mptsas_discovery_work(struct work_struct *work)
++mptsas_send_ir2_event(struct fw_event_work *fw_event)
+ {
+- struct mptsas_discovery_event *ev =
+- container_of(work, struct mptsas_discovery_event, work);
+- MPT_ADAPTER *ioc = ev->ioc;
+-
+- mutex_lock(&ioc->sas_discovery_mutex);
+- __mptsas_discovery_work(ioc);
+- mutex_unlock(&ioc->sas_discovery_mutex);
+- kfree(ev);
++ MPT_ADAPTER *ioc;
++ struct mptsas_hotplug_event hot_plug_info;
++ MPI_EVENT_DATA_IR2 * ir2_data;
++ u8 reasonCode;
++ RaidPhysDiskPage0_t phys_disk;
++
++ ioc = fw_event->ioc;
++ ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
++ reasonCode = ir2_data->ReasonCode;
++
++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "Entering %s: "
++ "ReasonCode=%02x\n", ioc->name,__FUNCTION__, reasonCode));
++
++ memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
++ hot_plug_info.id = ir2_data->TargetID;
++ hot_plug_info.channel = ir2_data->Bus;
++ switch (reasonCode) {
++ case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
++ hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
++ break;
++ case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
++ hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
++ hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
++ break;
++ case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
++ hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
++ mpt_raid_phys_disk_pg0(ioc,
++ ir2_data->PhysDiskNum, &phys_disk);
++ hot_plug_info.id = phys_disk.PhysDiskID;
++ hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
++ break;
++ default:
++ mptsas_free_fw_event(ioc, fw_event);
++ return;
++ }
++ mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
+ }
+
+-static struct mptsas_phyinfo *
+-mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
++static void
++mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
+ {
+- struct mptsas_portinfo *port_info;
+- struct mptsas_phyinfo *phy_info = NULL;
+- int i;
++ struct mptsas_portinfo *parent;
++ struct device *parent_dev;
++ struct sas_rphy *rphy;
++ int i;
++ u64 sas_address; /* expander sas address */
++ u32 handle;
+
+- mutex_lock(&ioc->sas_topology_mutex);
+- list_for_each_entry(port_info, &ioc->sas_topology, list) {
+- for (i = 0; i < port_info->num_phys; i++) {
+- if (!mptsas_is_end_device(
+- &port_info->phy_info[i].attached))
+- continue;
+- if (port_info->phy_info[i].attached.sas_address
+- != sas_address)
+- continue;
+- phy_info = &port_info->phy_info[i];
+- break;
+- }
+- }
+- mutex_unlock(&ioc->sas_topology_mutex);
+- return phy_info;
+-}
++ handle = port_info->phy_info[0].handle;
++ sas_address = port_info->phy_info[0].identify.sas_address;
++ for (i = 0; i < port_info->num_phys; i++) {
++ mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
++ (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
++ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
+
+-static struct mptsas_phyinfo *
+-mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
+-{
+- struct mptsas_portinfo *port_info;
+- struct mptsas_phyinfo *phy_info = NULL;
+- int i;
++ mptsas_sas_device_pg0(ioc,
++ &port_info->phy_info[i].identify,
++ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
++ port_info->phy_info[i].identify.handle);
++ port_info->phy_info[i].identify.phy_id =
++ port_info->phy_info[i].phy_id;
+
+- mutex_lock(&ioc->sas_topology_mutex);
+- list_for_each_entry(port_info, &ioc->sas_topology, list) {
+- for (i = 0; i < port_info->num_phys; i++) {
+- if (!mptsas_is_end_device(
+- &port_info->phy_info[i].attached))
+- continue;
+- if (port_info->phy_info[i].attached.id != id)
+- continue;
+- if (port_info->phy_info[i].attached.channel != channel)
+- continue;
+- phy_info = &port_info->phy_info[i];
+- break;
++ if (port_info->phy_info[i].attached.handle) {
++ mptsas_sas_device_pg0(ioc,
++ &port_info->phy_info[i].attached,
++ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
++ port_info->phy_info[i].attached.handle);
++ port_info->phy_info[i].attached.phy_id =
++ port_info->phy_info[i].phy_id;
+ }
+ }
+- mutex_unlock(&ioc->sas_topology_mutex);
+- return phy_info;
+-}
+-
+-static struct mptsas_phyinfo *
+-mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
+-{
+- struct mptsas_portinfo *port_info;
+- struct mptsas_phyinfo *phy_info = NULL;
+- int i;
+
+ mutex_lock(&ioc->sas_topology_mutex);
+- list_for_each_entry(port_info, &ioc->sas_topology, list) {
+- for (i = 0; i < port_info->num_phys; i++) {
+- if (!mptsas_is_end_device(
+- &port_info->phy_info[i].attached))
+- continue;
+- if (port_info->phy_info[i].attached.phys_disk_num == ~0)
+- continue;
+- if (port_info->phy_info[i].attached.phys_disk_num != id)
+- continue;
+- if (port_info->phy_info[i].attached.channel != channel)
+- continue;
+- phy_info = &port_info->phy_info[i];
+- break;
++ parent = mptsas_find_portinfo_by_handle(ioc,
++ port_info->phy_info[0].identify.handle_parent);
++ if (!parent) {
++ mutex_unlock(&ioc->sas_topology_mutex);
++ return;
++ }
++ for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
++ i++) {
++ if (parent->phy_info[i].attached.sas_address == sas_address) {
++ rphy = mptsas_get_rphy(&parent->phy_info[i]);
++ parent_dev = &rphy->dev;
+ }
+ }
+ mutex_unlock(&ioc->sas_topology_mutex);
+- return phy_info;
++
++ mptsas_setup_wide_ports(ioc, port_info);
++ for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
++ mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
++ ioc->sas_index, 0);
+ }
+
+-/*
+- * Work queue thread to clear the persitency table
+- */
+ static void
+-mptsas_persist_clear_table(struct work_struct *work)
++mptsas_expander_event_add(MPT_ADAPTER *ioc,
++ MpiEventDataSasExpanderStatusChange_t* expander_data)
+ {
+- MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
++ struct mptsas_portinfo *port_info;
++ int i;
++ __le64 sas_address;
+
+- mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
+-}
++ port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
++ if (!port_info)
++ BUG();
++ port_info->num_phys = (expander_data->NumPhys) ?
++ expander_data->NumPhys : 1;
++ port_info->phy_info = kcalloc(port_info->num_phys,
++ sizeof(struct mptsas_phyinfo),GFP_KERNEL);
++ if (!port_info->phy_info)
++ BUG();
++ memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
++ for (i = 0; i < port_info->num_phys; i++) {
++ port_info->phy_info[i].portinfo = port_info;
++ port_info->phy_info[i].handle =
++ le16_to_cpu(expander_data->DevHandle);
++ port_info->phy_info[i].identify.sas_address =
++ le64_to_cpu(sas_address);
++ port_info->phy_info[i].identify.handle_parent =
++ le16_to_cpu(expander_data->ParentDevHandle);
++ }
+
+-static void
+-mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
+-{
+- int rc;
++ mutex_lock(&ioc->sas_topology_mutex);
++ list_add_tail(&port_info->list, &ioc->sas_topology);
++ mutex_unlock(&ioc->sas_topology_mutex);
+
+- sdev->no_uld_attach = data ? 1 : 0;
+- rc = scsi_device_reprobe(sdev);
+-}
++ printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
++ "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
++ (unsigned long long)sas_address);
+
+-static void
+-mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
+-{
+- starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
+- mptsas_reprobe_lun);
++ mptsas_expander_refresh(ioc, port_info);
+ }
+
++/**
++ * mptsas_delete_expander_siblings - remove siblings attached to expander
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @parent: the parent port_info object
++ * @expander: the expander port_info object
++ **/
+ static void
+-mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
++mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
++ *parent, struct mptsas_portinfo *expander)
+ {
+- CONFIGPARMS cfg;
+- ConfigPageHeader_t hdr;
+- dma_addr_t dma_handle;
+- pRaidVolumePage0_t buffer = NULL;
+- RaidPhysDiskPage0_t phys_disk;
+- int i;
+- struct mptsas_hotplug_event *ev;
++ struct mptsas_phyinfo *phy_info;
++ struct mptsas_portinfo *port_info;
++ struct sas_rphy *rphy;
++ int i;
+
+- memset(&cfg, 0 , sizeof(CONFIGPARMS));
+- memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+- hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+- cfg.pageAddr = (channel << 8) + id;
+- cfg.cfghdr.hdr = &hdr;
+- cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
++ phy_info = expander->phy_info;
++ for (i = 0; i < expander->num_phys; i++, phy_info++) {
++ if (!(rphy = mptsas_get_rphy(phy_info)))
++ continue;
++ if (rphy->identify.device_type == SAS_END_DEVICE)
++ mptsas_del_end_device(ioc, phy_info);
++ }
+
+- if (mpt_config(ioc, &cfg) != 0)
+- goto out;
++ phy_info = expander->phy_info;
++ for (i = 0; i < expander->num_phys; i++, phy_info++) {
++ if (!(rphy = mptsas_get_rphy(phy_info)))
++ continue;
++ if (rphy->identify.device_type ==
++ MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
++ rphy->identify.device_type ==
++ MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
++ port_info = mptsas_find_portinfo_by_sas_address(ioc,
++ rphy->identify.sas_address);
++ if (!port_info)
++ continue;
++ if (port_info == parent) /* backlink rphy */
++ continue;
++ mptsas_expander_delete(ioc, port_info);
++ }
++ }
++}
+
+- if (!hdr.PageLength)
+- goto out;
+
+- buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+- &dma_handle);
++/**
++ * mptsas_expander_delete - remove this expander
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @port_info: expander port_info struct
++ *
++ **/
+
+- if (!buffer)
+- goto out;
++static void
++mptsas_expander_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
++{
+
+- cfg.physAddr = dma_handle;
+- cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
++ struct mptsas_portinfo *parent;
++ int i;
++ u64 expander_sas_address;
++ struct mptsas_phyinfo *phy_info;
++ struct mptsas_portinfo buffer;
++ struct mptsas_portinfo_details * port_details;
++ struct sas_port * port;
+
+- if (mpt_config(ioc, &cfg) != 0)
+- goto out;
++ if (!port_info)
++ return;
+
+- if (!(buffer->VolumeStatus.Flags &
+- MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
+- goto out;
++ /* see if expander is still there before deleting */
++ mptsas_sas_expander_pg0(ioc, &buffer,
++ (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
++ MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
++ port_info->phy_info[0].identify.handle);
+
+- if (!buffer->NumPhysDisks)
+- goto out;
++ if (buffer.num_phys) {
++ kfree(buffer.phy_info);
++ return;
++ }
+
+- for (i = 0; i < buffer->NumPhysDisks; i++) {
+
+- if (mpt_raid_phys_disk_pg0(ioc,
+- buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
+- continue;
++ /*
++ * Obtain the port_info instance to the parent port
++ */
++ port_details = NULL;
++ expander_sas_address =
++ port_info->phy_info[0].identify.sas_address;
++ parent = mptsas_find_portinfo_by_handle(ioc,
++ port_info->phy_info[0].identify.handle_parent);
++ mptsas_delete_expander_siblings(ioc, parent, port_info);
++ if (!parent)
++ goto out;
+
+- ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+- if (!ev) {
+- printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
+- goto out;
++ /*
++ * Delete rphys in the parent that point
++ * to this expander.
++ */
++ phy_info = parent->phy_info;
++ port = NULL;
++ for (i = 0; i < parent->num_phys; i++, phy_info++) {
++ if(!phy_info->phy)
++ continue;
++ if (phy_info->attached.sas_address !=
++ expander_sas_address)
++ continue;
++ if (!port) {
++ port = mptsas_get_port(phy_info);
++ port_details = phy_info->port_details;
+ }
+-
+- INIT_WORK(&ev->work, mptsas_hotplug_work);
+- ev->ioc = ioc;
+- ev->id = phys_disk.PhysDiskID;
+- ev->channel = phys_disk.PhysDiskBus;
+- ev->phys_disk_num_valid = 1;
+- ev->phys_disk_num = phys_disk.PhysDiskNum;
+- ev->event_type = MPTSAS_ADD_DEVICE;
+- schedule_work(&ev->work);
++ dev_printk(KERN_DEBUG, &phy_info->phy->dev,
++ MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
++ phy_info->phy_id, phy_info->phy);
++ sas_port_delete_phy(port, phy_info->phy);
++ }
++ if (port) {
++ dev_printk(KERN_DEBUG, &port->dev,
++ MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
++ ioc->name, port->port_identifier,
++ (unsigned long long)expander_sas_address);
++ sas_port_delete(port);
++ mptsas_port_delete(ioc, port_details);
+ }
+-
+ out:
+- if (buffer)
+- pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+- dma_handle);
++
++ printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
++ "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
++ (unsigned long long)expander_sas_address);
++
++ /*
++ * free link
++ */
++ list_del(&port_info->list);
++ kfree(port_info->phy_info);
++ kfree(port_info);
+ }
+-/*
+- * Work queue thread to handle SAS hotplug events
++
++
++/**
++ * mptsas_send_expander_event - expanders events
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @expander_data: event data
++ *
++ *
++ * This function handles adding, removing, and refreshing
++ * device handles within the expander objects.
+ */
+ static void
+-mptsas_hotplug_work(struct work_struct *work)
++mptsas_send_expander_event(struct fw_event_work *fw_event)
+ {
+- struct mptsas_hotplug_event *ev =
+- container_of(work, struct mptsas_hotplug_event, work);
++ MPT_ADAPTER *ioc;
++ MpiEventDataSasExpanderStatusChange_t* expander_data;
++ struct mptsas_portinfo *port_info;
++ __le64 sas_address;
++ int i;
+
+- MPT_ADAPTER *ioc = ev->ioc;
+- struct mptsas_phyinfo *phy_info;
+- struct sas_rphy *rphy;
+- struct sas_port *port;
+- struct scsi_device *sdev;
+- struct scsi_target * starget;
+- struct sas_identify identify;
+- char *ds = NULL;
+- struct mptsas_devinfo sas_device;
+- VirtTarget *vtarget;
+- VirtDevice *vdevice;
++ ioc = fw_event->ioc;
++ expander_data = (MpiEventDataSasExpanderStatusChange_t *)
++ fw_event->event_data;
++ memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
++ port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
++
++ if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
++ if (port_info) {
++ for (i = 0; i < port_info->num_phys; i++) {
++ port_info->phy_info[i].portinfo = port_info;
++ port_info->phy_info[i].handle =
++ le16_to_cpu(expander_data->DevHandle);
++ port_info->phy_info[i].identify.sas_address =
++ le64_to_cpu(sas_address);
++ port_info->phy_info[i].identify.handle_parent =
++ le16_to_cpu(expander_data->ParentDevHandle);
++ }
++ mptsas_expander_refresh(ioc, port_info);
++ } else if (!port_info && expander_data->NumPhys)
++ mptsas_expander_event_add(ioc, expander_data);
++ } else if (expander_data->ReasonCode ==
++ MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
++ mptsas_expander_delete(ioc, port_info);
+
+- mutex_lock(&ioc->sas_discovery_mutex);
+- switch (ev->event_type) {
+- case MPTSAS_DEL_DEVICE:
++ mptsas_free_fw_event(ioc, fw_event);
++}
+
+- phy_info = NULL;
+- if (ev->phys_disk_num_valid) {
+- if (ev->hidden_raid_component){
+- if (mptsas_sas_device_pg0(ioc, &sas_device,
+- (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+- MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+- (ev->channel << 8) + ev->id)) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- break;
+- }
+- phy_info = mptsas_find_phyinfo_by_sas_address(
+- ioc, sas_device.sas_address);
+- }else
+- phy_info = mptsas_find_phyinfo_by_phys_disk_num(
+- ioc, ev->channel, ev->phys_disk_num);
+- }
+
+- if (!phy_info)
+- phy_info = mptsas_find_phyinfo_by_target(ioc,
+- ev->channel, ev->id);
++/**
++ * mptsas_expander_add -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @handle:
++ *
++ */
++struct mptsas_portinfo *
++mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
++{
++ struct mptsas_portinfo buffer, *port_info;
++ int i;
+
+- /*
+- * Sanity checks, for non-existing phys and remote rphys.
+- */
+- if (!phy_info){
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- break;
+- }
+- if (!phy_info->port_details) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- break;
+- }
+- rphy = mptsas_get_rphy(phy_info);
+- if (!rphy) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- break;
+- }
++ if ((mptsas_sas_expander_pg0(ioc, &buffer,
++ (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
++ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
++ return NULL;
+
+- port = mptsas_get_port(phy_info);
+- if (!port) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- break;
+- }
++ port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
++ if (!port_info) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: exit at line=%d\n", ioc->name,
++ __FUNCTION__, __LINE__));
++ return NULL;
++ }
++ port_info->num_phys = buffer.num_phys;
++ port_info->phy_info = buffer.phy_info;
++ for (i = 0; i < port_info->num_phys; i++)
++ port_info->phy_info[i].portinfo = port_info;
++ mutex_lock(&ioc->sas_topology_mutex);
++ list_add_tail(&port_info->list, &ioc->sas_topology);
++ mutex_unlock(&ioc->sas_topology_mutex);
++ printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
++ "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
++ (unsigned long long)buffer.phy_info[0].identify.sas_address);
++ mptsas_expander_refresh(ioc, port_info);
++ return port_info;
++}
+
+- starget = mptsas_get_starget(phy_info);
+- if (starget) {
+- vtarget = starget->hostdata;
++static void
++mptsas_send_link_status_event(struct fw_event_work *fw_event)
++{
++ MPT_ADAPTER *ioc;
++ MpiEventDataSasPhyLinkStatus_t *link_data;
++ struct mptsas_portinfo *port_info;
++ struct mptsas_phyinfo *phy_info = NULL;
++ __le64 sas_address;
++ u8 phy_num;
++ u8 link_rate;
+
+- if (!vtarget) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- break;
+- }
++ ioc = fw_event->ioc;
++ link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
+
+- /*
+- * Handling RAID components
+- */
+- if (ev->phys_disk_num_valid &&
+- ev->hidden_raid_component) {
+- printk(MYIOC_s_INFO_FMT
+- "RAID Hidding: channel=%d, id=%d, "
+- "physdsk %d \n", ioc->name, ev->channel,
+- ev->id, ev->phys_disk_num);
+- vtarget->id = ev->phys_disk_num;
+- vtarget->tflags |=
+- MPT_TARGET_FLAGS_RAID_COMPONENT;
+- mptsas_reprobe_target(starget, 1);
+- phy_info->attached.phys_disk_num =
+- ev->phys_disk_num;
+- break;
++ memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
++ sas_address = le64_to_cpu(sas_address);
++ link_rate = link_data->LinkRates >> 4;
++ phy_num = link_data->PhyNum;
++
++ port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
++ if (port_info) {
++ phy_info = &port_info->phy_info[phy_num];
++ if (phy_info)
++ phy_info->negotiated_link_rate = link_rate;
++ }
++
++ if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
++ link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
++
++ if (!port_info) {
++ if (ioc->old_sas_discovery_protocal) {
++ port_info = mptsas_expander_add(ioc,
++ le16_to_cpu(link_data->DevHandle));
++ if (port_info)
++ goto out;
+ }
++ goto out;
+ }
++ if (port_info == ioc->hba_port_info)
++ mptsas_probe_hba_phys(ioc);
++ else
++ mptsas_expander_refresh(ioc, port_info);
++ } else if (phy_info && phy_info->phy) {
++ if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
++ phy_info->phy->negotiated_linkrate =
++ SAS_PHY_DISABLED;
++ else if (link_rate ==
++ MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
++ phy_info->phy->negotiated_linkrate =
++ SAS_LINK_RATE_FAILED;
++ else
++ phy_info->phy->negotiated_linkrate =
++ SAS_LINK_RATE_UNKNOWN;
++ }
++ out:
++ mptsas_free_fw_event(ioc, fw_event);
++}
+
+- if (phy_info->attached.device_info &
+- MPI_SAS_DEVICE_INFO_SSP_TARGET)
+- ds = "ssp";
+- if (phy_info->attached.device_info &
+- MPI_SAS_DEVICE_INFO_STP_TARGET)
+- ds = "stp";
+- if (phy_info->attached.device_info &
+- MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+- ds = "sata";
+-
+- printk(MYIOC_s_INFO_FMT
+- "removing %s device, channel %d, id %d, phy %d\n",
+- ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
+- dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
+- "delete port (%d)\n", ioc->name, port->port_identifier);
+- sas_port_delete(port);
+- mptsas_port_delete(ioc, phy_info->port_details);
+- break;
+- case MPTSAS_ADD_DEVICE:
+-
+- if (ev->phys_disk_num_valid)
+- mpt_findImVolumes(ioc);
+
+- /*
+- * Refresh sas device pg0 data
+- */
+- if (mptsas_sas_device_pg0(ioc, &sas_device,
+- (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+- MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+- (ev->channel << 8) + ev->id)) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- break;
++static void
++mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
++{
++ MPT_ADAPTER *ioc;
++ EventDataQueueFull_t *qfull_data;
++ struct sas_device_info *sas_info;
++ struct scsi_device *sdev;
++ int depth;
++ int id = -1;
++ int channel = -1;
++ int fw_id, fw_channel;
++ u16 current_depth;
++
++
++ ioc = fw_event->ioc;
++ qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
++ fw_id = qfull_data->TargetID;
++ fw_channel = qfull_data->Bus;
++ current_depth = le16_to_cpu(qfull_data->CurrentDepth);
++
++ /* if hidden raid component, look for the volume id */
++ down(&ioc->sas_device_info_mutex);
++ if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
++ list_for_each_entry(sas_info, &ioc->sas_device_info_list,
++ list) {
++ if (sas_info->is_cached ||
++ sas_info->is_logical_volume)
++ continue;
++ if (sas_info->is_hidden_raid_component &&
++ (sas_info->fw.channel == fw_channel &&
++ sas_info->fw.id == fw_id)) {
++ id = sas_info->volume_id;
++ channel = MPTSAS_RAID_CHANNEL;
++ goto out;
++ }
+ }
+-
+- __mptsas_discovery_work(ioc);
+-
+- phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+- sas_device.sas_address);
+-
+- if (!phy_info || !phy_info->port_details) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- break;
++ } else {
++ list_for_each_entry(sas_info, &ioc->sas_device_info_list,
++ list) {
++ if (sas_info->is_cached ||
++ sas_info->is_hidden_raid_component ||
++ sas_info->is_logical_volume)
++ continue;
++ if (sas_info->fw.channel == fw_channel &&
++ sas_info->fw.id == fw_id) {
++ id = sas_info->os.id;
++ channel = sas_info->os.channel;
++ goto out;
++ }
+ }
+
+- starget = mptsas_get_starget(phy_info);
+- if (starget && (!ev->hidden_raid_component)){
+-
+- vtarget = starget->hostdata;
++ }
+
+- if (!vtarget) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- break;
+- }
+- /*
+- * Handling RAID components
+- */
+- if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
+- printk(MYIOC_s_INFO_FMT
+- "RAID Exposing: channel=%d, id=%d, "
+- "physdsk %d \n", ioc->name, ev->channel,
+- ev->id, ev->phys_disk_num);
+- vtarget->tflags &=
+- ~MPT_TARGET_FLAGS_RAID_COMPONENT;
+- vtarget->id = ev->id;
+- mptsas_reprobe_target(starget, 0);
+- phy_info->attached.phys_disk_num = ~0;
++ out:
++ up(&ioc->sas_device_info_mutex);
++
++ if (id != -1) {
++ shost_for_each_device(sdev, ioc->sh) {
++ if (sdev->id == id && sdev->channel == channel) {
++ if (current_depth > sdev->queue_depth) {
++ sdev_printk(KERN_INFO, sdev,
++ "strange observation, the queue "
++ "depth is (%d) meanwhile fw queue "
++ "depth (%d)\n", sdev->queue_depth,
++ current_depth);
++ continue;
++ }
++ depth = scsi_track_queue_full(sdev,
++ current_depth - 1);
++ if (depth > 0)
++ sdev_printk(KERN_INFO, sdev,
++ "Queue depth reduced to (%d)\n",
++ depth);
++ else if (depth < 0)
++ sdev_printk(KERN_INFO, sdev,
++ "Tagged Command Queueing is being "
++ "disabled\n");
++ else if (depth == 0)
++ sdev_printk(KERN_INFO, sdev,
++ "Queue depth not changed yet\n");
+ }
+- break;
+ }
++ }
+
+- if (mptsas_get_rphy(phy_info)) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- if (ev->channel) printk("%d\n", __LINE__);
+- break;
+- }
++ mptsas_free_fw_event(ioc, fw_event);
++}
+
+- port = mptsas_get_port(phy_info);
+- if (!port) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- break;
+- }
+- memcpy(&phy_info->attached, &sas_device,
+- sizeof(struct mptsas_devinfo));
++/**
++ * mptsas_firmware_event_work - work thread for processing fw events
++ * @work: work queue payload containing info describing the event
++ * Context: user
++ *
++ */
++static void
++mptsas_firmware_event_work(struct work_struct *work)
++{
++ struct fw_event_work *fw_event =
++ container_of(work, struct fw_event_work, work.work);
++ MPT_ADAPTER *ioc = fw_event->ioc;
++
++ /* special rescan topology handling */
++ if (fw_event->event == -1) {
++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: rescan after "
++ "reset\n", ioc->name,__FUNCTION__));
++ mptsas_not_responding_devices(ioc);
++ mptsas_scan_sas_topology(ioc);
++ mptsas_free_fw_event(ioc, fw_event);
++ return;
++ }
+
+- if (phy_info->attached.device_info &
+- MPI_SAS_DEVICE_INFO_SSP_TARGET)
+- ds = "ssp";
+- if (phy_info->attached.device_info &
+- MPI_SAS_DEVICE_INFO_STP_TARGET)
+- ds = "stp";
+- if (phy_info->attached.device_info &
+- MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+- ds = "sata";
+-
+- printk(MYIOC_s_INFO_FMT
+- "attaching %s device, channel %d, id %d, phy %d\n",
+- ioc->name, ds, ev->channel, ev->id, ev->phy_id);
++ /* events handling turned off during host reset */
++ if (ioc->fw_events_off) {
++ mptsas_free_fw_event(ioc, fw_event);
++ return;
++ }
+
+- mptsas_parse_device_info(&identify, &phy_info->attached);
+- rphy = sas_end_device_alloc(port);
+- if (!rphy) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- break; /* non-fatal: an rphy can be added later */
+- }
++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: fw_event=(0x%p), "
++ "event = (0x%02x)\n", ioc->name,__FUNCTION__, fw_event,
++ (fw_event->event & 0xFF)));
+
+- rphy->identify = identify;
+- if (sas_rphy_add(rphy)) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+- "%s: exit at line=%d\n", ioc->name,
+- __func__, __LINE__));
+- sas_rphy_free(rphy);
+- break;
+- }
+- mptsas_set_rphy(ioc, phy_info, rphy);
++ switch (fw_event->event) {
++ case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
++ mptsas_send_sas_event(fw_event);
+ break;
+- case MPTSAS_ADD_RAID:
+- sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
+- ev->id, 0);
+- if (sdev) {
+- scsi_device_put(sdev);
+- break;
+- }
+- printk(MYIOC_s_INFO_FMT
+- "attaching raid volume, channel %d, id %d\n",
+- ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
+- scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
+- mpt_findImVolumes(ioc);
++ case MPI_EVENT_INTEGRATED_RAID:
++ mptsas_send_raid_event(fw_event);
+ break;
+- case MPTSAS_DEL_RAID:
+- sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
+- ev->id, 0);
+- if (!sdev)
+- break;
+- printk(MYIOC_s_INFO_FMT
+- "removing raid volume, channel %d, id %d\n",
+- ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
+- vdevice = sdev->hostdata;
+- scsi_remove_device(sdev);
+- scsi_device_put(sdev);
+- mpt_findImVolumes(ioc);
++ case MPI_EVENT_IR2:
++ mptsas_send_ir2_event(fw_event);
+ break;
+- case MPTSAS_ADD_INACTIVE_VOLUME:
+- mptsas_adding_inactive_raid_components(ioc,
+- ev->channel, ev->id);
++ case MPI_EVENT_PERSISTENT_TABLE_FULL:
++ mptbase_sas_persist_operation(ioc,
++ MPI_SAS_OP_CLEAR_NOT_PRESENT);
++ mptsas_free_fw_event(ioc, fw_event);
+ break;
+- case MPTSAS_IGNORE_EVENT:
+- default:
++ case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
++ mptsas_broadcast_primative_work(fw_event);
++ break;
++ case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
++ mptsas_send_expander_event(fw_event);
++ break;
++ case MPI_EVENT_SAS_PHY_LINK_STATUS:
++ mptsas_send_link_status_event(fw_event);
++ break;
++ case MPI_EVENT_QUEUE_FULL:
++ mptsas_handle_queue_full_event(fw_event);
+ break;
+ }
+-
+- mutex_unlock(&ioc->sas_discovery_mutex);
+- kfree(ev);
+ }
+
+-static void
+-mptsas_send_sas_event(MPT_ADAPTER *ioc,
+- EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
+-{
+- struct mptsas_hotplug_event *ev;
+- u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
+- __le64 sas_address;
+
+- if ((device_info &
+- (MPI_SAS_DEVICE_INFO_SSP_TARGET |
+- MPI_SAS_DEVICE_INFO_STP_TARGET |
+- MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
+- return;
++/**
++ * mptsas_event_process -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @reply:
++ *
++ **/
++static int
++mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
++{
++ u32 event = le32_to_cpu(reply->Event);
++ int sz, event_data_sz;
++ struct fw_event_work *fw_event;
++ unsigned long delay;
+
+- switch (sas_event_data->ReasonCode) {
+- case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
++ /* events turned off due to host reset or driver unloading */
++ if (ioc->fw_events_off)
++ return 0;
+
+- mptsas_target_reset_queue(ioc, sas_event_data);
++ delay = msecs_to_jiffies(1);
++ switch (event) {
++ case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
++ {
++ EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
++ (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
++ if (broadcast_event_data->Primitive !=
++ MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
++ return 0;
++ if (ioc->broadcast_aen_busy)
++ return 0;
++ ioc->broadcast_aen_busy = 1;
+ break;
++ }
++ case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
++ {
++ EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
++ (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
+
+- case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
+- ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+- if (!ev) {
+- printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
+- break;
++ if (sas_event_data->ReasonCode ==
++ MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
++ mptsas_target_reset_queue(ioc, sas_event_data);
++ return 0;
+ }
++ break;
++ }
++ case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
++ {
++ MpiEventDataSasExpanderStatusChange_t *expander_data =
++ (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
+
+- INIT_WORK(&ev->work, mptsas_hotplug_work);
+- ev->ioc = ioc;
+- ev->handle = le16_to_cpu(sas_event_data->DevHandle);
+- ev->parent_handle =
+- le16_to_cpu(sas_event_data->ParentDevHandle);
+- ev->channel = sas_event_data->Bus;
+- ev->id = sas_event_data->TargetID;
+- ev->phy_id = sas_event_data->PhyNum;
+- memcpy(&sas_address, &sas_event_data->SASAddress,
+- sizeof(__le64));
+- ev->sas_address = le64_to_cpu(sas_address);
+- ev->device_info = device_info;
++ if (ioc->old_sas_discovery_protocal)
++ return 0;
+
+- if (sas_event_data->ReasonCode &
+- MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
+- ev->event_type = MPTSAS_ADD_DEVICE;
+- else
+- ev->event_type = MPTSAS_DEL_DEVICE;
+- schedule_work(&ev->work);
++ if (expander_data->ReasonCode ==
++ MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
++ ioc->device_missing_delay)
++ delay = HZ * ioc->device_missing_delay;
+ break;
+- case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
+- /*
+- * Persistent table is full.
+- */
+- INIT_WORK(&ioc->sas_persist_task,
+- mptsas_persist_clear_table);
+- schedule_work(&ioc->sas_persist_task);
++ }
++ case MPI_EVENT_SAS_DISCOVERY:
++ {
++ u32 discovery_status;
++ EventDataSasDiscovery_t *discovery_data =
++ (EventDataSasDiscovery_t *)reply->Data;
++
++ discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
++ ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
++ if (ioc->old_sas_discovery_protocal && !discovery_status)
++ mptsas_queue_rescan(ioc);
++ return 0;
++ }
++ case MPI_EVENT_INTEGRATED_RAID:
++ case MPI_EVENT_PERSISTENT_TABLE_FULL:
++ case MPI_EVENT_IR2:
++ case MPI_EVENT_SAS_PHY_LINK_STATUS:
++ case MPI_EVENT_QUEUE_FULL:
+ break;
+- /*
+- * TODO, handle other events
+- */
+- case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
+- case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
+- case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
+- case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
+- case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
+- case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
+- case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
+ default:
+- break;
++ return 0;
+ }
++
++ event_data_sz = ((reply->MsgLength * 4) -
++ offsetof(EventNotificationReply_t, Data));
++ sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
++ fw_event = kzalloc(sz, GFP_ATOMIC);
++ if (!fw_event) {
++ printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
++ __FUNCTION__, __LINE__);
++ return 0;
++ }
++ memcpy(fw_event->event_data, reply->Data, event_data_sz);
++ fw_event->event = event;
++ fw_event->ioc = ioc;
++ mptsas_add_fw_event(ioc, fw_event, delay);
++ return 0;
+ }
+-static void
+-mptsas_send_raid_event(MPT_ADAPTER *ioc,
+- EVENT_DATA_RAID *raid_event_data)
++
++
++/* Delete a volume when no longer listed in ioc pg2
++ */
++static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
+ {
+- struct mptsas_hotplug_event *ev;
+- int status = le32_to_cpu(raid_event_data->SettingsStatus);
+- int state = (status >> 8) & 0xff;
++ struct scsi_device *sdev;
++ int i;
+
+- if (ioc->bus_type != SAS)
++ sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
++ if (!sdev)
+ return;
++ if (!ioc->raid_data.pIocPg2)
++ goto out;
++ if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
++ goto out;
++ for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
++ if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
++ goto release_sdev;
++ out:
++ printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
++ "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,id);
++ scsi_remove_device(sdev);
++ release_sdev:
++ scsi_device_put(sdev);
++}
++
++static void
++mptsas_not_responding_devices(MPT_ADAPTER *ioc)
++{
++ struct mptsas_portinfo buffer, *port_info;
++ struct sas_device_info *sas_info;
++ struct mptsas_devinfo sas_device;
++ u32 handle;
++ VirtTarget *vtarget = NULL;
++ struct mptsas_phyinfo *phy_info;
++ u8 found_expander;
+
+- ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+- if (!ev) {
+- printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
++ if (ioc->disable_hotplug_remove)
+ return;
++
++ mpt_findImVolumes(ioc);
++
++ /* devices, logical volumes */
++ redo_device_scan:
++ list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
++ if (sas_info->is_cached)
++ continue;
++ if (!sas_info->is_logical_volume) {
++ sas_device.handle = 0;
++ mptsas_sas_device_pg0(ioc, &sas_device,
++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
++ (sas_info->fw.channel << 8) +
++ sas_info->fw.id);
++ if (sas_device.handle)
++ continue;
++ /* delete device */
++ if ((vtarget = mptsas_find_vtarget(ioc,
++ sas_info->fw.channel,
++ sas_info->fw.id)))
++ vtarget->deleted = 1;
++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
++ sas_info->sas_address);
++ if (phy_info) {
++ mptsas_del_end_device(ioc, phy_info);
++ goto redo_device_scan;
++ }
++ } else
++ mptsas_volume_delete(ioc, sas_info->fw.id);
+ }
+
+- INIT_WORK(&ev->work, mptsas_hotplug_work);
+- ev->ioc = ioc;
+- ev->id = raid_event_data->VolumeID;
+- ev->channel = raid_event_data->VolumeBus;
+- ev->event_type = MPTSAS_IGNORE_EVENT;
++ /* expanders */
++ redo_expander_scan:
++ list_for_each_entry(port_info, &ioc->sas_topology, list) {
+
+- switch (raid_event_data->ReasonCode) {
+- case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
+- ev->phys_disk_num_valid = 1;
+- ev->phys_disk_num = raid_event_data->PhysDiskNum;
+- ev->event_type = MPTSAS_ADD_DEVICE;
+- break;
+- case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
+- ev->phys_disk_num_valid = 1;
+- ev->phys_disk_num = raid_event_data->PhysDiskNum;
+- ev->hidden_raid_component = 1;
+- ev->event_type = MPTSAS_DEL_DEVICE;
+- break;
+- case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
+- switch (state) {
+- case MPI_PD_STATE_ONLINE:
+- case MPI_PD_STATE_NOT_COMPATIBLE:
+- ev->phys_disk_num_valid = 1;
+- ev->phys_disk_num = raid_event_data->PhysDiskNum;
+- ev->hidden_raid_component = 1;
+- ev->event_type = MPTSAS_ADD_DEVICE;
+- break;
+- case MPI_PD_STATE_MISSING:
+- case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
+- case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
+- case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
+- ev->phys_disk_num_valid = 1;
+- ev->phys_disk_num = raid_event_data->PhysDiskNum;
+- ev->event_type = MPTSAS_DEL_DEVICE;
+- break;
+- default:
+- break;
++ if (port_info->phy_info &&
++ (!(port_info->phy_info[0].identify.device_info &
++ MPI_SAS_DEVICE_INFO_SMP_TARGET)))
++ continue;
++ found_expander = 0;
++ handle = 0xFFFF;
++ while (!mptsas_sas_expander_pg0(ioc, &buffer,
++ (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
++ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
++ !found_expander) {
++
++ handle = buffer.phy_info[0].handle;
++ if (buffer.phy_info[0].identify.sas_address ==
++ port_info->phy_info[0].identify.sas_address) {
++ found_expander = 1;
++ }
++ kfree(buffer.phy_info);
+ }
+- break;
+- case MPI_EVENT_RAID_RC_VOLUME_DELETED:
+- ev->event_type = MPTSAS_DEL_RAID;
+- break;
+- case MPI_EVENT_RAID_RC_VOLUME_CREATED:
+- ev->event_type = MPTSAS_ADD_RAID;
+- break;
+- case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
+- switch (state) {
+- case MPI_RAIDVOL0_STATUS_STATE_FAILED:
+- case MPI_RAIDVOL0_STATUS_STATE_MISSING:
+- ev->event_type = MPTSAS_DEL_RAID;
+- break;
+- case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
+- case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
+- ev->event_type = MPTSAS_ADD_RAID;
+- break;
+- default:
+- break;
++
++ if (!found_expander) {
++ mptsas_expander_delete(ioc, port_info);
++ goto redo_expander_scan;
+ }
+- break;
+- default:
+- break;
+ }
+- schedule_work(&ev->work);
+ }
+
++/**
++ * mptsas_probe_expanders - adding expanders
++ * @ioc: Pointer to MPT_ADAPTER structure
++ *
++ **/
+ static void
+-mptsas_send_discovery_event(MPT_ADAPTER *ioc,
+- EVENT_DATA_SAS_DISCOVERY *discovery_data)
++mptsas_probe_expanders(MPT_ADAPTER *ioc)
+ {
+- struct mptsas_discovery_event *ev;
++ struct mptsas_portinfo buffer, *port_info;
++ u32 handle;
++ int i;
+
+- /*
+- * DiscoveryStatus
+- *
+- * This flag will be non-zero when firmware
+- * kicks off discovery, and return to zero
+- * once its completed.
+- */
+- if (discovery_data->DiscoveryStatus)
+- return;
++ handle = 0xFFFF;
++ while (!mptsas_sas_expander_pg0(ioc, &buffer,
++ (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
++ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
+
+- ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+- if (!ev)
+- return;
+- INIT_WORK(&ev->work, mptsas_discovery_work);
+- ev->ioc = ioc;
+- schedule_work(&ev->work);
+-};
++ handle = buffer.phy_info[0].handle;
++ port_info = mptsas_find_portinfo_by_sas_address(ioc,
++ buffer.phy_info[0].identify.sas_address);
++
++ if (port_info) {
++ /* refreshing handles */
++ for (i = 0; i < buffer.num_phys; i++) {
++ port_info->phy_info[i].handle = handle;
++ port_info->phy_info[i].identify.handle_parent =
++ buffer.phy_info[0].identify.handle_parent;
++ }
++ mptsas_expander_refresh(ioc, port_info);
++ kfree(buffer.phy_info);
++ continue;
++ }
++
++ port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
++ if (!port_info) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "%s: exit at line=%d\n", ioc->name,
++ __FUNCTION__, __LINE__));
++ return;
++ }
++ port_info->num_phys = buffer.num_phys;
++ port_info->phy_info = buffer.phy_info;
++ for (i = 0; i < port_info->num_phys; i++)
++ port_info->phy_info[i].portinfo = port_info;
++ mutex_lock(&ioc->sas_topology_mutex);
++ list_add_tail(&port_info->list, &ioc->sas_topology);
++ mutex_unlock(&ioc->sas_topology_mutex);
++ printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
++ "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
++ (unsigned long long)buffer.phy_info[0].identify.sas_address);
++ mptsas_expander_refresh(ioc, port_info);
++ }
++}
+
+-/*
+- * mptsas_send_ir2_event - handle exposing hidden disk when
+- * an inactive raid volume is added
+- *
+- * @ioc: Pointer to MPT_ADAPTER structure
+- * @ir2_data
+- *
+- */
+ static void
+-mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
++mptsas_probe_devices(MPT_ADAPTER *ioc)
+ {
+- struct mptsas_hotplug_event *ev;
++ u16 retry_count;
++ u16 handle;
++ struct mptsas_devinfo sas_device;
++ struct mptsas_phyinfo *phy_info;
++ enum device_state state;
+
+- if (ir2_data->ReasonCode !=
+- MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
+- return;
++ handle = 0xFFFF;
++ while (!(mptsas_sas_device_pg0(ioc, &sas_device,
++ MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
++
++ handle = sas_device.handle;
++
++ if ((sas_device.device_info &
++ (MPI_SAS_DEVICE_INFO_SSP_TARGET |
++ MPI_SAS_DEVICE_INFO_STP_TARGET |
++ MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
++ continue;
+
+- ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+- if (!ev)
+- return;
++ phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
++ if (!phy_info)
++ continue;
+
+- INIT_WORK(&ev->work, mptsas_hotplug_work);
+- ev->ioc = ioc;
+- ev->id = ir2_data->TargetID;
+- ev->channel = ir2_data->Bus;
+- ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
++ if (mptsas_get_rphy(phy_info))
++ continue;
+
+- schedule_work(&ev->work);
+-};
++ state = DEVICE_RETRY;
++ retry_count = 0;
++ while(state == DEVICE_RETRY) {
++ state = mptsas_test_unit_ready(ioc, sas_device.channel,
++ sas_device.id, retry_count++);
++ ssleep(1);
++ }
++ if (state == DEVICE_READY)
++ mptsas_add_end_device(ioc, phy_info);
++ }
++}
+
+-static int
+-mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
++/**
++ * mptsas_scan_sas_topology -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @sas_address:
++ *
++ **/
++static void
++mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
+ {
+- int rc=1;
+- u8 event = le32_to_cpu(reply->Event) & 0xFF;
++ struct scsi_device *sdev;
++ int i;
+
+- if (!ioc->sh)
+- goto out;
++ mptsas_probe_hba_phys(ioc);
++ mptsas_probe_expanders(ioc);
++ mptsas_probe_devices(ioc);
+
+ /*
+- * sas_discovery_ignore_events
+- *
+- * This flag is to prevent anymore processing of
+- * sas events once mptsas_remove function is called.
+- */
+- if (ioc->sas_discovery_ignore_events) {
+- rc = mptscsih_event_process(ioc, reply);
+- goto out;
+- }
+-
+- switch (event) {
+- case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
+- mptsas_send_sas_event(ioc,
+- (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
+- break;
+- case MPI_EVENT_INTEGRATED_RAID:
+- mptsas_send_raid_event(ioc,
+- (EVENT_DATA_RAID *)reply->Data);
+- break;
+- case MPI_EVENT_PERSISTENT_TABLE_FULL:
+- INIT_WORK(&ioc->sas_persist_task,
+- mptsas_persist_clear_table);
+- schedule_work(&ioc->sas_persist_task);
+- break;
+- case MPI_EVENT_SAS_DISCOVERY:
+- mptsas_send_discovery_event(ioc,
+- (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
+- break;
+- case MPI_EVENT_IR2:
+- mptsas_send_ir2_event(ioc,
+- (PTR_MPI_EVENT_DATA_IR2)reply->Data);
+- break;
+- default:
+- rc = mptscsih_event_process(ioc, reply);
+- break;
++ Reporting RAID volumes.
++ */
++ if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
++ !ioc->raid_data.pIocPg2->NumActiveVolumes)
++ return;
++ for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
++ if ((sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0))) {
++ scsi_device_put(sdev);
++ continue;
++ }
++ printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
++ "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
++ scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
+ }
+- out:
+-
+- return rc;
+ }
+
++/**
++ * mptsas_probe -
++ * @pdev:
++ * @id:
++ *
++ **/
+ static int
+ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ {
+@@ -3129,6 +5071,7 @@ mptsas_probe(struct pci_dev *pdev, const
+ return r;
+
+ ioc = pci_get_drvdata(pdev);
++ mptsas_fw_event_off(ioc);
+ ioc->DoneCtx = mptsasDoneCtx;
+ ioc->TaskCtx = mptsasTaskCtx;
+ ioc->InternalCtx = mptsasInternalCtx;
+@@ -3173,7 +5116,7 @@ mptsas_probe(struct pci_dev *pdev, const
+ ioc->name);
+ error = -1;
+ goto out_mptsas_probe;
+- }
++ }
+
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
+
+@@ -3187,10 +5130,9 @@ mptsas_probe(struct pci_dev *pdev, const
+
+ /* set 16 byte cdb's */
+ sh->max_cmd_len = 16;
+-
++ sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
+ sh->max_id = ioc->pfacts[0].PortSCSIID;
+ sh->max_lun = max_lun;
+-
+ sh->transportt = mptsas_transport_template;
+
+ /* Required entry.
+@@ -3199,10 +5141,10 @@ mptsas_probe(struct pci_dev *pdev, const
+
+ INIT_LIST_HEAD(&ioc->sas_topology);
+ mutex_init(&ioc->sas_topology_mutex);
+- mutex_init(&ioc->sas_discovery_mutex);
+ mutex_init(&ioc->sas_mgmt.mutex);
+ init_completion(&ioc->sas_mgmt.done);
+
++
+ /* Verify that we won't exceed the maximum
+ * number of chain buffers
+ * We can optimize: ZZ = req_sz/sizeof(SGE)
+@@ -3212,17 +5154,16 @@ mptsas_probe(struct pci_dev *pdev, const
+ * A slightly different algorithm is required for
+ * 64bit SGEs.
+ */
+- scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+- if (sizeof(dma_addr_t) == sizeof(u64)) {
++
++ scale = ioc->req_sz/ioc->SGE_size;
++ if (ioc->sg_addr_size == sizeof(u64)) {
+ numSGE = (scale - 1) *
+ (ioc->facts.MaxChainDepth-1) + scale +
+- (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
+- sizeof(u32));
++ (ioc->req_sz - 60) / ioc->SGE_size;
+ } else {
+ numSGE = 1 + (scale - 1) *
+ (ioc->facts.MaxChainDepth-1) + scale +
+- (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
+- sizeof(u32));
++ (ioc->req_sz - 64) / ioc->SGE_size;
+ }
+
+ if (numSGE < sh->sg_tablesize) {
+@@ -3250,34 +5191,17 @@ mptsas_probe(struct pci_dev *pdev, const
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
+ ioc->name, ioc->ScsiLookup));
+
+- /* Clear the TM flags
+- */
+- hd->tmPending = 0;
+- hd->tmState = TM_STATE_NONE;
+- hd->resetPending = 0;
+- hd->abortSCpnt = NULL;
+-
+- /* Clear the pointer used to store
+- * single-threaded commands, i.e., those
+- * issued during a bus scan, dv and
+- * configuration pages.
+- */
+- hd->cmdPtr = NULL;
+-
+- /* Initialize this SCSI Hosts' timers
+- * To use, set the timer expires field
+- * and add_timer
+- */
+- init_timer(&hd->timer);
+- hd->timer.data = (unsigned long) hd;
+- hd->timer.function = mptscsih_timer_expired;
+-
++ ioc->sdev_queue_depth = mpt_sdev_queue_depth;
+ ioc->sas_data.ptClear = mpt_pt_clear;
+-
+- init_waitqueue_head(&hd->scandv_waitq);
+- hd->scandv_wait_done = 0;
+ hd->last_queue_full = 0;
++ ioc->disable_hotplug_remove = mpt_disable_hotplug_remove;
++ if (ioc->disable_hotplug_remove)
++ printk(MYIOC_s_INFO_FMT "disabling hotplug remove\n", ioc->name);
++
+ INIT_LIST_HEAD(&hd->target_reset_list);
++ INIT_LIST_HEAD(&ioc->sas_device_info_list);
++ init_MUTEX(&ioc->sas_device_info_mutex);
++
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+ if (ioc->sas_data.ptClear==1) {
+@@ -3292,8 +5216,11 @@ mptsas_probe(struct pci_dev *pdev, const
+ goto out_mptsas_probe;
+ }
+
++ /* older firmware doesn't support expander events */
++ if ((ioc->facts.HeaderVersion >> 8) < 0xE)
++ ioc->old_sas_discovery_protocal = 1;
+ mptsas_scan_sas_topology(ioc);
+-
++ mptsas_fw_event_on(ioc);
+ return 0;
+
+ out_mptsas_probe:
+@@ -3302,13 +5229,23 @@ mptsas_probe(struct pci_dev *pdev, const
+ return error;
+ }
+
+-static void __devexit mptsas_remove(struct pci_dev *pdev)
++/**
++ * mptsas_remove -
++ * @pdev:
++ *
++ **/
++static void __devexit
++mptsas_remove(struct pci_dev *pdev)
+ {
+ MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+ struct mptsas_portinfo *p, *n;
+ int i;
+
+- ioc->sas_discovery_ignore_events = 1;
++ mptsas_fw_event_off(ioc);
++ mptsas_cleanup_fw_event_q(ioc);
++
++ mptsas_del_device_components(ioc);
++
+ sas_remove_host(ioc->sh);
+
+ mutex_lock(&ioc->sas_topology_mutex);
+@@ -3316,11 +5253,12 @@ static void __devexit mptsas_remove(stru
+ list_del(&p->list);
+ for (i = 0 ; i < p->num_phys ; i++)
+ mptsas_port_delete(ioc, p->phy_info[i].port_details);
++
+ kfree(p->phy_info);
+ kfree(p);
+ }
+ mutex_unlock(&ioc->sas_topology_mutex);
+-
++ ioc->hba_port_info = NULL;
+ mptscsih_remove(pdev);
+ }
+
+@@ -3352,6 +5290,10 @@ static struct pci_driver mptsas_driver =
+ #endif
+ };
+
++/**
++ * mptsas_init -
++ *
++ **/
+ static int __init
+ mptsas_init(void)
+ {
+@@ -3365,10 +5307,12 @@ mptsas_init(void)
+ return -ENODEV;
+
+ mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
+- mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
++ mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
+ mptsasInternalCtx =
+ mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
+ mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
++ mptsasDeviceResetCtx =
++ mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
+
+ mpt_event_register(mptsasDoneCtx, mptsas_event_process);
+ mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
+@@ -3380,6 +5324,10 @@ mptsas_init(void)
+ return error;
+ }
+
++/**
++ * mptsas_exit -
++ *
++ **/
+ static void __exit
+ mptsas_exit(void)
+ {
+@@ -3393,6 +5341,7 @@ mptsas_exit(void)
+ mpt_deregister(mptsasInternalCtx);
+ mpt_deregister(mptsasTaskCtx);
+ mpt_deregister(mptsasDoneCtx);
++ mpt_deregister(mptsasDeviceResetCtx);
+ }
+
+ module_init(mptsas_init);
+--- a/drivers/message/fusion/mptsas.h
++++ b/drivers/message/fusion/mptsas.h
+@@ -50,9 +50,10 @@
+ /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+ struct mptsas_target_reset_event {
+- struct list_head list;
+- EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
++ struct list_head list;
++ MpiEventDataSasDeviceStatusChange_t sas_event_data;
+ u8 target_reset_issued;
++ unsigned long time_count;
+ };
+
+ enum mptsas_hotplug_action {
+@@ -61,11 +62,34 @@ enum mptsas_hotplug_action {
+ MPTSAS_ADD_RAID,
+ MPTSAS_DEL_RAID,
+ MPTSAS_ADD_INACTIVE_VOLUME,
++ MPTSAS_ADD_PHYSDISK,
++ MPTSAS_ADD_PHYSDISK_REPROBE,
++ MPTSAS_DEL_PHYSDISK,
++ MPTSAS_DEL_PHYSDISK_REPROBE,
++ MPTSAS_REQUEUE_EVENT,
+ MPTSAS_IGNORE_EVENT,
+ };
+
++struct sas_mapping{
++ u8 id;
++ u8 channel;
++};
++
++struct sas_device_info {
++ struct list_head list;
++ struct sas_mapping os; /* operating system mapping*/
++ struct sas_mapping fw; /* firmware mapping */
++ u64 sas_address;
++ u32 device_info; /* specific bits for devices */
++ u16 slot; /* enclosure slot id */
++ u64 enclosure_logical_id; /*enclosure address */
++ u8 is_logical_volume; /* is this logical volume */
++ u8 is_hidden_raid_component; /* this belongs to volume */
++ u8 volume_id; /* this valid when is_hidden_raid_component set */
++ u8 is_cached; /* cached data for a removed device */
++};
++
+ struct mptsas_hotplug_event {
+- struct work_struct work;
+ MPT_ADAPTER *ioc;
+ enum mptsas_hotplug_action event_type;
+ u64 sas_address;
+@@ -73,17 +97,28 @@ struct mptsas_hotplug_event {
+ u8 id;
+ u32 device_info;
+ u16 handle;
+- u16 parent_handle;
+ u8 phy_id;
+- u8 phys_disk_num_valid; /* hrc (hidden raid component) */
+ u8 phys_disk_num; /* hrc - unique index*/
+- u8 hidden_raid_component; /* hrc - don't expose*/
++ struct scsi_device *sdev;
+ };
+
+-struct mptsas_discovery_event {
++
++struct fw_event_work {
++ struct list_head list;
++ struct delayed_work work;
++ MPT_ADAPTER *ioc;
++ u32 event;
++ u8 retries;
++ u8 event_data[1];
++};
++
++#if 0
++struct mptsas_link_status_event {
+ struct work_struct work;
++ MpiEventDataSasPhyLinkStatus_t link_data;
+ MPT_ADAPTER *ioc;
+ };
++#endif
+
+ /*
+ * SAS topology structures
+@@ -113,32 +148,35 @@ struct mptsas_devinfo {
+ * Specific details on ports, wide/narrow
+ */
+ struct mptsas_portinfo_details{
+- u16 num_phys; /* number of phys belong to this port */
+- u64 phy_bitmask; /* TODO, extend support for 255 phys */
+- struct sas_rphy *rphy; /* transport layer rphy object */
++ u16 num_phys; /* number of phys beloing to this port */
++ u64 phy_bitmask; /* this needs extending to support 128 phys */
++ struct sas_rphy *rphy; /* rphy for end devices */
+ struct sas_port *port; /* transport layer port object */
+ struct scsi_target *starget;
+ struct mptsas_portinfo *port_info;
+ };
+
+ struct mptsas_phyinfo {
+- u16 handle; /* unique id to address this */
+- u8 phy_id; /* phy index */
+- u8 port_id; /* firmware port identifier */
++ u16 handle; /* handle for this phy */
++ u8 phy_id; /* phy index */
++ u8 port_id; /* port number this phy is part of */
+ u8 negotiated_link_rate; /* nego'd link rate for this phy */
+- u8 hw_link_rate; /* hardware max/min phys link rate */
++ u8 hw_link_rate; /* hardware max/min phys link rate */
+ u8 programmed_link_rate; /* programmed max/min phy link rate */
+ u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/
++ u8 change_count; /* change count of the phy */
++ u8 port_flags; /* info wrt host sas ports */
++ u32 phy_info; /* various info wrt the phy */
+ struct mptsas_devinfo identify; /* point to phy device info */
+ struct mptsas_devinfo attached; /* point to attached device info */
+- struct sas_phy *phy; /* transport layer phy object */
++ struct sas_phy *phy;
+ struct mptsas_portinfo *portinfo;
+ struct mptsas_portinfo_details * port_details;
+ };
+
+ struct mptsas_portinfo {
+ struct list_head list;
+- u16 num_phys; /* number of phys */
++ u16 num_phys; /* number of phys */
+ struct mptsas_phyinfo *phy_info;
+ };
+
+@@ -156,3 +194,4 @@ struct mptsas_enclosure {
+
+ /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ #endif
++
+--- a/drivers/message/fusion/mptscsih.c
++++ b/drivers/message/fusion/mptscsih.c
+@@ -53,7 +53,9 @@
+ #include <linux/delay.h> /* for mdelay */
+ #include <linux/interrupt.h> /* needed for in_interrupt() proto */
+ #include <linux/reboot.h> /* notifier code */
++#include <linux/sched.h>
+ #include <linux/workqueue.h>
++#include <linux/pci.h>
+
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -77,10 +79,15 @@ MODULE_LICENSE("GPL");
+ MODULE_VERSION(my_VERSION);
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++typedef struct _BIG_SENSE_BUF {
++ u8 data[MPT_SENSE_BUFFER_ALLOC];
++} BIG_SENSE_BUF;
++
++
+ /*
+ * Other private/forward protos...
+ */
+-static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
++struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
+ static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
+ static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
+ static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
+@@ -92,17 +99,10 @@ static int mptscsih_AddSGE(MPT_ADAPTER *
+ SCSIIORequest_t *pReq, int req_idx);
+ static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
+ static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
+-static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
+-static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
+-
+-static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
+
+ int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
+ int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+-
+-int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+-static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
+-static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
++static void mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice);
+
+ void mptscsih_remove(struct pci_dev *);
+ void mptscsih_shutdown(struct pci_dev *);
+@@ -111,81 +111,17 @@ int mptscsih_suspend(struct pci_dev *p
+ int mptscsih_resume(struct pci_dev *pdev);
+ #endif
+
+-#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE
+-
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/**
+- * mptscsih_add_sge - Place a simple SGE at address pAddr.
+- * @pAddr: virtual address for SGE
+- * @flagslength: SGE flags and data transfer length
+- * @dma_addr: Physical address
+- *
+- * This routine places a MPT request frame back on the MPT adapter's
+- * FreeQ.
+- */
+-static inline void
+-mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
+-{
+- if (sizeof(dma_addr_t) == sizeof(u64)) {
+- SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+- u32 tmp = dma_addr & 0xFFFFFFFF;
+-
+- pSge->FlagsLength = cpu_to_le32(flagslength);
+- pSge->Address.Low = cpu_to_le32(tmp);
+- tmp = (u32) ((u64)dma_addr >> 32);
+- pSge->Address.High = cpu_to_le32(tmp);
+-
+- } else {
+- SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+- pSge->FlagsLength = cpu_to_le32(flagslength);
+- pSge->Address = cpu_to_le32(dma_addr);
+- }
+-} /* mptscsih_add_sge() */
++#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+- * mptscsih_add_chain - Place a chain SGE at address pAddr.
+- * @pAddr: virtual address for SGE
+- * @next: nextChainOffset value (u32's)
+- * @length: length of next SGL segment
+- * @dma_addr: Physical address
+- *
+- * This routine places a MPT request frame back on the MPT adapter's
+- * FreeQ.
+- */
+-static inline void
+-mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+-{
+- if (sizeof(dma_addr_t) == sizeof(u64)) {
+- SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
+- u32 tmp = dma_addr & 0xFFFFFFFF;
+-
+- pChain->Length = cpu_to_le16(length);
+- pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
+-
+- pChain->NextChainOffset = next;
+-
+- pChain->Address.Low = cpu_to_le32(tmp);
+- tmp = (u32) ((u64)dma_addr >> 32);
+- pChain->Address.High = cpu_to_le32(tmp);
+- } else {
+- SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
+- pChain->Length = cpu_to_le16(length);
+- pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
+- pChain->NextChainOffset = next;
+- pChain->Address = cpu_to_le32(dma_addr);
+- }
+-} /* mptscsih_add_chain() */
+-
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
+ * mptscsih_getFreeChainBuffer - Function to get a free chain
+ * from the MPT_SCSI_HOST FreeChainQ.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @req_idx: Index of the SCSI IO request frame. (output)
+ *
+ * return SUCCESS or FAILED
+- */
++ **/
+ static inline int
+ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
+ {
+@@ -195,7 +131,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER
+ int chain_idx;
+
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
+- ioc->name));
++ ioc->name));
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
+ if (!list_empty(&ioc->FreeChainQ)) {
+ int offset;
+@@ -206,14 +142,13 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER
+ offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
+ chain_idx = offset / ioc->req_sz;
+ rc = SUCCESS;
+- dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
+- ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
++ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
++ ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
+ } else {
+ rc = FAILED;
+ chain_idx = MPT_HOST_NO_CHAIN;
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
+- ioc->name));
++ ioc->name));
+ }
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+@@ -222,7 +157,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER
+ } /* mptscsih_getFreeChainBuffer() */
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
++/**
+ * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
+ * SCSIIORequest_t Message Frame.
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -230,7 +165,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER
+ * @pReq: Pointer to SCSIIORequest_t structure
+ *
+ * Returns ...
+- */
++ **/
+ static int
+ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
+ SCSIIORequest_t *pReq, int req_idx)
+@@ -281,10 +216,10 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct
+ */
+
+ nextSGEset:
+- numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
++ numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size );
+ numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
+
+- sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
++ sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
+
+ /* Get first (num - 1) SG elements
+ * Skip any SG entries with a length of 0
+@@ -299,11 +234,11 @@ nextSGEset:
+ }
+
+ v2 = sg_dma_address(sg);
+- mptscsih_add_sge(psge, sgflags | thisxfer, v2);
++ ioc->add_sge(psge, sgflags | thisxfer, v2);
+
+ sg = sg_next(sg); /* Get next SG element from the OS */
+- psge += (sizeof(u32) + sizeof(dma_addr_t));
+- sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
++ psge += ioc->SGE_size;
++ sgeOffset += ioc->SGE_size;
+ sg_done++;
+ }
+
+@@ -320,12 +255,8 @@ nextSGEset:
+ thisxfer = sg_dma_len(sg);
+
+ v2 = sg_dma_address(sg);
+- mptscsih_add_sge(psge, sgflags | thisxfer, v2);
+- /*
+- sg = sg_next(sg);
+- psge += (sizeof(u32) + sizeof(dma_addr_t));
+- */
+- sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
++ ioc->add_sge(psge, sgflags | thisxfer, v2);
++ sgeOffset += ioc->SGE_size;
+ sg_done++;
+
+ if (chainSge) {
+@@ -334,7 +265,7 @@ nextSGEset:
+ * Update the chain element
+ * Offset and Length fields.
+ */
+- mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
++ ioc->add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
+ } else {
+ /* The current buffer is the original MF
+ * and there is no Chain buffer.
+@@ -367,7 +298,7 @@ nextSGEset:
+ * set properly).
+ */
+ if (sg_done) {
+- u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
++ u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
+ sgflags = le32_to_cpu(*ptmp);
+ sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
+ *ptmp = cpu_to_le32(sgflags);
+@@ -381,8 +312,8 @@ nextSGEset:
+ * Old chain element is now complete.
+ */
+ u8 nextChain = (u8) (sgeOffset >> 2);
+- sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+- mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
++ sgeOffset += ioc->SGE_size;
++ ioc->add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
+ } else {
+ /* The original MF buffer requires a chain buffer -
+ * set the offset.
+@@ -461,7 +392,7 @@ mptscsih_issue_sep_command(MPT_ADAPTER *
+
+ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
+- ioc->name,__func__));
++ ioc->name,__FUNCTION__));
+ return;
+ }
+
+@@ -592,14 +523,14 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, s
+ }
+
+ scsi_print_command(sc);
+- printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
+- ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
+- printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
+- "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
+- scsi_get_resid(sc));
+- printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
+- "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
++ printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n",
++ ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
++ printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, resid = %d\n",
++ ioc->name, scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc));
++ printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, sc->result = %08X\n",
++ ioc->name, le16_to_cpu(pScsiReply->TaskTag),
+ le32_to_cpu(pScsiReply->TransferCount), sc->result);
++
+ printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
+ "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
+ ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
+@@ -625,7 +556,7 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, s
+ #endif
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
++/**
+ * mptscsih_io_done - Main SCSI IO callback routine registered to
+ * Fusion MPT (base) driver
+ * @ioc: Pointer to MPT_ADAPTER structure
+@@ -638,7 +569,7 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, s
+ * load/init time via the mpt_register() API call.
+ *
+ * Returns 1 indicating alloc'd request frame ptr should be freed.
+- */
++ **/
+ int
+ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+ {
+@@ -651,14 +582,15 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ VirtTarget *vtarget;
+
+ hd = shost_priv(ioc->sh);
++
+ req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+ req_idx_MR = (mr != NULL) ?
+ le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
+ if ((req_idx != req_idx_MR) ||
+- (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
+- printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
+- ioc->name);
+- printk (MYIOC_s_ERR_FMT
++ (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf)) {
++ printk(MYIOC_s_WARN_FMT
++ "Received a mf that was already freed\n", ioc->name);
++ printk (MYIOC_s_WARN_FMT
+ "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
+ ioc->name, req_idx, req_idx_MR, mf, mr,
+ mptscsih_get_scsi_lookup(ioc, req_idx_MR));
+@@ -693,7 +625,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+
+ if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
++ "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task_tag=%d)\n",
+ ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
+ }else{
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+@@ -706,6 +638,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ ;
+ } else {
+ u32 xfer_cnt;
++ u32 difftransfer;
+ u16 status;
+ u8 scsi_state, scsi_status;
+ u32 log_info;
+@@ -716,6 +649,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
+ scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
+ log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
++ vdevice = sc->device->hostdata;
+
+ /*
+ * if we get a data underrun indication, yet no data was
+@@ -733,20 +667,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
+ mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
+
+- /*
+- * Look for + dump FCP ResponseInfo[]!
+- */
+- if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
+- pScsiReply->ResponseInfo) {
+- printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
+- "FCP_ResponseInfo=%08xh\n", ioc->name,
+- sc->device->host->host_no, sc->device->channel,
+- sc->device->id, sc->device->lun,
+- le32_to_cpu(pScsiReply->ResponseInfo));
+- }
+-
+ switch(status) {
+ case MPI_IOCSTATUS_BUSY: /* 0x0002 */
++ case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
+ /* CHECKME!
+ * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
+ * But not: DID_BUS_BUSY lest one risk
+@@ -771,7 +694,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
+ hd->sel_timeout[pScsiReq->TargetID]++;
+
+- vdevice = sc->device->hostdata;
+ if (!vdevice)
+ break;
+ vtarget = vdevice->vtarget;
+@@ -793,14 +715,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ }
+ }
+ } else if (ioc->bus_type == FC) {
+- /*
+- * The FC IOC may kill a request for variety of
+- * reasons, some of which may be recovered by a
+- * retry, some which are unlikely to be
+- * recovered. Return DID_ERROR instead of
+- * DID_RESET to permit retry of the command,
+- * just not an infinite number of them
+- */
++ /* The FC IOC may kill a request for variety of reasons,
++ some of which may be recovered by a retry, some which
++ are unlikely to be recovered. Return DID_ERROR instead
++ of DID_RESET to permit retry of the command, just not
++ an infinite number of them */
+ sc->result = DID_ERROR << 16;
+ break;
+ }
+@@ -810,12 +729,16 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ */
+
+ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
+- case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
+ /* Linux handles an unsolicited DID_RESET better
+ * than an unsolicited DID_ABORT.
+ */
+ sc->result = DID_RESET << 16;
+
++ case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
++ if ( ioc->bus_type == FC )
++ sc->result = DID_ERROR << 16;
++ else
++ sc->result = DID_RESET << 16;
+ break;
+
+ case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
+@@ -824,9 +747,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ sc->result=DID_SOFT_ERROR << 16;
+ else /* Sufficient data transfer occurred */
+ sc->result = (DID_OK << 16) | scsi_status;
+- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
+- ioc->name, sc->result, sc->device->channel, sc->device->id));
+ break;
+
+ case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
+@@ -835,11 +755,34 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ * precedence!
+ */
+ sc->result = (DID_OK << 16) | scsi_status;
+- if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+- /* Have already saved the status and sense data
++
++ if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
++
++ /*
++ * For an Errata on LSI53C1030
++ * When the length of request data
++ * and transfer data are different
++ * with result of command (READ or VERIFY),
++ * DID_SOFT_ERROR is set.
+ */
+- ;
+- } else {
++ if (ioc->bus_type == SPI && vdevice &&
++ vdevice->vtarget->type == TYPE_DISK) {
++ if (pScsiReq->CDB[0] == READ_6 ||
++ pScsiReq->CDB[0] == READ_10 ||
++ pScsiReq->CDB[0] == READ_12 ||
++ pScsiReq->CDB[0] == READ_16 ||
++ pScsiReq->CDB[0] == VERIFY ||
++ pScsiReq->CDB[0] == VERIFY_16) {
++ if (scsi_bufflen(sc) !=
++ xfer_cnt) {
++ sc->result = DID_SOFT_ERROR << 16;
++ printk(MYIOC_s_WARN_FMT "Errata"
++ "on LSI53C1030 occurred. sc->request_bufflen=0x%02x, "
++ "xfer_cnt=0x%02x\n", ioc->name, scsi_bufflen(sc), xfer_cnt);
++ }
++ }
++ }
++
+ if (xfer_cnt < sc->underflow) {
+ if (scsi_status == SAM_STAT_BUSY)
+ sc->result = SAM_STAT_BUSY;
+@@ -848,7 +791,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ }
+ if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+ /* What to do?
+- */
++ */
+ sc->result = DID_SOFT_ERROR << 16;
+ }
+ else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
+@@ -857,13 +800,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ }
+ }
+
+-
+- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
+- ioc->name, sc->underflow));
+- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
+-
+ /* Report Queue Full
+ */
+ if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
+@@ -879,6 +815,44 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ if (scsi_state == 0) {
+ ;
+ } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
++
++ /*
++ * For potential trouble on LSI53C1030. (date:2007.xx.)
++ * It is checked whether the length of request data is equal to
++ * the length of transfer and residual.
++ * MEDIUM_ERROR is set by incorrect data.
++ */
++ if (ioc->bus_type == SPI && vdevice &&
++ vdevice->vtarget->type == TYPE_DISK) {
++ if (sc->sense_buffer[2] & 0x20) {
++ difftransfer =
++ sc->sense_buffer[3] << 24 |
++ sc->sense_buffer[4] << 16 |
++ sc->sense_buffer[5] << 8 |
++ sc->sense_buffer[6];
++ if ((sc->sense_buffer[3] & 0x80) == 0x80) {
++ if (scsi_bufflen(sc) != xfer_cnt) {
++ sc->sense_buffer[2] = MEDIUM_ERROR;
++ sc->sense_buffer[12] = 0xff;
++ sc->sense_buffer[13] = 0xff;
++ printk(MYIOC_s_WARN_FMT "Errata on "
++ "LSI53C1030 occurred. sc->request_bufflen=0x%02x,"
++ "xfer_cnt=0x%02x\n", ioc->name, scsi_bufflen(sc), xfer_cnt);
++ }
++ } else {
++ if (scsi_bufflen(sc) != xfer_cnt + difftransfer) {
++ sc->sense_buffer[2] = MEDIUM_ERROR;
++ sc->sense_buffer[12] = 0xff;
++ sc->sense_buffer[13] = 0xff;
++ printk(MYIOC_s_WARN_FMT "Errata on "
++ "LSI53C1030 occurred. sc->request_bufflen=0x%02x,"
++ " xfer_cnt=0x%02x, difftransfer=0x%02x\n",
++ ioc->name, scsi_bufflen(sc) , xfer_cnt, difftransfer);
++ }
++ }
++ }
++ }
++
+ /*
+ * If running against circa 200003dd 909 MPT f/w,
+ * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
+@@ -890,7 +864,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+
+ }
+ else if (scsi_state &
+- (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
++ (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
+ ) {
+ /*
+ * What to do?
+@@ -926,7 +900,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
+ case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
+ case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
+- case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
+ case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
+ case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
+ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
+@@ -957,7 +930,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ return 1;
+ }
+
+-/*
++/**
+ * mptscsih_flush_running_cmds - For each command found, search
+ * Scsi_Host instance taskQ and reply to OS.
+ * Called only if recovering from a FW reload.
+@@ -966,7 +939,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
+ * Returns: None.
+ *
+ * Must be called while new I/Os are being queued.
+- */
++ **/
+ static void
+ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
+ {
+@@ -992,14 +965,14 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOS
+ scsi_dma_unmap(sc);
+ sc->result = DID_RESET << 16;
+ sc->host_scribble = NULL;
+- sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
+- "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
+- " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
++ dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
++ "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
++ "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
+ sc->scsi_done(sc);
+ }
+ }
+
+-/*
++/**
+ * mptscsih_search_running_cmds - Delete any commands associated
+ * with the specified target and lun. Function called only
+ * when a lun is disable by mid-layer.
+@@ -1012,15 +985,15 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOS
+ * Returns: None.
+ *
+ * Called from slave_destroy.
+- */
++ **/
+ static void
+ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
+ {
+ SCSIIORequest_t *mf = NULL;
+ int ii;
+ struct scsi_cmnd *sc;
+- struct scsi_lun lun;
+- MPT_ADAPTER *ioc = hd->ioc;
++ struct scsi_lun lun;
++ MPT_ADAPTER *ioc = hd->ioc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+@@ -1030,8 +1003,11 @@ mptscsih_search_running_cmds(MPT_SCSI_HO
+ mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
+ if (mf == NULL)
+ continue;
+- /* If the device is a hidden raid component, then its
+- * expected that the mf->function will be RAID_SCSI_IO
++
++ /*
++ * If the device is a hidden raid component,
++ * then its expected that
++ * the function would be raid scsi io
+ */
+ if (vdevice->vtarget->tflags &
+ MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
+@@ -1053,9 +1029,11 @@ mptscsih_search_running_cmds(MPT_SCSI_HO
+ scsi_dma_unmap(sc);
+ sc->host_scribble = NULL;
+ sc->result = DID_NO_CONNECT << 16;
+- sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
+- "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
+- vdevice->vtarget->id, sc, mf, ii);
++ dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
++ MYIOC_s_FMT "completing cmds: fw_channel %d, "
++ "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
++ vdevice->vtarget->channel, vdevice->vtarget->id,
++ sc, mf, ii));
+ sc->scsi_done(sc);
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ }
+@@ -1067,7 +1045,7 @@ mptscsih_search_running_cmds(MPT_SCSI_HO
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
++/**
+ * mptscsih_report_queue_full - Report QUEUE_FULL status returned
+ * from a SCSI target device.
+ * @sc: Pointer to scsi_cmnd structure
+@@ -1077,12 +1055,12 @@ mptscsih_search_running_cmds(MPT_SCSI_HO
+ * This routine periodically reports QUEUE_FULL status returned from a
+ * SCSI target device. It reports this to the console via kernel
+ * printk() API call, not more than once every 10 seconds.
+- */
++ **/
+ static void
+ mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
+ {
+ long time = jiffies;
+- MPT_SCSI_HOST *hd;
++ MPT_SCSI_HOST *hd;
+ MPT_ADAPTER *ioc;
+
+ if (sc->device == NULL)
+@@ -1100,12 +1078,12 @@ mptscsih_report_queue_full(struct scsi_c
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
++/**
+ * mptscsih_remove - Removed scsi devices
+ * @pdev: Pointer to pci_dev structure
+ *
+ *
+- */
++ **/
+ void
+ mptscsih_remove(struct pci_dev *pdev)
+ {
+@@ -1151,10 +1129,10 @@ mptscsih_remove(struct pci_dev *pdev)
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
++/**
+ * mptscsih_shutdown - reboot notifier
+ *
+- */
++ **/
+ void
+ mptscsih_shutdown(struct pci_dev *pdev)
+ {
+@@ -1162,11 +1140,11 @@ mptscsih_shutdown(struct pci_dev *pdev)
+
+ #ifdef CONFIG_PM
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
++/**
+ * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
+ *
+ *
+- */
++ **/
+ int
+ mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
+ {
+@@ -1179,11 +1157,11 @@ mptscsih_suspend(struct pci_dev *pdev, p
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
++/**
+ * mptscsih_resume - Fusion MPT scsi driver resume routine.
+ *
+ *
+- */
++ **/
+ int
+ mptscsih_resume(struct pci_dev *pdev)
+ {
+@@ -1205,7 +1183,7 @@ mptscsih_resume(struct pci_dev *pdev)
+ * (linux scsi_host_template.info routine)
+ *
+ * Returns pointer to buffer where information was written.
+- */
++ **/
+ const char *
+ mptscsih_info(struct Scsi_Host *SChost)
+ {
+@@ -1338,7 +1316,7 @@ mptscsih_proc_info(struct Scsi_Host *hos
+ * from a linux scsi_cmnd request and send it to the IOC.
+ *
+ * Returns 0. (rtn value discarded by linux scsi mid-layer)
+- */
++ **/
+ int
+ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+ {
+@@ -1346,7 +1324,6 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v
+ MPT_FRAME_HDR *mf;
+ SCSIIORequest_t *pScsiReq;
+ VirtDevice *vdevice = SCpnt->device->hostdata;
+- int lun;
+ u32 datalen;
+ u32 scsictl;
+ u32 scsidir;
+@@ -1357,24 +1334,20 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v
+
+ hd = shost_priv(SCpnt->device->host);
+ ioc = hd->ioc;
+- lun = SCpnt->device->lun;
+ SCpnt->scsi_done = done;
+
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
+ ioc->name, SCpnt, done));
+
+- if (hd->resetPending) {
+- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
+- ioc->name, SCpnt));
++ if (ioc->taskmgmt_quiesce_io)
+ return SCSI_MLQUEUE_HOST_BUSY;
+- }
+
+ /*
+ * Put together a MPT SCSI request...
+ */
+ if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
+ dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
+- ioc->name));
++ ioc->name));
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+@@ -1422,7 +1395,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v
+ pScsiReq->CDBLength = SCpnt->cmd_len;
+ pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+ pScsiReq->Reserved = 0;
+- pScsiReq->MsgFlags = mpt_msg_flags();
++ pScsiReq->MsgFlags = mpt_msg_flags(ioc);
+ int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
+ pScsiReq->Control = cpu_to_le32(scsictl);
+
+@@ -1448,7 +1421,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v
+ */
+ if (datalen == 0) {
+ /* Add a NULL SGE */
+- mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
++ ioc->add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
+ (dma_addr_t) -1);
+ } else {
+ /* Add a 32 or 64 bit SGE */
+@@ -1472,7 +1445,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
++/**
+ * mptscsih_freeChainBuffers - Function to free chain buffers associated
+ * with a SCSI IO request
+ * @hd: Pointer to the MPT_SCSI_HOST instance
+@@ -1480,7 +1453,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v
+ *
+ * Called if SG chain buffer allocation fails and mptscsih callbacks.
+ * No return.
+- */
++ **/
+ static void
+ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
+ {
+@@ -1527,243 +1500,457 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *i
+ */
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/**
+- * mptscsih_TMHandler - Generic handler for SCSI Task Management.
+- * @hd: Pointer to MPT SCSI HOST structure
+- * @type: Task Management type
+- * @channel: channel number for task management
+- * @id: Logical Target ID for reset (if appropriate)
+- * @lun: Logical Unit for reset (if appropriate)
+- * @ctx2abort: Context for the task to be aborted (if appropriate)
+- * @timeout: timeout for task management control
+- *
+- * Fall through to mpt_HardResetHandler if: not operational, too many
+- * failed TM requests or handshake failure.
+- *
+- * Remark: Currently invoked from a non-interrupt thread (_bh).
+- *
+- * Note: With old EH code, at most 1 SCSI TaskMgmt function per IOC
+- * will be active.
+- *
+- * Returns 0 for SUCCESS, or %FAILED.
+- **/
+-int
+-mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
+-{
+- MPT_ADAPTER *ioc;
+- int rc = -1;
+- u32 ioc_raw_state;
+- unsigned long flags;
+-
+- ioc = hd->ioc;
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
+-
+- // SJR - CHECKME - Can we avoid this here?
+- // (mpt_HardResetHandler has this check...)
+- spin_lock_irqsave(&ioc->diagLock, flags);
+- if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
+- spin_unlock_irqrestore(&ioc->diagLock, flags);
+- return FAILED;
+- }
+- spin_unlock_irqrestore(&ioc->diagLock, flags);
+-
+- /* Wait a fixed amount of time for the TM pending flag to be cleared.
+- * If we time out and not bus reset, then we return a FAILED status
+- * to the caller.
+- * The call to mptscsih_tm_pending_wait() will set the pending flag
+- * if we are
+- * successful. Otherwise, reload the FW.
+- */
+- if (mptscsih_tm_pending_wait(hd) == FAILED) {
+- if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
+- "Timed out waiting for last TM (%d) to complete! \n",
+- ioc->name, hd->tmPending));
+- return FAILED;
+- } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
+- "reset: Timed out waiting for last TM (%d) "
+- "to complete! \n", ioc->name,
+- hd->tmPending));
+- return FAILED;
+- } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
+- "Timed out waiting for last TM (%d) to complete! \n",
+- ioc->name, hd->tmPending));
+- return FAILED;
+- }
+- } else {
+- spin_lock_irqsave(&ioc->FreeQlock, flags);
+- hd->tmPending |= (1 << type);
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+- }
+-
+- ioc_raw_state = mpt_GetIocState(ioc, 0);
+-
+- if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
+- printk(MYIOC_s_WARN_FMT
+- "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
+- ioc->name, type, ioc_raw_state);
+- printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
+- if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
+- printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
+- "FAILED!!\n", ioc->name);
+- return FAILED;
+- }
+-
+- if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
+- printk(MYIOC_s_WARN_FMT
+- "TM Handler for type=%x: ioc_state: "
+- "DOORBELL_ACTIVE (0x%x)!\n",
+- ioc->name, type, ioc_raw_state);
+- return FAILED;
+- }
+-
+- /* Isse the Task Mgmt request.
+- */
+- if (hd->hard_resets < -1)
+- hd->hard_resets++;
+-
+- rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
+- ctx2abort, timeout);
+- if (rc)
+- printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
+- ioc->name);
+- else
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
+- ioc->name));
+-
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "TMHandler rc = %d!\n", ioc->name, rc));
+-
+- return rc;
+-}
+-
+-
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/**
+- * mptscsih_IssueTaskMgmt - Generic send Task Management function.
+- * @hd: Pointer to MPT_SCSI_HOST structure
+- * @type: Task Management type
+- * @channel: channel number for task management
+- * @id: Logical Target ID for reset (if appropriate)
+- * @lun: Logical Unit for reset (if appropriate)
+- * @ctx2abort: Context for the task to be aborted (if appropriate)
+- * @timeout: timeout for task management control
+- *
+- * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
+- * or a non-interrupt thread. In the former, must not call schedule().
+- *
+- * Not all fields are meaningfull for all task types.
+- *
+- * Returns 0 for SUCCESS, or FAILED.
+- *
+- **/
++
+ static int
+-mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
++mptscsih_scandv_bus_reset(MPT_ADAPTER *ioc)
+ {
+ MPT_FRAME_HDR *mf;
+ SCSITaskMgmt_t *pScsiTm;
++ SCSITaskMgmtReply_t *pScsiTmReply;
+ int ii;
+ int retval;
+- MPT_ADAPTER *ioc = hd->ioc;
++ unsigned long timeout;
++ unsigned long time_count;
++ u16 iocstatus;
++
++ mutex_lock(&ioc->taskmgmt_cmds.mutex);
++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++ return -EPERM;
++ }
+
+- /* Return Fail to calling function if no message frames available.
++ /* Send request
+ */
+ if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
++ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
+ ioc->name));
+- return FAILED;
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ retval = -ENOMEM;
++ goto out;
+ }
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
+- ioc->name, mf));
+
+- /* Format the Request
+- */
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
++ ioc->name, mf));
++
+ pScsiTm = (SCSITaskMgmt_t *) mf;
+- pScsiTm->TargetID = id;
+- pScsiTm->Bus = channel;
+- pScsiTm->ChainOffset = 0;
++ memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
+ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+-
++ pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
++ pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
++ pScsiTm->TargetID = 0;
++ pScsiTm->Bus = 0;
++ pScsiTm->ChainOffset = 0;
+ pScsiTm->Reserved = 0;
+- pScsiTm->TaskType = type;
+ pScsiTm->Reserved1 = 0;
+- pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
+- ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
+-
+- int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
+-
++ pScsiTm->TaskMsgContext = 0;
++ for (ii= 0; ii < 8; ii++)
++ pScsiTm->LUN[ii] = 0;
+ for (ii=0; ii < 7; ii++)
+ pScsiTm->Reserved2[ii] = 0;
+
+- pScsiTm->TaskMsgContext = ctx2abort;
+-
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
+- "type=%d\n", ioc->name, ctx2abort, type));
++ switch (ioc->bus_type) {
++ case FC:
++ timeout = 40;
++ break;
++ case SAS:
++ timeout = 30;
++ break;
++ case SPI:
++ default:
++ timeout = 2;
++ break;
++ }
+
+- DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
++ ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
+
++ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
++ CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
++ retval = 0;
++ time_count = jiffies;
+ if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+ (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+ mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
+ else {
+ retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
+- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+- if (retval) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
+- " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
+- ioc, mf, retval));
+- goto fail_out;
++ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
++ if (retval != 0) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt send_handshake FAILED!"
++ " (ioc %p, mf %p, rc=%d) \n", ioc->name,
++ ioc, mf, retval));
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ goto out;
+ }
+ }
+
+- if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
+- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
+- " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
+- ioc, mf));
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
+- ioc->name));
+- retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
+- ioc->name, retval));
+- goto fail_out;
++ /* Now wait for the command to complete */
++ ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt failed\n", ioc->name));
++ mpt_free_msg_frame(ioc, mf);
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ retval = -1; /* return failure */
++ goto out;
+ }
+
+- /*
+- * Handle success case, see if theres a non-zero ioc_status.
+- */
+- if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
+- hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
+- hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
+- retval = 0;
+- else
+- retval = FAILED;
++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt failed\n", ioc->name));
++ retval = -1; /* return failure */
++ goto out;
++ }
+
+- return retval;
++ pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
++ "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
++ "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
++ pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
++ le16_to_cpu(pScsiTmReply->IOCStatus),
++ le32_to_cpu(pScsiTmReply->IOCLogInfo),
++ pScsiTmReply->ResponseCode,
++ le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+- fail_out:
++ iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+- /*
+- * Free task management mf, and corresponding tm flags
+- */
+- mpt_free_msg_frame(ioc, mf);
+- hd->tmPending = 0;
+- hd->tmState = TM_STATE_NONE;
+- return FAILED;
++ if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
++ iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED ||
++ iocstatus == MPI_IOCSTATUS_SUCCESS)
++ retval = 0;
++ else {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt failed\n", ioc->name));
++ retval = -1; /* return failure */
++ }
++
++ out:
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
++ return retval;
+ }
+
+-static int
+-mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
++int
++mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+ {
+- switch (ioc->bus_type) {
+- case FC:
+- return 40;
+- case SAS:
+- return 10;
++ MPT_SCSI_HOST *hd;
++
++ if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
++ return 0;
++
++ switch (reset_phase) {
++ case MPT_IOC_SETUP_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
++ break;
++ case MPT_IOC_PRE_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
++ hd = shost_priv(ioc->sh);
++ mptscsih_flush_running_cmds(hd);
++ break;
++ case MPT_IOC_POST_RESET:
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__));
++ if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
++ ioc->internal_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
++ complete(&ioc->internal_cmds.done);
++ }
++ break;
++ default:
++ break;
++ }
++ return 1; /* currently means nothing really */
++}
++
++void
++mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
++{
++ char *desc;
++
++ switch (response_code) {
++ case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
++ desc = "The task completed.";
++ break;
++ case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
++ desc = "The IOC received an invalid frame status.";
++ break;
++ case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
++ desc = "The task type is not supported.";
++ break;
++ case MPI_SCSITASKMGMT_RSP_TM_FAILED:
++ desc = "The requested task failed.";
++ break;
++ case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
++ desc = "The task completed successfully.";
++ break;
++ case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
++ desc = "The LUN request is invalid.";
++ break;
++ case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
++ desc = "The task is in the IOC queue and has not been sent to target.";
++ break;
++ default:
++ desc = "unknown";
++ break;
++ }
++ printk(MYIOC_s_DEBUG_FMT "Response Code(0x%08x): F/W: %s\n",
++ ioc->name, response_code, desc);
++}
++
++static int
++mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, SCSITaskMgmtReply_t *pScsiTmReply)
++{
++ u16 iocstatus;
++ u32 termination_count;
++ int retval;
++
++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
++ retval = FAILED;
++ goto out;
++ }
++
++ DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
++
++ iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
++ termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
++
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
++ "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
++ "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
++ pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
++ le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
++ termination_count));
++
++ if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
++ pScsiTmReply->ResponseCode)
++ mptscsih_taskmgmt_response_code(ioc,
++ pScsiTmReply->ResponseCode);
++
++ if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
++ retval = 0;
++ goto out;
++ }
++
++ retval = FAILED;
++ if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
++ if (termination_count == 1)
++ retval = 0;
++ goto out;
++ }
++
++ if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
++ iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
++ retval = 0;
++
++ out:
++ return retval;
++}
++
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++/**
++ * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @mf: Pointer to SCSI task mgmt request frame
++ * @mr: Pointer to SCSI task mgmt reply frame
++ *
++ * This routine is called from mptbase.c::mpt_interrupt() at the completion
++ * of any SCSI task management request.
++ * This routine is registered with the MPT (base) driver at driver
++ * load/init time via the mpt_register() API call.
++ *
++ * Returns 1 indicating alloc'd request frame ptr should be freed.
++ **/
++int
++mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
++{
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n",
++ ioc->name, mf, mr));
++
++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
++
++ if (!mr)
++ goto out;
++
++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
++ memcpy(ioc->taskmgmt_cmds.reply, mr,
++ min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
++ out:
++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
++ complete(&ioc->taskmgmt_cmds.done);
++ return 1;
++ }
++ return 0;
++}
++
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++/**
++ * mptscsih_IssueTaskMgmt - Generic send Task Management function.
++ * @hd: Pointer to MPT_SCSI_HOST structure
++ * @type: Task Management type
++ * @channel: channel number for task management
++ * @id: Logical Target ID for reset (if appropriate)
++ * @lun: Logical Unit for reset (if appropriate)
++ * @ctx2abort: Context for the task to be aborted (if appropriate)
++ * @timeout: timeout for task management control
++ *
++ * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
++ * or a non-interrupt thread. In the former, must not call schedule().
++ *
++ * Not all fields are meaningfull for all task types.
++ *
++ * Returns 0 for SUCCESS, or FAILED.
++ *
++ **/
++int
++mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
++{
++ MPT_FRAME_HDR *mf = NULL;
++ SCSITaskMgmt_t *pScsiTm;
++ int ii;
++ int retval;
++ MPT_ADAPTER *ioc = hd->ioc;
++ unsigned long timeleft;
++ u8 issue_hard_reset;
++ u32 ioc_raw_state;
++ unsigned long time_count;
++
++ issue_hard_reset = 0;
++ ioc_raw_state = mpt_GetIocState(ioc, 0);
++
++ if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
++ printk(MYIOC_s_WARN_FMT
++ "TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
++ ioc->name, type, ioc_raw_state);
++ printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
++ ioc->name, __FUNCTION__);
++ if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
++ printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
++ "FAILED!!\n", ioc->name);
++ return 0;
++ }
++
++ if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
++ printk(MYIOC_s_WARN_FMT
++ "TaskMgmt type=%x: ioc_state: "
++ "DOORBELL_ACTIVE (0x%x)!\n",
++ ioc->name, type, ioc_raw_state);
++ return FAILED;
++ }
++
++ mutex_lock(&ioc->taskmgmt_cmds.mutex);
++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++ retval = FAILED;
++ goto out;
++ }
++
++ /* Return Fail to calling function if no message frames available.
++ */
++ if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt no msg frames!!\n",
++ ioc->name));
++ retval = FAILED;
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ goto out;
++ }
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
++ ioc->name, mf));
++
++ /* Format the Request
++ */
++ pScsiTm = (SCSITaskMgmt_t *) mf;
++ pScsiTm->TargetID = id;
++ pScsiTm->Bus = channel;
++ pScsiTm->ChainOffset = 0;
++ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
++
++ pScsiTm->Reserved = 0;
++ pScsiTm->TaskType = type;
++ pScsiTm->Reserved1 = 0;
++ pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
++ ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
++
++ int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
++
++ for (ii=0; ii < 7; ii++)
++ pScsiTm->Reserved2[ii] = 0;
++
++ pScsiTm->TaskMsgContext = ctx2abort;
++
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
++ "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
++ type, timeout));
++
++ DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
++
++ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
++ time_count = jiffies;
++ if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
++ (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
++ mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
++ else {
++ retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
++ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
++ if (retval) {
++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt handshake FAILED!"
++ " (mf=%p, rc=%d) \n", ioc->name, mf, retval));
++ mpt_free_msg_frame(ioc, mf);
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ goto out;
++ }
++ }
++
++ timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ retval = FAILED;
++ dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
++ "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
++ mpt_clear_taskmgmt_in_progress_flag(ioc);
++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
++ goto out;
++ issue_hard_reset = 1;
++ goto out;
++ }
++
++ retval = mptscsih_taskmgmt_reply(ioc, type,
++ (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
++
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "TaskMgmt completed (%d seconds)\n",
++ ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
++
++ out:
++
++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
++ if(issue_hard_reset) {
++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
++ ioc->name, __FUNCTION__);
++ if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0)
++ retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
++ mpt_free_msg_frame(ioc, mf);
++ }
++
++ retval = (retval == 0) ? 0 : FAILED;
++ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
++ return retval;
++}
++
++static int
++mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
++{
++ switch (ioc->bus_type) {
++ case FC:
++ return 40;
++ case SAS:
++ return 30;
+ case SPI:
+ default:
+- return 2;
++ return 10;
+ }
+ }
+
+@@ -1786,7 +1973,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
+ int retval;
+ VirtDevice *vdevice;
+ ulong sn = SCpnt->serial_number;
+- MPT_ADAPTER *ioc;
++ MPT_ADAPTER *ioc;
+
+ /* If we can't locate our host adapter structure, return FAILED status.
+ */
+@@ -1810,7 +1997,21 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
+ ioc->name, SCpnt));
+ SCpnt->result = DID_NO_CONNECT << 16;
+ SCpnt->scsi_done(SCpnt);
+- retval = 0;
++ retval = SUCCESS;
++ goto out;
++ }
++
++ /* Find this command
++ */
++ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
++ /* Cmd not found in ScsiLookup.
++ * Do OS callback.
++ */
++ SCpnt->result = DID_RESET << 16;
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "task abort: command not in the active list! (sc=%p)\n",
++ ioc->name, SCpnt));
++ retval = SUCCESS;
+ goto out;
+ }
+
+@@ -1825,27 +2026,23 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
+ goto out;
+ }
+
+- /* Find this command
++ /* Task aborts are not supported for volumes.
+ */
+- if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
+- /* Cmd not found in ScsiLookup.
+- * Do OS callback.
+- */
++ if (vdevice->vtarget->raidVolume) {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "task abort: raid volume (sc=%p)\n",
++ ioc->name, SCpnt));
+ SCpnt->result = DID_RESET << 16;
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
+- "Command not in the active list! (sc=%p)\n", ioc->name,
+- SCpnt));
+- retval = 0;
+- goto out;
+- }
+-
+- if (hd->resetPending) {
+ retval = FAILED;
+ goto out;
+ }
+
+- if (hd->timeouts < -1)
+- hd->timeouts++;
++ if(mpt_fwfault_debug)
++ mpt_halt_firmware(ioc);
++
++ if (ioc->timeouts < -1)
++ ioc->timeouts++;
++
+
+ /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
+ * (the IO to be ABORT'd)
+@@ -1856,25 +2053,31 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
+ */
+ mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
+ ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
+-
+- hd->abortSCpnt = SCpnt;
+-
+- retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
++ mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
+ vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
+ ctx2abort, mptscsih_get_tm_timeout(ioc));
+
++ /* check to see whether command actually completed and/or
++ * terminated
++ */
+ if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
+- SCpnt->serial_number == sn)
++ SCpnt->serial_number == sn) {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "task abort: command still in active list! (sc=%p)\n",
++ ioc->name, SCpnt));
+ retval = FAILED;
++ } else {
++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "task abort: command cleared from active list! (sc=%p)\n",
++ ioc->name, SCpnt));
++ retval = SUCCESS;
++ }
+
+ out:
+ printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
+- ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
++ ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED" ), SCpnt);
+
+- if (retval == 0)
+- return SUCCESS;
+- else
+- return FAILED;
++ return retval;
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+@@ -1907,14 +2110,9 @@ mptscsih_dev_reset(struct scsi_cmnd * SC
+ ioc->name, SCpnt);
+ scsi_print_command(SCpnt);
+
+- if (hd->resetPending) {
+- retval = FAILED;
+- goto out;
+- }
+-
+ vdevice = SCpnt->device->hostdata;
+ if (!vdevice || !vdevice->vtarget) {
+- retval = 0;
++ retval = SUCCESS;
+ goto out;
+ }
+
+@@ -1925,12 +2123,12 @@ mptscsih_dev_reset(struct scsi_cmnd * SC
+ goto out;
+ }
+
+- retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+- vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
+- mptscsih_get_tm_timeout(ioc));
++ retval = mptscsih_IssueTaskMgmt(hd,
++ MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, vdevice->vtarget->channel,
++ vdevice->vtarget->id, 0, 0, mptscsih_get_tm_timeout(ioc));
+
+ out:
+- printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
++ printk(MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
+ ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+
+ if (retval == 0)
+@@ -1955,12 +2153,12 @@ mptscsih_bus_reset(struct scsi_cmnd * SC
+ MPT_SCSI_HOST *hd;
+ int retval;
+ VirtDevice *vdevice;
+- MPT_ADAPTER *ioc;
++ MPT_ADAPTER *ioc;
+
+ /* If we can't locate our host adapter structure, return FAILED status.
+ */
+ if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+- printk(KERN_ERR MYNAM ": bus reset: "
++ printk(KERN_ERR MYNAM ": bus_reset: "
+ "Can't locate host! (sc=%p)\n", SCpnt);
+ return FAILED;
+ }
+@@ -1970,11 +2168,13 @@ mptscsih_bus_reset(struct scsi_cmnd * SC
+ ioc->name, SCpnt);
+ scsi_print_command(SCpnt);
+
+- if (hd->timeouts < -1)
+- hd->timeouts++;
++ if (ioc->timeouts < -1)
++ ioc->timeouts++;
+
+ vdevice = SCpnt->device->hostdata;
+- retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
++ if (!vdevice || !vdevice->vtarget)
++ return SUCCESS;
++ retval = mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+ vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
+
+ printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
+@@ -1999,8 +2199,9 @@ int
+ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
+ {
+ MPT_SCSI_HOST * hd;
+- int retval;
+- MPT_ADAPTER *ioc;
++ int status = SUCCESS;
++ MPT_ADAPTER *ioc;
++ int retval;
+
+ /* If we can't locate the host to reset, then we failed. */
+ if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+@@ -2011,237 +2212,29 @@ mptscsih_host_reset(struct scsi_cmnd *SC
+
+ ioc = hd->ioc;
+ printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
+- ioc->name, SCpnt);
++ ioc->name, SCpnt);
+
+ /* If our attempts to reset the host failed, then return a failed
+ * status. The host will be taken off line by the SCSI mid-layer.
+ */
+- if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
+- retval = FAILED;
+- } else {
+- /* Make sure TM pending is cleared and TM state is set to
+- * NONE.
+- */
+- retval = 0;
+- hd->tmPending = 0;
+- hd->tmState = TM_STATE_NONE;
+- }
++ if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0)
++ retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
++
++ if (retval < 0)
++ status = FAILED;
++ else
++ status = SUCCESS;
+
+ printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
+ ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+
+- return retval;
+-}
+-
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/**
+- * mptscsih_tm_pending_wait - wait for pending task management request to complete
+- * @hd: Pointer to MPT host structure.
+- *
+- * Returns {SUCCESS,FAILED}.
+- */
+-static int
+-mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
+-{
+- unsigned long flags;
+- int loop_count = 4 * 10; /* Wait 10 seconds */
+- int status = FAILED;
+- MPT_ADAPTER *ioc = hd->ioc;
+-
+- do {
+- spin_lock_irqsave(&ioc->FreeQlock, flags);
+- if (hd->tmState == TM_STATE_NONE) {
+- hd->tmState = TM_STATE_IN_PROGRESS;
+- hd->tmPending = 1;
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+- status = SUCCESS;
+- break;
+- }
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+- msleep(250);
+- } while (--loop_count);
+-
+ return status;
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+- * mptscsih_tm_wait_for_completion - wait for completion of TM task
+- * @hd: Pointer to MPT host structure.
+- * @timeout: timeout value
+- *
+- * Returns {SUCCESS,FAILED}.
+- */
+-static int
+-mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
+-{
+- unsigned long flags;
+- int loop_count = 4 * timeout;
+- int status = FAILED;
+- MPT_ADAPTER *ioc = hd->ioc;
+-
+- do {
+- spin_lock_irqsave(&ioc->FreeQlock, flags);
+- if(hd->tmPending == 0) {
+- status = SUCCESS;
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+- break;
+- }
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+- msleep(250);
+- } while (--loop_count);
+-
+- return status;
+-}
+-
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-static void
+-mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
+-{
+- char *desc;
+-
+- switch (response_code) {
+- case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
+- desc = "The task completed.";
+- break;
+- case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
+- desc = "The IOC received an invalid frame status.";
+- break;
+- case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
+- desc = "The task type is not supported.";
+- break;
+- case MPI_SCSITASKMGMT_RSP_TM_FAILED:
+- desc = "The requested task failed.";
+- break;
+- case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
+- desc = "The task completed successfully.";
+- break;
+- case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
+- desc = "The LUN request is invalid.";
+- break;
+- case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
+- desc = "The task is in the IOC queue and has not been sent to target.";
+- break;
+- default:
+- desc = "unknown";
+- break;
+- }
+- printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
+- ioc->name, response_code, desc);
+-}
+-
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/**
+- * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
+- * @ioc: Pointer to MPT_ADAPTER structure
+- * @mf: Pointer to SCSI task mgmt request frame
+- * @mr: Pointer to SCSI task mgmt reply frame
+- *
+- * This routine is called from mptbase.c::mpt_interrupt() at the completion
+- * of any SCSI task management request.
+- * This routine is registered with the MPT (base) driver at driver
+- * load/init time via the mpt_register() API call.
+- *
+- * Returns 1 indicating alloc'd request frame ptr should be freed.
+- **/
+-int
+-mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+-{
+- SCSITaskMgmtReply_t *pScsiTmReply;
+- SCSITaskMgmt_t *pScsiTmReq;
+- MPT_SCSI_HOST *hd;
+- unsigned long flags;
+- u16 iocstatus;
+- u8 tmType;
+- u32 termination_count;
+-
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
+- ioc->name, mf, mr));
+- if (!ioc->sh) {
+- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
+- "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
+- return 1;
+- }
+-
+- if (mr == NULL) {
+- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
+- "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
+- return 1;
+- }
+-
+- hd = shost_priv(ioc->sh);
+- pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
+- pScsiTmReq = (SCSITaskMgmt_t*)mf;
+- tmType = pScsiTmReq->TaskType;
+- iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+- termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
+-
+- if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
+- pScsiTmReply->ResponseCode)
+- mptscsih_taskmgmt_response_code(ioc,
+- pScsiTmReply->ResponseCode);
+- DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
+-
+-#ifdef CONFIG_FUSION_LOGGING
+- if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
+- (ioc->debug_level & MPT_DEBUG_TM ))
+- printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
+- "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
+- "term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus,
+- pScsiTmReply->TargetID, pScsiTmReq->TaskType,
+- le16_to_cpu(pScsiTmReply->IOCStatus),
+- le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
+- le32_to_cpu(pScsiTmReply->TerminationCount));
+-#endif
+- if (!iocstatus) {
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
+- hd->abortSCpnt = NULL;
+- goto out;
+- }
+-
+- /* Error? (anything non-zero?) */
+-
+- /* clear flags and continue.
+- */
+- switch (tmType) {
+-
+- case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
+- if (termination_count == 1)
+- iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
+- hd->abortSCpnt = NULL;
+- break;
+-
+- case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
+-
+- /* If an internal command is present
+- * or the TM failed - reload the FW.
+- * FC FW may respond FAILED to an ABORT
+- */
+- if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
+- hd->cmdPtr)
+- if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
+- printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
+- break;
+-
+- case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+- default:
+- break;
+- }
+-
+- out:
+- spin_lock_irqsave(&ioc->FreeQlock, flags);
+- hd->tmPending = 0;
+- hd->tmState = TM_STATE_NONE;
+- hd->tm_iocstatus = iocstatus;
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+-
+- return 1;
+-}
+-
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
+ * This is anyones guess quite frankly.
+- */
++ **/
+ int
+ mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
+ sector_t capacity, int geom[])
+@@ -2278,40 +2271,82 @@ mptscsih_bios_param(struct scsi_device *
+ return 0;
+ }
+
+-/* Search IOC page 3 to determine if this is hidden physical disk
++/**
++ * Search IOC page 3 to determine if this is hidden physical disk
+ *
+- */
++ **/
+ int
+ mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
+ {
+ struct inactive_raid_component_info *component_info;
+- int i;
++ u8 i, j;
++ RaidPhysDiskPage1_t *phys_disk;
+ int rc = 0;
++ int num_paths;
+
+ if (!ioc->raid_data.pIocPg3)
+ goto out;
+ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+ if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
+- (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
++ (channel ==
++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
+ rc = 1;
+ goto out;
+ }
+ }
+
++ if (ioc->bus_type != SAS)
++ goto out;
++
++ /*
++ * Check if dual path
++ */
++ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
++ num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
++ if (num_paths < 2)
++ continue;
++ phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) +
++ (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
++ if (!phys_disk)
++ continue;
++ if ((mpt_raid_phys_disk_pg1(ioc,
++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
++ phys_disk))) {
++ kfree(phys_disk);
++ continue;
++ }
++ for (j = 0; j < num_paths; j++) {
++ if ((phys_disk->Path[j].Flags &
++ MPI_RAID_PHYSDISK1_FLAG_INVALID))
++ continue;
++ if ((phys_disk->Path[j].Flags &
++ MPI_RAID_PHYSDISK1_FLAG_BROKEN))
++ continue;
++ if ((id == phys_disk->Path[j].PhysDiskID) &&
++ (channel == phys_disk->Path[j].PhysDiskBus)) {
++ rc = 1;
++ kfree(phys_disk);
++ goto out;
++ }
++ }
++ kfree(phys_disk);
++ }
++
+ /*
+ * Check inactive list for matching phys disks
+ */
+ if (list_empty(&ioc->raid_data.inactive_list))
+ goto out;
+
+- mutex_lock(&ioc->raid_data.inactive_list_mutex);
++ down(&ioc->raid_data.inactive_list_mutex);
+ list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
+ list) {
+ if ((component_info->d.PhysDiskID == id) &&
+ (component_info->d.PhysDiskBus == channel))
+ rc = 1;
+ }
+- mutex_unlock(&ioc->raid_data.inactive_list_mutex);
++ up(&ioc->raid_data.inactive_list_mutex);
+
+ out:
+ return rc;
+@@ -2322,43 +2357,84 @@ u8
+ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
+ {
+ struct inactive_raid_component_info *component_info;
+- int i;
++ int i,j;
++ RaidPhysDiskPage1_t *phys_disk;
+ int rc = -ENXIO;
++ u8 num_paths;
+
+ if (!ioc->raid_data.pIocPg3)
+ goto out;
+ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+ if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
+- (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
++ (channel ==
++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
+ rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
+ goto out;
+ }
+ }
+
++ if (ioc->bus_type != SAS)
++ goto out;
++
++ /*
++ * Check if dual path
++ */
++ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
++ num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
++ if (num_paths < 2)
++ continue;
++ phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) +
++ (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
++ if (!phys_disk)
++ continue;
++ if ((mpt_raid_phys_disk_pg1(ioc,
++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
++ phys_disk))) {
++ kfree(phys_disk);
++ continue;
++ }
++ for (j = 0; j < num_paths; j++) {
++ if ((phys_disk->Path[j].Flags &
++ MPI_RAID_PHYSDISK1_FLAG_INVALID))
++ continue;
++ if ((phys_disk->Path[j].Flags &
++ MPI_RAID_PHYSDISK1_FLAG_BROKEN))
++ continue;
++ if ((id == phys_disk->Path[j].PhysDiskID) &&
++ (channel == phys_disk->Path[j].PhysDiskBus)) {
++ rc = phys_disk->PhysDiskNum;
++ kfree(phys_disk);
++ goto out;
++ }
++ }
++ kfree(phys_disk);
++ }
++
+ /*
+ * Check inactive list for matching phys disks
+ */
+ if (list_empty(&ioc->raid_data.inactive_list))
+ goto out;
+
+- mutex_lock(&ioc->raid_data.inactive_list_mutex);
++ down(&ioc->raid_data.inactive_list_mutex);
+ list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
+ list) {
+ if ((component_info->d.PhysDiskID == id) &&
+ (component_info->d.PhysDiskBus == channel))
+ rc = component_info->d.PhysDiskNum;
+ }
+- mutex_unlock(&ioc->raid_data.inactive_list_mutex);
++ up(&ioc->raid_data.inactive_list_mutex);
+
+ out:
+ return rc;
+ }
+ EXPORT_SYMBOL(mptscsih_raid_id_to_num);
+
+-/*
++/**
+ * OS entry point to allow for host driver to free allocated memory
+ * Called if no device present or device being unloaded
+- */
++ **/
+ void
+ mptscsih_slave_destroy(struct scsi_device *sdev)
+ {
+@@ -2370,23 +2446,25 @@ mptscsih_slave_destroy(struct scsi_devic
+
+ starget = scsi_target(sdev);
+ vtarget = starget->hostdata;
++ vtarget->num_luns--;
+ vdevice = sdev->hostdata;
++ if (!vdevice)
++ return;
+
+ mptscsih_search_running_cmds(hd, vdevice);
+- vtarget->num_luns--;
+- mptscsih_synchronize_cache(hd, vdevice);
++ mptscsih_synchronize_cache(sdev, hd, vdevice);
+ kfree(vdevice);
+ sdev->hostdata = NULL;
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
++/**
+ * mptscsih_change_queue_depth - This function will set a devices queue depth
+ * @sdev: per scsi_device pointer
+ * @qdepth: requested queue depth
+ *
+ * Adding support for new 'change_queue_depth' api.
+-*/
++ **/
+ int
+ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
+ {
+@@ -2401,15 +2479,16 @@ mptscsih_change_queue_depth(struct scsi_
+ vtarget = starget->hostdata;
+
+ if (ioc->bus_type == SPI) {
+- if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+- max_depth = 1;
+- else if (sdev->type == TYPE_DISK &&
+- vtarget->minSyncFactor <= MPT_ULTRA160)
++ if (sdev->type == TYPE_DISK &&
++ vtarget->minSyncFactor <= MPT_ULTRA160)
+ max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
+ else
+ max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
+ } else
+- max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
++ max_depth = ioc->sh->can_queue;
++
++ if (!sdev->tagged_supported)
++ max_depth = 1;
+
+ if (qdepth > max_depth)
+ qdepth = max_depth;
+@@ -2419,15 +2498,24 @@ mptscsih_change_queue_depth(struct scsi_
+ tagged = MSG_SIMPLE_TAG;
+
+ scsi_adjust_queue_depth(sdev, tagged, qdepth);
++
++ if (sdev->inquiry_len > 7)
++ sdev_printk(KERN_INFO, sdev, MYIOC_s_FMT "qdepth=%d, "
++ "tagged=%d, simple=%d, ordered=%d, scsi_level=%d, "
++ "cmd_que=%d\n", ioc->name, sdev->queue_depth,
++ sdev->tagged_supported, sdev->simple_tags,
++ sdev->ordered_tags, sdev->scsi_level,
++ (sdev->inquiry[7] & 2) >> 1);
++
+ return sdev->queue_depth;
+ }
+
+-/*
++/**
+ * OS entry point to adjust the queue_depths on a per-device basis.
+ * Called once per device the bus scan. Use it to force the queue_depth
+ * member to 1 if a device does not support Q tags.
+ * Return non-zero if fails.
+- */
++ **/
+ int
+ mptscsih_slave_configure(struct scsi_device *sdev)
+ {
+@@ -2436,52 +2524,37 @@ mptscsih_slave_configure(struct scsi_dev
+ VirtDevice *vdevice;
+ struct scsi_target *starget;
+ MPT_SCSI_HOST *hd = shost_priv(sh);
+- MPT_ADAPTER *ioc = hd->ioc;
++ MPT_ADAPTER *ioc = hd->ioc;
+
+ starget = scsi_target(sdev);
+ vtarget = starget->hostdata;
+ vdevice = sdev->hostdata;
++ vdevice->configured_lun = 1;
+
+- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "device @ %p, channel=%d, id=%d, lun=%d\n",
+- ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
+- if (ioc->bus_type == SPI)
+- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "sdtr %d wdtr %d ppr %d inq length=%d\n",
+- ioc->name, sdev->sdtr, sdev->wdtr,
+- sdev->ppr, sdev->inquiry_len));
++ if ((ioc->bus_type != SAS) && (sdev->id > sh->max_id)) {
++ /* error case, should never happen */
++ scsi_adjust_queue_depth(sdev, 0, 1);
++ goto slave_configure_exit;
++ }
+
+- vdevice->configured_lun = 1;
+- mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
++ mptscsih_change_queue_depth(sdev, ioc->sdev_queue_depth);
+
+- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "Queue depth=%d, tflags=%x\n",
+- ioc->name, sdev->queue_depth, vtarget->tflags));
+-
+- if (ioc->bus_type == SPI)
+- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
+- ioc->name, vtarget->negoFlags, vtarget->maxOffset,
+- vtarget->minSyncFactor));
+-
+- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "tagged %d, simple %d, ordered %d\n",
+- ioc->name,sdev->tagged_supported, sdev->simple_tags,
+- sdev->ordered_tags));
++slave_configure_exit:
+
+ return 0;
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
++/**
+ * Private routines...
+ */
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/* Utility function to copy sense data from the scsi_cmnd buffer
++/**
++ * Utility function to copy sense data from the scsi_cmnd buffer
+ * to the FC and SCSI target structures.
+ *
+- */
++ **/
+ static void
+ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
+ {
+@@ -2521,31 +2594,31 @@ mptscsih_copy_sense_data(struct scsi_cmn
+ ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
+
+ ioc->eventContext++;
+- if (ioc->pcidev->vendor ==
+- PCI_VENDOR_ID_IBM) {
+- mptscsih_issue_sep_command(ioc,
+- vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
+- vdevice->vtarget->tflags |=
+- MPT_TARGET_FLAGS_LED_ON;
++ if (ioc->pcidev->vendor == PCI_VENDOR_ID_IBM) {
++ mptscsih_issue_sep_command(ioc, vdevice->vtarget,
++ MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
++ vdevice->vtarget->tflags |= MPT_TARGET_FLAGS_LED_ON;
+ }
+ }
+ }
+ } else {
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
+- ioc->name));
++ ioc->name));
+ }
+ }
+
+ /**
+ * mptscsih_get_scsi_lookup
+- * @ioc: Pointer to MPT_ADAPTER structure
+- * @i: index into the array
+ *
+ * retrieves scmd entry from ScsiLookup[] array list
+ *
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @i: index into the array
++ *
+ * Returns the scsi_cmd pointer
++ *
+ **/
+-static struct scsi_cmnd *
++struct scsi_cmnd *
+ mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
+ {
+ unsigned long flags;
+@@ -2560,12 +2633,14 @@ mptscsih_get_scsi_lookup(MPT_ADAPTER *io
+
+ /**
+ * mptscsih_getclear_scsi_lookup
+- * @ioc: Pointer to MPT_ADAPTER structure
+- * @i: index into the array
+ *
+ * retrieves and clears scmd entry from ScsiLookup[] array list
+ *
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @i: index into the array
++ *
+ * Returns the scsi_cmd pointer
++ *
+ **/
+ static struct scsi_cmnd *
+ mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
+@@ -2602,10 +2677,14 @@ mptscsih_set_scsi_lookup(MPT_ADAPTER *io
+ }
+
+ /**
+- * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
++ * SCPNT_TO_LOOKUP_IDX
++ *
++ * search's for a given scmd in the ScsiLookup[] array list
++ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+- * @sc: scsi_cmnd pointer
+- */
++ * @scmd: scsi_cmnd pointer
++ *
++ **/
+ static int
+ SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
+ {
+@@ -2627,380 +2706,226 @@ SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, st
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ int
+-mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
++mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+ {
+- MPT_SCSI_HOST *hd;
+- unsigned long flags;
+-
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- ": IOC %s_reset routed to SCSI host driver!\n",
+- ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+-
+- /* If a FW reload request arrives after base installed but
+- * before all scsi hosts have been attached, then an alt_ioc
+- * may have a NULL sh pointer.
+- */
+- if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
+- return 0;
+- else
+- hd = shost_priv(ioc->sh);
+-
+- if (reset_phase == MPT_IOC_SETUP_RESET) {
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
+-
+- /* Clean Up:
+- * 1. Set Hard Reset Pending Flag
+- * All new commands go to doneQ
+- */
+- hd->resetPending = 1;
+-
+- } else if (reset_phase == MPT_IOC_PRE_RESET) {
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
+-
+- /* 2. Flush running commands
+- * Clean ScsiLookup (and associated memory)
+- * AND clean mytaskQ
+- */
++ u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+
+- /* 2b. Reply to OS all known outstanding I/O commands.
+- */
+- mptscsih_flush_running_cmds(hd);
++ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "MPT event (=%02Xh) routed to SCSI host driver!\n",
++ ioc->name, event));
+
+- /* 2c. If there was an internal command that
+- * has not completed, configuration or io request,
+- * free these resources.
+- */
+- if (hd->cmdPtr) {
+- del_timer(&hd->timer);
+- mpt_free_msg_frame(ioc, hd->cmdPtr);
+- }
++ if ((event == MPI_EVENT_IOC_BUS_RESET ||
++ event == MPI_EVENT_EXT_BUS_RESET) &&
++ (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
++ ioc->soft_resets++;
+
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
++ return 1; /* currently means nothing really */
++}
+
+- } else {
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
++int
++mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
++{
++ MPT_ADAPTER *ioc = hd->ioc;
++ MpiRaidActionRequest_t *pReq;
++ MPT_FRAME_HDR *mf;
++ int ret;
++ unsigned long timeleft;
+
+- /* Once a FW reload begins, all new OS commands are
+- * redirected to the doneQ w/ a reset status.
+- * Init all control structures.
+- */
++ mutex_lock(&ioc->internal_cmds.mutex);
+
+- /* 2. Chain Buffer initialization
+- */
++ /* Get and Populate a free Frame
++ */
++ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
++ dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!\n",
++ ioc->name, __FUNCTION__));
++ ret = -EAGAIN;
++ goto out;
++ }
++ pReq = (MpiRaidActionRequest_t *)mf;
++ if (quiesce)
++ pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO;
++ else
++ pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO;
++ pReq->Reserved1 = 0;
++ pReq->ChainOffset = 0;
++ pReq->Function = MPI_FUNCTION_RAID_ACTION;
++ pReq->VolumeID = id;
++ pReq->VolumeBus = channel;
++ pReq->PhysDiskNum = 0;
++ pReq->MsgFlags = 0;
++ pReq->Reserved2 = 0;
++ pReq->ActionDataWord = 0; /* Reserved for this action */
+
+- /* 4. Renegotiate to all devices, if SPI
+- */
++ ioc->add_sge((char *)&pReq->ActionDataSGE,
++ MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
+
+- /* 5. Enable new commands to be posted
+- */
+- spin_lock_irqsave(&ioc->FreeQlock, flags);
+- hd->tmPending = 0;
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+- hd->resetPending = 0;
+- hd->tmState = TM_STATE_NONE;
++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
++ ioc->name, pReq->Action, channel, id));
+
+- /* 6. If there was an internal command,
+- * wake this process up.
+- */
+- if (hd->cmdPtr) {
+- /*
+- * Wake up the original calling thread
+- */
+- hd->pLocal = &hd->localReply;
+- hd->pLocal->completion = MPT_SCANDV_DID_RESET;
+- hd->scandv_wait_done = 1;
+- wake_up(&hd->scandv_waitq);
+- hd->cmdPtr = NULL;
++ INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
++ mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
++ timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ);
++ if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ ret = -ETIME;
++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n",
++ ioc->name, __FUNCTION__));
++ if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
++ goto out;
++ if (!timeleft) {
++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
++ ioc->name, __FUNCTION__);
++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
++ mpt_HardResetHandler(ioc, CAN_SLEEP);
++ mpt_free_msg_frame(ioc, mf);
+ }
+-
+- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
+-
++ goto out;
+ }
+
+- return 1; /* currently means nothing really */
++ ret = ioc->internal_cmds.completion_code;
++
++ out:
++ CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
++ mutex_unlock(&ioc->internal_cmds.mutex);
++ return ret;
+ }
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-int
+-mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
++/**
++ * mptscsih_get_completion_code -
++ * @ioc: Pointer to MPT_ADAPTER structure
++ * @reply:
++ * @cmd:
++ *
++ **/
++static int
++mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
+ {
+- MPT_SCSI_HOST *hd;
+- u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
++ SCSIIOReply_t *pReply;
++ MpiRaidActionReply_t *pr;
++ u8 scsi_status;
++ u16 status;
++ int completion_code;
+
+- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
+- ioc->name, event));
++ pReply = (SCSIIOReply_t *)reply;
++ status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
++ scsi_status = pReply->SCSIStatus;
+
+- if (ioc->sh == NULL ||
+- ((hd = shost_priv(ioc->sh)) == NULL))
+- return 1;
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
++ ioc->name, status, pReply->SCSIState, scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
+
+- switch (event) {
+- case MPI_EVENT_UNIT_ATTENTION: /* 03 */
+- /* FIXME! */
+- break;
+- case MPI_EVENT_IOC_BUS_RESET: /* 04 */
+- case MPI_EVENT_EXT_BUS_RESET: /* 05 */
+- if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
+- hd->soft_resets++;
+- break;
+- case MPI_EVENT_LOGOUT: /* 09 */
+- /* FIXME! */
++ switch(status) {
++
++ case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
++ completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
+ break;
+
+- case MPI_EVENT_RESCAN: /* 06 */
++ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
++ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
++ case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
++ case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
++ completion_code = MPT_SCANDV_DID_RESET;
+ break;
+
+- /*
+- * CHECKME! Don't think we need to do
+- * anything for these, but...
+- */
+- case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
+- case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
+- /*
+- * CHECKME! Falling thru...
+- */
++ case MPI_IOCSTATUS_BUSY:
++ case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
++ completion_code = MPT_SCANDV_BUSY;
+ break;
+
+- case MPI_EVENT_INTEGRATED_RAID: /* 0B */
++ case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
++ case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
++ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
++ if (pReply->Function == MPI_FUNCTION_CONFIG) {
++ completion_code = MPT_SCANDV_GOOD;
++ } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
++ pr = (MpiRaidActionReply_t *)reply;
++ if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
++ completion_code = MPT_SCANDV_GOOD;
++ else
++ completion_code = MPT_SCANDV_SOME_ERROR;
++ } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
++ completion_code = MPT_SCANDV_SENSE;
++ else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
++ if (req->u.scsireq.CDB[0] == INQUIRY)
++ completion_code = MPT_SCANDV_ISSUE_SENSE;
++ else
++ completion_code = MPT_SCANDV_DID_RESET;
++ }
++ else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
++ completion_code = MPT_SCANDV_DID_RESET;
++ else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
++ completion_code = MPT_SCANDV_DID_RESET;
++ else if (scsi_status == MPI_SCSI_STATUS_BUSY)
++ completion_code = MPT_SCANDV_BUSY;
++ else
++ completion_code = MPT_SCANDV_GOOD;
+ break;
+
+- case MPI_EVENT_NONE: /* 00 */
+- case MPI_EVENT_LOG_DATA: /* 01 */
+- case MPI_EVENT_STATE_CHANGE: /* 02 */
+- case MPI_EVENT_EVENT_CHANGE: /* 0A */
++ case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
++ if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
++ completion_code = MPT_SCANDV_DID_RESET;
++ else
++ completion_code = MPT_SCANDV_SOME_ERROR;
++ break;
+ default:
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
+- ioc->name, event));
++ completion_code = MPT_SCANDV_SOME_ERROR;
+ break;
+- }
+
+- return 1; /* currently means nothing really */
+-}
++ } /* switch(status) */
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
+- * Bus Scan and Domain Validation functionality ...
+- */
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ " completionCode set to %08xh\n", ioc->name, completion_code));
++ return completion_code;
++}
+
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
+- * mptscsih_scandv_complete - Scan and DV callback routine registered
+- * to Fustion MPT (base) driver.
+- *
++/**
++ * mptscsih_scandv_complete -
+ * @ioc: Pointer to MPT_ADAPTER structure
+- * @mf: Pointer to original MPT request frame
+- * @mr: Pointer to MPT reply frame (NULL if TurboReply)
++ * @req:
++ * @reply:
+ *
+- * This routine is called from mpt.c::mpt_interrupt() at the completion
+- * of any SCSI IO request.
+- * This routine is registered with the Fusion MPT (base) driver at driver
+- * load/init time via the mpt_register() API call.
+- *
+- * Returns 1 indicating alloc'd request frame ptr should be freed.
+- *
+- * Remark: Sets a completion code and (possibly) saves sense data
+- * in the IOC member localReply structure.
+- * Used ONLY for DV and other internal commands.
+- */
++ **/
+ int
+-mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
++mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
+ {
+- MPT_SCSI_HOST *hd;
+ SCSIIORequest_t *pReq;
+- int completionCode;
++ SCSIIOReply_t *pReply;
++ u8 cmd;
+ u16 req_idx;
++ u8 *sense_data;
++ int sz;
+
+- hd = shost_priv(ioc->sh);
+-
+- if ((mf == NULL) ||
+- (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+- printk(MYIOC_s_ERR_FMT
+- "ScanDvComplete, %s req frame ptr! (=%p)\n",
+- ioc->name, mf?"BAD":"NULL", (void *) mf);
+- goto wakeup;
+- }
+-
+- del_timer(&hd->timer);
+- req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+- mptscsih_set_scsi_lookup(ioc, req_idx, NULL);
+- pReq = (SCSIIORequest_t *) mf;
++ ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
++ ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
++ if (!reply)
++ goto out;
+
+- if (mf != hd->cmdPtr) {
+- printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
+- ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
++ pReply = (SCSIIOReply_t *) reply;
++ pReq = (SCSIIORequest_t *) req;
++ ioc->internal_cmds.completion_code =
++ mptscsih_get_completion_code(ioc, req, reply);
++ ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
++ memcpy(ioc->internal_cmds.reply, reply,
++ min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
++ cmd = reply->u.hdr.Function;
++ if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
++ (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
++ (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
++ req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
++ sense_data = ((u8 *)ioc->sense_buf_pool +
++ (req_idx * MPT_SENSE_BUFFER_ALLOC));
++ sz = min_t(int, pReq->SenseBufferLength,
++ MPT_SENSE_BUFFER_ALLOC);
++ memcpy(ioc->internal_cmds.sense, sense_data, sz);
+ }
+- hd->cmdPtr = NULL;
+-
+- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
+- ioc->name, mf, mr, req_idx));
+-
+- hd->pLocal = &hd->localReply;
+- hd->pLocal->scsiStatus = 0;
+-
+- /* If target struct exists, clear sense valid flag.
+- */
+- if (mr == NULL) {
+- completionCode = MPT_SCANDV_GOOD;
+- } else {
+- SCSIIOReply_t *pReply;
+- u16 status;
+- u8 scsi_status;
+-
+- pReply = (SCSIIOReply_t *) mr;
+-
+- status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+- scsi_status = pReply->SCSIStatus;
+-
+-
+- switch(status) {
+-
+- case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
+- completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
+- break;
+-
+- case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
+- case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
+- case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
+- case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
+- completionCode = MPT_SCANDV_DID_RESET;
+- break;
+-
+- case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
+- case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
+- case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
+- if (pReply->Function == MPI_FUNCTION_CONFIG) {
+- ConfigReply_t *pr = (ConfigReply_t *)mr;
+- completionCode = MPT_SCANDV_GOOD;
+- hd->pLocal->header.PageVersion = pr->Header.PageVersion;
+- hd->pLocal->header.PageLength = pr->Header.PageLength;
+- hd->pLocal->header.PageNumber = pr->Header.PageNumber;
+- hd->pLocal->header.PageType = pr->Header.PageType;
+-
+- } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
+- /* If the RAID Volume request is successful,
+- * return GOOD, else indicate that
+- * some type of error occurred.
+- */
+- MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
+- if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
+- completionCode = MPT_SCANDV_GOOD;
+- else
+- completionCode = MPT_SCANDV_SOME_ERROR;
+- memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
+-
+- } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+- u8 *sense_data;
+- int sz;
+-
+- /* save sense data in global structure
+- */
+- completionCode = MPT_SCANDV_SENSE;
+- hd->pLocal->scsiStatus = scsi_status;
+- sense_data = ((u8 *)ioc->sense_buf_pool +
+- (req_idx * MPT_SENSE_BUFFER_ALLOC));
+-
+- sz = min_t(int, pReq->SenseBufferLength,
+- SCSI_STD_SENSE_BYTES);
+- memcpy(hd->pLocal->sense, sense_data, sz);
+-
+- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n",
+- ioc->name, sense_data));
+- } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
+- if (pReq->CDB[0] == INQUIRY)
+- completionCode = MPT_SCANDV_ISSUE_SENSE;
+- else
+- completionCode = MPT_SCANDV_DID_RESET;
+- }
+- else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
+- completionCode = MPT_SCANDV_DID_RESET;
+- else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+- completionCode = MPT_SCANDV_DID_RESET;
+- else {
+- completionCode = MPT_SCANDV_GOOD;
+- hd->pLocal->scsiStatus = scsi_status;
+- }
+- break;
+-
+- case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
+- if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+- completionCode = MPT_SCANDV_DID_RESET;
+- else
+- completionCode = MPT_SCANDV_SOME_ERROR;
+- break;
+-
+- default:
+- completionCode = MPT_SCANDV_SOME_ERROR;
+- break;
+-
+- } /* switch(status) */
+-
+- } /* end of address reply case */
+-
+- hd->pLocal->completion = completionCode;
+-
+- /* MF and RF are freed in mpt_interrupt
+- */
+-wakeup:
+- /* Free Chain buffers (will never chain) in scan or dv */
+- //mptscsih_freeChainBuffers(ioc, req_idx);
+-
+- /*
+- * Wake up the original calling thread
+- */
+- hd->scandv_wait_done = 1;
+- wake_up(&hd->scandv_waitq);
+-
++ out:
++ if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
++ return 0;
++ ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
++ complete(&ioc->internal_cmds.done);
+ return 1;
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/* mptscsih_timer_expired - Call back for timer process.
+- * Used only for dv functionality.
+- * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+- *
+- */
+-void
+-mptscsih_timer_expired(unsigned long data)
+-{
+- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
+- MPT_ADAPTER *ioc = hd->ioc;
+-
+- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
+-
+- if (hd->cmdPtr) {
+- MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
+-
+- if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
+- /* Desire to issue a task management request here.
+- * TM requests MUST be single threaded.
+- * If old eh code and no TM current, issue request.
+- * If new eh code, do nothing. Wait for OS cmd timeout
+- * for bus reset.
+- */
+- } else {
+- /* Perform a FW reload */
+- if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
+- printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
+- }
+- }
+- } else {
+- /* This should NEVER happen */
+- printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
+- }
+-
+- /* No more processing.
+- * TM call will generate an interrupt for SCSI TM Management.
+- * The FW will reply to all outstanding commands, callback will finish cleanup.
+- * Hard reset clean-up will free all resources.
+- */
+- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
+-
+- return;
+-}
+-
+-
+-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mptscsih_do_cmd - Do internal command.
+ * @hd: MPT_SCSI_HOST pointer
+@@ -3019,28 +2944,33 @@ mptscsih_timer_expired(unsigned long dat
+ * 0 if good
+ *
+ * > 0 if command complete but some type of completion error.
+- */
+-static int
++ **/
++int
+ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
+ {
+ MPT_FRAME_HDR *mf;
+ SCSIIORequest_t *pScsiReq;
+- SCSIIORequest_t ReqCopy;
+ int my_idx, ii, dir;
+- int rc, cmdTimeout;
+- int in_isr;
++ int timeout;
+ char cmdLen;
+ char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+- char cmd = io->cmd;
+- MPT_ADAPTER *ioc = hd->ioc;
++ u8 cmd = io->cmd;
++ MPT_ADAPTER *ioc = hd->ioc;
++ int ret = 0;
++ unsigned long timeleft;
++ unsigned long flags;
+
+- in_isr = in_interrupt();
+- if (in_isr) {
+- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
+- ioc->name));
+- return -EPERM;
++ /* don't send internal command during diag reset */
++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
++ if (ioc->ioc_reset_in_progress) {
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: busy with host reset\n", ioc->name, __FUNCTION__));
++ return MPT_SCANDV_BUSY;
+ }
++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
++ mutex_lock(&ioc->internal_cmds.mutex);
+
+ /* Set command specific information
+ */
+@@ -3050,13 +2980,13 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER
+ dir = MPI_SCSIIO_CONTROL_READ;
+ CDB[0] = cmd;
+ CDB[4] = io->size;
+- cmdTimeout = 10;
++ timeout = 10;
+ break;
+
+ case TEST_UNIT_READY:
+ cmdLen = 6;
+ dir = MPI_SCSIIO_CONTROL_READ;
+- cmdTimeout = 10;
++ timeout = 10;
+ break;
+
+ case START_STOP:
+@@ -3064,7 +2994,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER
+ dir = MPI_SCSIIO_CONTROL_READ;
+ CDB[0] = cmd;
+ CDB[4] = 1; /*Spin up the disk */
+- cmdTimeout = 15;
++ timeout = 15;
+ break;
+
+ case REQUEST_SENSE:
+@@ -3072,7 +3002,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER
+ CDB[0] = cmd;
+ CDB[4] = io->size;
+ dir = MPI_SCSIIO_CONTROL_READ;
+- cmdTimeout = 10;
++ timeout = 10;
+ break;
+
+ case READ_BUFFER:
+@@ -3091,7 +3021,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER
+ CDB[6] = (io->size >> 16) & 0xFF;
+ CDB[7] = (io->size >> 8) & 0xFF;
+ CDB[8] = io->size & 0xFF;
+- cmdTimeout = 10;
++ timeout = 10;
+ break;
+
+ case WRITE_BUFFER:
+@@ -3106,21 +3036,21 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER
+ CDB[6] = (io->size >> 16) & 0xFF;
+ CDB[7] = (io->size >> 8) & 0xFF;
+ CDB[8] = io->size & 0xFF;
+- cmdTimeout = 10;
++ timeout = 10;
+ break;
+
+ case RESERVE:
+ cmdLen = 6;
+ dir = MPI_SCSIIO_CONTROL_READ;
+ CDB[0] = cmd;
+- cmdTimeout = 10;
++ timeout = 10;
+ break;
+
+ case RELEASE:
+ cmdLen = 6;
+ dir = MPI_SCSIIO_CONTROL_READ;
+ CDB[0] = cmd;
+- cmdTimeout = 10;
++ timeout = 10;
+ break;
+
+ case SYNCHRONIZE_CACHE:
+@@ -3128,20 +3058,42 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER
+ dir = MPI_SCSIIO_CONTROL_READ;
+ CDB[0] = cmd;
+ // CDB[1] = 0x02; /* set immediate bit */
+- cmdTimeout = 10;
++ timeout = 10;
++ break;
++
++ case REPORT_LUNS:
++ cmdLen = 12;
++ dir = MPI_SCSIIO_CONTROL_READ;
++ CDB[0] = cmd;
++ CDB[6] = (io->size >> 24) & 0xFF;
++ CDB[7] = (io->size >> 16) & 0xFF;
++ CDB[8] = (io->size >> 8) & 0xFF;
++ CDB[9] = io->size & 0xFF;
++ timeout = 10;
++ break;
++
++ case TRANSPORT_LAYER_RETRIES:
++ CDB[0] = cmd;
++ CDB[1] = 0x01;
++ cmdLen = 6;
++ dir = MPI_SCSIIO_CONTROL_READ;
++ timeout = 10;
+ break;
+
+ default:
+ /* Error Case */
+- return -EFAULT;
++ ret = -EFAULT;
++ goto out;
+ }
+
+ /* Get and Populate a free Frame
++ * MsgContext set in mpt_get_msg_frame call
+ */
+ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
+- ioc->name));
+- return -EBUSY;
++ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
++ ioc->name, __FUNCTION__));
++ ret = MPT_SCANDV_BUSY;
++ goto out;
+ }
+
+ pScsiReq = (SCSIIORequest_t *) mf;
+@@ -3164,14 +3116,10 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER
+
+ pScsiReq->CDBLength = cmdLen;
+ pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+-
+ pScsiReq->Reserved = 0;
+-
+- pScsiReq->MsgFlags = mpt_msg_flags();
+- /* MsgContext set in mpt_get_msg_fram call */
++ pScsiReq->MsgFlags = mpt_msg_flags(ioc);
+
+ int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
+-
+ if (io->flags & MPT_ICFLAG_TAGGED_CMD)
+ pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
+ else
+@@ -3179,74 +3127,61 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER
+
+ if (cmd == REQUEST_SENSE) {
+ pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
+- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
+- ioc->name, cmd));
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: Untagged! 0x%02x\n", ioc->name, __FUNCTION__, cmd));
+ }
+
+- for (ii=0; ii < 16; ii++)
+- pScsiReq->CDB[ii] = CDB[ii];
++ for (ii = 0; ii < 16; ii++)
++ pScsiReq->CDB[ii] = CDB[ii];
+
+ pScsiReq->DataLength = cpu_to_le32(io->size);
+ pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
+ + (my_idx * MPT_SENSE_BUFFER_ALLOC));
+
+- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
+- ioc->name, cmd, io->channel, io->id, io->lun));
+-
+- if (dir == MPI_SCSIIO_CONTROL_READ) {
+- mpt_add_sge((char *) &pScsiReq->SGL,
+- MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
+- io->data_dma);
+- } else {
+- mpt_add_sge((char *) &pScsiReq->SGL,
+- MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
+- io->data_dma);
+- }
+-
+- /* The ISR will free the request frame, but we need
+- * the information to initialize the target. Duplicate.
+- */
+- memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
+-
+- /* Issue this command after:
+- * finish init
+- * add timer
+- * Wait until the reply has been received
+- * ScsiScanDvCtx callback function will
+- * set hd->pLocal;
+- * set scandv_wait_done and call wake_up
+- */
+- hd->pLocal = NULL;
+- hd->timer.expires = jiffies + HZ*cmdTimeout;
+- hd->scandv_wait_done = 0;
+-
+- /* Save cmd pointer, for resource free if timeout or
+- * FW reload occurs
+- */
+- hd->cmdPtr = mf;
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
++ ioc->name, __FUNCTION__, cmd, io->channel, io->id, io->lun));
++
++ if (dir == MPI_SCSIIO_CONTROL_READ)
++ ioc->add_sge((char *) &pScsiReq->SGL,
++ MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
++ else
++ ioc->add_sge((char *) &pScsiReq->SGL,
++ MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
+
+- add_timer(&hd->timer);
++ INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
+ mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
+- wait_event(hd->scandv_waitq, hd->scandv_wait_done);
+-
+- if (hd->pLocal) {
+- rc = hd->pLocal->completion;
+- hd->pLocal->skip = 0;
+-
+- /* Always set fatal error codes in some cases.
+- */
+- if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
+- rc = -ENXIO;
+- else if (rc == MPT_SCANDV_SOME_ERROR)
+- rc = -rc;
+- } else {
+- rc = -EFAULT;
+- /* This should never happen. */
+- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
+- ioc->name));
++ timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
++ timeout*HZ);
++ if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ ret = MPT_SCANDV_DID_RESET;
++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
++ "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __FUNCTION__,
++ cmd));
++ if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
++ mpt_free_msg_frame(ioc, mf);
++ goto out;
++ }
++ if (!timeleft) {
++ if (!mptscsih_scandv_bus_reset(ioc))
++ goto out;
++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
++ ioc->name, __FUNCTION__);
++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
++ mpt_HardResetHandler(ioc, CAN_SLEEP);
++ mpt_free_msg_frame(ioc, mf);
++ }
++ goto out;
+ }
+
+- return rc;
++ ret = ioc->internal_cmds.completion_code;
++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
++ ioc->name, __FUNCTION__, ret));
++
++ out:
++ CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
++ mutex_unlock(&ioc->internal_cmds.mutex);
++ return ret;
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+@@ -3260,9 +3195,10 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER
+ *
+ */
+ static void
+-mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
++mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice)
+ {
+ INTERNAL_CMD iocmd;
++ MPT_ADAPTER *ioc = hd->ioc;
+
+ /* Ignore hidden raid components, this is handled when the command
+ * is sent to the volume
+@@ -3274,23 +3210,23 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST
+ !vdevice->configured_lun)
+ return;
+
+- /* Following parameters will not change
+- * in this routine.
+- */
++ memset(&iocmd, 0, sizeof(INTERNAL_CMD));
+ iocmd.cmd = SYNCHRONIZE_CACHE;
+- iocmd.flags = 0;
+ iocmd.physDiskNum = -1;
+ iocmd.data = NULL;
+ iocmd.data_dma = -1;
+- iocmd.size = 0;
+- iocmd.rsvd = iocmd.rsvd2 = 0;
+ iocmd.channel = vdevice->vtarget->channel;
+ iocmd.id = vdevice->vtarget->id;
+ iocmd.lun = vdevice->lun;
+
++ sdev_printk(KERN_INFO, sdev, MYIOC_s_FMT "SYNCHRONIZE_CACHE: fw_channel %d,"
++ " fw_id %d\n", ioc->name, vdevice->vtarget->channel, vdevice->vtarget->id);
+ mptscsih_do_cmd(hd, &iocmd);
+ }
+
++/*
++ * shost attributes
++ */
+ static ssize_t
+ mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+@@ -3464,13 +3400,44 @@ mptscsih_debug_level_store(struct device
+ return -EINVAL;
+
+ ioc->debug_level = val;
+- printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
+- ioc->name, ioc->debug_level);
++ printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n", ioc->name,
++ ioc->debug_level);
+ return strlen(buf);
+ }
+ static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
+ mptscsih_debug_level_show, mptscsih_debug_level_store);
+
++static ssize_t
++mptscsih_disable_hotplug_remove_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct Scsi_Host *host = class_to_shost(dev);
++ MPT_SCSI_HOST *hd = shost_priv(host);
++ MPT_ADAPTER *ioc = hd->ioc;
++
++ return snprintf(buf, PAGE_SIZE, "%02xh\n", ioc->disable_hotplug_remove);
++}
++static ssize_t
++mptscsih_disable_hotplug_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct Scsi_Host *host = class_to_shost(dev);
++ MPT_SCSI_HOST *hd = shost_priv(host);
++ MPT_ADAPTER *ioc = hd->ioc;
++ int val = 0;
++
++ if (sscanf(buf, "%x", &val) != 1)
++ return -EINVAL;
++
++ ioc->disable_hotplug_remove = val;
++ if (ioc->disable_hotplug_remove)
++ printk(MYIOC_s_INFO_FMT "disabling hotplug remove\n",
++ ioc->name);
++ else
++ printk(MYIOC_s_INFO_FMT "eanbling hotplug remove\n", ioc->name);
++ return strlen(buf);
++}
++static DEVICE_ATTR(disable_hotplug_remove, S_IRUGO | S_IWUSR,
++ mptscsih_disable_hotplug_remove_show, mptscsih_disable_hotplug_remove_store);
++
+ struct device_attribute *mptscsih_host_attrs[] = {
+ &dev_attr_version_fw,
+ &dev_attr_version_bios,
+@@ -3484,6 +3451,7 @@ struct device_attribute *mptscsih_host_a
+ &dev_attr_io_delay,
+ &dev_attr_device_delay,
+ &dev_attr_debug_level,
++ &dev_attr_disable_hotplug_remove,
+ NULL,
+ };
+ EXPORT_SYMBOL(mptscsih_host_attrs);
+@@ -3510,7 +3478,9 @@ EXPORT_SYMBOL(mptscsih_scandv_complete);
+ EXPORT_SYMBOL(mptscsih_event_process);
+ EXPORT_SYMBOL(mptscsih_ioc_reset);
+ EXPORT_SYMBOL(mptscsih_change_queue_depth);
+-EXPORT_SYMBOL(mptscsih_timer_expired);
+-EXPORT_SYMBOL(mptscsih_TMHandler);
+-
++EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
++EXPORT_SYMBOL(mptscsih_do_cmd);
++EXPORT_SYMBOL(mptscsih_quiesce_raid);
++EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
++EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+--- a/drivers/message/fusion/mptscsih.h
++++ b/drivers/message/fusion/mptscsih.h
+@@ -60,6 +60,7 @@
+ #define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008)
+ #define MPT_SCANDV_ISSUE_SENSE (0x00000010)
+ #define MPT_SCANDV_FALLBACK (0x00000020)
++#define MPT_SCANDV_BUSY (0x00000040)
+
+ #define MPT_SCANDV_MAX_RETRIES (10)
+
+@@ -71,6 +72,7 @@
+ #define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */
+ #define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */
+
++
+ #define MPT_SCSI_CMD_PER_DEV_HIGH 64
+ #define MPT_SCSI_CMD_PER_DEV_LOW 32
+
+@@ -84,9 +86,11 @@
+ #define MPTSCSIH_DOMAIN_VALIDATION 1
+ #define MPTSCSIH_MAX_WIDTH 1
+ #define MPTSCSIH_MIN_SYNC 0x08
++#define MPTSCSIH_QAS 1
+ #define MPTSCSIH_SAF_TE 0
+ #define MPTSCSIH_PT_CLEAR 0
+
++#define TRANSPORT_LAYER_RETRIES 0xC2
+ #endif
+
+ typedef struct _internal_cmd {
+@@ -112,7 +116,7 @@ extern int mptscsih_resume(struct pci_de
+ extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func);
+ extern const char * mptscsih_info(struct Scsi_Host *SChost);
+ extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *));
+-extern void mptscsih_slave_destroy(struct scsi_device *device);
++extern void mptscsih_slave_destroy(struct scsi_device *sdev);
+ extern int mptscsih_slave_configure(struct scsi_device *device);
+ extern int mptscsih_abort(struct scsi_cmnd * SCpnt);
+ extern int mptscsih_dev_reset(struct scsi_cmnd * SCpnt);
+@@ -125,8 +129,11 @@ extern int mptscsih_scandv_complete(MPT_
+ extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+ extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
+ extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
+-extern void mptscsih_timer_expired(unsigned long data);
+-extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
++extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
+ extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
+ extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
++extern int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
+ extern struct device_attribute *mptscsih_host_attrs[];
++extern int mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id);
++extern struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
++extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
+--- a/drivers/message/fusion/mptspi.c
++++ b/drivers/message/fusion/mptspi.c
+@@ -53,8 +53,10 @@
+ #include <linux/delay.h> /* for mdelay */
+ #include <linux/interrupt.h> /* needed for in_interrupt() proto */
+ #include <linux/reboot.h> /* notifier code */
++#include <linux/sched.h>
+ #include <linux/workqueue.h>
+ #include <linux/raid_class.h>
++#include <linux/pci.h>
+
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -83,6 +85,10 @@ static int mpt_saf_te = MPTSCSIH_SAF_TE;
+ module_param(mpt_saf_te, int, 0);
+ MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0)");
+
++static int mpt_qas = MPTSCSIH_QAS;
++module_param(mpt_qas, int, 1);
++MODULE_PARM_DESC(mpt_qas, " Quick Arbitration and Selection (QAS) enabled=1, disabled=0 (default=MPTSCSIH_QAS=1)");
++
+ static void mptspi_write_offset(struct scsi_target *, int);
+ static void mptspi_write_width(struct scsi_target *, int);
+ static int mptspi_write_spi_device_pg1(struct scsi_target *,
+@@ -95,12 +101,12 @@ static u8 mptspiTaskCtx = MPT_MAX_PROTOC
+ static u8 mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
+
+ /**
+- * mptspi_setTargetNegoParms - Update the target negotiation parameters
++ * mptspi_setTargetNegoParms - Update the target negotiation parameters
+ * @hd: Pointer to a SCSI Host Structure
+ * @target: per target private data
+ * @sdev: SCSI device
+ *
+- * Update the target negotiation parameters based on the the Inquiry
++ * Update the target negotiation parameters based on the the Inquiry
+ * data, adapter capabilities, and NVRAM settings.
+ **/
+ static void
+@@ -131,7 +137,7 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST
+ if (scsi_device_sync(sdev)) {
+ factor = pspi_data->minSyncFactor;
+ if (!scsi_device_dt(sdev))
+- factor = MPT_ULTRA2;
++ factor = MPT_ULTRA2;
+ else {
+ if (!scsi_device_ius(sdev) &&
+ !scsi_device_qas(sdev))
+@@ -209,6 +215,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST
+ target->maxOffset = offset;
+ target->maxWidth = width;
+
++ spi_min_period(scsi_target(sdev)) = factor;
++ spi_max_offset(scsi_target(sdev)) = offset;
++ spi_max_width(scsi_target(sdev)) = width;
++
+ target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
+
+ /* Disable unused features.
+@@ -230,7 +240,7 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST
+ */
+
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
++ "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
+ }
+ }
+
+@@ -262,7 +272,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd,
+ */
+ if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
+- "writeIOCPage4 : no msg frames!\n",ioc->name));
++ "writeIOCPage4 : no msg frames!\n", ioc->name));
+ return -EAGAIN;
+ }
+
+@@ -300,11 +310,11 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd,
+ flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
+ (IOCPage4Ptr->Header.PageLength + ii) * 4;
+
+- mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
++ ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
+- ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
++ ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
+
+ mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
+
+@@ -371,7 +381,7 @@ mptspi_initTarget(MPT_SCSI_HOST *hd, Vir
+ * non-zero = true
+ * zero = false
+ *
+- */
++ **/
+ static int
+ mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
+ {
+@@ -399,12 +409,11 @@ static int mptspi_target_alloc(struct sc
+ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ struct _MPT_SCSI_HOST *hd = shost_priv(shost);
+ VirtTarget *vtarget;
+- MPT_ADAPTER *ioc;
++ MPT_ADAPTER *ioc = hd->ioc;
+
+ if (hd == NULL)
+ return -ENODEV;
+
+- ioc = hd->ioc;
+ vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
+ if (!vtarget)
+ return -ENOMEM;
+@@ -471,9 +480,12 @@ mptspi_target_destroy(struct scsi_target
+ static void
+ mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
+ {
+- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Requested = 0x%08x"
++ if (!(hd->ioc->debug_level & MPT_DEBUG_DV))
++ return;
++
++ starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT "Wrote = 0x%08x"
+ " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
+- hd->ioc->name, starget->id, ii,
++ hd->ioc->name, ii,
+ ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
+ ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
+ ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
+@@ -483,7 +495,7 @@ mptspi_print_write_nego(struct _MPT_SCSI
+ ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
+- ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
++ ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "");
+ }
+
+ /**
+@@ -496,9 +508,12 @@ mptspi_print_write_nego(struct _MPT_SCSI
+ static void
+ mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
+ {
+- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Read = 0x%08x"
++ if (!(hd->ioc->debug_level & MPT_DEBUG_DV))
++ return;
++
++ starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT "Read = 0x%08x"
+ " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
+- hd->ioc->name, starget->id, ii,
++ hd->ioc->name, ii,
+ ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
+ ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
+ ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
+@@ -508,7 +523,7 @@ mptspi_print_read_nego(struct _MPT_SCSI_
+ ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
+- ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
++ ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "");
+ }
+
+ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
+@@ -557,9 +572,11 @@ static int mptspi_read_spi_device_pg0(st
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.dir = 0;
+ cfg.pageAddr = starget->id;
++ cfg.timeout = 60;
+
+ if (mpt_config(ioc, &cfg)) {
+- starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
++ starget_printk(KERN_ERR, starget,
++ MYIOC_s_FMT "mpt_config failed\n", ioc->name);
+ goto out_free;
+ }
+ err = 0;
+@@ -614,64 +631,11 @@ static void mptspi_read_parameters(struc
+ spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0;
+ }
+
+-static int
+-mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
+-{
+- MpiRaidActionRequest_t *pReq;
+- MPT_FRAME_HDR *mf;
+- MPT_ADAPTER *ioc = hd->ioc;
+-
+- /* Get and Populate a free Frame
+- */
+- if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+- ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
+- ioc->name));
+- return -EAGAIN;
+- }
+- pReq = (MpiRaidActionRequest_t *)mf;
+- if (quiesce)
+- pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO;
+- else
+- pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO;
+- pReq->Reserved1 = 0;
+- pReq->ChainOffset = 0;
+- pReq->Function = MPI_FUNCTION_RAID_ACTION;
+- pReq->VolumeID = id;
+- pReq->VolumeBus = channel;
+- pReq->PhysDiskNum = 0;
+- pReq->MsgFlags = 0;
+- pReq->Reserved2 = 0;
+- pReq->ActionDataWord = 0; /* Reserved for this action */
+-
+- mpt_add_sge((char *)&pReq->ActionDataSGE,
+- MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
+-
+- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
+- ioc->name, pReq->Action, channel, id));
+-
+- hd->pLocal = NULL;
+- hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
+- hd->scandv_wait_done = 0;
+-
+- /* Save cmd pointer, for resource free if timeout or
+- * FW reload occurs
+- */
+- hd->cmdPtr = mf;
+-
+- add_timer(&hd->timer);
+- mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
+- wait_event(hd->scandv_waitq, hd->scandv_wait_done);
+-
+- if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0))
+- return -1;
+-
+- return 0;
+-}
+-
+ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
+ struct scsi_device *sdev)
+ {
+ VirtTarget *vtarget = scsi_target(sdev)->hostdata;
++ struct scsi_target *starget = scsi_target(sdev);
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ /* no DV on RAID devices */
+@@ -679,11 +643,20 @@ static void mptspi_dv_device(struct _MPT
+ mptspi_is_raid(hd, sdev->id))
+ return;
+
++ if (ioc->debug_level & MPT_DEBUG_DV)
++ starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT
++ "sdtr=%d, wdtr=%d, ppr=%d, min_period=0x%02x, "
++ "max_offset=0x%02x, max_width=%d, nego_flags=0x%02x, "
++ "tflags=0x%02x\n", ioc->name, sdev->sdtr, sdev->wdtr,
++ sdev->ppr, spi_min_period(starget),
++ spi_max_offset(starget), spi_max_width(starget),
++ vtarget->negoFlags, vtarget->tflags);
++
+ /* If this is a piece of a RAID, then quiesce first */
+ if (sdev->channel == 1 &&
+ mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
+- starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
+- "Integrated RAID quiesce failed\n", ioc->name);
++ starget_printk(KERN_ERR, scsi_target(sdev),
++ MYIOC_s_FMT "Integrated RAID quiesce failed\n", ioc->name);
+ return;
+ }
+
+@@ -693,8 +666,8 @@ static void mptspi_dv_device(struct _MPT
+
+ if (sdev->channel == 1 &&
+ mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
+- starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
+- "Integrated RAID resume failed\n", ioc->name);
++ starget_printk(KERN_ERR, scsi_target(sdev),
++ MYIOC_s_FMT "Integrated RAID resume failed\n", ioc->name);
+
+ mptspi_read_parameters(sdev->sdev_target);
+ spi_display_xfer_agreement(sdev->sdev_target);
+@@ -716,7 +689,7 @@ static int mptspi_slave_alloc(struct scs
+ vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+ if (!vdevice) {
+ printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
+- ioc->name, sizeof(VirtDevice));
++ ioc->name, sizeof(VirtDevice));
+ return -ENOMEM;
+ }
+
+@@ -738,21 +711,13 @@ static int mptspi_slave_configure(struct
+ {
+ struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host);
+ VirtTarget *vtarget = scsi_target(sdev)->hostdata;
+- int ret;
++ int ret;
+
+ mptspi_initTarget(hd, vtarget, sdev);
+-
+ ret = mptscsih_slave_configure(sdev);
+-
+ if (ret)
+ return ret;
+
+- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x"
+- " max_offset=0x%02x max_width=%d\n", hd->ioc->name,
+- sdev->id, spi_min_period(scsi_target(sdev)),
+- spi_max_offset(scsi_target(sdev)),
+- spi_max_width(scsi_target(sdev))));
+-
+ if ((sdev->channel == 1 ||
+ !(mptspi_is_raid(hd, sdev->id))) &&
+ !spi_initial_dv(sdev->sdev_target))
+@@ -857,8 +822,8 @@ static int mptspi_write_spi_device_pg1(s
+
+ pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL);
+ if (pg1 == NULL) {
+- starget_printk(KERN_ERR, starget, MYIOC_s_FMT
+- "dma_alloc_coherent for parameters failed\n", ioc->name);
++ starget_printk(KERN_ERR, starget,
++ MYIOC_s_FMT "dma_alloc_coherent for parameters failed\n", ioc->name);
+ return -EINVAL;
+ }
+
+@@ -887,8 +852,8 @@ static int mptspi_write_spi_device_pg1(s
+ mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
+
+ if (mpt_config(ioc, &cfg)) {
+- starget_printk(KERN_ERR, starget, MYIOC_s_FMT
+- "mpt_config failed\n", ioc->name);
++ starget_printk(KERN_ERR, starget,
++ MYIOC_s_FMT "mpt_config failed\n", ioc->name);
+ goto out_free;
+ }
+ err = 0;
+@@ -963,14 +928,15 @@ static void mptspi_write_dt(struct scsi_
+ if (spi_period(starget) == -1)
+ mptspi_read_parameters(starget);
+
+- if (!dt && spi_period(starget) < 10)
+- spi_period(starget) = 10;
++ if (!dt) {
++ spi_qas(starget) = 0;
++ spi_iu(starget) = 0;
++ }
+
+ spi_dt(starget) = dt;
+
+ nego = mptspi_getRP(starget);
+
+-
+ pg1.RequestedParameters = cpu_to_le32(nego);
+ pg1.Reserved = 0;
+ pg1.Configuration = 0;
+@@ -986,9 +952,6 @@ static void mptspi_write_iu(struct scsi_
+ if (spi_period(starget) == -1)
+ mptspi_read_parameters(starget);
+
+- if (!iu && spi_period(starget) < 9)
+- spi_period(starget) = 9;
+-
+ spi_iu(starget) = iu;
+
+ nego = mptspi_getRP(starget);
+@@ -1030,9 +993,11 @@ static void mptspi_write_qas(struct scsi
+ struct _MPT_SCSI_HOST *hd = shost_priv(shost);
+ VirtTarget *vtarget = starget->hostdata;
+ u32 nego;
++ MPT_ADAPTER *ioc = hd->ioc;
+
+- if ((vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) ||
+- hd->ioc->spi_data.noQas)
++ if (!mpt_qas ||
++ (vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) ||
++ ioc->spi_data.noQas)
+ spi_qas(starget) = 0;
+ else
+ spi_qas(starget) = qas;
+@@ -1053,8 +1018,8 @@ static void mptspi_write_width(struct sc
+
+ if (!width) {
+ spi_dt(starget) = 0;
+- if (spi_period(starget) < 10)
+- spi_period(starget) = 10;
++ spi_qas(starget) = 0;
++ spi_iu(starget) = 0;
+ }
+
+ spi_width(starget) = width;
+@@ -1074,7 +1039,8 @@ struct work_queue_wrapper {
+ int disk;
+ };
+
+-static void mpt_work_wrapper(struct work_struct *work)
++static void
++mpt_work_wrapper(struct work_struct *work)
+ {
+ struct work_queue_wrapper *wqw =
+ container_of(work, struct work_queue_wrapper, work);
+@@ -1105,12 +1071,12 @@ static void mpt_work_wrapper(struct work
+ if(vtarget->id != disk)
+ continue;
+
+- starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT
+- "Integrated RAID requests DV of new device\n", ioc->name);
++ starget_printk(KERN_INFO, vtarget->starget,
++ MYIOC_s_FMT "Integrated RAID requests DV of new device\n", ioc->name);
+ mptspi_dv_device(hd, sdev);
+ }
+- shost_printk(KERN_INFO, shost, MYIOC_s_FMT
+- "Integrated RAID detects new device %d\n", ioc->name, disk);
++ shost_printk(KERN_INFO, shost,
++ MYIOC_s_FMT "Integrated RAID detects new device %d\n", ioc->name, disk);
+ scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, 1);
+ }
+
+@@ -1121,8 +1087,8 @@ static void mpt_dv_raid(struct _MPT_SCSI
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ if (!wqw) {
+- shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT
+- "Failed to act on RAID event for physical disk %d\n",
++ shost_printk(KERN_ERR, ioc->sh,
++ MYIOC_s_FMT "Failed to act on RAID event for physical disk %d\n",
+ ioc->name, disk);
+ return;
+ }
+@@ -1213,9 +1179,9 @@ static struct pci_device_id mptspi_pci_t
+ MODULE_DEVICE_TABLE(pci, mptspi_pci_table);
+
+
+-/*
++/**
+ * renegotiate for a given target
+- */
++ **/
+ static void
+ mptspi_dv_renegotiate_work(struct work_struct *work)
+ {
+@@ -1261,32 +1227,33 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_H
+ schedule_work(&wqw->work);
+ }
+
+-/*
++/**
+ * spi module reset handler
+- */
++ **/
+ static int
+ mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+ {
++ struct _MPT_SCSI_HOST *hd = NULL;
+ int rc;
+
+ rc = mptscsih_ioc_reset(ioc, reset_phase);
++ if ((ioc->bus_type != SPI) || (!rc))
++ goto out;
+
+- /* only try to do a renegotiation if we're properly set up
+- * if we get an ioc fault on bringup, ioc->sh will be NULL */
+- if (reset_phase == MPT_IOC_POST_RESET &&
+- ioc->sh) {
+- struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
++ hd = shost_priv(ioc->sh);
++ if (!hd->ioc)
++ goto out;
+
++ if (ioc->active && reset_phase == MPT_IOC_POST_RESET)
+ mptspi_dv_renegotiate(hd);
+- }
+-
++ out:
+ return rc;
+ }
+
+ #ifdef CONFIG_PM
+-/*
++/**
+ * spi module resume handler
+- */
++ **/
+ static int
+ mptspi_resume(struct pci_dev *pdev)
+ {
+@@ -1303,13 +1270,13 @@ mptspi_resume(struct pci_dev *pdev)
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+-/*
++/**
+ * mptspi_probe - Installs scsi devices per bus.
+ * @pdev: Pointer to pci_dev structure
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+- */
++ **/
+ static int
+ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ {
+@@ -1423,19 +1390,18 @@ mptspi_probe(struct pci_dev *pdev, const
+ * A slightly different algorithm is required for
+ * 64bit SGEs.
+ */
+- scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+- if (sizeof(dma_addr_t) == sizeof(u64)) {
++ scale = ioc->req_sz/ioc->SGE_size;
++ if (ioc->sg_addr_size == sizeof(u64)) {
+ numSGE = (scale - 1) *
+ (ioc->facts.MaxChainDepth-1) + scale +
+- (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
+- sizeof(u32));
++ (ioc->req_sz - 60) / ioc->SGE_size;
+ } else {
+ numSGE = 1 + (scale - 1) *
+ (ioc->facts.MaxChainDepth-1) + scale +
+- (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
+- sizeof(u32));
++ (ioc->req_sz - 64) / ioc->SGE_size;
+ }
+
++
+ if (numSGE < sh->sg_tablesize) {
+ /* Reset this value */
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+@@ -1444,11 +1410,11 @@ mptspi_probe(struct pci_dev *pdev, const
+ sh->sg_tablesize = numSGE;
+ }
+
+- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+-
+ hd = shost_priv(sh);
+ hd->ioc = ioc;
+
++ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
++
+ /* SCSI needs scsi_cmnd lookup table!
+ * (with size equal to req_depth*PtrSz!)
+ */
+@@ -1462,39 +1428,12 @@ mptspi_probe(struct pci_dev *pdev, const
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
+ ioc->name, ioc->ScsiLookup));
+
+- /* Clear the TM flags
+- */
+- hd->tmPending = 0;
+- hd->tmState = TM_STATE_NONE;
+- hd->resetPending = 0;
+- hd->abortSCpnt = NULL;
+-
+- /* Clear the pointer used to store
+- * single-threaded commands, i.e., those
+- * issued during a bus scan, dv and
+- * configuration pages.
+- */
+- hd->cmdPtr = NULL;
+-
+- /* Initialize this SCSI Hosts' timers
+- * To use, set the timer expires field
+- * and add_timer
+- */
+- init_timer(&hd->timer);
+- hd->timer.data = (unsigned long) hd;
+- hd->timer.function = mptscsih_timer_expired;
+-
++ ioc->sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
+ ioc->spi_data.Saf_Te = mpt_saf_te;
+-
+- hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+- "saf_te %x\n",
+- ioc->name,
+- mpt_saf_te));
+- ioc->spi_data.noQas = 0;
++ "saf_te %x\n", ioc->name, mpt_saf_te));
++ ioc->spi_data.noQas = mpt_qas ? 0 : MPT_TARGET_NO_NEGO_QAS;
+
+- init_waitqueue_head(&hd->scandv_waitq);
+- hd->scandv_wait_done = 0;
+ hd->last_queue_full = 0;
+ hd->spi_pending = 0;
+
+@@ -1514,7 +1453,7 @@ mptspi_probe(struct pci_dev *pdev, const
+ * issue internal bus reset
+ */
+ if (ioc->spi_data.bus_reset)
+- mptscsih_TMHandler(hd,
++ mptscsih_IssueTaskMgmt(hd,
+ MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+ 0, 0, 0, 0, 5);
+
+@@ -1544,7 +1483,7 @@ static struct pci_driver mptspi_driver =
+ * mptspi_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
+ *
+ * Returns 0 for success, non-zero for failure.
+- */
++ **/
+ static int __init
+ mptspi_init(void)
+ {
+@@ -1574,7 +1513,8 @@ mptspi_init(void)
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /**
+ * mptspi_exit - Unregisters MPT adapter(s)
+- */
++ *
++ **/
+ static void __exit
+ mptspi_exit(void)
+ {
+@@ -1582,7 +1522,6 @@ mptspi_exit(void)
+
+ mpt_reset_deregister(mptspiDoneCtx);
+ mpt_event_deregister(mptspiDoneCtx);
+-
+ mpt_deregister(mptspiInternalCtx);
+ mpt_deregister(mptspiTaskCtx);
+ mpt_deregister(mptspiDoneCtx);
+--- /dev/null
++++ b/drivers/message/fusion/rejected_ioctls/diag_buffer.c
+@@ -0,0 +1,667 @@
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++/* REGISTER DIAG BUFFER Routine.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -EBUSY if previous command timout and IOC reset is not complete.
++ * -ENODEV if no such device/adapter
++ * -ETIME if timer expires
++ * -ENOMEM if memory allocation error
++ */
++static int
++mptctl_register_diag_buffer (unsigned long arg)
++{
++ mpt_diag_register_t __user *uarg = (void __user *) arg;
++ mpt_diag_register_t karg;
++ MPT_ADAPTER *ioc;
++ int iocnum, rc, ii;
++ void * request_data;
++ dma_addr_t request_data_dma;
++ u32 request_data_sz;
++ MPT_FRAME_HDR *mf;
++ DiagBufferPostRequest_t *diag_buffer_post_request;
++ DiagBufferPostReply_t *diag_buffer_post_reply;
++ u32 tmp;
++ u8 buffer_type;
++ unsigned long timeleft;
++
++ rc = 0;
++ if (copy_from_user(&karg, uarg, sizeof(mpt_diag_register_t))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to read in mpt_diag_register_t struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
++ (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name,
++ __FUNCTION__));
++ buffer_type = karg.data.BufferType;
++ if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) {
++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for "
++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
++ return -ENODEV;
++ }
++
++ if (ioc->DiagBuffer_Status[buffer_type] &
++ MPT_DIAG_BUFFER_IS_REGISTERED) {
++ printk(MYIOC_s_DEBUG_FMT "%s: already has a Registered "
++ "buffer for buffer_type=%x\n", ioc->name, __FUNCTION__,
++ buffer_type);
++ return -EFAULT;
++ }
++
++ /* Get a free request frame and save the message context.
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
++ return -EAGAIN;
++
++ request_data = ioc->DiagBuffer[buffer_type];
++ request_data_sz = karg.data.RequestedBufferSize;
++
++ if (request_data) {
++ request_data_dma = ioc->DiagBuffer_dma[buffer_type];
++ if (request_data_sz != ioc->DiagBuffer_sz[buffer_type]) {
++ pci_free_consistent(ioc->pcidev,
++ ioc->DiagBuffer_sz[buffer_type],
++ request_data, request_data_dma);
++ request_data = NULL;
++ }
++ }
++
++ if (request_data == NULL) {
++ ioc->DiagBuffer_sz[buffer_type] = 0;
++ ioc->DiagBuffer_dma[buffer_type] = 0;
++ ioc->DataSize[buffer_type] = 0;
++ request_data = pci_alloc_consistent(
++ ioc->pcidev, request_data_sz, &request_data_dma);
++ if (request_data == NULL) {
++ printk(MYIOC_s_DEBUG_FMT "%s: pci_alloc_consistent"
++ " FAILED, (request_sz=%d)\n", ioc->name,
++ __FUNCTION__, request_data_sz);
++ mpt_free_msg_frame(ioc, mf);
++ return -EAGAIN;
++ }
++ ioc->DiagBuffer[buffer_type] = request_data;
++ ioc->DiagBuffer_sz[buffer_type] = request_data_sz;
++ ioc->DiagBuffer_dma[buffer_type] = request_data_dma;
++ }
++
++ ioc->DiagBuffer_Status[buffer_type] = 0;
++ diag_buffer_post_request = (DiagBufferPostRequest_t *)mf;
++ diag_buffer_post_request->Function = MPI_FUNCTION_DIAG_BUFFER_POST;
++ diag_buffer_post_request->ChainOffset = 0;
++ diag_buffer_post_request->BufferType = karg.data.BufferType;
++ diag_buffer_post_request->TraceLevel = ioc->TraceLevel[buffer_type] =
++ karg.data.TraceLevel;
++ diag_buffer_post_request->MsgFlags = 0;
++ diag_buffer_post_request->Reserved1 = 0;
++ diag_buffer_post_request->Reserved2 = 0;
++ diag_buffer_post_request->Reserved3 = 0;
++ diag_buffer_post_request->BufferAddress.High = 0;
++ if (buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED)
++ ioc->ExtendedType[buffer_type] = karg.data.ExtendedType;
++ else
++ ioc->ExtendedType[buffer_type] = 0;
++ diag_buffer_post_request->ExtendedType =
++ cpu_to_le32(ioc->ExtendedType[buffer_type]);
++ ioc->UniqueId[buffer_type] = karg.data.UniqueId;
++ diag_buffer_post_request->BufferLength = cpu_to_le32(request_data_sz);
++ for (ii = 0; ii < 4; ii++) {
++ ioc->ProductSpecific[buffer_type][ii] =
++ karg.data.ProductSpecific[ii];
++ diag_buffer_post_request->ProductSpecific[ii] =
++ cpu_to_le32(ioc->ProductSpecific[buffer_type][ii]);
++ }
++
++ tmp = request_data_dma & 0xFFFFFFFF;
++ diag_buffer_post_request->BufferAddress.Low = cpu_to_le32(tmp);
++ if (ioc->sg_addr_size == sizeof(u64)) {
++ tmp = (u32)((u64)request_data_dma >> 32);
++ diag_buffer_post_request->BufferAddress.High = cpu_to_le32(tmp);
++ }
++
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
++ diag_buffer_post_request->MsgContext);
++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
++ mpt_put_msg_frame(mptctl_id, ioc, mf);
++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
++ MPT_IOCTL_DEFAULT_TIMEOUT*HZ);
++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ rc = -ETIME;
++ printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name,
++ __FUNCTION__);
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
++ mpt_free_msg_frame(ioc, mf);
++ goto out;
++ }
++ if (!timeleft)
++ mptctl_timeout_expired(ioc, mf);
++ goto out;
++ }
++
++ /* process the completed Reply Message Frame */
++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n",
++ ioc->name, __FUNCTION__, ioc->ioctl_cmds.status));
++ rc = -EFAULT;
++ goto out;
++ }
++
++ diag_buffer_post_reply = (DiagBufferPostReply_t *)ioc->ioctl_cmds.reply;
++ if (le16_to_cpu(diag_buffer_post_reply->IOCStatus) ==
++ MPI_IOCSTATUS_SUCCESS) {
++ if (diag_buffer_post_reply->MsgLength > 5)
++ ioc->DataSize[buffer_type] =
++ le32_to_cpu(diag_buffer_post_reply->TransferLength);
++ ioc->DiagBuffer_Status[buffer_type] |=
++ MPT_DIAG_BUFFER_IS_REGISTERED;
++ } else {
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x "
++ "IOCLogInfo=%x\n", ioc->name, __FUNCTION__,
++ diag_buffer_post_reply->IOCStatus,
++ diag_buffer_post_reply->IOCLogInfo));
++ rc = -EFAULT;
++ }
++
++ out:
++
++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
++ if (rc)
++ pci_free_consistent(ioc->pcidev, request_data_sz,
++ request_data, request_data_dma);
++ return rc;
++}
++
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++/* RELEASE DIAG BUFFER Routine.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -EBUSY if previous command timout and IOC reset is not complete.
++ * -ENODEV if no such device/adapter
++ * -ETIME if timer expires
++ * -ENOMEM if memory allocation error
++ */
++static int
++mptctl_release_diag_buffer (unsigned long arg)
++{
++ mpt_diag_release_t __user *uarg = (void __user *) arg;
++ mpt_diag_release_t karg;
++ MPT_ADAPTER *ioc;
++ void * request_data;
++ int iocnum, rc;
++ MPT_FRAME_HDR *mf;
++ DiagReleaseRequest_t *diag_release;
++ DiagReleaseReply_t *diag_release_reply;
++ u8 buffer_type;
++ unsigned long timeleft;
++
++ rc = 0;
++ if (copy_from_user(&karg, uarg, sizeof(mpt_diag_release_t))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to read in mpt_diag_release_t struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
++ (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name,
++ __FUNCTION__));
++ buffer_type = karg.data.UniqueId & 0x000000ff;
++ if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) {
++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for "
++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
++ return -ENODEV;
++ }
++
++ if ((ioc->DiagBuffer_Status[buffer_type] &
++ MPT_DIAG_BUFFER_IS_REGISTERED) == 0 ) {
++ printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not "
++ "registered\n", ioc->name, __FUNCTION__, buffer_type);
++ return -EFAULT;
++ }
++
++ if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) {
++ printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n",
++ ioc->name, __FUNCTION__, karg.data.UniqueId);
++ return -EFAULT;
++ }
++
++ if (ioc->DiagBuffer_Status[buffer_type] & MPT_DIAG_BUFFER_IS_RELEASED) {
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x "
++ "is already released\n", ioc->name, __FUNCTION__,
++ buffer_type));
++ return rc;
++ }
++
++ request_data = ioc->DiagBuffer[buffer_type];
++
++ if (request_data == NULL) {
++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for "
++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
++ return -ENODEV;
++ }
++
++ /* Get a free request frame and save the message context.
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
++ return -EAGAIN;
++
++ diag_release = (DiagReleaseRequest_t *)mf;
++ diag_release->Function = MPI_FUNCTION_DIAG_RELEASE;
++ diag_release->BufferType = buffer_type;
++ diag_release->ChainOffset = 0;
++ diag_release->Reserved1 = 0;
++ diag_release->Reserved2 = 0;
++ diag_release->Reserved3 = 0;
++ diag_release->MsgFlags = 0;
++
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
++ diag_release->MsgContext);
++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
++ mpt_put_msg_frame(mptctl_id, ioc, mf);
++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
++ MPT_IOCTL_DEFAULT_TIMEOUT*HZ);
++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ rc = -ETIME;
++ printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name,
++ __FUNCTION__);
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
++ mpt_free_msg_frame(ioc, mf);
++ goto out;
++ }
++ if (!timeleft)
++ mptctl_timeout_expired(ioc, mf);
++ goto out;
++ }
++
++ /* process the completed Reply Message Frame */
++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n",
++ ioc->name, __FUNCTION__, ioc->ioctl_cmds.status));
++ rc = -EFAULT;
++ goto out;
++ }
++
++ diag_release_reply = (DiagReleaseReply_t *)ioc->ioctl_cmds.reply;
++ if (le16_to_cpu(diag_release_reply->IOCStatus) !=
++ MPI_IOCSTATUS_SUCCESS) {
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x "
++ "IOCLogInfo=%x\n",
++ ioc->name, __FUNCTION__, diag_release_reply->IOCStatus,
++ diag_release_reply->IOCLogInfo));
++ rc = -EFAULT;
++ } else
++ ioc->DiagBuffer_Status[buffer_type] |=
++ MPT_DIAG_BUFFER_IS_RELEASED;
++
++ out:
++
++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
++ return rc;
++}
++
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++/* UNREGISTER DIAG BUFFER Routine.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -EBUSY if previous command timout and IOC reset is not complete.
++ * -ENODEV if no such device/adapter
++ * -ETIME if timer expires
++ * -ENOMEM if memory allocation error
++ */
++static int
++mptctl_unregister_diag_buffer (unsigned long arg)
++{
++ mpt_diag_unregister_t __user *uarg = (void __user *) arg;
++ mpt_diag_unregister_t karg;
++ MPT_ADAPTER *ioc;
++ int iocnum;
++ void * request_data;
++ dma_addr_t request_data_dma;
++ u32 request_data_sz;
++ u8 buffer_type;
++
++ if (copy_from_user(&karg, uarg, sizeof(mpt_diag_unregister_t))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to read in mpt_diag_unregister_t struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
++ (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name,
++ __FUNCTION__));
++ buffer_type = karg.data.UniqueId & 0x000000ff;
++ if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) {
++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for "
++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
++ return -ENODEV;
++ }
++
++ if ((ioc->DiagBuffer_Status[buffer_type] &
++ MPT_DIAG_BUFFER_IS_REGISTERED) == 0) {
++ printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not "
++ "registered\n", ioc->name, __FUNCTION__, buffer_type);
++ return -EFAULT;
++ }
++ if ((ioc->DiagBuffer_Status[buffer_type] &
++ MPT_DIAG_BUFFER_IS_RELEASED) == 0) {
++ printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x has not been "
++ "released\n", ioc->name, __FUNCTION__, buffer_type);
++ return -EFAULT;
++ }
++
++ if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) {
++ printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n",
++ ioc->name, __FUNCTION__, karg.data.UniqueId);
++ return -EFAULT;
++ }
++
++ request_data = ioc->DiagBuffer[buffer_type];
++ if (!request_data) {
++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for "
++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
++ return -ENODEV;
++ }
++
++ request_data_sz = ioc->DiagBuffer_sz[buffer_type];
++ request_data_dma = ioc->DiagBuffer_dma[buffer_type];
++ pci_free_consistent(ioc->pcidev, request_data_sz,
++ request_data, request_data_dma);
++ ioc->DiagBuffer[buffer_type] = NULL;
++ ioc->DiagBuffer_Status[buffer_type] = 0;
++ return 0;
++}
++
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++/* QUERY DIAG BUFFER Routine.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -EBUSY if previous command timout and IOC reset is not complete.
++ * -ENODEV if no such device/adapter
++ * -ETIME if timer expires
++ * -ENOMEM if memory allocation error
++ */
++static int
++mptctl_query_diag_buffer (unsigned long arg)
++{
++ mpt_diag_query_t __user *uarg = (void __user *)arg;
++ mpt_diag_query_t karg;
++ MPT_ADAPTER *ioc;
++ void * request_data;
++ int iocnum, ii, rc;
++ u8 buffer_type;
++
++ rc = -EFAULT;
++ if (copy_from_user(&karg, uarg, sizeof(mpt_diag_query_t))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to read in mpt_diag_query_t struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ karg.data.Flags = 0;
++ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
++ (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ goto out;
++ }
++
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name,
++ __FUNCTION__));
++ buffer_type = karg.data.BufferType;
++ if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) {
++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for "
++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
++ goto out;
++ }
++
++ if ((ioc->DiagBuffer_Status[buffer_type] &
++ MPT_DIAG_BUFFER_IS_REGISTERED) == 0) {
++ printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not "
++ "registered\n", ioc->name, __FUNCTION__, buffer_type);
++ goto out;
++ }
++
++ if (karg.data.UniqueId & 0xffffff00) {
++ if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) {
++ printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not "
++ "registered\n", ioc->name, __FUNCTION__,
++ karg.data.UniqueId);
++ goto out;
++ }
++ }
++
++ request_data = ioc->DiagBuffer[buffer_type];
++ if (!request_data) {
++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for "
++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
++ goto out;
++ }
++
++ rc = 0;
++ if (buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED) {
++ if (karg.data.ExtendedType != ioc->ExtendedType[buffer_type])
++ goto out;
++ } else
++ karg.data.ExtendedType = 0;
++
++ if (ioc->DiagBuffer_Status[buffer_type] & MPT_DIAG_BUFFER_IS_RELEASED)
++ karg.data.Flags = 3;
++ else
++ karg.data.Flags = 7;
++ karg.data.TraceLevel = ioc->TraceLevel[buffer_type];
++ for (ii = 0; ii < 4; ii++)
++ karg.data.ProductSpecific[ii] =
++ ioc->ProductSpecific[buffer_type][ii];
++ karg.data.DataSize = ioc->DiagBuffer_sz[buffer_type];
++ karg.data.DriverAddedBufferSize = 0;
++ karg.data.UniqueId = ioc->UniqueId[buffer_type];
++
++ out:
++ if (copy_to_user(uarg, &karg, sizeof(mpt_diag_query_t))) {
++ printk(MYIOC_s_ERR_FMT "%s Unable to write mpt_diag_query_t "
++ "data @ %p\n", ioc->name, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++ return rc;
++}
++
++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
++/* READ DIAG BUFFER Routine.
++ *
++ * Outputs: None.
++ * Return: 0 if successful
++ * -EFAULT if data unavailable
++ * -EBUSY if previous command timout and IOC reset is not complete.
++ * -ENODEV if no such device/adapter
++ * -ETIME if timer expires
++ * -ENOMEM if memory allocation error
++ */
++static int
++mptctl_read_diag_buffer (unsigned long arg)
++{
++ mpt_diag_read_buffer_t __user *uarg = (void __user *) arg;
++ mpt_diag_read_buffer_t karg;
++ MPT_ADAPTER *ioc;
++ void *request_data, *diagData;
++ dma_addr_t request_data_dma;
++ DiagBufferPostRequest_t *diag_buffer_post_request;
++ DiagBufferPostReply_t *diag_buffer_post_reply;
++ MPT_FRAME_HDR *mf;
++ int iocnum, rc, ii;
++ u8 buffer_type;
++ u32 tmp;
++ unsigned long timeleft;
++
++ rc = 0;
++ if (copy_from_user(&karg, uarg, sizeof(mpt_diag_read_buffer_t))) {
++ printk(KERN_ERR "%s@%d::%s - "
++ "Unable to read in mpt_diag_read_buffer_t struct @ %p\n",
++ __FILE__, __LINE__, __FUNCTION__, uarg);
++ return -EFAULT;
++ }
++
++ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
++ (ioc == NULL)) {
++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
++ __FILE__, __FUNCTION__, __LINE__, iocnum);
++ return -ENODEV;
++ }
++
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name,
++ __FUNCTION__));
++ buffer_type = karg.data.UniqueId & 0x000000ff;
++ if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) {
++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability "
++ "for buffer_type=%x\n", ioc->name, __FUNCTION__,
++ buffer_type);
++ return -EFAULT;
++ }
++
++ if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) {
++ printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n",
++ ioc->name, __FUNCTION__, karg.data.UniqueId);
++ return -EFAULT;
++ }
++
++ request_data = ioc->DiagBuffer[buffer_type];
++ if (!request_data) {
++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for "
++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
++ return -EFAULT;
++ }
++
++ diagData = (void *)(request_data + karg.data.StartingOffset);
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: diagData=%p "
++ "request_data=%p StartingOffset=%x\n", ioc->name, __FUNCTION__,
++ diagData, request_data, karg.data.StartingOffset));
++
++ if (copy_to_user((void __user *)&uarg->data.DiagnosticData[0],
++ diagData, karg.data.BytesToRead)) {
++ printk(MYIOC_s_ERR_FMT "%s: Unable to write "
++ "mpt_diag_read_buffer_t data @ %p\n", ioc->name,
++ __FUNCTION__, diagData);
++ return -EFAULT;
++ }
++
++ if ((karg.data.Flags & MPI_FW_DIAG_FLAG_REREGISTER) == 0)
++ goto out;
++
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Reregister "
++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type));
++ if ((ioc->DiagBuffer_Status[buffer_type] &
++ MPT_DIAG_BUFFER_IS_RELEASED) == 0) {
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x "
++ "is still registered\n", ioc->name, __FUNCTION__,
++ buffer_type));
++ return rc;
++ }
++ /* Get a free request frame and save the message context.
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
++ return -EAGAIN;
++
++ diag_buffer_post_request = (DiagBufferPostRequest_t *)mf;
++ diag_buffer_post_request->Function = MPI_FUNCTION_DIAG_BUFFER_POST;
++ diag_buffer_post_request->ChainOffset = 0;
++ diag_buffer_post_request->BufferType = buffer_type;
++ diag_buffer_post_request->TraceLevel =
++ ioc->TraceLevel[buffer_type];
++ diag_buffer_post_request->MsgFlags = 0;
++ diag_buffer_post_request->Reserved1 = 0;
++ diag_buffer_post_request->Reserved2 = 0;
++ diag_buffer_post_request->Reserved3 = 0;
++ diag_buffer_post_request->BufferAddress.High = 0;
++ if ( buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED )
++ diag_buffer_post_request->ExtendedType =
++ cpu_to_le32(ioc->ExtendedType[buffer_type]);
++ diag_buffer_post_request->BufferLength =
++ cpu_to_le32(ioc->DiagBuffer_sz[buffer_type]);
++ for (ii = 0; ii < 4; ii++)
++ diag_buffer_post_request->ProductSpecific[ii] =
++ cpu_to_le32(ioc->ProductSpecific[buffer_type][ii]);
++ request_data_dma = ioc->DiagBuffer_dma[buffer_type];
++ tmp = request_data_dma & 0xFFFFFFFF;
++ diag_buffer_post_request->BufferAddress.Low = cpu_to_le32(tmp);
++ if (ioc->sg_addr_size == sizeof(u64)) {
++ tmp = (u32)((u64)request_data_dma >> 32);
++ diag_buffer_post_request->BufferAddress.High = cpu_to_le32(tmp);
++ }
++
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
++ diag_buffer_post_request->MsgContext);
++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
++ mpt_put_msg_frame(mptctl_id, ioc, mf);
++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
++ MPT_IOCTL_DEFAULT_TIMEOUT*HZ);
++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
++ rc = -ETIME;
++ printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name,
++ __FUNCTION__);
++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
++ mpt_free_msg_frame(ioc, mf);
++ goto out;
++ }
++ if (!timeleft)
++ mptctl_timeout_expired(ioc, mf);
++ goto out;
++ }
++
++ /* process the completed Reply Message Frame */
++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n",
++ ioc->name, __FUNCTION__, ioc->ioctl_cmds.status));
++ rc = -EFAULT;
++ }
++
++ diag_buffer_post_reply = (DiagBufferPostReply_t *)ioc->ioctl_cmds.reply;
++ if (le16_to_cpu(diag_buffer_post_reply->IOCStatus) ==
++ MPI_IOCSTATUS_SUCCESS) {
++ if (diag_buffer_post_reply->MsgLength > 5)
++ ioc->DataSize[buffer_type] =
++ le32_to_cpu(diag_buffer_post_reply->TransferLength);
++ ioc->DiagBuffer_Status[buffer_type] |=
++ MPT_DIAG_BUFFER_IS_REGISTERED;
++ } else {
++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x "
++ "IOCLogInfo=%x\n", ioc->name, __FUNCTION__,
++ diag_buffer_post_reply->IOCStatus,
++ diag_buffer_post_reply->IOCLogInfo));
++ rc = -EFAULT;
++ }
++
++ out:
++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
++ return rc;
++}
+--- /dev/null
++++ b/drivers/message/fusion/rejected_ioctls/diag_buffer.h
+@@ -0,0 +1,101 @@
++#define MPTDIAGREGISTER _IOWR(MPT_MAGIC_NUMBER,26,mpt_diag_register_t)
++#define MPTDIAGRELEASE _IOWR(MPT_MAGIC_NUMBER,27,mpt_diag_release_t)
++#define MPTDIAGUNREGISTER _IOWR(MPT_MAGIC_NUMBER,28,mpt_diag_unregister_t)
++#define MPTDIAGQUERY _IOWR(MPT_MAGIC_NUMBER,29,mpt_diag_query_t)
++#define MPTDIAGREADBUFFER _IOWR(MPT_MAGIC_NUMBER,30,mpt_diag_read_buffer_t)
++
++#define MPI_FW_DIAG_IOCTL (0x80646961)
++#define MPI_FW_DIAG_TYPE_REGISTER (0x00000001)
++#define MPI_FW_DIAG_TYPE_UNREGISTER (0x00000002)
++#define MPI_FW_DIAG_TYPE_QUERY (0x00000003)
++#define MPI_FW_DIAG_TYPE_READ_BUFFER (0x00000004)
++#define MPI_FW_DIAG_TYPE_RELEASE (0x00000005)
++
++#define MPI_FW_DIAG_INVALID_UID (0x00000000)
++#define FW_DIAGNOSTIC_BUFFER_COUNT (3)
++#define FW_DIAGNOSTIC_UID_NOT_FOUND (0xFF)
++
++#define MPI_FW_DIAG_ERROR_SUCCESS (0x00000000)
++#define MPI_FW_DIAG_ERROR_FAILURE (0x00000001)
++#define MPI_FW_DIAG_ERROR_INVALID_PARAMETER (0x00000002)
++#define MPI_FW_DIAG_ERROR_POST_FAILED (0x00000010)
++#define MPI_FW_DIAG_ERROR_INVALID_UID (0x00000011)
++
++#define MPI_FW_DIAG_ERROR_RELEASE_FAILED (0x00000012)
++#define MPI_FW_DIAG_ERROR_NO_BUFFER (0x00000013)
++#define MPI_FW_DIAG_ERROR_ALREADY_RELEASED (0x00000014)
++
++#define MPT_DIAG_CAPABILITY(bufftype) (MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER << bufftype)
++
++#define MPT_DIAG_BUFFER_IS_REGISTERED 1
++#define MPT_DIAG_BUFFER_IS_RELEASED 2
++
++typedef struct _MPI_FW_DIAG_REGISTER {
++ u8 TraceLevel;
++ u8 BufferType;
++ u16 Flags;
++ u32 ExtendedType;
++ u32 ProductSpecific[4];
++ u32 RequestedBufferSize;
++ u32 UniqueId;
++} MPI_FW_DIAG_REGISTER, *PTR_MPI_FW_DIAG_REGISTER;
++
++typedef struct _mpt_diag_register {
++ mpt_ioctl_header hdr;
++ MPI_FW_DIAG_REGISTER data;
++} mpt_diag_register_t;
++
++typedef struct _MPI_FW_DIAG_UNREGISTER {
++ u32 UniqueId;
++} MPI_FW_DIAG_UNREGISTER, *PTR_MPI_FW_DIAG_UNREGISTER;
++
++typedef struct _mpt_diag_unregister {
++ mpt_ioctl_header hdr;
++ MPI_FW_DIAG_UNREGISTER data;
++} mpt_diag_unregister_t;
++
++#define MPI_FW_DIAG_FLAG_APP_OWNED (0x0001)
++#define MPI_FW_DIAG_FLAG_BUFFER_VALID (0x0002)
++#define MPI_FW_DIAG_FLAG_FW_BUFFER_ACCESS (0x0004)
++
++typedef struct _MPI_FW_DIAG_QUERY {
++ u8 TraceLevel;
++ u8 BufferType;
++ u16 Flags;
++ u32 ExtendedType;
++ u32 ProductSpecific[4];
++ u32 DataSize;
++ u32 DriverAddedBufferSize;
++ u32 UniqueId;
++} MPI_FW_DIAG_QUERY, *PTR_MPI_FW_DIAG_QUERY;
++
++typedef struct _mpt_diag_query {
++ mpt_ioctl_header hdr;
++ MPI_FW_DIAG_QUERY data;
++} mpt_diag_query_t;
++
++typedef struct _MPI_FW_DIAG_RELEASE {
++ u32 UniqueId;
++} MPI_FW_DIAG_RELEASE, *PTR_MPI_FW_DIAG_RELEASE;
++
++typedef struct _mpt_diag_release {
++ mpt_ioctl_header hdr;
++ MPI_FW_DIAG_RELEASE data;
++} mpt_diag_release_t;
++
++#define MPI_FW_DIAG_FLAG_REREGISTER (0x0001)
++
++typedef struct _MPI_FW_DIAG_READ_BUFFER {
++ u8 Status;
++ u8 Reserved;
++ u16 Flags;
++ u32 StartingOffset;
++ u32 BytesToRead;
++ u32 UniqueId;
++ u32 DiagnosticData[1];
++} MPI_FW_DIAG_READ_BUFFER, *PTR_MPI_FW_DIAG_READ_BUFFER;
++
++typedef struct _mpt_diag_read_buffer {
++ mpt_ioctl_header hdr;
++ MPI_FW_DIAG_READ_BUFFER data;
++} mpt_diag_read_buffer_t;