From: Hannes Reinecke Date: Tue, 24 Nov 2009 14:40:54 +0100 Subject: Update MPT Fusion driver to 4.22.00.00-suse References: bnc#556587 Patch-Mainline: No This patch updates the MPT Fusion driver to version 4.22.00.00-suse. Signed-off-by: Hannes Reinecke --- drivers/message/fusion/Kconfig | 16 drivers/message/fusion/Makefile | 13 drivers/message/fusion/csmi/csmisas.c | 5805 +++++++++++++++++++ drivers/message/fusion/csmi/csmisas.h | 1854 ++++++ drivers/message/fusion/lsi/mpi.h | 5 drivers/message/fusion/lsi/mpi_cnfg.h | 21 drivers/message/fusion/lsi/mpi_history.txt | 55 drivers/message/fusion/lsi/mpi_log_sas.h | 14 drivers/message/fusion/lsi/mpi_type.h | 15 drivers/message/fusion/mptbase.c | 802 +- drivers/message/fusion/mptbase.h | 250 drivers/message/fusion/mptctl.c | 648 +- drivers/message/fusion/mptctl.h | 5 drivers/message/fusion/mptdebug.h | 11 drivers/message/fusion/mptfc.c | 173 drivers/message/fusion/mptlan.c | 222 drivers/message/fusion/mptlan.h | 2 drivers/message/fusion/mptsas.c | 1359 +++- drivers/message/fusion/mptsas.h | 60 drivers/message/fusion/mptscsih.c | 1043 ++- drivers/message/fusion/mptscsih.h | 13 drivers/message/fusion/mptspi.c | 262 drivers/message/fusion/rejected_ioctls/diag_buffer.c | 671 ++ drivers/message/fusion/rejected_ioctls/diag_buffer.h | 101 24 files changed, 12081 insertions(+), 1339 deletions(-) --- 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/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 --- /dev/null +++ b/drivers/message/fusion/csmi/csmisas.c @@ -0,0 +1,5805 @@ +/* + * 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 + +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; + + 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); + + 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; + + 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); + } + 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;iiResponseInfo);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 .... + */ + 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; + } + /* Send request + */ + if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) { + dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + mpt_clear_taskmgmt_in_progress_flag(ioc); + 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; + int_to_scsilun(karg.Parameters.bLun, + (struct scsi_lun *)pScsiTm->LUN); + pScsiTm->MsgContext = MsgContext; + pScsiTm->TaskMsgContext = TaskMsgContext; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + if (csmisas_send_handshake_wait(ioc, mf, + karg.IoctlHeader.Timeout) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + 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; + } + + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + + 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; iraid_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 + +#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 +#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/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.16 + * mpi.h Version: 01.05.17 * * Version History * --------------- @@ -82,6 +82,7 @@ * 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. + * 07-11-08 01.05.17 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -112,7 +113,7 @@ /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x13) +#define MPI_HEADER_VERSION_UNIT (0x14) #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_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.18 + * mpi_cnfg.h Version: 01.05.19 * * Version History * --------------- @@ -322,6 +322,14 @@ * 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. + * 07-11-08 01.05.19 Added defines MPI_MANPAGE4_EXTFLAGS_RAID0_SINGLE_DRIVE + * and MPI_MANPAGE4_EXTFLAGS_SSD_SCRUB_DISABLE for ExtFlags + * field of Manufacturing Page 4. + * Added defines for a new bit in BIOS Page 1 BiosOptions + * field to control adapter scan order. + * Added BootDeviceWaitTime field to SAS IO Unit Page 2. + * Added MPI_SAS_PHY0_PHYINFO_PHY_VACANT for use in PhyInfo + * field of SAS Expander Page 1. * -------------------------------------------------------------------------- */ @@ -700,6 +708,8 @@ typedef struct _CONFIG_PAGE_MANUFACTURIN #define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01) /* defines for the ExtFlags field */ +#define MPI_MANPAGE4_EXTFLAGS_RAID0_SINGLE_DRIVE (0x0400) +#define MPI_MANPAGE4_EXTFLAGS_SSD_SCRUB_DISABLE (0x0200) #define MPI_MANPAGE4_EXTFLAGS_MASK_COERCION_SIZE (0x0180) #define MPI_MANPAGE4_EXTFLAGS_SHIFT_COERCION_SIZE (7) #define MPI_MANPAGE4_EXTFLAGS_1GB_COERCION_SIZE (0) @@ -1219,6 +1229,10 @@ typedef struct _CONFIG_PAGE_BIOS_1 #define MPI_BIOSPAGE1_OPTIONS_SPI_ENABLE (0x00000400) #define MPI_BIOSPAGE1_OPTIONS_FC_ENABLE (0x00000200) #define MPI_BIOSPAGE1_OPTIONS_SAS_ENABLE (0x00000100) + +#define MPI_BIOSPAGE1_OPTIONS_SCAN_HIGH_TO_LOW (0x00000002) +#define MPI_BIOSPAGE1_OPTIONS_SCAN_LOW_TO_HIGH (0x00000000) + #define MPI_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) /* values for the IOCSettings field */ @@ -2712,7 +2726,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_ { CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ U8 NumDevsPerEnclosure; /* 08h */ - U8 Reserved1; /* 09h */ + U8 BootDeviceWaitTime; /* 09h */ U16 Reserved2; /* 0Ah */ U16 MaxPersistentIDs; /* 0Ch */ U16 NumPersistentIDsUsed; /* 0Eh */ @@ -2722,7 +2736,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_ } CONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2, SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t; -#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x06) +#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x07) /* values for SAS IO Unit Page 2 Status field */ #define MPI_SAS_IOUNIT2_STATUS_DEVICE_LIMIT_EXCEEDED (0x08) @@ -2997,6 +3011,7 @@ typedef struct _CONFIG_PAGE_SAS_PHY_0 #define MPI_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) /* values for SAS PHY Page 0 PhyInfo field */ +#define MPI_SAS_PHY0_PHYINFO_PHY_VACANT (0x80000000) #define MPI_SAS_PHY0_PHYINFO_SATA_PORT_ACTIVE (0x00004000) #define MPI_SAS_PHY0_PHYINFO_SATA_PORT_SELECTOR (0x00002000) #define MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY (0x00001000) --- a/drivers/message/fusion/lsi/mpi_history.txt +++ b/drivers/message/fusion/lsi/mpi_history.txt @@ -6,15 +6,15 @@ Copyright (c) 2000-2008 LSI Corporation. --------------------------------------- - Header Set Release Version: 01.05.19 - Header Set Release Date: 03-28-08 + Header Set Release Version: 01.05.20 + Header Set Release Date: 07-11-08 --------------------------------------- Filename Current version Prior version ---------- --------------- ------------- - 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.h 01.05.17 01.05.16 + mpi_ioc.h 01.05.16 01.05.16 + mpi_cnfg.h 01.05.19 01.05.18 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 @@ -24,7 +24,7 @@ mpi_inb.h 01.05.01 01.05.01 mpi_sas.h 01.05.05 01.05.05 mpi_type.h 01.05.02 01.05.02 - mpi_history.txt 01.05.19 01.05.18 + mpi_history.txt 01.05.20 01.05.19 * Date Version Description @@ -99,6 +99,7 @@ mpi.h * 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. + * 07-11-08 01.05.17 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- mpi_ioc.h @@ -130,7 +131,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. @@ -190,7 +191,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 @@ -523,6 +524,14 @@ mpi_cnfg.h * 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. + * 07-11-08 01.05.19 Added defines MPI_MANPAGE4_EXTFLAGS_RAID0_SINGLE_DRIVE + * and MPI_MANPAGE4_EXTFLAGS_SSD_SCRUB_DISABLE for ExtFlags + * field of Manufacturing Page 4. + * Added defines for a new bit in BIOS Page 1 BiosOptions + * field to control adapter scan order. + * Added BootDeviceWaitTime field to SAS IO Unit Page 2. + * Added MPI_SAS_PHY0_PHYINFO_PHY_VACANT for use in PhyInfo + * field of SAS Expander Page 1. * -------------------------------------------------------------------------- mpi_init.h @@ -623,7 +632,7 @@ mpi_fc.h * 11-02-00 01.01.01 Original release for post 1.0 work * 12-04-00 01.01.02 Added messages for Common Transport Send and * Primitive Send. - * 01-09-01 01.01.03 Modified some of the new flags to have an MPI prefix + * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix * and modified the FcPrimitiveSend flags. * 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger * field. @@ -743,20 +752,20 @@ mpi_type.h mpi_history.txt Parts list history -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.20 01.05.19 01.05.18 01.05.17 01.05.16 01.05.15 +---------- -------- -------- -------- -------- -------- -------- +mpi.h 01.05.17 01.05.16 01.05.15 01.05.14 01.05.13 01.05.12 +mpi_ioc.h 01.05.16 01.05.16 01.05.15 01.05.15 01.05.14 01.05.13 +mpi_cnfg.h 01.05.19 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 01.05.09 +mpi_targ.h 01.05.06 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 01.05.01 +mpi_lan.h 01.05.01 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.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 01.05.03 +mpi_inb.h 01.05.01 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.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 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_log_sas.h +++ b/drivers/message/fusion/lsi/mpi_log_sas.h @@ -161,11 +161,10 @@ #define PL_LOGINFO_SUB_CODE_INVALID_SGL (0x00000200) #define PL_LOGINFO_SUB_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00000300) -#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 WriteDataLenghtGTDataLengthErr */ +#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 WriteDataLenghtGTDataLengthErr */ #define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500) #define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600) @@ -180,8 +179,7 @@ #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_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) @@ -309,6 +307,8 @@ #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) /****************************************************************************/ --- a/drivers/message/fusion/lsi/mpi_type.h +++ b/drivers/message/fusion/lsi/mpi_type.h @@ -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/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -58,6 +58,7 @@ #include #include /* needed for in_interrupt() proto */ #include +#include #include #ifdef CONFIG_MTRR #include @@ -100,12 +101,13 @@ 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; EXPORT_SYMBOL(mpt_fwfault_debug); @@ -126,7 +128,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 @@ -144,7 +146,7 @@ static int MptDriverClass[MPT_MAX_PRO static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; /* Reset handler lookup table */ static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; -static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; +static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; /* @@ -157,7 +159,6 @@ static u8 last_drv_idx; /* * Forward protos... */ -static irqreturn_t mpt_interrupt(int irq, void *bus_id); 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, @@ -188,8 +189,8 @@ static int GetIoUnitPage2(MPT_ADAPTER *i int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); 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_read_ioc_pg_1(MPT_ADAPTER *ioc); +static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc); static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag); @@ -220,11 +221,11 @@ static void mpt_inactive_raid_list_free( static int __init fusion_init (void); static void __exit fusion_exit (void); -#define CHIPREG_READ32(addr) readl_relaxed(addr) +#define CHIPREG_READ32(addr) readl_relaxed(addr) #define CHIPREG_READ32_dmasync(addr) readl(addr) -#define CHIPREG_WRITE32(addr,val) writel(val, addr) +#define CHIPREG_WRITE32(addr,val) writel(val, addr) #define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr) -#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr) +#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr) static void pci_disable_io_access(struct pci_dev *pdev) @@ -246,6 +247,15 @@ pci_enable_io_access(struct pci_dev *pde pci_write_config_word(pdev, PCI_COMMAND, command_reg); } +/** + * 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); @@ -492,6 +502,9 @@ 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); @@ -782,6 +795,8 @@ 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) @@ -914,7 +929,8 @@ mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER 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])); @@ -1023,7 +1039,8 @@ mpt_add_sge_64bit(void *pAddr, u32 flags } /** - * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround). + * 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 @@ -1140,7 +1157,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; @@ -1582,6 +1599,7 @@ mpt_get_product_name(u16 vendor, u16 dev * @ioc: Pointer to pointer to IOC adapter * **/ +#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10)) static int mpt_mapresources(MPT_ADAPTER *ioc) { @@ -1591,9 +1609,9 @@ mpt_mapresources(MPT_ADAPTER *ioc) unsigned long port; u32 msize; u32 psize; - u8 revision; int r = -ENODEV; struct pci_dev *pdev; + struct sysinfo s; pdev = ioc->pcidev; ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); @@ -1608,22 +1626,21 @@ mpt_mapresources(MPT_ADAPTER *ioc) return r; } - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - if (sizeof(dma_addr_t) > 4) { - const uint64_t required_mask = dma_get_required_mask - (&pdev->dev); + uint64_t required_mask; + + required_mask = dma_get_required_mask(&pdev->dev); + if (required_mask > DMA_BIT_MASK(32) && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(64))) { + DMA_BIT_MASK(64))) { ioc->dma_mask = DMA_BIT_MASK(64); 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_BIT_MASK(32)) - && !pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32))) { + && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { ioc->dma_mask = DMA_BIT_MASK(32); dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", @@ -1635,8 +1652,7 @@ mpt_mapresources(MPT_ADAPTER *ioc) } } else { if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - && !pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32))) { + && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { ioc->dma_mask = DMA_BIT_MASK(32); dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", @@ -1648,6 +1664,11 @@ mpt_mapresources(MPT_ADAPTER *ioc) } } + si_meminfo(&s); + printk(MYIOC_s_INFO_FMT "%s BIT PCI BUS DMA ADDRESSING SUPPORTED, " + "total memory = %ld kB\n", + ioc->name, ioc->dma_mask == DMA_BIT_MASK(64) ? "64" : "32", + convert_to_kb(s.totalram)); mem_phys = msize = 0; port = psize = 0; for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) { @@ -1804,7 +1825,6 @@ mpt_attach(struct pci_dev *pdev, const s /* Find lookup slot. */ INIT_LIST_HEAD(&ioc->list); - /* Initialize workqueue */ INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work); @@ -1841,14 +1861,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); @@ -1948,7 +1968,6 @@ mpt_attach(struct pci_dev *pdev, const s iounmap(ioc->memmap); if (r != -5) pci_release_selected_regions(pdev, ioc->bars); - destroy_workqueue(ioc->reset_work_q); ioc->reset_work_q = NULL; @@ -2000,7 +2019,7 @@ mpt_attach(struct pci_dev *pdev, const s void mpt_detach(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); char pname[32]; u8 cb_idx; unsigned long flags; @@ -2273,6 +2292,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 /* hard_reset_done = 0 if a soft reset was performed * and 1 if a hard reset was performed. */ + if (!hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) { + /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ + 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; + reset_alt_ioc_active = 0; + } + if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) { if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; @@ -2472,7 +2500,7 @@ 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); switch (ioc->bus_type) { @@ -2641,13 +2669,12 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) 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, __func__); + ioc->name, __FUNCTION__); } else printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset " - "failed!\n", ioc->name, __func__); + "failed!\n", ioc->name, __FUNCTION__); } - /* Disable adapter interrupts! */ synchronize_irq(ioc->pcidev->irq); CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); @@ -2690,8 +2717,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; @@ -2882,6 +2911,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force */ if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { statefault = 2; + ioc->is_fault = 1; printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n", ioc->name); printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n", @@ -3066,6 +3096,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); @@ -3301,7 +3333,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) { // set MsgVersion and HeaderVersion host driver was built with ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION); - ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION); + ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION); if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) { ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE; @@ -3516,13 +3548,15 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee u32 flagsLength; int ii, sz, reply_sz; int cmdStatus; - int request_size; + int request_size; + /* If the image size is 0, we are done. */ - if ((sz = ioc->facts.FWImageSize) == 0) + sz = ioc->facts.FWImageSize; + if (!sz) return 0; - if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0) + if (mpt_alloc_fw_memory(ioc, sz) != 0) return -ENOMEM; dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n", @@ -3557,7 +3591,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee 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)); + sz, request_size)); DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest); ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest, @@ -3574,9 +3608,9 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee int status; status = le16_to_cpu(preply->IOCStatus) & MPI_IOCSTATUS_MASK; - if (status == MPI_IOCSTATUS_SUCCESS && - ioc->facts.FWImageSize == - le32_to_cpu(preply->ActualImageSize)) + 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", @@ -3618,7 +3652,7 @@ 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)); @@ -3672,6 +3706,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; @@ -3713,11 +3748,13 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw } /* 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, @@ -3734,17 +3771,6 @@ 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) @@ -3754,51 +3780,64 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw 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); + diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM); ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now 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; countname, 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; } @@ -3853,6 +3892,7 @@ KickStart(MPT_ADAPTER *ioc, int force, i if (hard_reset_done < 0) return hard_reset_done; + /* may not have worked but hard_reset_done doesn't always signal failure */ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n", ioc->name)); @@ -3861,7 +3901,7 @@ KickStart(MPT_ADAPTER *ioc, int force, i 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", - ioc->name, cnt)); + ioc->name, cnt)); return hard_reset_done; } if (sleepFlag == CAN_SLEEP) { @@ -3899,7 +3939,7 @@ 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; @@ -3931,8 +3971,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign */ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { if (MptResetHandlers[cb_idx]) - (*(MptResetHandlers[cb_idx]))(ioc, - MPT_IOC_PRE_RESET); + (*(MptResetHandlers[cb_idx]))(ioc, MPT_IOC_PRE_RESET); } for (count = 0; count < 60; count ++) { @@ -3941,29 +3980,39 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "looking for READY STATE: doorbell=%x" - " count=%d\n", + " count=%d\n", ioc->name, doorbell, count)); 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) msleep(1000); 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)); } @@ -3999,14 +4048,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)); } /* @@ -4022,7 +4071,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)); /* @@ -4033,11 +4082,9 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign */ 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); + 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); + mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET); } } } @@ -4059,7 +4106,7 @@ 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) { @@ -4092,6 +4139,12 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign break; } + /* + * Early out for hard fault + */ + if (count && doorbell == MPI_IOC_STATE_FAULT) + break; + /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { msleep (1000); @@ -4108,10 +4161,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign } 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)); } @@ -4167,11 +4220,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)); } /* @@ -4207,7 +4260,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<ReqToChain = (int *) mem; dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n", - ioc->name, mem, sz)); + ioc->name, mem, sz)); mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) return -1; ioc->RequestNB = (int *) mem; dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n", - ioc->name, mem, sz)); + ioc->name, mem, sz)); } for (ii = 0; ii < ioc->req_depth; ii++) { ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN; @@ -4345,7 +4398,7 @@ initChainBuffers(MPT_ADAPTER *ioc) ioc->ChainToChain = (int *) mem; dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n", - ioc->name, mem, sz)); + ioc->name, mem, sz)); } else { mem = (u8 *) ioc->ChainToChain; } @@ -4411,22 +4464,22 @@ PrimeIocFifos(MPT_ADAPTER *ioc) 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)); + ioc->name, ioc->reply_sz, ioc->reply_depth)); dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n", - ioc->name, reply_sz, reply_sz)); + ioc->name, reply_sz, reply_sz)); sz = (ioc->req_sz * ioc->req_depth); dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n", - ioc->name, ioc->req_sz, ioc->req_depth)); + ioc->name, ioc->req_sz, ioc->req_depth)); dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n", - ioc->name, sz, sz)); + ioc->name, sz, sz)); total_size += sz; sz = num_chain * ioc->req_sz; /* chain buffer pool size */ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n", - ioc->name, ioc->req_sz, num_chain)); + ioc->name, ioc->req_sz, num_chain)); dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n", - ioc->name, sz, sz, num_chain)); + ioc->name, sz, sz, num_chain)); total_size += sz; mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma); @@ -4437,7 +4490,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) } dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n", - ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size)); + ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size)); memset(mem, 0, total_size); ioc->alloc_total += total_size; @@ -4448,7 +4501,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n", - ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); + ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); alloc_dma += reply_sz; mem += reply_sz; @@ -4459,7 +4512,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) ioc->req_frames_dma = alloc_dma; dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n", - ioc->name, mem, (void *)(ulong)alloc_dma)); + ioc->name, mem, (void *)(ulong)alloc_dma)); ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); @@ -4487,13 +4540,11 @@ PrimeIocFifos(MPT_ADAPTER *ioc) dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n", ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA)); - /* Initialize the free chain Q. - */ + /* Initialize the free chain Q. */ INIT_LIST_HEAD(&ioc->FreeChainQ); - /* Post the chain buffers to the FreeChainQ. - */ + /* Post the chain buffers to the FreeChainQ. */ mem = (u8 *)ioc->ChainBuffer; for (i=0; i < num_chain; i++) { mf = (MPT_FRAME_HDR *) mem; @@ -4530,15 +4581,14 @@ PrimeIocFifos(MPT_ADAPTER *ioc) ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF); ioc->alloc_total += sz; dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n", - ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma)); + ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma)); } - /* Post Reply frames to FIFO - */ + /* Post Reply frames to FIFO */ alloc_dma = ioc->alloc_dma; dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n", - ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); + ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); for (i = 0; i < ioc->reply_depth; i++) { /* Write each address to the IOC! */ @@ -4767,18 +4817,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++; } } @@ -5015,7 +5065,7 @@ mptbase_sas_persist_operation(MPT_ADAPTE MPT_FRAME_HDR *mf = NULL; MPIHeader_t *mpi_hdr; int ret = 0; - unsigned long timeleft; + unsigned long timeleft; mutex_lock(&ioc->mptbase_cmds.mutex); @@ -5044,7 +5094,7 @@ mptbase_sas_persist_operation(MPT_ADAPTE printk(KERN_DEBUG "%s: no msg frames!\n", __func__); ret = -1; goto out; - } + } mpi_hdr = (MPIHeader_t *) mf; sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; @@ -5063,7 +5113,8 @@ mptbase_sas_persist_operation(MPT_ADAPTE if (!timeleft) { printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n", ioc->name, __func__); - mpt_HardResetHandler(ioc, CAN_SLEEP); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); mpt_free_msg_frame(ioc, mf); } goto out; @@ -5097,12 +5148,12 @@ static void mptbase_raid_process_event_data(MPT_ADAPTER *ioc, MpiEventDataRaid_t * pRaidEventData) { - int volume; - int reason; - int disk; - int status; - int flags; - int state; + int volume; + int reason; + int disk; + int status; + int flags; + int state; volume = pRaidEventData->VolumeID; reason = pRaidEventData->ReasonCode; @@ -5198,8 +5249,8 @@ mptbase_raid_process_event_data(MPT_ADAP : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED ? "failed requested" : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE - ? "offline" - : "state unknown", + ? "offline" + : "state unknown", flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC ? ", out of sync" : "", flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED @@ -5477,7 +5528,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc */ ioc->spi_data.bus_reset = (le32_to_cpu(pPP2->PortFlags) & - MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ? + MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ? 0 : 1 ; /* Save the Port Page 2 data @@ -5556,6 +5607,69 @@ 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 @@ -5568,13 +5682,13 @@ 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); } /** @@ -5591,10 +5705,12 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i ConfigPageHeader_t hdr; dma_addr_t dma_handle; pRaidVolumePage0_t buffer = NULL; - int i; - RaidPhysDiskPage0_t phys_disk; + 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)); @@ -5633,12 +5749,35 @@ 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) continue; @@ -5653,7 +5792,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) @@ -5743,8 +5882,8 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, int mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num) { - CONFIGPARMS cfg; - ConfigPageHeader_t hdr; + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; dma_addr_t dma_handle; pRaidPhysDiskPage1_t buffer = NULL; int rc; @@ -5795,7 +5934,6 @@ mpt_raid_phys_disk_get_num_paths(MPT_ADA return rc; } -EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths); /** * mpt_raid_phys_disk_pg1 - returns phys disk page 1 @@ -5809,11 +5947,10 @@ EXPORT_SYMBOL(mpt_raid_phys_disk_get_num * -ENOMEM if pci_alloc failed **/ int -mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, - RaidPhysDiskPage1_t *phys_disk) +mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, RaidPhysDiskPage1_t *phys_disk) { - CONFIGPARMS cfg; - ConfigPageHeader_t hdr; + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; dma_addr_t dma_handle; pRaidPhysDiskPage1_t buffer = NULL; int rc; @@ -5863,17 +6000,14 @@ mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, 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].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)); + 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)); + memcpy(&phys_disk->Path[i].OwnerWWID, &sas_address, sizeof(__le64)); } out: @@ -5884,8 +6018,33 @@ mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, return rc; } -EXPORT_SYMBOL(mpt_raid_phys_disk_pg1); +/** + * 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 @@ -5949,16 +6108,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); @@ -6118,6 +6283,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); @@ -6294,9 +6462,9 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS long timeout; int ret; u8 page_type = 0, extend_page; - unsigned long timeleft; + unsigned long timeleft; unsigned long flags; - int in_isr; + int in_isr; u8 issue_hard_reset = 0; u8 retry_count = 0; @@ -6308,7 +6476,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n", ioc->name)); return -EPERM; - } + } /* don't send a config page during diag reset */ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); @@ -6447,7 +6615,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n", ret, le32_to_cpu(pReply->IOCLogInfo))); -out: + out: CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) mutex_unlock(&ioc->mptbase_cmds.mutex); @@ -6455,7 +6623,8 @@ out: issue_hard_reset = 0; printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", ioc->name, __func__); - mpt_HardResetHandler(ioc, CAN_SLEEP); + 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) { @@ -6469,7 +6638,6 @@ out: } } return ret; - } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -6823,7 +6991,7 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, *size = y; } /** - * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management + * 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. @@ -6840,6 +7008,7 @@ mpt_set_taskmgmt_in_progress_flag(MPT_AD 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; @@ -6849,14 +7018,14 @@ mpt_set_taskmgmt_in_progress_flag(MPT_AD ioc->alt_ioc->taskmgmt_in_progress = 1; ioc->alt_ioc->taskmgmt_quiesce_io = 1; } - out: spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + out: return retval; } -EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag); /** - * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management + * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment * @ioc: Pointer to MPT_ADAPTER structure * **/ @@ -6874,8 +7043,6 @@ mpt_clear_taskmgmt_in_progress_flag(MPT_ } spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); } -EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag); - /** * mpt_halt_firmware - Halts the firmware if it is operational and panic @@ -6893,20 +7060,173 @@ mpt_halt_firmware(MPT_ADAPTER *ioc) 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); - panic("%s: Firmware is halted due to command timeout\n", - ioc->name); + 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); } } -EXPORT_SYMBOL(mpt_halt_firmware); -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Reset Handling - */ +/** + * 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; + int i; + + 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; + } + + if (ioc->bus_type == FC) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "skipping, because the bus type is FC!\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); + } + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->taskmgmt_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return -1; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + /* 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); + } + } + /* + * 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; + } + + 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 @@ -6931,7 +7251,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i u8 cb_idx; unsigned long flags; unsigned long time_count; - + int i; dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name)); #ifdef MFCNT printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name); @@ -6969,22 +7289,23 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i } time_count = jiffies; - rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag); - if (rc != 0) { - printk(KERN_WARNING MYNAM - ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name); + if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) { + printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n", + rc, ioc->name); } else { if (ioc->hard_resets < -1) ioc->hard_resets++; } spin_lock_irqsave(&ioc->taskmgmt_lock, flags); - ioc->ioc_reset_in_progress = 0; + if (ioc->is_fault == 1) + ioc->is_fault = 2; ioc->taskmgmt_quiesce_io = 0; + ioc->ioc_reset_in_progress = 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->ioc_reset_in_progress = 0; ioc->alt_ioc->taskmgmt_in_progress = 0; } spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); @@ -6993,11 +7314,22 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i 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); + mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET); } } + /* + * 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; + } + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler: completed (%d seconds): %s\n", ioc->name, @@ -7150,6 +7482,11 @@ mpt_display_event_info(MPT_ADAPTER *ioc, "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 " @@ -7170,6 +7507,11 @@ mpt_display_event_info(MPT_ADAPTER *ioc, "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: " @@ -7336,12 +7678,28 @@ mpt_display_event_info(MPT_ADAPTER *ioc, { 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; } @@ -7712,7 +8070,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l "IO Not Yet Executed", /* 13h */ "IO Executed", /* 14h */ "Persistent Reservation Out Not Affiliation " - "Owner", /* 15h */ + "Owner", /* 15h */ "Open Transmit DMA Abort", /* 16h */ "IO Device Missing Delay Retry", /* 17h */ "IO Cancelled Due to Recieve Error", /* 18h */ @@ -7737,19 +8095,19 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l NULL /* 07h */ }; static char *raid_sub_code_str[] = { - NULL, /* 00h */ + NULL, /* 00h */ "Volume Creation Failed: Data Passed too " - "Large", /* 01h */ + "Large", /* 01h */ "Volume Creation Failed: Duplicate Volumes " - "Attempted", /* 02h */ + "Attempted", /* 02h */ "Volume Creation Failed: Max Number " "Supported Volumes Exceeded", /* 03h */ "Volume Creation Failed: DMA Error", /* 04h */ "Volume Creation Failed: Invalid Volume Type", /* 05h */ "Volume Creation Failed: Error Reading " - "MFG Page 4", /* 06h */ + "MFG Page 4", /* 06h */ "Volume Creation Failed: Creating Internal " - "Structures", /* 07h */ + "Structures", /* 07h */ NULL, /* 08h */ NULL, /* 09h */ NULL, /* 0Ah */ @@ -7758,12 +8116,12 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l NULL, /* 0Dh */ NULL, /* 0Eh */ NULL, /* 0Fh */ - "Activation failed: Already Active Volume", /* 10h */ - "Activation failed: Unsupported Volume Type", /* 11h */ - "Activation failed: Too Many Active Volumes", /* 12h */ - "Activation failed: Volume ID in Use", /* 13h */ - "Activation failed: Reported Failure", /* 14h */ - "Activation failed: Importing a Volume", /* 15h */ + "Activation failed: Already Active Volume", /* 10h */ + "Activation failed: Unsupported Volume Type", /* 11h */ + "Activation failed: Too Many Active Volumes", /* 12h */ + "Activation failed: Volume ID in Use", /* 13h */ + "Activation failed: Reported Failure", /* 14h */ + "Activation failed: Importing a Volume", /* 15h */ NULL, /* 16h */ NULL, /* 17h */ NULL, /* 18h */ @@ -7774,12 +8132,12 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l NULL, /* 1Dh */ NULL, /* 1Eh */ NULL, /* 1Fh */ - "Phys Disk failed: Too Many Phys Disks", /* 20h */ + "Phys Disk failed: Too Many Phys Disks", /* 20h */ "Phys Disk failed: Data Passed too Large", /* 21h */ - "Phys Disk failed: DMA Error", /* 22h */ - "Phys Disk failed: Invalid ", /* 23h */ + "Phys Disk failed: DMA Error", /* 22h */ + "Phys Disk failed: Invalid ", /* 23h */ "Phys Disk failed: Creating Phys Disk Config " - "Page", /* 24h */ + "Page", /* 24h */ NULL, /* 25h */ NULL, /* 26h */ NULL, /* 27h */ @@ -7797,22 +8155,22 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l "Device ", /* 32h */ "Compatibility Error: Removable Device Found", /* 33h */ "Compatibility Error: Device SCSI Version not " - "2 or Higher", /* 34h */ + "2 or Higher", /* 34h */ "Compatibility Error: SATA Device, 48 BIT LBA " - "not Supported", /* 35h */ + "not Supported", /* 35h */ "Compatibility Error: Device doesn't have " - "512 Byte Block Sizes", /* 36h */ + "512 Byte Block Sizes", /* 36h */ "Compatibility Error: Volume Type Check Failed", /* 37h */ "Compatibility Error: Volume Type is " - "Unsupported by FW", /* 38h */ + "Unsupported by FW", /* 38h */ "Compatibility Error: Disk Drive too Small for " - "use in Volume", /* 39h */ + "use in Volume", /* 39h */ "Compatibility Error: Phys Disk for Create " - "Volume not Found", /* 3Ah */ + "Volume not Found", /* 3Ah */ "Compatibility Error: Too Many or too Few " - "Disks for Volume Type", /* 3Bh */ + "Disks for Volume Type", /* 3Bh */ "Compatibility Error: Disk stripe Sizes " - "Must be 64KB", /* 3Ch */ + "Must be 64KB", /* 3Ch */ "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */ }; @@ -8210,6 +8568,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); @@ -8227,13 +8586,18 @@ 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. --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -49,10 +49,6 @@ #define MPTBASE_H_INCLUDED /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -#include -#include -#include - #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.13" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.13" +#define MPT_LINUX_VERSION_COMMON "4.22.00.00" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-4.22.00.00" #define WHAT_MAGIC_STRING "@" "(" "#" ")" +#define MPT_LINUX_MAJOR_VERSION 4 +#define MPT_LINUX_MINOR_VERSION 22 +#define MPT_LINUX_BUILD_VERSION 00 +#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 */ @@ -135,7 +137,6 @@ #define MPT_COALESCING_TIMEOUT 0x10 - /* * SCSI transfer rate defines. */ @@ -164,10 +165,10 @@ /* * Set the MAX_SGE value based on user input. */ -#ifdef CONFIG_FUSION_MAX_SGE -#if CONFIG_FUSION_MAX_SGE < 16 +#ifdef CONFIG_FUSION_MAX_SGE +#if CONFIG_FUSION_MAX_SGE < 16 #define MPT_SCSI_SG_DEPTH 16 -#elif CONFIG_FUSION_MAX_SGE > 128 +#elif CONFIG_FUSION_MAX_SGE > 128 #define MPT_SCSI_SG_DEPTH 128 #else #define MPT_SCSI_SG_DEPTH CONFIG_FUSION_MAX_SGE @@ -176,10 +177,10 @@ #define MPT_SCSI_SG_DEPTH 40 #endif -#ifdef CONFIG_FUSION_MAX_FC_SGE -#if CONFIG_FUSION_MAX_FC_SGE < 16 +#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 +#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 @@ -189,9 +190,8 @@ #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__ /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -239,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... @@ -369,6 +368,31 @@ typedef struct _SYSIF_REGS * in conjunction with SYSIF_REGS accesses! */ +/* + * End to End Data Protection Support + */ +#define EEDP_SUPPORT +#ifdef EEDP_SUPPORT + +#define PRO_R MPI_SCSIIO32_EEDPFLAGS_CHKRM_OP +#define PRO_W MPI_SCSIIO32_EEDPFLAGS_INSERT_OP +#define PRO_V MPI_SCSIIO32_EEDPFLAGS_INSERT_OP + +/* the read capacity 16 byte parameter block - defined in SBC-3 */ +struct read_cap_parameter{ + u64 logical_block_addr; + u32 logical_block_length; + u8 prot_en:1; + u8 p_type:3; + u8 reserved0:4; + u8 logical_blocks_per_phyical_block:4; + u8 reserved1:4; + u16 lowest_aligned_log_block_address:14; + u16 reserved2:2; + u8 reserved3[16]; +}; +#endif + /* * Dynamic Multi-Pathing specific stuff... @@ -378,7 +402,7 @@ typedef struct _SYSIF_REGS #define MPT_TARGET_NO_NEGO_WIDE 0x01 #define MPT_TARGET_NO_NEGO_SYNC 0x02 #define MPT_TARGET_NO_NEGO_QAS 0x04 -#define MPT_TAPE_NEGO_IDP 0x08 +#define MPT_TAPE_NEGO_IDP 0x08 /* * VirtDevice - FC LUN device or SCSI target device @@ -387,8 +411,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 */ @@ -396,13 +420,18 @@ 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 { VirtTarget *vtarget; u8 configured_lun; int lun; +#ifdef EEDP_SUPPORT + u8 eedp_enable; + u8 eedp_type; + u32 eedp_block_length; +#endif } VirtDevice; /* @@ -442,21 +471,14 @@ do { \ } while (0) -/* - * IOCTL structure and associated defines - */ - -#define MPTCTL_RESET_OK 0x01 /* Issue Bus Reset */ - #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_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 MPT_MGMT_STATUS_FREE_MF 0x40 /* free the mf from complete routine */ + #define INITIALIZE_MGMT_STATUS(status) \ status = MPT_MGMT_STATUS_PENDING; @@ -475,7 +497,7 @@ typedef struct _MPT_MGMT { u8 status; /* current command status */ int completion_code; u32 msg_context; -} MPT_MGMT; +}MPT_MGMT; /* * Event Structure and define @@ -538,7 +560,7 @@ typedef struct _SasCfgData { * @inactive_list */ struct inactive_raid_component_info { - struct list_head list; + struct list_head list; u8 volumeID; /* volume target id */ u8 volumeBus; /* volume channel */ IOC_3_PHYS_DISK d; /* phys disk info */ @@ -547,7 +569,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 */ @@ -578,8 +601,8 @@ struct mptfc_rport_info }; typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr); -typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length, - dma_addr_t dma_addr); +typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr); +typedef void (*MPT_SCHEDULE_TARGET_RESET)(void *ioc); /* * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS @@ -591,8 +614,7 @@ typedef struct _MPT_ADAPTER char name[MPT_NAME_LENGTH]; /* "iocN" */ char prod_name[MPT_NAME_LENGTH]; /* "LSIFC9x9" */ #ifdef CONFIG_FUSION_LOGGING - /* used in mpt_display_event_info */ - char evStr[EVENT_DESCR_STR_SZ]; + char evStr[EVENT_DESCR_STR_SZ]; /* used in mpt_display_event_info */ #endif char board_name[16]; char board_assembly[16]; @@ -605,8 +627,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; @@ -621,10 +643,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 */ + 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. @@ -653,18 +673,18 @@ 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 */ + 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 */ u32 biosVersion; /* BIOS version from IO Unit Page 2 */ @@ -673,7 +693,7 @@ typedef struct _MPT_ADAPTER 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; + dma_addr_t cached_fw_dma; int hs_reply_idx; #ifndef MFCNT u32 pad0; @@ -688,8 +708,14 @@ typedef struct _MPT_ADAPTER FCPortPage0_t fc_port_page0[2]; 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 @@ -701,7 +727,6 @@ typedef struct _MPT_ADAPTER u8 FirstWhoInit; u8 upload_fw; /* If set, do a fw upload */ u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */ - u8 pad1[4]; u8 DoneCtx; u8 TaskCtx; u8 InternalCtx; @@ -709,37 +734,39 @@ typedef struct _MPT_ADAPTER struct net_device *netdev; struct list_head sas_topology; struct mutex sas_topology_mutex; + u8 disable_hotplug_remove; - struct workqueue_struct *fw_event_q; + 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[MPT_KOBJ_NAME_LEN]; - - struct mutex sas_discovery_mutex; - u8 sas_discovery_runtime; - u8 sas_discovery_ignore_events; + char fw_event_q_name[MPT_KOBJ_NAME_LEN]; - /* port_info object for the host */ - struct mptsas_portinfo *hba_port_info; + 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 mutex sas_device_info_mutex; + struct semaphore sas_device_info_mutex; u8 old_sas_discovery_protocal; u8 sas_discovery_quiesce_io; int sas_index; /* index refrencing */ MPT_MGMT sas_mgmt; - MPT_MGMT mptbase_cmds; /* for sending config pages */ MPT_MGMT internal_cmds; + MPT_MGMT mptbase_cmds; /* for sending config pages */ MPT_MGMT taskmgmt_cmds; - MPT_MGMT ioctl_cmds; - spinlock_t taskmgmt_lock; /* diagnostic reset lock */ + 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; - struct work_struct sas_persist_task; + MPT_SCHEDULE_TARGET_RESET schedule_target_reset; +#if defined(CPQ_CIM) + u8 num_ports; +#endif + char reset_work_q_name[MPT_KOBJ_NAME_LEN]; + 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; @@ -748,26 +775,32 @@ typedef struct _MPT_ADAPTER struct work_struct fc_rescan_work; char fc_rescan_work_q_name[MPT_KOBJ_NAME_LEN]; struct workqueue_struct *fc_rescan_work_q; - - /* driver forced bus resets count */ - unsigned long hard_resets; - /* fw/external bus resets count */ - unsigned long soft_resets; - /* cmd timeouts */ - unsigned long timeouts; - + 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; - u64 dma_mask; + int sdev_queue_depth; /* sdev queue depth */ + u64 dma_mask; u32 broadcast_aen_busy; - char reset_work_q_name[MPT_KOBJ_NAME_LEN]; - struct workqueue_struct *reset_work_q; - struct delayed_work fault_reset_work; - +#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 in_rescan; u8 SGE_size; - + u8 in_rescan; + /* diag buffer bits for sysfs */ + u8 is_fault; + u32 ring_buffer_offset; + u32 ring_buffer_sz; } MPT_ADAPTER; /* @@ -804,11 +837,9 @@ typedef struct _mpt_sge { dma_addr_t Address; } MptSge_t; - #define mpt_msg_flags(ioc) \ - (ioc->sg_addr_size == sizeof(u64)) ? \ - MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \ - MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32 + (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) @@ -830,26 +861,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) @@ -865,13 +880,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, @@ -881,7 +889,7 @@ typedef enum { typedef struct _MPT_SCSI_HOST { MPT_ADAPTER *ioc; ushort sel_timeout[MPT_MAX_FC_DEVICES]; - char *info_kbuf; + char *info_kbuf; long last_queue_full; u16 spi_pending; struct list_head target_reset_list; @@ -889,14 +897,6 @@ typedef struct _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 { @@ -934,37 +934,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 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_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); - +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 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -71,6 +71,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 @@ -113,6 +122,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 *); @@ -128,7 +173,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 int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function); /* * Reset Handler cleanup function @@ -234,8 +278,7 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME 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)) { + (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 @@ -246,8 +289,7 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME le16_to_cpu(reply->u.sreply.TaskTag), le32_to_cpu(reply->u.sreply.TransferCount))); - if (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); @@ -262,10 +304,16 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME /* 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) + 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); + ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->ioctl_cmds.done); + if (ioc->bus_type == SAS) + ioc->schedule_target_reset(ioc); + } else { + ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->ioctl_cmds.done); + } } out_continuation: @@ -275,55 +323,14 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME return 1; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptctl_timeout_expired - * - * Expecting an interrupt, however timed out. - * - */ -static void -mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) -{ - unsigned long flags; - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n", - ioc->name, __func__)); - - 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); - - - if (!mptctl_bus_reset(ioc, mf->u.hdr.Function)) - 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) - mpt_HardResetHandler(ioc, CAN_SLEEP); - mpt_free_msg_frame(ioc, mf); -} - static int mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) { if (!mf) return 0; - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "TaskMgmt completed (mf=%p, mr=%p)\n", - ioc->name, mf, 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; @@ -338,17 +345,15 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, mpt_clear_taskmgmt_in_progress_flag(ioc); ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; complete(&ioc->taskmgmt_cmds.done); + if (ioc->bus_type == SAS) + ioc->schedule_target_reset(ioc); return 1; } return 0; } -/* mptctl_bus_reset - * - * Bus reset code. - * - */ -static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function) +static int +mptctl_do_taskmgmt(MPT_ADAPTER *ioc, u8 tm_type, u8 bus_id, u8 target_id) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; @@ -359,13 +364,6 @@ static int mptctl_bus_reset(MPT_ADAPTER 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; - } mutex_lock(&ioc->taskmgmt_cmds.mutex); if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { @@ -375,15 +373,13 @@ static int mptctl_bus_reset(MPT_ADAPTER retval = 0; - /* Send request - */ - mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc); - if (mf == NULL) { - dtmprintk(ioc, printk(MYIOC_s_WARN_FMT - "TaskMgmt, no msg frames!!\n", ioc->name)); + 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; + goto tm_done; } dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", @@ -392,10 +388,13 @@ static int mptctl_bus_reset(MPT_ADAPTER pScsiTm = (SCSITaskMgmt_t *) mf; 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->TaskType = tm_type; + if ((tm_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && + (ioc->bus_type == FC)) + pScsiTm->MsgFlags = + MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; + pScsiTm->TargetID = target_id; + pScsiTm->Bus = bus_id; pScsiTm->ChainOffset = 0; pScsiTm->Reserved = 0; pScsiTm->Reserved1 = 0; @@ -406,43 +405,45 @@ static int mptctl_bus_reset(MPT_ADAPTER pScsiTm->Reserved2[ii] = 0; switch (ioc->bus_type) { - case FC: - timeout = 40; - break; - case SAS: - timeout = 30; - break; - case SPI: - default: - timeout = 2; - break; + case FC: + timeout = 40; + break; + case SAS: + timeout = 30; + break; + case SPI: + default: + timeout = 10; + break; } - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "TaskMgmt type=%d timeout=%ld\n", - ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout)); + dtmprintk(ioc, + printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n", + ioc->name, tm_type, timeout)); 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_taskmgmt_id, ioc, - sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP); + sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); if (retval != 0) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + dfailprintk(ioc, + printk(MYIOC_s_ERR_FMT "TaskMgmt send_handshake FAILED!" " (ioc %p, mf %p, rc=%d) \n", ioc->name, ioc, mf, retval)); + mpt_free_msg_frame(ioc, mf); mpt_clear_taskmgmt_in_progress_flag(ioc); - goto mptctl_bus_reset_done; + goto tm_done; } } /* 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)); @@ -452,14 +453,14 @@ static int mptctl_bus_reset(MPT_ADAPTER retval = 0; else retval = -1; /* return failure */ - goto mptctl_bus_reset_done; + goto tm_done; } 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; + goto tm_done; } pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; @@ -467,7 +468,7 @@ static int mptctl_bus_reset(MPT_ADAPTER "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, + pScsiTmReply->TargetID, tm_type, le16_to_cpu(pScsiTmReply->IOCStatus), le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode, @@ -485,14 +486,67 @@ static int mptctl_bus_reset(MPT_ADAPTER retval = -1; /* return failure */ } - - mptctl_bus_reset_done: + tm_done: mutex_unlock(&ioc->taskmgmt_cmds.mutex); CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) return retval; } +static void +mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) +{ + unsigned long flags; + int ret_val = -1; + SCSIIORequest_t *scsi_req = (SCSIIORequest_t *) mf; + u8 function = mf->u.hdr.Function; + + 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); + + + CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) + + if (ioc->bus_type == SAS) { + if (function == MPI_FUNCTION_SCSI_IO_REQUEST) + ret_val = mptctl_do_taskmgmt(ioc, + MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, + scsi_req->Bus, scsi_req->TargetID); + else if (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) + ret_val = mptctl_do_taskmgmt(ioc, + MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + scsi_req->Bus, 0); + if (!ret_val) + return; + } else { + if ((function == MPI_FUNCTION_SCSI_IO_REQUEST) || + (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) + ret_val = mptctl_do_taskmgmt(ioc, + MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + scsi_req->Bus, 0); + if (!ret_val) + return; + } + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling Reset! \n", + ioc->name)); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* mptctl_ioc_reset * @@ -580,15 +634,17 @@ 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 +mptctl_release(struct inode *inode, struct file *filep) +{ + return fasync_helper(-1, filep, 0, &async_queue); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -608,6 +664,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", @@ -624,12 +681,6 @@ __mptctl_ioctl(struct file *file, unsign (iocp == NULL)) 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 @@ -649,6 +700,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 @@ -657,6 +727,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) @@ -667,6 +739,57 @@ __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; @@ -699,6 +822,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 */ @@ -789,13 +913,13 @@ mptctl_do_fw_download(int ioc, char __us 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 { /* Valid device. Get a message frame and construct the FW download message. - */ + */ if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL) return -EAGAIN; } @@ -870,8 +994,7 @@ mptctl_do_fw_download(int ioc, char __us * 96 8 * 64 4 */ - maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - - sizeof(FWDownloadTCSGE_t)) + maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / iocp->SGE_size; if (numfrags > maxfrags) { ret = -EMLINK; @@ -904,8 +1027,8 @@ mptctl_do_fw_download(int ioc, char __us 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; @@ -930,7 +1053,7 @@ retry_wait: 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, __func__); + 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; @@ -943,7 +1066,7 @@ retry_wait: } if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { - printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__); + printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __FUNCTION__); mpt_free_msg_frame(iocp, mf); ret = -ENODATA; goto fwdl_out; @@ -955,21 +1078,21 @@ retry_wait: 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; } @@ -979,7 +1102,7 @@ fwdl_out: CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status); SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0); - kfree_sgl(sgl, sgl_dma, buflist, iocp); + kfree_sgl(sgl, sgl_dma, buflist, iocp); return ret; } @@ -1061,9 +1184,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; @@ -1072,8 +1195,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i bytes_allocd += this_alloc; sgl->FlagsLength = (0x10000000|sgdir|this_alloc); - dma_addr = pci_map_single(ioc->pcidev, - buflist[buflist_ent].kptr, this_alloc, dir); + 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; fragcnt++; @@ -1087,8 +1211,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; } @@ -1097,9 +1221,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; } } @@ -1221,7 +1345,7 @@ mptctl_getiocinfo (unsigned long arg, un unsigned int port; int cim_rev; u8 revision; - struct scsi_device *sdev; + struct scsi_device *sdev; VirtDevice *vdevice; /* Add of PCI INFO results in unaligned access for @@ -1256,6 +1380,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); @@ -1265,8 +1390,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; } @@ -1318,6 +1443,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; @@ -1378,7 +1505,7 @@ mptctl_gettargetinfo (unsigned long arg) int maxWordsLeft; int numBytes; u8 port; - struct scsi_device *sdev; + struct scsi_device *sdev; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) { printk(KERN_ERR MYNAM "%s@%d::mptctl_gettargetinfo - " @@ -1389,6 +1516,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; @@ -1405,8 +1533,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; } @@ -1426,8 +1554,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; @@ -1439,6 +1567,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; @@ -1503,6 +1633,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; @@ -1564,6 +1695,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; @@ -1603,6 +1735,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; @@ -1616,15 +1749,14 @@ 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; } ioc->alloc_total += sz; ioc->eventContext = 0; - } + } /* Update the IOC event logging flag. */ @@ -1652,13 +1784,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); @@ -1706,6 +1839,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; @@ -1737,8 +1871,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; } @@ -1755,7 +1889,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 @@ -1780,6 +1914,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; @@ -1795,7 +1930,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 @@ -1818,7 +1953,7 @@ 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; @@ -1831,6 +1966,7 @@ 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; @@ -1862,8 +1998,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_ /* Get a free request frame and save the message context. */ - if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) - return -EAGAIN; + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) + return -EAGAIN; hdr = (MPIHeader_t *) mf; msgContext = le32_to_cpu(hdr->MsgContext); @@ -1884,11 +2020,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_ 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 (function) { case MPI_FUNCTION_IOC_FACTS: @@ -1967,6 +2102,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)) @@ -1987,7 +2124,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_ pScsiReq->Control = cpu_to_le32(scsidir | qtag); pScsiReq->DataLength = cpu_to_le32(dataSize); - } else { printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", @@ -2000,7 +2136,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. */ @@ -2077,12 +2213,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_ { 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)); + 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; } @@ -2094,7 +2228,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 { @@ -2102,6 +2236,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)) || @@ -2137,12 +2276,12 @@ mptctl_do_mpt_command (struct mpt_ioctl_ MPI_FUNCTION_FC_ABORT MPI_FUNCTION_LAN_SEND MPI_FUNCTION_LAN_RECEIVE - MPI_FUNCTION_LAN_RESET + MPI_FUNCTION_LAN_RESET */ 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; } @@ -2168,7 +2307,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) + MPI_SGE_FLAGS_DIRECTION ) << MPI_SGE_FLAGS_SHIFT; } else { flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; @@ -2230,7 +2369,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext); INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) - if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { + if (function == MPI_FUNCTION_SCSI_TASK_MGMT) { mutex_lock(&ioc->taskmgmt_cmds.mutex); if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { @@ -2244,8 +2383,8 @@ 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", @@ -2256,19 +2395,17 @@ mptctl_do_mpt_command (struct mpt_ioctl_ 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; retry_wait: - timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, - HZ*timeout); + 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, __func__)); + ioc->name, __FUNCTION__)); if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { if (function == MPI_FUNCTION_SCSI_TASK_MGMT) mutex_unlock(&ioc->taskmgmt_cmds.mutex); @@ -2279,7 +2416,8 @@ retry_wait: mutex_unlock(&ioc->taskmgmt_cmds.mutex); mptctl_timeout_expired(ioc, mf); mf = NULL; - } else + } + else goto retry_wait; goto done_free_mem; } @@ -2287,7 +2425,6 @@ retry_wait: if (function == MPI_FUNCTION_SCSI_TASK_MGMT) mutex_unlock(&ioc->taskmgmt_cmds.mutex); - mf = NULL; /* If a valid reply frame, copy to the user. @@ -2295,8 +2432,7 @@ retry_wait: */ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { if (karg.maxReplyBytes < ioc->reply_sz) { - sz = min(karg.maxReplyBytes, - 4*ioc->ioctl_cmds.reply[2]); + sz = min(karg.maxReplyBytes, 4*ioc->ioctl_cmds.reply[2]); } else { sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]); } @@ -2318,8 +2454,7 @@ retry_wait: 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_cmds.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__, @@ -2334,8 +2469,7 @@ retry_wait: * to user. */ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) && - (karg.dataInSize > 0) && (bufIn.kptr)) { - + (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 - " @@ -2378,7 +2512,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 @@ -2389,18 +2523,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 */ @@ -2420,13 +2553,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 */ @@ -2466,42 +2600,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; @@ -2537,21 +2638,23 @@ mptctl_hp_hostinfo(unsigned long arg, un } } - /* + /* * Gather ISTWI(Industry Standard Two Wire Interface) Data */ 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__)); + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", + 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); @@ -2561,23 +2664,21 @@ 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; - ioc->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); retval = 0; - SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, - IstwiRWRequest->MsgContext); + 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); - retry_wait: - timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, - HZ*MPT_IOCTL_DEFAULT_TIMEOUT); + 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, __func__); + 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; @@ -2617,7 +2718,7 @@ retry_wait: return -EFAULT; } - return 0; + return retval; } @@ -2627,7 +2728,7 @@ retry_wait: * 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 @@ -2639,12 +2740,12 @@ mptctl_hp_targetinfo(unsigned long arg) SCSIDevicePage0_t *pg0_alloc; SCSIDevicePage3_t *pg3_alloc; MPT_ADAPTER *ioc; - MPT_SCSI_HOST *hd = NULL; + MPT_SCSI_HOST *hd = NULL; hp_target_info_t karg; int iocnum; int data_sz; dma_addr_t page_dma; - CONFIGPARMS cfg; + CONFIGPARMS cfg; ConfigPageHeader_t hdr; int tmp, np, rc = 0; @@ -2657,13 +2758,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)) @@ -2773,10 +2875,11 @@ 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, - .fasync = mptctl_fasync, + .release = mptctl_release, + .fasync = mptctl_fasync, .unlocked_ioctl = mptctl_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = compat_mpctl_ioctl, @@ -2812,8 +2915,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; } @@ -2852,8 +2956,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; } @@ -2902,6 +3007,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; @@ -2938,6 +3068,7 @@ mptctl_probe(struct pci_dev *pdev, const mutex_init(&ioc->ioctl_cmds.mutex); init_completion(&ioc->ioctl_cmds.done); + return 0; } @@ -2951,6 +3082,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; + + /* + * 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 = { @@ -3012,16 +3159,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_reset_deregister(mptctl_taskmgmt_id); - - mpt_device_driver_deregister(MPTCTL_DRIVER); + 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,10 +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 +#define MPT_DEBUG_36GB_MEM 0x00400000 /* * CONFIG_FUSION_LOGGING - enabled in Kconfig @@ -127,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) @@ -139,7 +147,6 @@ #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 #include #include #include @@ -52,8 +53,10 @@ #include /* for mdelay */ #include /* needed for in_interrupt() proto */ #include /* notifier code */ +#include #include #include +#include #include #include @@ -80,10 +83,18 @@ MODULE_VERSION(my_VERSION); static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO; /* reasonable default */ module_param(mptfc_dev_loss_tmo, int, 0); MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the " - " transport to wait for an rport to " + " transport to wait for an rport to " " 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; @@ -118,7 +129,7 @@ static struct scsi_host_template mptfc_d .slave_configure = mptscsih_slave_configure, .target_destroy = mptfc_target_destroy, .slave_destroy = mptscsih_slave_destroy, - .change_queue_depth = mptscsih_change_queue_depth, + .change_queue_depth = mptscsih_change_queue_depth, .eh_abort_handler = mptfc_abort, .eh_device_reset_handler = mptfc_dev_reset, .eh_bus_reset_handler = mptfc_bus_reset, @@ -183,6 +194,35 @@ 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, + SCSI_QDEPTH_DEFAULT); + 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 +234,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 +271,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 @@ -335,7 +375,7 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, in data_sz = hdr.PageLength * 4; ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz, - &page0_dma); + &page0_dma); rc = -ENOMEM; if (!ppage0_alloc) break; @@ -371,7 +411,7 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, in *p_pp0++ = p_p0++; /* save addr */ } pci_free_consistent(ioc->pcidev, data_sz, - (u8 *) ppage0_alloc, page0_dma); + (u8 *) ppage0_alloc, page0_dma); if (rc != 0) break; @@ -476,6 +516,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 +554,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 +602,7 @@ mptfc_target_alloc(struct scsi_target *s return rc; } + /* * mptfc_dump_lun_info * @ioc @@ -589,7 +632,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 +646,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 +656,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 +676,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 +982,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 +995,8 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTE #define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS) for (ii=0; iifacts.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 +1007,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; } @@ -1003,10 +1044,10 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,in fc_host_maxframe_size(sh) = pp0->MaxFrameSize; fc_host_node_name(sh) = - (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low; + (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low; fc_host_port_name(sh) = - (u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low; + (u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low; fc_host_port_id(sh) = pp0->PortIdentifier; @@ -1082,10 +1123,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 +1137,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 +1161,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 +1204,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; @@ -1157,7 +1227,7 @@ mptfc_probe(struct pci_dev *pdev, const { struct Scsi_Host *sh; MPT_SCSI_HOST *hd; - MPT_ADAPTER *ioc; + MPT_ADAPTER *ioc; unsigned long flags; int ii; int numSGE = 0; @@ -1215,7 +1285,7 @@ mptfc_probe(struct pci_dev *pdev, const ioc->name); error = -1; goto out_mptfc_probe; - } + } spin_lock_init(&ioc->fc_rescan_work_lock); INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices); @@ -1238,6 +1308,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; @@ -1300,8 +1374,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, MPT_KOBJ_NAME_LEN, "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) @@ -1314,7 +1388,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 - @@ -1352,8 +1425,8 @@ 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->bus_type != FC) + return 0; if (ioc->sh == NULL || ((hd = shost_priv(ioc->sh)) == NULL)) @@ -1390,45 +1463,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) { @@ -1460,12 +1533,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) { @@ -1475,6 +1547,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); @@ -1517,7 +1591,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) - * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -78,6 +77,12 @@ MODULE_VERSION(my_VERSION); * Fusion MPT LAN private structures */ +struct NAA_Hosed { + u16 NAA; + u8 ieee[FC_ALEN]; + struct NAA_Hosed *next; +}; + struct BufferControl { struct sk_buff *skb; dma_addr_t dma; @@ -107,6 +112,7 @@ struct mpt_lan_priv { u32 total_posted; u32 total_received; + struct net_device_stats stats; /* Per device statistics */ struct delayed_work post_buckets_task; struct net_device *dev; @@ -153,6 +159,16 @@ static u8 LanCtx = MPT_MAX_PROTOCOL_DRIV static u32 max_buckets_out = 127; static u32 tx_max_out_p = 127 - 16; +#ifdef QLOGIC_NAA_WORKAROUND +static struct NAA_Hosed *mpt_bad_naa = NULL; +DEFINE_RWLOCK(bad_naa_lock); +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Fusion MPT LAN external data + */ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * lan_reply - Handle all data sent from the hardware. @@ -179,8 +195,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)) { @@ -429,6 +444,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)); @@ -572,7 +588,6 @@ mpt_lan_tx_timeout(struct net_device *de } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -//static inline int static int mpt_lan_send_turbo(struct net_device *dev, u32 tmsg) { @@ -585,12 +600,12 @@ mpt_lan_send_turbo(struct net_device *de ctx = GET_LAN_BUFFER_CONTEXT(tmsg); sent = priv->SendCtl[ctx].skb; - dev->stats.tx_packets++; - dev->stats.tx_bytes += sent->len; + priv->stats.tx_packets++; + priv->stats.tx_bytes += sent->len; 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, @@ -627,7 +642,7 @@ mpt_lan_send_reply(struct net_device *de switch (le16_to_cpu(pSendRep->IOCStatus) & MPI_IOCSTATUS_MASK) { case MPI_IOCSTATUS_SUCCESS: - dev->stats.tx_packets += count; + priv->stats.tx_packets += count; break; case MPI_IOCSTATUS_LAN_CANCELED: @@ -635,13 +650,13 @@ mpt_lan_send_reply(struct net_device *de break; case MPI_IOCSTATUS_INVALID_SGL: - dev->stats.tx_errors += count; + priv->stats.tx_errors += count; printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n", IOC_AND_NETDEV_NAMES_s_s(dev)); goto out; default: - dev->stats.tx_errors += count; + priv->stats.tx_errors += count; break; } @@ -652,11 +667,11 @@ mpt_lan_send_reply(struct net_device *de ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext)); sent = priv->SendCtl[ctx].skb; - dev->stats.tx_bytes += sent->len; + priv->stats.tx_bytes += sent->len; 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, @@ -695,7 +710,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) { @@ -703,8 +718,8 @@ 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); - return NETDEV_TX_BUSY; + __FUNCTION__, priv->mpt_txfidx_tail); + return 1; } mf = mpt_get_msg_frame(LanCtx, mpt_dev); @@ -713,8 +728,8 @@ 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__); - return NETDEV_TX_BUSY; + __FUNCTION__); + return 1; } ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--]; @@ -731,7 +746,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s skb_reset_mac_header(skb); skb_pull(skb, 12); - dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len, + dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len, PCI_DMA_TODEVICE); priv->SendCtl[ctx].skb = skb; @@ -761,6 +776,32 @@ mpt_lan_sdu_send (struct sk_buff *skb, s mac = skb_mac_header(skb); +#ifdef QLOGIC_NAA_WORKAROUND +{ + struct NAA_Hosed *nh; + + /* Munge the NAA for Tx packets to QLogic boards, which don't follow + RFC 2625. The longer I look at this, the more my opinion of Qlogic + drops. */ + read_lock_irq(&bad_naa_lock); + for (nh = mpt_bad_naa; nh != NULL; nh=nh->next) { + if ((nh->ieee[0] == mac[0]) && + (nh->ieee[1] == mac[1]) && + (nh->ieee[2] == mac[2]) && + (nh->ieee[3] == mac[3]) && + (nh->ieee[4] == mac[4]) && + (nh->ieee[5] == mac[5])) { + cur_naa = nh->NAA; + dlprintk ((KERN_INFO "mptlan/sdu_send: using NAA value " + "= %04x.\n", cur_naa)); + break; + } + } + read_unlock_irq(&bad_naa_lock); +} +#endif + + pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) | (mac[0] << 8) | (mac[1] << 0)); @@ -784,7 +825,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; @@ -796,7 +837,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s IOC_AND_NETDEV_NAMES_s_s(dev), le32_to_cpu(pSimple->FlagsLength))); - return NETDEV_TX_OK; + return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -807,7 +848,7 @@ mpt_lan_wake_post_buckets_task(struct ne */ { struct mpt_lan_priv *priv = netdev_priv(dev); - + if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { if (priority) { schedule_delayed_work(&priv->post_buckets_task, 0); @@ -816,7 +857,7 @@ mpt_lan_wake_post_buckets_task(struct ne dioprintk((KERN_INFO MYNAM ": post_buckets queued on " "timer.\n")); } - dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n", + dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n", IOC_AND_NETDEV_NAMES_s_s(dev) )); } } @@ -833,8 +874,8 @@ mpt_lan_receive_skb(struct net_device *d "delivered to upper level.\n", IOC_AND_NETDEV_NAMES_s_s(dev), skb->len)); - dev->stats.rx_bytes += skb->len; - dev->stats.rx_packets++; + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; skb->dev = dev; netif_rx(skb); @@ -1073,7 +1114,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, @@ -1121,22 +1161,20 @@ mpt_lan_receive_post_reply(struct net_de "(priv->buckets_out = %d)\n", IOC_AND_NETDEV_NAMES_s_s(dev), remaining, atomic_read(&priv->buckets_out)); - + if ((remaining < priv->bucketthresh) && ((atomic_read(&priv->buckets_out) - remaining) > MPT_LAN_BUCKETS_REMAIN_MISMATCH_THRESH)) { - printk (KERN_WARNING MYNAM " Mismatch between driver's " "buckets_out count and fw's BucketsRemaining " "count has crossed the threshold, issuing a " "LanReset to clear the fw's hashtable. You may " "want to check your /var/log/messages for \"CRC " "error\" event notifications.\n"); - mpt_lan_reset(dev); mpt_lan_wake_post_buckets_task(dev, 0); } - + return mpt_lan_receive_skb(dev, skb); } @@ -1164,7 +1202,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)); @@ -1173,9 +1211,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; @@ -1200,7 +1238,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; @@ -1223,7 +1261,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; @@ -1251,7 +1289,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; @@ -1261,7 +1299,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; } @@ -1285,9 +1323,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); } @@ -1296,7 +1334,7 @@ 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 const struct net_device_ops mpt_netdev_ops = { @@ -1311,11 +1349,10 @@ static const struct net_device_ops mpt_n 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; @@ -1327,8 +1364,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", @@ -1351,6 +1389,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; @@ -1372,6 +1412,8 @@ mpt_register_lan_device (MPT_ADAPTER *mp tx_max_out_p : MPT_TX_MAX_OUT_LIM; dev->netdev_ops = &mpt_netdev_ops; + +/* Not in 2.3.42. Need 2.3.45+ */ dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT; dlprintk((KERN_INFO MYNAM ": Finished registering dev " @@ -1387,7 +1429,7 @@ mpt_register_lan_device (MPT_ADAPTER *mp static int mptlan_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct net_device *dev; int i; @@ -1414,14 +1456,16 @@ mptlan_probe(struct pci_dev *pdev, const ioc->pfacts[i].PortNumber); continue; } - + printk(KERN_INFO MYNAM ": %s: Fusion MPT LAN device " "registered as '%s'\n", ioc->name, dev->name); printk(KERN_INFO MYNAM ": %s/%s: " - "LanAddr = %pM\n", + "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", IOC_AND_NETDEV_NAMES_s_s(dev), - dev->dev_addr); - + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + ioc->netdev = dev; return 0; @@ -1433,7 +1477,7 @@ mptlan_probe(struct pci_dev *pdev, const static void mptlan_remove(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct net_device *dev = ioc->netdev; if(dev != NULL) { @@ -1466,7 +1510,6 @@ static int __init mpt_lan_init (void) } dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); - mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER); return 0; } @@ -1505,8 +1548,9 @@ mpt_lan_type_trans(struct sk_buff *skb, printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n", NETDEV_PTR_TO_IOC_NAME_s(dev)); - printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %pM\n", - fch->saddr); + printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", + fch->saddr[0], fch->saddr[1], fch->saddr[2], + fch->saddr[3], fch->saddr[4], fch->saddr[5]); } if (*fch->daddr & 1) { @@ -1525,6 +1569,80 @@ mpt_lan_type_trans(struct sk_buff *skb, fcllc = (struct fcllc *)skb->data; +#ifdef QLOGIC_NAA_WORKAROUND +{ + u16 source_naa = fch->stype, found = 0; + + /* Workaround for QLogic not following RFC 2625 in regards to the NAA + value. */ + + if ((source_naa & 0xF000) == 0) + source_naa = swab16(source_naa); + + if (fcllc->ethertype == htons(ETH_P_ARP)) + dlprintk ((KERN_INFO "mptlan/type_trans: got arp req/rep w/ naa of " + "%04x.\n", source_naa)); + + if ((fcllc->ethertype == htons(ETH_P_ARP)) && + ((source_naa >> 12) != MPT_LAN_NAA_RFC2625)){ + struct NAA_Hosed *nh, *prevnh; + int i; + + dlprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep from " + "system with non-RFC 2625 NAA value (%04x).\n", + source_naa)); + + write_lock_irq(&bad_naa_lock); + for (prevnh = nh = mpt_bad_naa; nh != NULL; + prevnh=nh, nh=nh->next) { + if ((nh->ieee[0] == fch->saddr[0]) && + (nh->ieee[1] == fch->saddr[1]) && + (nh->ieee[2] == fch->saddr[2]) && + (nh->ieee[3] == fch->saddr[3]) && + (nh->ieee[4] == fch->saddr[4]) && + (nh->ieee[5] == fch->saddr[5])) { + found = 1; + dlprintk ((KERN_INFO "mptlan/type_trans: ARP Re" + "q/Rep w/ bad NAA from system already" + " in DB.\n")); + break; + } + } + + if ((!found) && (nh == NULL)) { + + nh = kmalloc(sizeof(struct NAA_Hosed), GFP_KERNEL); + dlprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep w/" + " bad NAA from system not yet in DB.\n")); + + if (nh != NULL) { + nh->next = NULL; + if (!mpt_bad_naa) + mpt_bad_naa = nh; + if (prevnh) + prevnh->next = nh; + + nh->NAA = source_naa; /* Set the S_NAA value. */ + for (i = 0; i < FC_ALEN; i++) + nh->ieee[i] = fch->saddr[i]; + dlprintk ((KERN_INFO "Got ARP from %02x:%02x:%02x:%02x:" + "%02x:%02x with non-compliant S_NAA value.\n", + fch->saddr[0], fch->saddr[1], fch->saddr[2], + fch->saddr[3], fch->saddr[4],fch->saddr[5])); + } else { + printk (KERN_ERR "mptlan/type_trans: Unable to" + " kmalloc a NAA_Hosed struct.\n"); + } + } else if (!found) { + printk (KERN_ERR "mptlan/type_trans: found not" + " set, but nh isn't null. Evil " + "funkiness abounds.\n"); + } + write_unlock_irq(&bad_naa_lock); + } +} +#endif + /* Strip the SNAP header from ARP packets since we don't * pass them through to the 802.2/SNAP layers. */ --- 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) - * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -73,6 +72,7 @@ #include #include +#include /* 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 #include #include -#include +#include #include +#include #include /* for mdelay */ +#include #include #include @@ -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" @@ -73,6 +74,7 @@ #define MPTSAS_RAID_CHANNEL 1 #define SAS_CONFIG_PAGE_TIMEOUT 30 + MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); @@ -84,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 = 300; +module_param(mpt_cmd_retry_count, int, 0); +MODULE_PARM_DESC(mpt_cmd_retry_count, + " Device discovery TUR command retry count: default=300"); + +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; @@ -96,7 +117,6 @@ static u8 mptsasInternalCtx = MPT_MAX_PR static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; -static void mptsas_firmware_event_work(struct work_struct *work); static void mptsas_send_sas_event(struct fw_event_work *fw_event); static void mptsas_send_raid_event(struct fw_event_work *fw_event); static void mptsas_send_ir2_event(struct fw_event_work *fw_event); @@ -126,6 +146,39 @@ static void mptsas_broadcast_primative_w static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); + +void mptsas_schedule_target_reset(void *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; + + 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, + SCSI_QDEPTH_DEFAULT); + 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) { @@ -279,6 +332,10 @@ mptsas_add_fw_event(MPT_ADAPTER *ioc, st { 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); @@ -297,7 +354,7 @@ mptsas_requeue_fw_event(MPT_ADAPTER *ioc unsigned long flags; spin_lock_irqsave(&ioc->fw_event_lock, flags); devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task " - "(fw_event=0x%p)\n", ioc->name, __func__, fw_event)); + "(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)); @@ -325,7 +382,7 @@ mptsas_cleanup_fw_event_q(MPT_ADAPTER *i { struct fw_event_work *fw_event, *next; struct mptsas_target_reset_event *target_reset_list, *n; - MPT_SCSI_HOST *hd = shost_priv(ioc->sh); + MPT_SCSI_HOST *hd = shost_priv(ioc->sh); /* flush the target_reset_list */ if (!list_empty(&hd->target_reset_list)) { @@ -436,7 +493,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) { @@ -465,6 +529,11 @@ mptsas_port_delete(MPT_ADAPTER *ioc, str kfree(port_details); } +/** + * mptsas_get_rphy - + * @phy_info: + * + **/ static inline struct sas_rphy * mptsas_get_rphy(struct mptsas_phyinfo *phy_info) { @@ -474,6 +543,13 @@ 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) { @@ -491,6 +567,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) { @@ -500,6 +581,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) { @@ -514,6 +602,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) { @@ -523,6 +616,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) @@ -544,15 +643,15 @@ static void 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_device_info *sas_info, *next; + struct sas_device_info *sas_info, *next; struct scsi_device *sdev; struct scsi_target *starget; - struct sas_rphy *rphy; + struct sas_rphy *rphy; /* * Delete all matching devices out of the list */ - mutex_lock(&ioc->sas_device_info_mutex); + 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 && @@ -564,7 +663,7 @@ mptsas_add_device_component(MPT_ADAPTER } } - sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); + sas_info = kzalloc(sizeof(struct sas_device_info), GFP_KERNEL); if (!sas_info) goto out; @@ -594,7 +693,7 @@ mptsas_add_device_component(MPT_ADAPTER } out: - mutex_unlock(&ioc->sas_device_info_mutex); + up(&ioc->sas_device_info_mutex); return; } @@ -631,23 +730,23 @@ mptsas_add_device_component_by_fw(MPT_AD } /** - * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list + * 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_add_device_component_starget_ir(MPT_ADAPTER *ioc, - struct scsi_target *starget) +mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, struct scsi_target *starget) { CONFIGPARMS cfg; ConfigPageHeader_t hdr; dma_addr_t dma_handle; pRaidVolumePage0_t buffer = NULL; int i; - RaidPhysDiskPage0_t phys_disk; - struct mptsas_device_info *sas_info, *next; + RaidPhysDiskPage0_t phys_disk; + struct sas_device_info *sas_info, *next; memset(&cfg, 0 , sizeof(CONFIGPARMS)); memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); @@ -684,14 +783,14 @@ mptsas_add_device_component_starget_ir(M */ for (i = 0; i < buffer->NumPhysDisks; i++) { - if (mpt_raid_phys_disk_pg0(ioc, + if(mpt_raid_phys_disk_pg0(ioc, buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) continue; mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus, phys_disk.PhysDiskID); - mutex_lock(&ioc->sas_device_info_mutex); + down(&ioc->sas_device_info_mutex); list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) { if (!sas_info->is_logical_volume && @@ -701,14 +800,13 @@ mptsas_add_device_component_starget_ir(M sas_info->volume_id = starget->id; } } - mutex_unlock(&ioc->sas_device_info_mutex); - + up(&ioc->sas_device_info_mutex); } /* * Delete all matching devices out of the list */ - mutex_lock(&ioc->sas_device_info_mutex); + 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 == @@ -718,7 +816,7 @@ mptsas_add_device_component_starget_ir(M } } - sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); + 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; @@ -727,7 +825,7 @@ mptsas_add_device_component_starget_ir(M INIT_LIST_HEAD(&sas_info->list); list_add_tail(&sas_info->list, &ioc->sas_device_info_list); } - mutex_unlock(&ioc->sas_device_info_mutex); + up(&ioc->sas_device_info_mutex); out: if (buffer) @@ -770,7 +868,8 @@ mptsas_add_device_component_starget(MPT_ } /** - * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached + * 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: @@ -779,7 +878,7 @@ mptsas_add_device_component_starget(MPT_ static void mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) { - struct mptsas_device_info *sas_info, *next; + struct sas_device_info *sas_info, *next; /* * Set is_cached flag @@ -799,20 +898,24 @@ mptsas_del_device_component_by_os(MPT_AD static void mptsas_del_device_components(MPT_ADAPTER *ioc) { - struct mptsas_device_info *sas_info, *next; + struct sas_device_info *sas_info, *next; - mutex_lock(&ioc->sas_device_info_mutex); + 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); } - mutex_unlock(&ioc->sas_device_info_mutex); + up(&ioc->sas_device_info_mutex); } /* * mptsas_setup_wide_ports + * configuration + * in the sas_topology + * @ioc: Pointer to MPT_ADAPTER structure + * @port_info: * * Updates for new and existing narrow/wide port configuration * in the sas_topology @@ -836,13 +939,14 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc 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)); + "%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)); @@ -945,19 +1049,18 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc } /** - * csmisas_find_vtarget - * - * @ioc - * @volume_id - * @volume_bus + * 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; + struct scsi_device *sdev; VirtDevice *vdevice; - VirtTarget *vtarget = NULL; + VirtTarget *vtarget = NULL; shost_for_each_device(sdev, ioc->sh) { vdevice = sdev->hostdata; @@ -1017,16 +1120,14 @@ mptsas_queue_rescan(MPT_ADAPTER *ioc) /** - * mptsas_target_reset - * - * Issues TARGET_RESET to end device using handshaking method - * - * @ioc - * @channel - * @id + * 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 + * Returns (1) success + * (0) failure * **/ static int @@ -1034,6 +1135,7 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) return 0; @@ -1075,16 +1177,27 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 return 0; } +static void +mptsas_block_io_sdev(struct scsi_device *sdev, void *data) +{ + scsi_device_set_state(sdev, SDEV_BLOCK); +} + +static void +mptsas_block_io_starget(struct scsi_target *starget) +{ + if (starget) + starget_for_each_device(starget, NULL, mptsas_block_io_sdev); +} + /** - * 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_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_reset_queue(MPT_ADAPTER *ioc, @@ -1098,10 +1211,12 @@ mptsas_target_reset_queue(MPT_ADAPTER *i id = sas_event_data->TargetID; channel = sas_event_data->Bus; - if (!(vtarget = mptsas_find_vtarget(ioc, channel, id))) - return; - - vtarget->deleted = 1; /* block IO */ + if ((vtarget = mptsas_find_vtarget(ioc, channel, id))) { + if (!ioc->disable_hotplug_remove) { + mptsas_block_io_starget(vtarget->starget); + vtarget->deleted = 1; /* block IO */ + } + } target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), GFP_ATOMIC); @@ -1124,20 +1239,57 @@ mptsas_target_reset_queue(MPT_ADAPTER *i } /** - * mptsas_taskmgmt_complete - complete SAS task management function + * mptsas_schedule_target_reset- send pending target reset + * @iocp: per adapter object + * + * This function will delete scheduled target reset from the list and + * try to send next target reset. This will be called from completion + * context of any Task managment command. + */ + +void +mptsas_schedule_target_reset(void *iocp) +{ + MPT_ADAPTER *ioc = (MPT_ADAPTER*)(iocp); + 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; + /* + * issue target reset to next device in the queue + */ + + head = &hd->target_reset_list; + if (list_empty(head)) + return; + + 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; +} + + +/** + * 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 * - * 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. **/ static int mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) { MPT_SCSI_HOST *hd = shost_priv(ioc->sh); - struct list_head *head = &hd->target_reset_list; - u8 id, channel; + struct list_head *head = &hd->target_reset_list; struct mptsas_target_reset_event *target_reset_list; + u8 id, channel; SCSITaskMgmtReply_t *pScsiTmReply; dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: " @@ -1212,32 +1364,15 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *io &target_reset_list->sas_event_data); - /* - * 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; + ioc->schedule_target_reset(ioc); return 1; } /** - * mptscsih_ioc_reset - * - * @ioc - * @reset_phase + * mptsas_ioc_reset - + * @ioc: Pointer to MPT_ADAPTER structure + * @reset_phase: * **/ static int @@ -1282,7 +1417,6 @@ mptsas_ioc_reset(MPT_ADAPTER *ioc, int r return rc; } - /** * enum device_state - * @DEVICE_RETRY: need to retry the TUR @@ -1296,6 +1430,15 @@ enum device_state{ DEVICE_READY, }; + +/** + * 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) @@ -1440,7 +1583,8 @@ mptsas_add_end_device(MPT_ADAPTER *ioc, } /** - * mptsas_del_end_device - report a deleted end device to sas transport layer + * mptsas_del_end_device - report a deleted end device to sas transport + * layer * @ioc: Pointer to MPT_ADAPTER structure * @phy_info: decribes attached device * @@ -1638,13 +1782,297 @@ mptsas_firmware_event_work(struct work_s +/** + * 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) +{ + 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; + + 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; + } + + 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; + } + + /* + * 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 ((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; + } + + 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; + } + + data = (u8 *)lun_data; + length = ((data[0] << 24) | (data[1] << 16) | + (data[2] << 8) | (data[3] << 0)); + + 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]); + +#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 + + out: + if (lun_data) + pci_free_consistent(ioc->pcidev, lun_data_len, lun_data, + lun_data_dma); + kfree(iocmd); + return rc; +} + +/** + * 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) { + state = DEVICE_RETRY; + break; + } 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); + } +} + +/** + * 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; + 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"); @@ -1664,10 +2092,19 @@ mptsas_slave_configure(struct scsi_devic 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 mptscsih_slave_configure(sdev); } +/** + * mptsas_target_alloc - + * @starget: + * + **/ static int mptsas_target_alloc(struct scsi_target *starget) { @@ -1677,7 +2114,7 @@ mptsas_target_alloc(struct scsi_target * u8 id, channel; struct sas_rphy *rphy; struct mptsas_portinfo *p; - int i; + int i; MPT_ADAPTER *ioc = hd->ioc; vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); @@ -1698,13 +2135,9 @@ mptsas_target_alloc(struct scsi_target * 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; - } - } + 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; } @@ -1720,6 +2153,12 @@ mptsas_target_alloc(struct scsi_target * 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 */ @@ -1746,6 +2185,11 @@ mptsas_target_alloc(struct scsi_target * return 0; } +/** + * mptsas_target_destroy - + * @starget: + * + **/ static void mptsas_target_destroy(struct scsi_target *starget) { @@ -1753,7 +2197,7 @@ mptsas_target_destroy(struct scsi_target MPT_SCSI_HOST *hd = shost_priv(host); struct sas_rphy *rphy; struct mptsas_portinfo *p; - int i; + int i; MPT_ADAPTER *ioc = hd->ioc; VirtTarget *vtarget; @@ -1765,7 +2209,6 @@ mptsas_target_destroy(struct scsi_target mptsas_del_device_component_by_os(ioc, starget->channel, starget->id); - if (starget->channel == MPTSAS_RAID_CHANNEL) goto out; @@ -1794,7 +2237,11 @@ mptsas_target_destroy(struct scsi_target starget->hostdata = NULL; } - +/** + * mptsas_slave_alloc - + * @sdev: + * + **/ static int mptsas_slave_alloc(struct scsi_device *sdev) { @@ -1803,8 +2250,8 @@ mptsas_slave_alloc(struct scsi_device *s struct sas_rphy *rphy; struct mptsas_portinfo *p; VirtDevice *vdevice; - struct scsi_target *starget; - int i; + struct scsi_target *starget; + int i; MPT_ADAPTER *ioc = hd->ioc; vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); @@ -1816,6 +2263,9 @@ mptsas_slave_alloc(struct scsi_device *s starget = scsi_target(sdev); vdevice->vtarget = starget->hostdata; + /* + * RAID volumes placed beyond the last expected port. + */ if (sdev->channel == MPTSAS_RAID_CHANNEL) goto out; @@ -1849,6 +2299,12 @@ mptsas_slave_alloc(struct scsi_device *s return 0; } +/** + * mptsas_qcmd - + * @SCpnt: + * @done: + * + **/ static int mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { @@ -1868,7 +2324,8 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, voi if (ioc->sas_discovery_quiesce_io) return SCSI_MLQUEUE_HOST_BUSY; -// scsi_print_command(SCpnt); + if (ioc->debug_level & MPT_DEBUG_SCSI) + scsi_print_command(SCpnt); return mptscsih_qcmd(SCpnt,done); } @@ -1878,7 +2335,7 @@ static struct scsi_host_template mptsas_ .module = THIS_MODULE, .proc_name = "mptsas", .proc_info = mptscsih_proc_info, - .name = "MPT SPI Host", + .name = "MPT SAS Host", .info = mptscsih_info, .queuecommand = mptsas_qcmd, .target_alloc = mptsas_target_alloc, @@ -1886,7 +2343,7 @@ static struct scsi_host_template mptsas_ .slave_configure = mptsas_slave_configure, .target_destroy = mptsas_target_destroy, .slave_destroy = mptscsih_slave_destroy, - .change_queue_depth = mptscsih_change_queue_depth, + .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, @@ -1901,6 +2358,11 @@ static struct scsi_host_template mptsas_ .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); @@ -1963,6 +2425,13 @@ static int mptsas_get_linkerrors(struct 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) { @@ -1981,6 +2450,12 @@ static int mptsas_mgmt_done(MPT_ADAPTER 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); @@ -2019,14 +2494,16 @@ static int mptsas_phy_reset(struct sas_p 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 (!timeleft) { - /* On timeout reset the board */ + 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); - mpt_HardResetHandler(ioc, CAN_SLEEP); - error = -ETIMEDOUT; + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out_unlock; + if (!timeleft) { + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + } goto out_unlock; } @@ -2055,6 +2532,12 @@ static int mptsas_phy_reset(struct sas_p return error; } +/** + * mptsas_get_enclosure_identifier - + * @rphy: + * @identifier: + * + **/ static int mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) { @@ -2089,6 +2572,11 @@ mptsas_get_enclosure_identifier(struct s return error; } +/** + * mptsas_get_bay_identifier - + * @rphy: + * + **/ static int mptsas_get_bay_identifier(struct sas_rphy *rphy) { @@ -2176,10 +2664,14 @@ static int mptsas_smp_handler(struct Scs (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); /* request */ - flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | - MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_DIRECTION) - << MPI_SGE_FLAGS_SHIFT; + + 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 |= (blk_rq_bytes(req) - 4); dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio), @@ -2200,20 +2692,27 @@ static int mptsas_smp_handler(struct Scs dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio), blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_in) - goto unmap; + goto out_unmap; + ioc->add_sge(psge, flagsLength, dma_addr_in); 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 (!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; + if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + mpt_free_msg_frame(ioc, mf); + mf = NULL; + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out_unmap; + if (!timeleft) { + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + } + goto out_unmap; } + mf = NULL; if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { @@ -2230,7 +2729,7 @@ static int mptsas_smp_handler(struct Scs ioc->name, __func__); ret = -ENXIO; } -unmap: +out_unmap: if (dma_addr_out) pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); @@ -2247,6 +2746,7 @@ out: return ret; } + static struct sas_function_template mptsas_transport_functions = { .get_linkerrors = mptsas_get_linkerrors, .get_enclosure_identifier = mptsas_get_enclosure_identifier, @@ -2257,6 +2757,12 @@ static struct sas_function_template mpts 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) { @@ -2305,7 +2811,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(struct mptsas_phyinfo), GFP_KERNEL); + sizeof(struct mptsas_phyinfo),GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; @@ -2335,6 +2841,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) { @@ -2350,11 +2861,11 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) cfg.cfghdr.ehdr = &hdr; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 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) @@ -2392,6 +2903,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) @@ -2412,12 +2931,12 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, str cfg.cfghdr.ehdr = &hdr; cfg.dir = 0; /* read */ - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; /* 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) @@ -2456,6 +2975,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) @@ -2482,7 +3009,6 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, cfg.dir = 0; /* read */ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - memset(device_info, 0, sizeof(struct mptsas_devinfo)); error = mpt_config(ioc, &cfg); if (error) goto out; @@ -2502,6 +3028,12 @@ 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; @@ -2530,6 +3062,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) @@ -2557,7 +3097,6 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc cfg.dir = 0; /* read */ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - memset(port_info, 0, sizeof(struct mptsas_portinfo)); error = mpt_config(ioc, &cfg); if (error) goto out; @@ -2578,18 +3117,18 @@ 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) ? buffer->NumPhys : 1; port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(struct mptsas_phyinfo), GFP_KERNEL); + sizeof(struct mptsas_phyinfo),GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; @@ -2613,6 +3152,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) @@ -2658,7 +3205,6 @@ mptsas_sas_expander_pg1(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; @@ -2686,6 +3232,199 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc return error; } +struct rep_manu_request{ + u8 smp_frame_type; + u8 function; + u8 reserved; + u8 request_length; +}; + +struct rep_manu_reply{ + u8 smp_frame_type; /* 0x41 */ + u8 function; /* 0x01 */ + u8 function_result; + u8 response_length; + u16 expander_change_count; + u8 reserved0[2]; + u8 sas_format:1; + u8 reserved1:7; + u8 reserved2[3]; + u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; + u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; + u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; + u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; + u16 component_id; + u8 component_revision_id; + u8 reserved3; + u8 vendor_specific[8]; +}; + +/** + * mptsas_exp_repmanufacture_info - + * @ioc: per adapter object + * @sas_address: expander sas address + * @edev: the sas_expander_device object + * + * Fills in the sas_expander_device object when SMP port is created. + * + * Returns 0 for success, non-zero for failure. + */ +static int +mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc, + u64 sas_address, struct sas_expander_device *edev) +{ + MPT_FRAME_HDR *mf; + SmpPassthroughRequest_t *smpreq; + SmpPassthroughReply_t *smprep; + struct rep_manu_reply *manufacture_reply; + struct rep_manu_request *manufacture_request; + int ret; + int flagsLength; + unsigned long timeleft; + char *psge; + unsigned long flags; + void *data_out = NULL; + dma_addr_t data_out_dma = 0; + u32 sz; + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); + if (ret) + goto out; + + mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); + if (!mf) { + ret = -ENOMEM; + goto out_unlock; + } + + smpreq = (SmpPassthroughRequest_t *)mf; + memset(smpreq, 0, sizeof(*smpreq)); + + sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); + + data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma); + if (!data_out) { + printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + ret = -ENOMEM; + goto put_mf; + } + + manufacture_request = data_out; + manufacture_request->smp_frame_type = 0x40; + manufacture_request->function = 1; + manufacture_request->reserved = 0; + manufacture_request->request_length = 0; + + smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; + smpreq->PhysicalPort = 0xFF; + *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); + smpreq->RequestDataLength = sizeof(struct rep_manu_request); + + psge = (char *) + (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); + + 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 |= sizeof(struct rep_manu_request); + + ioc->add_sge(psge, flagsLength, data_out_dma); + psge += ioc->SGE_size; + + 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 |= sizeof(struct rep_manu_reply); + ioc->add_sge(psge, flagsLength, data_out_dma + + sizeof(struct rep_manu_request)); + + 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)) { + ret = -ETIME; + mpt_free_msg_frame(ioc, mf); + mf = NULL; + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out_free; + if (!timeleft) { + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + } + goto out_free; + } + + mf = NULL; + + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { + u8 *tmp; + + smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; + if (le16_to_cpu(smprep->ResponseDataLength) != + sizeof(struct rep_manu_reply)) + goto out_free; + + manufacture_reply = data_out + sizeof(struct rep_manu_request); + strncpy(edev->vendor_id, manufacture_reply->vendor_id, + SAS_EXPANDER_VENDOR_ID_LEN); + strncpy(edev->product_id, manufacture_reply->product_id, + SAS_EXPANDER_PRODUCT_ID_LEN); + strncpy(edev->product_rev, manufacture_reply->product_rev, + SAS_EXPANDER_PRODUCT_REV_LEN); + edev->level = manufacture_reply->sas_format; + if (manufacture_reply->sas_format) { + strncpy(edev->component_vendor_id, + manufacture_reply->component_vendor_id, + SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); + tmp = (u8 *)&manufacture_reply->component_id; + edev->component_id = tmp[0] << 8 | tmp[1]; + edev->component_revision_id = + manufacture_reply->component_revision_id; + } + + } else { + printk(MYIOC_s_ERR_FMT + "%s: smp passthru reply failed to be returned\n", + ioc->name, __func__); + ret = -ENXIO; + } + +out_free: + if (data_out_dma) + pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma); +put_mf: + if (mf) + mpt_free_msg_frame(ioc, mf); +out_unlock: + CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) + mutex_unlock(&ioc->sas_mgmt.mutex); +out: + return ret; + +} + + +/** + * mptsas_parse_device_info - + * @identify: + * @device_info: + * + **/ static void mptsas_parse_device_info(struct sas_identify *identify, struct mptsas_devinfo *device_info) @@ -2745,6 +3484,13 @@ mptsas_parse_device_info(struct sas_iden } } +/** + * 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) { @@ -2868,7 +3614,6 @@ static int mptsas_probe_one_phy(struct d ioc = phy_to_ioc(phy_info->phy); if (phy_info->sas_port_add_phy) { - if (!port) { port = sas_port_alloc_num(dev); if (!port) { @@ -2886,20 +3631,18 @@ static int mptsas_probe_one_phy(struct d 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)); + (unsigned long long)phy_info->attached.sas_address)); } - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "sas_port_add_phy: phy_id=%d\n", - ioc->name, phy_info->phy_id)); + 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; 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) { + if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { struct sas_rphy *rphy; struct device *parent; struct sas_identify identify; @@ -2967,12 +3710,23 @@ static int mptsas_probe_one_phy(struct d goto out; } mptsas_set_rphy(ioc, phy_info, rphy); + if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE || + identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) + mptsas_exp_repmanufacture_info(ioc, + identify.sas_address, + rphy_to_expander_device(rphy)); } out: return error; } +/** + * mptsas_probe_hba_phys - + * @ioc: Pointer to MPT_ADAPTER structure + * @handle: + * + **/ static int mptsas_probe_hba_phys(MPT_ADAPTER *ioc) { @@ -3403,13 +4157,12 @@ mptsas_send_link_status_event(struct fw_ if (!port_info) { if (ioc->old_sas_discovery_protocal) { port_info = mptsas_expander_add(ioc, - le16_to_cpu(link_data->DevHandle)); + 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 @@ -3434,7 +4187,7 @@ static void mptsas_not_responding_devices(MPT_ADAPTER *ioc) { struct mptsas_portinfo buffer, *port_info; - struct mptsas_device_info *sas_info; + struct sas_device_info *sas_info; struct mptsas_devinfo sas_device; u32 handle; VirtTarget *vtarget = NULL; @@ -3443,6 +4196,9 @@ mptsas_not_responding_devices(MPT_ADAPTE int retval, retry_count; unsigned long flags; + if (ioc->disable_hotplug_remove) + return; + mpt_findImVolumes(ioc); spin_lock_irqsave(&ioc->taskmgmt_lock, flags); @@ -3456,74 +4212,66 @@ mptsas_not_responding_devices(MPT_ADAPTE spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); /* devices, logical volumes */ - mutex_lock(&ioc->sas_device_info_mutex); 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; - retry_count = 0; + sas_device.handle = 0; + retry_count = 0; retry_page: - retval = mptsas_sas_device_pg0(ioc, &sas_device, + retval = 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; - if (retval == -EBUSY) { - spin_lock_irqsave(&ioc->taskmgmt_lock, flags); - if (ioc->ioc_reset_in_progress) { - dfailprintk(ioc, - printk(MYIOC_s_DEBUG_FMT - "%s: exiting due to reset\n", - ioc->name, __func__)); - spin_unlock_irqrestore - (&ioc->taskmgmt_lock, flags); - mutex_unlock(&ioc-> - sas_device_info_mutex); - return; - } - spin_unlock_irqrestore(&ioc->taskmgmt_lock, - flags); + if (sas_device.handle) + continue; + if (retval == -EBUSY) { + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + dfailprintk(ioc, + printk(MYIOC_s_DEBUG_FMT + "%s: exiting due to reset\n", + ioc->name, __func__)); + spin_unlock_irqrestore + (&ioc->taskmgmt_lock, flags); + return; } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, + flags); + } - if (retval && (retval != -ENODEV)) { - if (retry_count < 10) { - retry_count++; - goto retry_page; - } else { - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s: Config page retry exceeded retry " - "count deleting device 0x%llx\n", - ioc->name, __func__, - sas_info->sas_address)); - } + if (retval && (retval != -ENODEV)) { + if (retry_count < 10) { + retry_count++; + goto retry_page; + } else { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Config page retry exceeded retry " + "count deleting device 0x%llx\n", + ioc->name, __func__, + sas_info->sas_address)); } + } - /* delete device */ - vtarget = mptsas_find_vtarget(ioc, + /* delete device */ + vtarget = mptsas_find_vtarget(ioc, sas_info->fw.channel, sas_info->fw.id); - - if (vtarget) - 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; - } + if (vtarget) + 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); } - mutex_unlock(&ioc->sas_device_info_mutex); /* expanders */ - mutex_lock(&ioc->sas_topology_mutex); redo_expander_scan: list_for_each_entry(port_info, &ioc->sas_topology, list) { @@ -3551,7 +4299,6 @@ retry_page: goto redo_expander_scan; } } - mutex_unlock(&ioc->sas_topology_mutex); } /** @@ -3563,7 +4310,7 @@ static void mptsas_probe_expanders(MPT_ADAPTER *ioc) { struct mptsas_portinfo buffer, *port_info; - u32 handle; + u32 handle; int i; handle = 0xFFFF; @@ -3611,9 +4358,11 @@ mptsas_probe_expanders(MPT_ADAPTER *ioc) static void mptsas_probe_devices(MPT_ADAPTER *ioc) { + u16 retry_count; u16 handle; struct mptsas_devinfo sas_device; struct mptsas_phyinfo *phy_info; + enum device_state state; handle = 0xFFFF; while (!(mptsas_sas_device_pg0(ioc, &sas_device, @@ -3634,7 +4383,17 @@ mptsas_probe_devices(MPT_ADAPTER *ioc) if (mptsas_get_rphy(phy_info)) continue; - mptsas_add_end_device(ioc, phy_info); + 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); + else + memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); } } @@ -3676,13 +4435,14 @@ mptsas_scan_sas_topology(MPT_ADAPTER *io } + static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event) { MPT_ADAPTER *ioc; EventDataQueueFull_t *qfull_data; - struct mptsas_device_info *sas_info; - struct scsi_device *sdev; + struct sas_device_info *sas_info; + struct scsi_device *sdev; int depth; int id = -1; int channel = -1; @@ -3697,7 +4457,7 @@ mptsas_handle_queue_full_event(struct fw current_depth = le16_to_cpu(qfull_data->CurrentDepth); /* if hidden raid component, look for the volume id */ - mutex_lock(&ioc->sas_device_info_mutex); + 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) { @@ -3730,7 +4490,7 @@ mptsas_handle_queue_full_event(struct fw } out: - mutex_unlock(&ioc->sas_device_info_mutex); + up(&ioc->sas_device_info_mutex); if (id != -1) { shost_for_each_device(sdev, ioc->sh) { @@ -3764,6 +4524,12 @@ mptsas_handle_queue_full_event(struct fw } +/** + * 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) { @@ -3788,6 +4554,7 @@ mptsas_find_phyinfo_by_sas_address(MPT_A return phy_info; } + /** * mptsas_find_phyinfo_by_phys_disk_num - * @ioc: Pointer to MPT_ADAPTER structure @@ -3814,7 +4581,7 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT 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) + + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); if (!phys_disk) goto out; @@ -3827,8 +4594,7 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT (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); + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, sas_address); goto out; } } @@ -3850,11 +4616,9 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT 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)) + 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]; } } @@ -3862,6 +4626,12 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT return phy_info; } +/** + * mptsas_reprobe_lun - + * @sdev: + * @data: + * + **/ static void mptsas_reprobe_lun(struct scsi_device *sdev, void *data) { @@ -3871,6 +4641,12 @@ mptsas_reprobe_lun(struct scsi_device *s rc = scsi_device_reprobe(sdev); } +/** + * mptsas_reprobe_target - + * @starget: + * @uld_attach: + * + **/ static void mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) { @@ -3878,6 +4654,15 @@ mptsas_reprobe_target(struct scsi_target 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) { @@ -3885,7 +4670,7 @@ mptsas_adding_inactive_raid_components(M ConfigPageHeader_t hdr; dma_addr_t dma_handle; pRaidVolumePage0_t buffer = NULL; - RaidPhysDiskPage0_t phys_disk; + RaidPhysDiskPage0_t phys_disk; int i; struct mptsas_phyinfo *phy_info; struct mptsas_devinfo sas_device; @@ -3896,6 +4681,7 @@ mptsas_adding_inactive_raid_components(M cfg.pageAddr = (channel << 8) + id; cfg.cfghdr.hdr = &hdr; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; if (mpt_config(ioc, &cfg) != 0) goto out; @@ -3956,6 +4742,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st struct scsi_target * starget; struct mptsas_devinfo sas_device; VirtTarget *vtarget; + enum device_state state; int i; switch (hot_plug_info->event_type) { @@ -3995,13 +4782,27 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st if (mptsas_get_rphy(phy_info)) break; - mptsas_add_end_device(ioc, phy_info); + 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; + } + + if (state == DEVICE_READY) + mptsas_add_end_device(ioc, phy_info); + else + memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); break; case MPTSAS_DEL_DEVICE: - phy_info = mptsas_find_phyinfo_by_sas_address(ioc, - hot_plug_info->sas_address); - mptsas_del_end_device(ioc, phy_info); + + 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; case MPTSAS_DEL_PHYSDISK: @@ -4009,9 +4810,8 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st mpt_findImVolumes(ioc); phy_info = mptsas_find_phyinfo_by_phys_disk_num( - ioc, hot_plug_info->phys_disk_num, - hot_plug_info->channel, - hot_plug_info->id); + ioc, hot_plug_info->phys_disk_num, hot_plug_info->channel, + hot_plug_info->id); mptsas_del_end_device(ioc, phy_info); break; @@ -4162,6 +4962,14 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st mptsas_free_fw_event(ioc, fw_event); } +/** + * mptsas_send_sas_event + * + * + * @ioc + * @sas_event_data + * + **/ static void mptsas_send_sas_event(struct fw_event_work *fw_event) { @@ -4228,6 +5036,15 @@ mptsas_send_sas_event(struct fw_event_wo } } + +/** + * mptsas_send_raid_event + * + * + * @ioc + * @raid_event_data + * + **/ static void mptsas_send_raid_event(struct fw_event_work *fw_event) { @@ -4347,19 +5164,19 @@ mptsas_send_raid_event(struct fw_event_w /** * mptsas_issue_tm - send mptsas internal tm request * @ioc: Pointer to MPT_ADAPTER 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) - * @task_context: Context for the task to be aborted - * @timeout: timeout for task management control + * @type + * @channel + * @id + * @lun + * @task_context + * @timeout * - * return 0 on success and -1 on failure: + * 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) +mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, int task_context, ulong timeout, + u8 *issue_reset) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; @@ -4367,8 +5184,7 @@ mptsas_issue_tm(MPT_ADAPTER *ioc, u8 typ unsigned long timeleft; *issue_reset = 0; - mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); - if (mf == NULL) { + 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)); @@ -4426,20 +5242,20 @@ mptsas_issue_tm(MPT_ADAPTER *ioc, u8 typ } /** - * mptsas_broadcast_primative_work - Handle broadcast primitives + * mptsas_broadcast_primative_work - Work queue thread to handle + * broadcast primitive events * @work: work queue payload containing info describing the event * - * this will be handled in workqueue context. - */ + **/ static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event) { MPT_ADAPTER *ioc = fw_event->ioc; - MPT_FRAME_HDR *mf; - VirtDevice *vdevice; + MPT_FRAME_HDR *mf; + VirtDevice *vdevice; int ii; struct scsi_cmnd *sc; - SCSITaskMgmtReply_t *pScsiTmReply; + SCSITaskMgmtReply_t * pScsiTmReply; u8 issue_reset; int task_context; u8 channel, id; @@ -4448,7 +5264,7 @@ mptsas_broadcast_primative_work(struct f u32 query_count; dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s - enter\n", ioc->name, __func__)); + "%s - enter\n", ioc->name, __FUNCTION__)); mutex_lock(&ioc->taskmgmt_cmds.mutex); if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { @@ -4506,7 +5322,7 @@ mptsas_broadcast_primative_work(struct f out: dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s - exit, query_count = %d termination_count = %d\n", - ioc->name, __func__, query_count, termination_count)); + ioc->name, __FUNCTION__, query_count, termination_count)); ioc->broadcast_aen_busy = 0; mpt_clear_taskmgmt_in_progress_flag(ioc); @@ -4514,20 +5330,19 @@ mptsas_broadcast_primative_work(struct f if (issue_reset) { printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", - ioc->name, __func__); - mpt_HardResetHandler(ioc, CAN_SLEEP); + ioc->name, __FUNCTION__); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP)) + mpt_HardResetHandler(ioc, CAN_SLEEP); } mptsas_free_fw_event(ioc, fw_event); } -/* - * mptsas_send_ir2_event - handle exposing hidden disk when - * an inactive raid volume is added - * - * @ioc: Pointer to MPT_ADAPTER structure - * @ir2_data +/** + * 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(struct fw_event_work *fw_event) { @@ -4569,6 +5384,13 @@ mptsas_send_ir2_event(struct fw_event_wo mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); } + +/** + * mptsas_event_process - + * @ioc: Pointer to MPT_ADAPTER structure + * @reply: + * + **/ static int mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) { @@ -4577,6 +5399,9 @@ mptsas_event_process(MPT_ADAPTER *ioc, E struct fw_event_work *fw_event; unsigned long delay; + if (ioc->bus_type != SAS) + return 0; + /* events turned off due to host reset or driver unloading */ if (ioc->fw_events_off) return 0; @@ -4659,6 +5484,7 @@ mptsas_event_process(MPT_ADAPTER *ioc, E return 0; } + /* Delete a volume when no longer listed in ioc pg2 */ static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id) @@ -4678,18 +5504,24 @@ static void mptsas_volume_delete(MPT_ADA goto release_sdev; out: printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " - "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id); + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,id); scsi_remove_device(sdev); release_sdev: scsi_device_put(sdev); } +/** + * mptsas_probe - + * @pdev: + * @id: + * + **/ static int mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct Scsi_Host *sh; MPT_SCSI_HOST *hd; - MPT_ADAPTER *ioc; + MPT_ADAPTER *ioc; unsigned long flags; int ii; int numSGE = 0; @@ -4707,7 +5539,7 @@ mptsas_probe(struct pci_dev *pdev, const ioc->DoneCtx = mptsasDoneCtx; ioc->TaskCtx = mptsasTaskCtx; ioc->InternalCtx = mptsasInternalCtx; - + ioc->schedule_target_reset = &mptsas_schedule_target_reset; /* Added sanity check on readiness of the MPT adapter. */ if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { @@ -4748,7 +5580,7 @@ mptsas_probe(struct pci_dev *pdev, const ioc->name); error = -1; goto out_mptsas_probe; - } + } spin_lock_irqsave(&ioc->FreeQlock, flags); @@ -4773,10 +5605,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) @@ -4786,6 +5618,7 @@ mptsas_probe(struct pci_dev *pdev, const * A slightly different algorithm is required for * 64bit SGEs. */ + scale = ioc->req_sz/ioc->SGE_size; if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * @@ -4822,12 +5655,16 @@ mptsas_probe(struct pci_dev *pdev, const dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", ioc->name, ioc->ScsiLookup)); + ioc->sdev_queue_depth = mpt_sdev_queue_depth; ioc->sas_data.ptClear = mpt_pt_clear; - 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); - mutex_init(&ioc->sas_device_info_mutex); + init_MUTEX(&ioc->sas_device_info_mutex); spin_unlock_irqrestore(&ioc->FreeQlock, flags); @@ -4865,7 +5702,14 @@ mptsas_shutdown(struct pci_dev *pdev) mptsas_cleanup_fw_event_q(ioc); } -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; @@ -4875,7 +5719,6 @@ static void __devexit mptsas_remove(stru mptsas_del_device_components(ioc); - ioc->sas_discovery_ignore_events = 1; sas_remove_host(ioc->sh); mutex_lock(&ioc->sas_topology_mutex); @@ -4920,6 +5763,10 @@ static struct pci_driver mptsas_driver = #endif }; +/** + * mptsas_init - + * + **/ static int __init mptsas_init(void) { @@ -4950,6 +5797,10 @@ mptsas_init(void) return error; } +/** + * mptsas_exit - + * + **/ static void __exit mptsas_exit(void) { --- a/drivers/message/fusion/mptsas.h +++ b/drivers/message/fusion/mptsas.h @@ -50,8 +50,8 @@ /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 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; }; @@ -61,34 +61,32 @@ enum mptsas_hotplug_action { MPTSAS_DEL_DEVICE, 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_ADD_INACTIVE_VOLUME, + MPTSAS_REQUEUE_EVENT, MPTSAS_IGNORE_EVENT, }; -struct mptsas_mapping{ +struct sas_mapping{ u8 id; u8 channel; }; -struct mptsas_device_info { - struct list_head list; - struct mptsas_mapping os; /* operating system mapping*/ - struct mptsas_mapping fw; /* firmware mapping */ +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 */ - /* this belongs to volume */ - u8 is_hidden_raid_component; - /* this valid when is_hidden_raid_component set */ - u8 volume_id; - /* cached data for a removed device */ - u8 is_cached; + 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 { @@ -104,19 +102,23 @@ struct mptsas_hotplug_event { struct scsi_device *sdev; }; + struct fw_event_work { - struct list_head list; + struct list_head list; struct delayed_work work; - MPT_ADAPTER *ioc; + MPT_ADAPTER *ioc; u32 event; u8 retries; u8 event_data[1]; }; -struct mptsas_discovery_event { +#if 0 +struct mptsas_link_status_event { struct work_struct work; + MpiEventDataSasPhyLinkStatus_t link_data; MPT_ADAPTER *ioc; }; +#endif /* * SAS topology structures @@ -146,20 +148,20 @@ 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*/ struct mptsas_devinfo identify; /* point to phy device info */ @@ -171,7 +173,7 @@ struct mptsas_phyinfo { struct mptsas_portinfo { struct list_head list; - u16 num_phys; /* number of phys */ + u16 num_phys; /* number of phys */ struct mptsas_phyinfo *phy_info; }; @@ -186,6 +188,12 @@ struct mptsas_enclosure { u8 sep_id; /* SEP device logical target id */ u8 sep_channel; /* SEP channel logical channel id */ }; - +#if 0 +struct mptsas_broadcast_primative_event { + struct delayed_work aen_work; + MPT_ADAPTER *ioc; +}; +#endif /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif + --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -53,7 +53,9 @@ #include /* for mdelay */ #include /* needed for in_interrupt() proto */ #include /* notifier code */ +#include #include +#include #include #include @@ -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... */ -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); @@ -93,32 +100,20 @@ static int mptscsih_AddSGE(MPT_ADAPTER * 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); -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); +static void mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice); -void -mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code); -static int mptscsih_get_completion_code(MPT_ADAPTER *ioc, - MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); -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 int -mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, - SCSITaskMgmtReply_t *pScsiTmReply); -void mptscsih_remove(struct pci_dev *); -void mptscsih_shutdown(struct pci_dev *); +void mptscsih_remove(struct pci_dev *); +void mptscsih_shutdown(struct pci_dev *); #ifdef CONFIG_PM -int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state); -int mptscsih_resume(struct pci_dev *pdev); +int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state); +int mptscsih_resume(struct pci_dev *pdev); #endif - -#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE - +static int mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, + SCSITaskMgmtReply_t *pScsiTmReply); +static int mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, + MPT_FRAME_HDR *reply); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -178,7 +173,7 @@ static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, SCSIIORequest_t *pReq, int req_idx) { - char *psge; + char *psge; char *chainSge; struct scatterlist *sg; int frm_sz; @@ -193,16 +188,29 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct dma_addr_t v2; u32 RequestNB; - sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK; +#ifdef EEDP_SUPPORT + if (pReq->Function == MPI_FUNCTION_SCSI_IO_32) { + SCSIIO32Request_t *mpi_request = (SCSIIO32Request_t *)pReq; + + sgdir = le32_to_cpu(mpi_request->Control) + & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK; + psge = (char *) &mpi_request->SGL; + } else { +#endif + sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK; + psge = (char *) &pReq->SGL; +#ifdef EEDP_SUPPORT + } +#endif if (sgdir == MPI_SCSIIO_CONTROL_WRITE) { sgdir = MPT_TRANSFER_HOST_TO_IOC; } else { sgdir = MPT_TRANSFER_IOC_TO_HOST; } - psge = (char *) &pReq->SGL; frm_sz = ioc->req_sz; + /* Map the data portion, if any. * sges_left = 0 if no data transfer. */ @@ -214,7 +222,7 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct */ sg = scsi_sglist(SCpnt); sg_done = 0; - sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION); + sgeOffset = psge - (char *) pReq; chainSge = NULL; /* Prior to entering this loop - the following must be set @@ -237,7 +245,7 @@ nextSGEset: thisxfer = sg_dma_len(sg); if (thisxfer == 0) { /* Get next SG element from the OS */ - sg = sg_next(sg); + sg = mpt_sg_next(sg); sg_done++; continue; } @@ -246,7 +254,7 @@ nextSGEset: ioc->add_sge(psge, sgflags | thisxfer, v2); /* Get next SG element from the OS */ - sg = sg_next(sg); + sg = mpt_sg_next(sg); psge += ioc->SGE_size; sgeOffset += ioc->SGE_size; sg_done++; @@ -346,7 +354,7 @@ nextSGEset: if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) { dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n", - ioc->name, pReq->CDB[0], SCpnt)); + ioc->name, pReq->CDB[0], SCpnt)); return FAILED; } @@ -392,7 +400,7 @@ mptscsih_issue_sep_command(MPT_ADAPTER * U32 SlotStatus) { MPT_FRAME_HDR *mf; - SEPRequest_t *SEPMsg; + SEPRequest_t *SEPMsg; if (ioc->bus_type != SAS) return; @@ -598,14 +606,16 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F 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; - - /* Special case, where already freed message frame is received from - * Firmware. It happens with Resetting IOC. - * Return immediately. Do not care - */ if ((req_idx != req_idx_MR) || - (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf)) + (le32_to_cpu(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 + "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)); return 0; + } sc = mptscsih_getclear_scsi_lookup(ioc, req_idx); if (sc == NULL) { @@ -658,6 +668,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; @@ -668,6 +679,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 @@ -685,18 +697,6 @@ 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 */ @@ -724,7 +724,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; @@ -769,7 +768,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F sc->result = DID_RESET << 16; case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ - if (ioc->bus_type == FC) + if ( ioc->bus_type == FC ) sc->result = DID_ERROR << 16; else sc->result = DID_RESET << 16; @@ -830,7 +829,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) { @@ -923,7 +922,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? @@ -954,6 +953,13 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ sc->result = DID_SOFT_ERROR << 16; break; +#ifdef EEDP_SUPPORT + case MPI_IOCSTATUS_EEDP_GUARD_ERROR: + case MPI_IOCSTATUS_EEDP_REF_TAG_ERROR: + case MPI_IOCSTATUS_EEDP_APP_TAG_ERROR: + sc->result = DID_PARITY << 16; + break; +#endif /* EEDP Support */ case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ @@ -1143,8 +1149,8 @@ mptscsih_report_queue_full(struct scsi_c void mptscsih_remove(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - struct Scsi_Host *host = ioc->sh; + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct Scsi_Host *host = ioc->sh; MPT_SCSI_HOST *hd; int sz1; @@ -1204,7 +1210,7 @@ mptscsih_shutdown(struct pci_dev *pdev) int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); scsi_block_requests(ioc->sh); flush_scheduled_work(); @@ -1221,7 +1227,7 @@ mptscsih_suspend(struct pci_dev *pdev, p int mptscsih_resume(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); int rc; rc = mpt_resume(pdev); @@ -1280,13 +1286,13 @@ mptscsih_copy_mem_info(struct info_str * } if (info->pos < info->offset) { - data += (info->offset - info->pos); - len -= (info->offset - info->pos); + data += (info->offset - info->pos); + len -= (info->offset - info->pos); } if (len > 0) { - memcpy(info->buffer + info->pos, data, len); - info->pos += len; + memcpy(info->buffer + info->pos, data, len); + info->pos += len; } } @@ -1326,12 +1332,12 @@ mptscsih_host_info(MPT_ADAPTER *ioc, cha /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_proc_info - Return information about MPT adapter - * @host: scsi host struct - * @buffer: if write, user data; if read, buffer for user + * @host: scsi host struct + * @buffer: if write, user data; if read, buffer for user * @start: returns the buffer address - * @offset: if write, 0; if read, the current offset into the buffer from - * the previous read. - * @length: if write, return length; + * @offset: if write, 0; if read, the current offset into the buffer from + * the previous read. + * @length: if write, return length; * @func: write = 1; read = 0 * * (linux scsi_host_template.info routine) @@ -1358,6 +1364,103 @@ mptscsih_proc_info(struct Scsi_Host *hos return size; } +#ifdef EEDP_SUPPORT +u8 opcode_protection[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, + 0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/** + * _scsih_setup_eedp - setup MPI request for EEDP transfer + * @ioc: + * @scmd: pointer to scsi command object + * @mpi_request: pointer to the SCSI_IO reqest message frame + * + * Supporting protection 1 only. + * + * Returns nothing + */ +static int +_scsih_setup_eedp(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd, SCSIIO32Request_t *mpi_request) +{ + VirtDevice *vdevice = scmd->device->hostdata; + u16 eedp_flags; + u8 scsi_opcode; + int lba_byte; + u32 *lba32; + + vdevice = scmd->device->hostdata; + if (!vdevice->eedp_enable) + return -1; + + /* protection type 1 support only */ + if (vdevice->eedp_type != 0) + return -1; + + /* check whether scsi opcode supports eedp transfer */ + scsi_opcode = scmd->cmnd[0]; + eedp_flags = opcode_protection[scsi_opcode]; + if (!eedp_flags) + return -1; + + /* + * enable ref/app/guard checking + * auto increment ref and app tag + */ + mpi_request->EEDPFlags = eedp_flags | + MPI_SCSIIO32_EEDPFLAGS_INC_PRI_REFTAG | + MPI_SCSIIO32_EEDPFLAGS_T10_CHK_REFTAG | + MPI_SCSIIO32_EEDPFLAGS_T10_CHK_LBATAG | + MPI_SCSIIO32_EEDPFLAGS_T10_CHK_GUARD; + + /* set block size */ + mpi_request->EEDPBlockSize = vdevice->eedp_block_length; + mpi_request->EEDPBlockSize += 8; + memset(mpi_request->CDB.CDB32, 0, 32); + + mpi_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xFFFF; + + /* set reference tag to low 32bit lba */ + lba_byte = (scmd->cmd_len == 16) ? 6 : 2; + lba32 = (u32 *)&scmd->cmnd[lba_byte]; + mpi_request->CDB.EEDP32.PrimaryReferenceTag = *lba32; + + /* set RDPROTECT, WRPROTECT, VRPROTECT bits to (001b) */ + scmd->cmnd[1] = (scmd->cmnd[1] & 0x1F) | 0x20; + + /* add the rest of the bits */ + mpi_request->Port = 0; + mpi_request->Flags = MPI_SCSIIO32_FLAGS_FORM_SCSIID; + mpi_request->DeviceAddress.SCSIID.TargetID = vdevice->vtarget->id; + mpi_request->DeviceAddress.SCSIID.Bus = vdevice->vtarget->channel; + mpi_request->ChainOffset = 0; + mpi_request->Function = MPI_FUNCTION_SCSI_IO_32; + mpi_request->CDBLength = scmd->cmd_len; + mpi_request->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; + mpi_request->MsgFlags = mpt_msg_flags(ioc); + int_to_scsilun(scmd->device->lun, (struct scsi_lun *)mpi_request->LUN); + memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); + mpi_request->SGLOffset0 = offsetof(SCSIIO32Request_t, SGL) / 4; + mpi_request->SGLOffset1 = 0; + mpi_request->SGLOffset2 = 0; + mpi_request->SGLOffset3 = 0; + return 0; +} +#endif /* EEDP Support */ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #define ADD_INDEX_LOG(req_ent) do { } while(0) @@ -1444,6 +1547,36 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v /* Use the above information to set up the message frame */ +#ifdef EEDP_SUPPORT + if (_scsih_setup_eedp(ioc, SCpnt, (SCSIIO32Request_t *)mf) == 0) { + SCSIIO32Request_t *mpi_request = (SCSIIO32Request_t *)mf; + + /* finish off setting the rest of the SCSIIO32 */ + mpi_request->Control = cpu_to_le32(scsictl); + mpi_request->DataLength = cpu_to_le32(datalen); + + /* SenseBuffer low address */ + mpi_request->SenseBufferLowAddr = + cpu_to_le32(ioc->sense_buf_low_dma + + (my_idx * MPT_SENSE_BUFFER_ALLOC)); + + /* Now add the SG list + * Always have a SGE even if null length. + */ + if (datalen == 0) { + /* Add a NULL SGE */ + ioc->add_sge((char *)&mpi_request->SGL, + MPT_SGE_FLAGS_SSIMPLE_READ | 0, + (dma_addr_t) -1); + } else { + /* Add a 32 or 64 bit SGE */ + if (mptscsih_AddSGE(ioc, SCpnt, + pScsiReq, my_idx) != SUCCESS) + goto fail; + } + goto send_mf; + } +#endif pScsiReq->TargetID = (u8) vdevice->vtarget->id; pScsiReq->Bus = vdevice->vtarget->channel; pScsiReq->ChainOffset = 0; @@ -1489,6 +1622,9 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v goto fail; } +#ifdef EEDP_SUPPORT + send_mf: +#endif SCpnt->host_scribble = (unsigned char *)mf; mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt); @@ -1560,6 +1696,137 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *i */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +static int +mptscsih_scandv_bus_reset(MPT_ADAPTER *ioc) +{ + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + SCSITaskMgmtReply_t *pScsiTmReply; + int ii; + int retval; + 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; + } + + /* Send request + */ + if ((mf = mpt_get_msg_frame(ioc->TaskCtx, 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 out; + } + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", + ioc->name, mf)); + + pScsiTm = (SCSITaskMgmt_t *) mf; + 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->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; + + switch (ioc->bus_type) { + case FC: + timeout = 40; + break; + case SAS: + timeout = 30; + break; + case SPI: + default: + timeout = 2; + break; + } + + 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 != 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; + } + } + + /* 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; + } + + 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; + } + + 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))); + + 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 */ + } + + out: + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + return retval; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_IssueTaskMgmt - Generic send Task Management function. * @hd: Pointer to MPT_SCSI_HOST structure @@ -1579,14 +1846,13 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *i * **/ int -mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, - int ctx2abort, ulong timeout) +mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; int ii; int retval; - MPT_ADAPTER *ioc = hd->ioc; + MPT_ADAPTER *ioc = hd->ioc; unsigned long timeleft; u8 issue_hard_reset; u32 ioc_raw_state; @@ -1646,7 +1912,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd pScsiTm->TaskType = type; pScsiTm->Reserved1 = 0; pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) - ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0; + ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0; int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); @@ -1705,7 +1971,8 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd if (issue_hard_reset) { printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", ioc->name, __func__); - retval = mpt_HardResetHandler(ioc, CAN_SLEEP); + if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0) + retval = mpt_HardResetHandler(ioc, CAN_SLEEP); mpt_free_msg_frame(ioc, mf); } @@ -1713,7 +1980,6 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd mutex_unlock(&ioc->taskmgmt_cmds.mutex); return retval; } -EXPORT_SYMBOL(mptscsih_IssueTaskMgmt); static int mptscsih_get_tm_timeout(MPT_ADAPTER *ioc) @@ -1722,6 +1988,7 @@ mptscsih_get_tm_timeout(MPT_ADAPTER *ioc case FC: return 40; case SAS: + return 30; case SPI: default: return 10; @@ -1746,7 +2013,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) int scpnt_idx; int retval; VirtDevice *vdevice; - ulong sn = SCpnt->serial_number; + ulong sn = SCpnt->serial_number; MPT_ADAPTER *ioc; /* If we can't locate our host adapter structure, return FAILED status. @@ -1771,7 +2038,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; } @@ -1786,25 +2067,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 = SUCCESS; + retval = FAILED; goto out; } + if (mpt_fwfault_debug) + mpt_halt_firmware(ioc); + if (ioc->timeouts < -1) ioc->timeouts++; - if (mpt_fwfault_debug) - mpt_halt_firmware(ioc); /* Most important! Set TaskMsgContext to SCpnt's MsgContext! * (the IO to be ABORT'd) @@ -1821,6 +2100,10 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) 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) { dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT @@ -1836,7 +2119,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) out: printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n", - ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt); + ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED" ), SCpnt); return retval; } @@ -1964,7 +2247,7 @@ int mptscsih_host_reset(struct scsi_cmnd *SCpnt) { MPT_SCSI_HOST * hd; - int status = SUCCESS; + int status = SUCCESS; MPT_ADAPTER *ioc; int retval; @@ -1975,9 +2258,6 @@ mptscsih_host_reset(struct scsi_cmnd *SC return FAILED; } - /* make sure we have no outstanding commands at this stage */ - mptscsih_flush_running_cmds(hd); - ioc = hd->ioc; printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n", ioc->name, SCpnt); @@ -1985,7 +2265,9 @@ mptscsih_host_reset(struct scsi_cmnd *SC /* 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. */ - retval = mpt_HardResetHandler(ioc, CAN_SLEEP); + if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0) + retval = mpt_HardResetHandler(ioc, CAN_SLEEP); + if (retval < 0) status = FAILED; else @@ -1997,6 +2279,7 @@ mptscsih_host_reset(struct scsi_cmnd *SC return status; } + static int mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, SCSITaskMgmtReply_t *pScsiTmReply) @@ -2083,7 +2366,6 @@ mptscsih_taskmgmt_response_code(MPT_ADAP printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n", ioc->name, response_code, desc); } -EXPORT_SYMBOL(mptscsih_taskmgmt_response_code); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** @@ -2119,6 +2401,8 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER * mpt_clear_taskmgmt_in_progress_flag(ioc); ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; complete(&ioc->taskmgmt_cmds.done); + if (ioc->bus_type == SAS) + ioc->schedule_target_reset(ioc); return 1; } return 0; @@ -2135,7 +2419,7 @@ mptscsih_bios_param(struct scsi_device * int heads; int sectors; sector_t cylinders; - ulong dummy; + ulong dummy; heads = 64; sectors = 32; @@ -2164,14 +2448,15 @@ 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, j; + u8 i, j; RaidPhysDiskPage1_t *phys_disk; int rc = 0; int num_paths; @@ -2197,7 +2482,7 @@ mptscsih_is_phys_disk(MPT_ADAPTER *ioc, ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); if (num_paths < 2) continue; - phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); if (!phys_disk) continue; @@ -2224,21 +2509,20 @@ mptscsih_is_phys_disk(MPT_ADAPTER *ioc, 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; @@ -2249,10 +2533,10 @@ u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) { struct inactive_raid_component_info *component_info; - int i, j; + int i,j; RaidPhysDiskPage1_t *phys_disk; int rc = -ENXIO; - int num_paths; + u8 num_paths; if (!ioc->raid_data.pIocPg3) goto out; @@ -2275,7 +2559,7 @@ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); if (num_paths < 2) continue; - phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); if (!phys_disk) continue; @@ -2308,14 +2592,14 @@ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc 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; @@ -2333,15 +2617,17 @@ mptscsih_slave_destroy(struct scsi_devic MPT_SCSI_HOST *hd = shost_priv(host); VirtTarget *vtarget; VirtDevice *vdevice; - struct scsi_target *starget; + struct scsi_target *starget; 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; } @@ -2359,8 +2645,8 @@ int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) { MPT_SCSI_HOST *hd = shost_priv(sdev->host); - VirtTarget *vtarget; - struct scsi_target *starget; + VirtTarget *vtarget; + struct scsi_target *starget; int max_depth; int tagged; MPT_ADAPTER *ioc = hd->ioc; @@ -2372,15 +2658,13 @@ mptscsih_change_queue_depth(struct scsi_ return -EOPNOTSUPP; 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 = ioc->sh->can_queue; + max_depth = ioc->sh->can_queue; if (!sdev->tagged_supported) max_depth = 1; @@ -2393,9 +2677,120 @@ 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; } +#ifdef EEDP_SUPPORT +/** + * _scsih_read_capacity_16 - send READ_CAPACITY_16 to target + * + */ +static int +_scsih_read_capacity_16(MPT_SCSI_HOST *hd, int id, int channel, u32 lun, + void *data, u32 length) +{ + INTERNAL_CMD iocmd; + dma_addr_t data_dma; + struct read_cap_parameter *parameter_data; + u32 data_length; + MPT_ADAPTER *ioc = hd->ioc; + int rc; + int count; + u8 skey; + u8 asc; + u8 ascq; + + data_length = sizeof(struct read_cap_parameter); + parameter_data = pci_alloc_consistent(ioc->pcidev, + data_length, &data_dma); + if (!parameter_data) { + printk(MYIOC_s_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + + iocmd.cmd = SERVICE_ACTION_IN; + iocmd.data_dma = data_dma; + iocmd.data = (u8 *)parameter_data; + iocmd.size = data_length; + iocmd.channel = channel; + iocmd.id = id; + iocmd.lun = lun; + + for (count=0; count < 4; count++) { + rc = mptscsih_do_cmd(hd, &iocmd); + + if(rc == MPT_SCANDV_GOOD) { + memcpy(data, parameter_data, + min_t(u32, data_length, length)); + break; + } else if(rc == 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)); + continue; + } else if(rc == 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)); + continue; + } else if(rc == 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,arc,ascq]: " + "[0x%02x,0x%02x,0x%02x]\n", ioc->name, + __FUNCTION__, channel, id, skey, asc, ascq)); + if( skey == UNIT_ATTENTION || + skey == NOT_READY || + skey == ILLEGAL_REQUEST ) { + continue; + } else { + 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); + break; + } + } else if(rc == MPT_SCANDV_SELECTION_TIMEOUT) { + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "read capacity failed due to no device\n", ioc->name, + __FUNCTION__, channel, id); + break; + } else if(rc == MPT_SCANDV_SOME_ERROR) { + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "read capacity failed due to some error\n", ioc->name, + __FUNCTION__, channel, id); + break; + } else { + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "read capacity failed due to some error\n", ioc->name, + __FUNCTION__, channel, id); + break; + } + } + + if(count > 4 && rc != 0) { + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "read capacity failed to many times\n", ioc->name, + __FUNCTION__, channel, id); + } + + pci_free_consistent(ioc->pcidev, data_length, parameter_data, data_dma); + return rc; +} +#endif + /* * 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 @@ -2408,7 +2803,7 @@ mptscsih_slave_configure(struct scsi_dev struct Scsi_Host *sh = sdev->host; VirtTarget *vtarget; VirtDevice *vdevice; - struct scsi_target *starget; + struct scsi_target *starget; MPT_SCSI_HOST *hd = shost_priv(sh); MPT_ADAPTER *ioc = hd->ioc; @@ -2416,6 +2811,45 @@ mptscsih_slave_configure(struct scsi_dev vtarget = starget->hostdata; vdevice = sdev->hostdata; +#ifdef EEDP_SUPPORT + if ((!(vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) && + (!(vdevice->vtarget->raidVolume))) { + + struct read_cap_parameter data; + memset(&data, 0, sizeof(struct read_cap_parameter)); + + /* + * check PROTECT bit + * + * NOTE: The crack monkey target mode driver doesn't + * set this bit(bug has been reported). + * The cm_target command line option is a work around. + */ + if (!(sdev->inquiry[5] & 1)) + goto out; + + if ((ioc->bus_type == FC) && + (_scsih_read_capacity_16(hd, vtarget->id, + vtarget->channel, sdev->lun, &data, + sizeof(struct read_cap_parameter)) == 0)) { + vdevice->eedp_enable = data.prot_en; + vdevice->eedp_type = data.p_type; + vdevice->eedp_block_length = + be32_to_cpu(data.logical_block_length); + + if (!vdevice->eedp_enable) + goto out; + + sdev_printk(KERN_INFO, sdev, "EEDP enabled: " + "protection_type(%d), block_length(%d)\n", + vdevice->eedp_type+1, + vdevice->eedp_block_length); + } + } + out: +#endif /* EEDP Support */ + + 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)); @@ -2427,6 +2861,11 @@ mptscsih_slave_configure(struct scsi_dev vdevice->configured_lun = 1; + 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; + } dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Queue depth=%d, tflags=%x\n", ioc->name, sdev->queue_depth, vtarget->tflags)); @@ -2437,8 +2876,10 @@ mptscsih_slave_configure(struct scsi_dev ioc->name, vtarget->negoFlags, vtarget->maxOffset, vtarget->minSyncFactor)); - mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH, + mptscsih_change_queue_depth(sdev, ioc->sdev_queue_depth, SCSI_QDEPTH_DEFAULT); + +slave_configure_exit: dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "tagged %d, simple %d, ordered %d\n", ioc->name,sdev->tagged_supported, sdev->simple_tags, @@ -2463,7 +2904,7 @@ mptscsih_copy_sense_data(struct scsi_cmn VirtDevice *vdevice; SCSIIORequest_t *pReq; u32 sense_count = le32_to_cpu(pScsiReply->SenseCount); - MPT_ADAPTER *ioc = hd->ioc; + MPT_ADAPTER *ioc = hd->ioc; /* Get target structure */ @@ -2477,8 +2918,11 @@ mptscsih_copy_sense_data(struct scsi_cmn /* Copy the sense received into the scsi command block. */ req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); - memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc)); + if (sense_count > SCSI_SENSE_BUFFERSIZE) + sense_count = SCSI_SENSE_BUFFERSIZE; + + memcpy(sc->sense_buffer, sense_data, sense_count); /* Log SMART data (asc = 0x5D, non-IM case only) if required. */ if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) { @@ -2496,12 +2940,10 @@ 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; } } } @@ -2512,12 +2954,16 @@ mptscsih_copy_sense_data(struct scsi_cmn } /** - * mptscsih_get_scsi_lookup - retrieves scmd entry + * mptscsih_get_scsi_lookup + * + * retrieves scmd entry from ScsiLookup[] array list + * * @ioc: Pointer to MPT_ADAPTER structure * @i: index into the array * * Returns the scsi_cmd pointer - */ + * + **/ struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i) { @@ -2530,10 +2976,12 @@ mptscsih_get_scsi_lookup(MPT_ADAPTER *io return scmd; } -EXPORT_SYMBOL(mptscsih_get_scsi_lookup); /** - * mptscsih_getclear_scsi_lookup - retrieves and clears scmd entry from ScsiLookup[] array list + * mptscsih_getclear_scsi_lookup + * + * retrieves and clears scmd entry from ScsiLookup[] array list + * * @ioc: Pointer to MPT_ADAPTER structure * @i: index into the array * @@ -2604,7 +3052,7 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int { MPT_SCSI_HOST *hd; - if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL) + if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL)) return 0; hd = shost_priv(ioc->sh); @@ -2684,7 +3132,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *io SCSIIOReply_t *pReply; u8 cmd; u16 req_idx; - u8 *sense_data; + u8 *sense_data; int sz; ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; @@ -2722,8 +3170,8 @@ mptscsih_scandv_complete(MPT_ADAPTER *io /** * mptscsih_get_completion_code - * @ioc: Pointer to MPT_ADAPTER structure - * @req: Pointer to original MPT request frame - * @reply: Pointer to MPT reply frame (NULL if TurboReply) + * @reply: + * @cmd: * **/ static int @@ -2829,7 +3277,7 @@ mptscsih_get_completion_code(MPT_ADAPTER * * > 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; @@ -2849,7 +3297,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER 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, __func__)); + "%s: busy with host reset\n", ioc->name, __FUNCTION__)); return MPT_SCANDV_BUSY; } spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); @@ -2945,6 +3393,35 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER 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; +#ifdef EEDP_SUPPORT + case SERVICE_ACTION_IN: + CDB[0] = cmd; + CDB[1] = 0x10; + CDB[13] = io->size & 0xFF; + dir = MPI_SCSIIO_CONTROL_READ; + timeout = 10; + cmdLen = 16; + break; +#endif + default: /* Error Case */ ret = -EFAULT; @@ -3032,9 +3509,12 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER goto out; } if (!timeleft) { + if (!mptscsih_scandv_bus_reset(ioc)) + goto out; printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", ioc->name, __func__); - mpt_HardResetHandler(ioc, CAN_SLEEP); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); mpt_free_msg_frame(ioc, mf); } goto out; @@ -3050,6 +3530,73 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER return ret; } +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; + + mutex_lock(&ioc->internal_cmds.mutex); + + /* 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 */ + + ioc->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)); + + 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); + } + goto out; + } + + ret = ioc->internal_cmds.completion_code; + + out: + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) + mutex_unlock(&ioc->internal_cmds.mutex); + return ret; +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks. @@ -3061,9 +3608,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 @@ -3075,23 +3623,124 @@ 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_fault_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, "%d\n", ioc->is_fault); +} +static ssize_t +mptscsih_fault_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, "%d", &val) != 1) + return -EINVAL; + + ioc->is_fault = val; + return strlen(buf); + +} + +struct DIAG_BUFFER_START { + u32 Size; + u32 DiagVersion; + u8 BufferType; + u8 Reserved[3]; + u32 Reserved1; + u32 Reserved2; + u32 Reserved3; +}; + +static ssize_t +mptscsih_ring_buffer_size_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; + u32 size = 0; + struct DIAG_BUFFER_START *request_data; + + ioc->ring_buffer_sz = 0; + if (!ioc->DiagBuffer[0]) + return 0; + + request_data = (struct DIAG_BUFFER_START *)ioc->DiagBuffer[0]; + if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 || + le32_to_cpu(request_data->DiagVersion) == 0x01000000) && + le32_to_cpu(request_data->Reserved3) == 0x4742444c) { + size = le32_to_cpu(request_data->Size); + ioc->ring_buffer_sz = size; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", size); +} + +static ssize_t +mptscsih_ring_buffer_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; + void *request_data; + u32 size; + + if (!ioc->DiagBuffer[0]) + return 0; + + if (ioc->ring_buffer_offset > ioc->ring_buffer_sz) + return 0; + + size = ioc->ring_buffer_sz - ioc->ring_buffer_offset; + size = (size > PAGE_SIZE) ? PAGE_SIZE : size; + request_data = ioc->DiagBuffer[0] + ioc->ring_buffer_offset; + memcpy(buf, request_data, size); + return size; +} + +static ssize_t +mptscsih_ring_buffer_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, "%d", &val) != 1) + return -EINVAL; + + ioc->ring_buffer_offset = val; + return strlen(buf); +} + static ssize_t mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -3106,7 +3755,6 @@ mptscsih_version_fw_show(struct device * (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, ioc->facts.FWVersion.Word & 0x000000FF); } -static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL); static ssize_t mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr, @@ -3116,13 +3764,12 @@ mptscsih_version_bios_show(struct device MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; - return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n", + return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", (ioc->biosVersion & 0xFF000000) >> 24, (ioc->biosVersion & 0x00FF0000) >> 16, (ioc->biosVersion & 0x0000FF00) >> 8, ioc->biosVersion & 0x000000FF); } -static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL); static ssize_t mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr, @@ -3132,14 +3779,17 @@ mptscsih_version_mpi_show(struct device MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; - return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion); + if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) + return snprintf(buf, PAGE_SIZE, "%03x.%02x\n", + ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8); + else + return snprintf(buf, PAGE_SIZE, "%03x\n", + ioc->facts.MsgVersion); } -static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL); static ssize_t mptscsih_version_product_show(struct device *dev, - struct device_attribute *attr, -char *buf) + struct device_attribute *attr, char *buf) { struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); @@ -3147,8 +3797,6 @@ char *buf) return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name); } -static DEVICE_ATTR(version_product, S_IRUGO, - mptscsih_version_product_show, NULL); static ssize_t mptscsih_version_nvdata_persistent_show(struct device *dev, @@ -3162,8 +3810,6 @@ mptscsih_version_nvdata_persistent_show( return snprintf(buf, PAGE_SIZE, "%02xh\n", ioc->nvdata_version_persistent); } -static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, - mptscsih_version_nvdata_persistent_show, NULL); static ssize_t mptscsih_version_nvdata_default_show(struct device *dev, @@ -3175,8 +3821,6 @@ mptscsih_version_nvdata_default_show(str return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default); } -static DEVICE_ATTR(version_nvdata_default, S_IRUGO, - mptscsih_version_nvdata_default_show, NULL); static ssize_t mptscsih_board_name_show(struct device *dev, struct device_attribute *attr, @@ -3188,11 +3832,10 @@ mptscsih_board_name_show(struct device * return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name); } -static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL); static ssize_t -mptscsih_board_assembly_show(struct device *dev, - struct device_attribute *attr, char *buf) +mptscsih_board_assembly_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); @@ -3200,8 +3843,6 @@ mptscsih_board_assembly_show(struct devi return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly); } -static DEVICE_ATTR(board_assembly, S_IRUGO, - mptscsih_board_assembly_show, NULL); static ssize_t mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr, @@ -3213,8 +3854,6 @@ mptscsih_board_tracer_show(struct device return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer); } -static DEVICE_ATTR(board_tracer, S_IRUGO, - mptscsih_board_tracer_show, NULL); static ssize_t mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr, @@ -3226,8 +3865,6 @@ mptscsih_io_delay_show(struct device *de return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); } -static DEVICE_ATTR(io_delay, S_IRUGO, - mptscsih_io_delay_show, NULL); static ssize_t mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr, @@ -3239,8 +3876,6 @@ mptscsih_device_delay_show(struct device return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); } -static DEVICE_ATTR(device_delay, S_IRUGO, - mptscsih_device_delay_show, NULL); static ssize_t mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr, @@ -3252,6 +3887,7 @@ mptscsih_debug_level_show(struct device return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level); } + static ssize_t mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -3265,14 +3901,78 @@ 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 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(fault, S_IRUGO | S_IWUSR, + mptscsih_fault_show, mptscsih_fault_store); +static DEVICE_ATTR(ring_buffer_size, S_IRUGO, + mptscsih_ring_buffer_size_show, NULL); +static DEVICE_ATTR(ring_buffer, S_IRUGO | S_IWUSR, + mptscsih_ring_buffer_show, mptscsih_ring_buffer_store); +static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL); +static DEVICE_ATTR(version_bios, S_IRUGO, + mptscsih_version_bios_show, NULL); +static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL); +static DEVICE_ATTR(version_product, S_IRUGO, + mptscsih_version_product_show, NULL); +static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, + mptscsih_version_nvdata_persistent_show, NULL); +static DEVICE_ATTR(version_nvdata_default, S_IRUGO, + mptscsih_version_nvdata_default_show, NULL); +static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL); +static DEVICE_ATTR(board_assembly, S_IRUGO, + mptscsih_board_assembly_show, NULL); +static DEVICE_ATTR(board_tracer, S_IRUGO, + mptscsih_board_tracer_show, NULL); +static DEVICE_ATTR(io_delay, S_IRUGO, + mptscsih_io_delay_show, NULL); +static DEVICE_ATTR(device_delay, S_IRUGO, + mptscsih_device_delay_show, NULL); static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR, - mptscsih_debug_level_show, mptscsih_debug_level_store); + mptscsih_debug_level_show, mptscsih_debug_level_store); +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_fault, + &dev_attr_ring_buffer_size, + &dev_attr_ring_buffer, &dev_attr_version_fw, &dev_attr_version_bios, &dev_attr_version_mpi, @@ -3285,6 +3985,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, }; @@ -3312,5 +4013,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_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 @@ -85,12 +85,14 @@ #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 - +#define mpt_sg_next(sg) sg_next(sg) typedef struct _internal_cmd { char *data; /* data pointer */ dma_addr_t data_dma; /* data dma address */ @@ -114,9 +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 int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, - u8 id, int lun, int ctx2abort, ulong timeout); -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); @@ -130,8 +130,11 @@ extern int mptscsih_event_process(MPT_AD extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason); +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 struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); +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 @@ -43,7 +43,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - +#include #include #include #include @@ -53,8 +53,10 @@ #include /* for mdelay */ #include /* needed for in_interrupt() proto */ #include /* notifier code */ +#include #include #include +#include #include #include @@ -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; } @@ -304,7 +314,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, 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,76 +631,11 @@ static void mptspi_read_parameters(struc spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0; } -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; - - mutex_lock(&ioc->internal_cmds.mutex); - - /* 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, __func__)); - 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 */ - - ioc->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)); - - 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, __func__)); - 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, __func__); - mpt_HardResetHandler(ioc, CAN_SLEEP); - mpt_free_msg_frame(ioc, mf); - } - goto out; - } - - ret = ioc->internal_cmds.completion_code; - - out: - CLEAR_MGMT_STATUS(ioc->internal_cmds.status) - mutex_unlock(&ioc->internal_cmds.mutex); - return ret; -} - 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 */ @@ -691,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; } @@ -705,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); @@ -728,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; } @@ -750,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)) @@ -869,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; } @@ -899,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; @@ -975,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; @@ -998,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); @@ -1042,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; @@ -1065,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; @@ -1086,10 +1039,17 @@ struct work_queue_wrapper { int disk; }; -static void mpt_work_wrapper(struct work_struct *work) +static void +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) +mpt_work_wrapper(struct work_struct *work) { struct work_queue_wrapper *wqw = container_of(work, struct work_queue_wrapper, work); +#else +mpt_work_wrapper(void *data) +{ + struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; +#endif struct _MPT_SCSI_HOST *hd = wqw->hd; MPT_ADAPTER *ioc = hd->ioc; struct Scsi_Host *shost = ioc->sh; @@ -1117,12 +1077,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); } @@ -1133,12 +1093,16 @@ 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; } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) INIT_WORK(&wqw->work, mpt_work_wrapper); +#else + INIT_WORK(&wqw->work, mpt_work_wrapper, wqw); +#endif wqw->hd = hd; wqw->disk = disk; @@ -1151,6 +1115,9 @@ mptspi_event_process(MPT_ADAPTER *ioc, E u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); + if (ioc->bus_type != SPI) + return 0; + if (hd && event == MPI_EVENT_INTEGRATED_RAID) { int reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16; @@ -1225,14 +1192,20 @@ static struct pci_device_id mptspi_pci_t MODULE_DEVICE_TABLE(pci, mptspi_pci_table); -/* +/** * renegotiate for a given target - */ + **/ static void +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) mptspi_dv_renegotiate_work(struct work_struct *work) { struct work_queue_wrapper *wqw = container_of(work, struct work_queue_wrapper, work); +#else +mptspi_dv_renegotiate_work(void *data) +{ + struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; +#endif struct _MPT_SCSI_HOST *hd = wqw->hd; struct scsi_device *sdev; struct scsi_target *starget; @@ -1267,38 +1240,43 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_H if (!wqw) return; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work); +#else + INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work, wqw); +#endif wqw->hd = hd; 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) { @@ -1315,13 +1293,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) { @@ -1446,6 +1424,7 @@ mptspi_probe(struct pci_dev *pdev, const (ioc->req_sz - 64) / ioc->SGE_size; } + if (numSGE < sh->sg_tablesize) { /* Reset this value */ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT @@ -1454,11 +1433,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!) */ @@ -1472,12 +1451,11 @@ mptspi_probe(struct pci_dev *pdev, const dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", ioc->name, ioc->ScsiLookup)); + ioc->sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH; ioc->spi_data.Saf_Te = mpt_saf_te; 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; hd->last_queue_full = 0; hd->spi_pending = 0; @@ -1528,7 +1506,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) { @@ -1558,7 +1536,8 @@ mptspi_init(void) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptspi_exit - Unregisters MPT adapter(s) - */ + * + **/ static void __exit mptspi_exit(void) { @@ -1566,7 +1545,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,671 @@ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* 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); + ioc->DiagBuffer[buffer_type] = NULL; + ioc->DiagBuffer_sz[buffer_type] = 0; + ioc->DiagBuffer_dma[buffer_type] = 0; + } + 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;