Index: linux-2.6.18.i386/drivers/message/fusion/Kconfig =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/Kconfig +++ linux-2.6.18.i386/drivers/message/fusion/Kconfig @@ -1,14 +1,19 @@ -menu "Fusion MPT device support" +menuconfig FUSION + bool "Fusion MPT device support" + depends on PCI + ---help--- + Say Y here to get to see options for Fusion Message + Passing Technology (MPT) drivers. + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. -config FUSION - bool - default n +if FUSION config FUSION_SPI tristate "Fusion MPT ScsiHost drivers for SPI" depends on PCI && SCSI - select FUSION select SCSI_SPI_ATTRS ---help--- SCSI HOST support for a parallel SCSI host adapters. @@ -19,11 +24,11 @@ config FUSION_SPI LSI53C1020A LSI53C1030 LSI53C1035 + ATTO UL4D config FUSION_FC tristate "Fusion MPT ScsiHost drivers for FC" depends on PCI && SCSI - select FUSION select SCSI_FC_ATTRS ---help--- SCSI HOST support for a Fiber Channel host adapters. @@ -36,11 +41,13 @@ config FUSION_FC LSIFC929 LSIFC929X LSIFC929XL + LSIFC949X + LSIFC949E + Brocade FC 410/420 config FUSION_SAS tristate "Fusion MPT ScsiHost drivers for SAS" depends on PCI && SCSI - select FUSION select SCSI_SAS_ATTRS ---help--- SCSI HOST support for a SAS host adapters. @@ -51,22 +58,34 @@ config FUSION_SAS LSISAS1068 LSISAS1064E LSISAS1068E + LSISAS1078 config FUSION_MAX_SGE - int "Maximum number of scatter gather entries (16 - 128)" - depends on FUSION + 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. config FUSION_CTL tristate "Fusion MPT misc device (ioctl) driver" - depends on FUSION_SPI || FUSION_FC + depends on FUSION_SPI || FUSION_FC || FUSION_SAS ---help--- The Fusion MPT misc device driver provides specialized control of MPT adapters via system ioctl calls. Use of ioctl calls to @@ -100,4 +119,17 @@ config FUSION_LAN If unsure whether you really want or need this, say N. -endmenu +config FUSION_LOGGING + bool "Fusion MPT logging facility" + ---help--- + This turns on a logging facility that can be used to debug a number + of Fusion MPT related problems. + + The debug level can be programmed on the fly via SysFS (hex values) + + echo [level] > /sys/class/scsi_host/host#/debug_level + + There are various debug levels that can be found in the source: + file:drivers/message/fusion/mptdebug.h + +endif # FUSION Index: linux-2.6.18.i386/drivers/message/fusion/Makefile =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/Makefile +++ linux-2.6.18.i386/drivers/message/fusion/Makefile @@ -1,42 +1,16 @@ -# Fusion MPT drivers; recognized debug defines... -# MPT general: -#EXTRA_CFLAGS += -DMPT_DEBUG -#EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME -#EXTRA_CFLAGS += -DMPT_DEBUG_SG -#EXTRA_CFLAGS += -DMPT_DEBUG_EVENTS -#EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE_EVENTS -#EXTRA_CFLAGS += -DMPT_DEBUG_INIT -#EXTRA_CFLAGS += -DMPT_DEBUG_EXIT -#EXTRA_CFLAGS += -DMPT_DEBUG_FAIL -#EXTRA_CFLAGS += -DMPT_DEBUG_DV -#EXTRA_CFLAGS += -DMPT_DEBUG_TM -#EXTRA_CFLAGS += -DMPT_DEBUG_REPLY - -# -# driver/module specifics... -# -# For mptbase: -#CFLAGS_mptbase.o += -DMPT_DEBUG_HANDSHAKE -#CFLAGS_mptbase.o += -DMPT_DEBUG_CONFIG -#CFLAGS_mptbase.o += -DMPT_DEBUG_DL -#CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ -#CFLAGS_mptbase.o += -DMPT_DEBUG_RESET -# -# For mptscsih: -#CFLAGS_mptscsih.o += -DMPT_DEBUG_SCSI # -# For mptctl: -#CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL +# LSI mpt fusion # -# For mptfc: -#CFLAGS_mptfc.o += -DMPT_DEBUG_FC -# For mptsas: -#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS -#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS_WIDE +# csmi ioctls enable +EXTRA_CFLAGS += -DCPQ_CIM +EXTRA_CFLAGS += -DDIAG_BUFFER_SUPPORT +EXTRA_CFLAGS += -DCONFIG_FUSION_LOGGING -#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC +# enable verbose logging +# CONFIG_FUSION_LOGGING needs to be enabled in Kconfig +#EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE obj-$(CONFIG_FUSION_SPI) += mptbase.o mptscsih.o mptspi.o obj-$(CONFIG_FUSION_FC) += mptbase.o mptscsih.o mptfc.o Index: linux-2.6.18.i386/drivers/message/fusion/csmi/csmisas.c =================================================================== --- /dev/null +++ linux-2.6.18.i386/drivers/message/fusion/csmi/csmisas.c @@ -0,0 +1,5888 @@ +/* + * linux/drivers/message/fusion/csmi/csmisas.c + * For use with LSI PCI chip/adapter(s) + * running LSI Fusion MPT (Message Passing Technology) firmware. + * + * Copyright (c) 1999-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#define MPT_CSMI_DESCRIPTION "LSI Corporation: Fusion MPT Driver "MPT_LINUX_VERSION_COMMON +#define csmisas_is_this_sas_cntr(ioc) (ioc->bus_type == SAS) ? 1 : 0 + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) +#define __user +#include +#endif + +static int csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus, + u8 VolumeId, pMpiRaidActionReply_t reply); +static u8 map_sas_status_to_csmi(u8 mpi_sas_status); + +/** + * reverse_byte_order64 + * + * @data64 + * + **/ +static u64 +reverse_byte_order64(u64 data64) +{ + int i; + u64 rc; + u8 *inWord = (u8*)&data64, *outWord = (u8*)&rc; + + for (i = 0 ; i < 8 ; i++) + outWord[i] = inWord[7-i]; + + return rc; +} + +/** + * csmisas_is_sata + * + * @phys_disk + * + **/ +static int +csmisas_is_sata(RaidPhysDiskPage0_t *phys_disk) +{ + if ((phys_disk->ExtDiskIdentifier[0] == 'A') && + (phys_disk->ExtDiskIdentifier[1] == 'T') && + (phys_disk->ExtDiskIdentifier[2] == 'A')) + return 1; + else + return 0; +} + +/** + * csmisas_is_end_device + * + * @attached + * + **/ +static inline int +csmisas_is_end_device(struct mptsas_devinfo * attached) +{ + if ((attached->sas_address) && + (attached->device_info & + MPI_SAS_DEVICE_INFO_END_DEVICE) && + ((attached->device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET) | + (attached->device_info & + MPI_SAS_DEVICE_INFO_STP_TARGET) | + (attached->device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE))) + return 1; + else + return 0; +} + +/** + * csmisas_is_phys_disk + * + * returns (1) success (0) fail - not a phys disk + **/ +static int +csmisas_is_phys_disk(MPT_ADAPTER *ioc, int channel, int id) +{ + struct inactive_raid_component_info *component_info; + int i; + int rc = 0; + + if (!ioc->raid_data.pIocPg3) + goto out; + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && + (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { + rc = 1; + goto out; + } + } + + /* + * Check inactive list for matching phys disks + */ + if (list_empty(&ioc->raid_data.inactive_list)) + goto out; + + down(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry(component_info, &ioc->raid_data.inactive_list, + list) { + if ((component_info->d.PhysDiskID == id) && + (component_info->d.PhysDiskBus == channel)) + rc = 1; + } + up(&ioc->raid_data.inactive_list_mutex); + + out: + return rc; +} + +/** + * csmisas_raid_id_to_num + * + * Obtains the phys disk num for given H:C:T nexus + * + * input (channel/id) + * output (phys disk number - used by SCSI_IO_PASSTHRU to access hidden component) + * + * returns - signed return means failure + **/ +static s8 +csmisas_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + struct inactive_raid_component_info *component_info; + int i; + s8 rc = -ENXIO; + + if (!ioc->raid_data.pIocPg3) + goto out; + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && + (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { + rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum; + goto out; + } + } + + /* + * Check inactive list for matching phys disks + */ + if (list_empty(&ioc->raid_data.inactive_list)) + goto out; + + down(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry(component_info, &ioc->raid_data.inactive_list, + list) { + if ((component_info->d.PhysDiskID == id) && + (component_info->d.PhysDiskBus == channel)) + rc = component_info->d.PhysDiskNum; + } + up(&ioc->raid_data.inactive_list_mutex); + + out: + return rc; +} + +/** + * csmisas_get_device_component_by_os + * + * Obtain device component object by operating system mapping + * + * @ioc + * @channel + * @id + * + **/ +static struct sas_device_info * +csmisas_get_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + struct sas_device_info *sas_info, *p; + + sas_info = NULL; + + down(&ioc->sas_device_info_mutex); + list_for_each_entry(p, &ioc->sas_device_info_list, list) { + if (p->os.channel == channel && p->os.id == id) { + sas_info = p; + goto out; + } + } + + out: + up(&ioc->sas_device_info_mutex); + return sas_info; +} + +/** + * csmisas_get_device_component + * + * Obtain device component object by firmware system mapping + * + * @ioc + * @channel + * @id + * + **/ +static struct sas_device_info * +csmisas_get_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + struct sas_device_info *sas_info, *p; + + sas_info = NULL; + + down(&ioc->sas_device_info_mutex); + list_for_each_entry(p, &ioc->sas_device_info_list, list) { + if (p->fw.channel == channel && p->fw.id == id) { + sas_info = p; + goto out; + } + } + + out: + up(&ioc->sas_device_info_mutex); + return sas_info; +} + + +/** + * csmisas_get_device_component_by_sas_addr + * + * Obtain device component object by sas address + * + * @ioc + * @channel + * @id + * + **/ +static struct sas_device_info * +csmisas_get_device_component_by_sas_addr(MPT_ADAPTER *ioc, u64 sas_address) +{ + struct sas_device_info *sas_info, *p; + + sas_info = NULL; + + down(&ioc->sas_device_info_mutex); + list_for_each_entry(p, &ioc->sas_device_info_list, list) { + if (p->sas_address == sas_address) { + sas_info = p; + goto out; + } + } + + out: + up(&ioc->sas_device_info_mutex); + return sas_info; +} + +/** + * csmisas_send_command_wait + * + * Send mf to firmware + * + * @ioc + * @mf + * @timeout - timeout + * + * Return: 0 for success + * non-zero, failure + **/ +static int +csmisas_send_command_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout) +{ + int rc; + unsigned long timeleft; + + timeout = max_t(unsigned long, MPT_IOCTL_DEFAULT_TIMEOUT, timeout); + rc = 0; + timeleft = 0; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) + + INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status) + ioc->ioctl_cmds.wait_done = 0; + ioc->ioctl_cmds.timer.expires = jiffies + (MPT_JIFFY * timeout); + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE; + ADD_TIMER(&ioc->ioctl_cmds.timer); + mpt_put_msg_frame(mptctl_id, ioc, mf); + WAIT_EVENT(mptctl_wait, ioc->ioctl_cmds.wait_done); + +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) + + INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status) + ioc->ioctl_cmds.wait_done = 0; + mpt_put_msg_frame(mptctl_id, ioc, mf); + + if ((wait_event_timeout(mptctl_wait, + ioc->ioctl_cmds.wait_done == 1, HZ * timeout) <=0) && + ioc->ioctl_cmds.wait_done != 1 ) { + mptctl_timeout_expired(ioc,mf); + mpt_free_msg_frame(ioc, mf); + rc = -1; + } + +#else + + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, + mf->u.hdr.MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) + mpt_put_msg_frame(mptctl_id, ioc, mf); + timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, timeout*HZ); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -1; + printk("%s: failed\n", __FUNCTION__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) + return rc; + } + if (!timeleft) + mptctl_timeout_expired(ioc, mf); + } + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); +#endif + return rc; +} + +/** + * csmisas_send_handshake_wait + * + * Handshake a mf to firmware + * + * @ioc + * @mf + * @mf_size + * @timeout - timeout + * + * Return: 0 for success + * non-zero, failure + **/ +static int +csmisas_send_handshake_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout) +{ + int rc; + unsigned long timeleft; + + timeout = max_t(unsigned long, MPT_IOCTL_DEFAULT_TIMEOUT, timeout); + rc = 0; + timeleft = 0; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) + + INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status) + ioc->taskmgmt_cmds.timer.expires = jiffies + (MPT_JIFFY*timeout); + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE; + ioc->taskmgmt_cmds.wait_done = 0; + ADD_TIMER(&ioc->taskmgmt_cmds.timer); + rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc, + sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP); + if (rc != 0) + return rc; + WAIT_EVENT(mptctl_taskmgmt_wait, ioc->taskmgmt_cmds.wait_done); + +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) + + INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status) + ioc->taskmgmt_cmds.wait_done = 0; + rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc, + sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP); + if (rc != 0) + return rc; + if ((wait_event_timeout(mptctl_taskmgmt_wait, + ioc->taskmgmt_cmds.wait_done == 1, HZ * timeout) <=0) && + ioc->taskmgmt_cmds.wait_done != 1 ) { + mptctl_timeout_expired(ioc, mf); + mpt_free_msg_frame(ioc, mf); + rc = -1; + } + +#else + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf); + timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -1; + printk("%s: failed\n", __FUNCTION__); + mpt_clear_taskmgmt_in_progress_flag(ioc); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + return rc; + } + if (!timeleft) + mptctl_timeout_expired(ioc, mf); + } +#endif + return rc; +} + +/** + * csmisas_get_number_hotspares - returns num hot spares in this ioc + * @ioc: Pointer to MPT_ADAPTER structure + * + * Return: number of hotspares + * + **/ +static int +csmisas_get_number_hotspares(MPT_ADAPTER *ioc) +{ + ConfigPageHeader_t hdr; + CONFIGPARMS cfg; + IOCPage5_t *buffer = NULL; + dma_addr_t dma_handle; + int data_sz; + int rc; + + memset(&hdr, 0, sizeof(ConfigPageHeader_t)); + memset(&cfg, 0, sizeof(CONFIGPARMS)); + + rc = 0; + data_sz = 0; + hdr.PageNumber = 5; + hdr.PageType = MPI_CONFIG_PAGETYPE_IOC; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if (mpt_config(ioc, &cfg) != 0) + goto get_ioc_pg5; + + if (hdr.PageLength == 0) + goto get_ioc_pg5; + + data_sz = hdr.PageLength * 4; + buffer = (IOCPage5_t *) pci_alloc_consistent(ioc->pcidev, + data_sz, &dma_handle); + if (!buffer) + goto get_ioc_pg5; + + memset((u8 *)buffer, 0, data_sz); + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if (mpt_config(ioc, &cfg) != 0) + goto get_ioc_pg5; + + rc = buffer->NumHotSpares; + + get_ioc_pg5: + + if (buffer) + pci_free_consistent(ioc->pcidev, data_sz, + (u8 *) buffer, dma_handle); + + return rc; +} + + +/** + * csmisas_get_ioc_pg5 - ioc Page 5 hot spares + * @ioc: Pointer to MPT_ADAPTER structure + * @pIocPage5: ioc page 5 + * @data_size: expected data size(units=bytes) + * + * Return: 0 for success + * -ENOMEM if no memory available + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) + **/ +static int +csmisas_get_ioc_pg5(MPT_ADAPTER *ioc, IOCPage5_t *iocPage5, int data_size) +{ + ConfigPageHeader_t hdr; + CONFIGPARMS cfg; + IOCPage5_t *buffer = NULL; + dma_addr_t dma_handle; + int data_sz; + int rc; + + memset(&hdr, 0, sizeof(ConfigPageHeader_t)); + memset(&cfg, 0, sizeof(CONFIGPARMS)); + + rc = 0; + data_sz = 0; + hdr.PageNumber = 5; + hdr.PageType = MPI_CONFIG_PAGETYPE_IOC; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) + goto get_ioc_pg5; + + if (hdr.PageLength == 0) { + rc = -EFAULT; + goto get_ioc_pg5; + } + + data_sz = hdr.PageLength * 4; + buffer = (IOCPage5_t *) pci_alloc_consistent(ioc->pcidev, + data_sz, &dma_handle); + if (!buffer) { + rc = -ENOMEM; + goto get_ioc_pg5; + } + + memset((u8 *)buffer, 0, data_sz); + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) + goto get_ioc_pg5; + + memcpy(iocPage5, buffer, data_size); + + get_ioc_pg5: + + if (buffer) + pci_free_consistent(ioc->pcidev, data_sz, + (u8 *) buffer, dma_handle); + + return rc; +} + +/** + * csmisas_sas_device_pg0 - sas device page 0 + * @ioc: Pointer to MPT_ADAPTER structure + * @mptsas_devinfo: structure found in mptsas.h + * @form, @form_specific - defines the Page Address field in the config page + * (pls refer to chapter 5.1 in the mpi spec) + * + * Return: 0 for success + * -ENOMEM if no memory available + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) + **/ +static int +csmisas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, + u32 form, u32 form_specific) +{ + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasDevicePage0_t *buffer; + dma_addr_t dma_handle; + u64 sas_address; + int rc; + + rc = 0; + hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE; + + cfg.cfghdr.ehdr = &hdr; + cfg.pageAddr = form + form_specific; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = 10; + + memset(device_info, 0, sizeof(struct mptsas_devinfo)); + if ((rc = mpt_config(ioc, &cfg)) != 0) + goto out; + + if (!hdr.ExtPageLength) { + rc = -ENXIO; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, + hdr.ExtPageLength * 4, &dma_handle); + if (!buffer) { + rc = -ENOMEM; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) + goto out_free_consistent; + + device_info->handle = le16_to_cpu(buffer->DevHandle); + device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); + device_info->handle_enclosure = + le16_to_cpu(buffer->EnclosureHandle); + device_info->slot = le16_to_cpu(buffer->Slot); + device_info->phy_id = buffer->PhyNum; + device_info->port_id = buffer->PhysicalPort; + device_info->id = buffer->TargetID; + device_info->channel = buffer->Bus; + memcpy(&sas_address, &buffer->SASAddress, sizeof(u64)); + device_info->sas_address = le64_to_cpu(sas_address); + device_info->device_info = + le32_to_cpu(buffer->DeviceInfo); + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + buffer, dma_handle); + out: + return rc; +} + +/** + * Routine for the CSMI Sas Get Driver Info command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_get_driver_info(unsigned long arg) +{ + + CSMI_SAS_DRIVER_INFO_BUFFER __user *uarg = (void __user *) arg; + CSMI_SAS_DRIVER_INFO_BUFFER karg; + MPT_ADAPTER *ioc = NULL; + int iocnum; + + if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in csmi_sas_get_driver_info_buffer struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + + /* Fill in the data and return the structure to the calling + * program + */ + memcpy( karg.Information.szName, MPT_MISCDEV_BASENAME, + sizeof(MPT_MISCDEV_BASENAME)); + memcpy( karg.Information.szDescription, MPT_CSMI_DESCRIPTION, + sizeof(MPT_CSMI_DESCRIPTION)); + + karg.Information.usMajorRevision = MPT_LINUX_MAJOR_VERSION; + karg.Information.usMinorRevision = MPT_LINUX_MINOR_VERSION; + karg.Information.usBuildRevision = MPT_LINUX_BUILD_VERSION; + karg.Information.usReleaseRevision = MPT_LINUX_RELEASE_VERSION; + + karg.Information.usCSMIMajorRevision = CSMI_MAJOR_REVISION; + karg.Information.usCSMIMinorRevision = CSMI_MINOR_REVISION; + + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return 0; +} + +/** + * Prototype Routine for the CSMI_SAS_GET_CNTLR_CONFIG command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_get_cntlr_config(unsigned long arg) +{ + + CSMI_SAS_CNTLR_CONFIG_BUFFER __user *uarg = (void __user *) arg; + CSMI_SAS_CNTLR_CONFIG_BUFFER karg; + MPT_ADAPTER *ioc = NULL; + int iocnum; + u64 mem_phys; + + if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_CONFIG_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in csmi_sas_get_cntlr_config_buffer struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + + /* Clear the struct before filling in data. */ + memset( &karg.Configuration, 0, sizeof(CSMI_SAS_CNTLR_CONFIG)); + + /* Fill in the data and return the structure to the calling + * program + */ + + karg.Configuration.uBaseIoAddress = ioc->pio_mem_phys; + karg.Configuration.BaseMemoryAddress.uLowPart = ioc->mem_phys; + if (sizeof(ioc->mem_phys) == sizeof(u64)) { + mem_phys = ioc->mem_phys; + karg.Configuration.BaseMemoryAddress.uHighPart = + (u32)(mem_phys >> 32); + } + + karg.Configuration.uBoardID = (ioc->pcidev->subsystem_device << 16) | + (ioc->pcidev->subsystem_vendor); + + karg.Configuration.usSlotNumber = + (ioc->pci_slot_number = 0xff) ? + SLOT_NUMBER_UNKNOWN : ioc->pci_slot_number; + karg.Configuration.bControllerClass = CSMI_SAS_CNTLR_CLASS_HBA; + karg.Configuration.bIoBusType = CSMI_SAS_BUS_TYPE_PCI; + karg.Configuration.BusAddress.PciAddress.bBusNumber = + ioc->pcidev->bus->number; + karg.Configuration.BusAddress.PciAddress.bDeviceNumber = + PCI_SLOT(ioc->pcidev->devfn); + karg.Configuration.BusAddress.PciAddress.bFunctionNumber = + PCI_FUNC(ioc->pcidev->devfn); + karg.Configuration.BusAddress.PciAddress.bReserved = 0; + memcpy( &karg.Configuration.szSerialNumber, ioc->board_tracer, 16 ); + karg.Configuration.usMajorRevision = ioc->facts.FWVersion.Struct.Major; + karg.Configuration.usMinorRevision = ioc->facts.FWVersion.Struct.Minor; + karg.Configuration.usBuildRevision = ioc->facts.FWVersion.Struct.Unit; + karg.Configuration.usReleaseRevision = ioc->facts.FWVersion.Struct.Dev; + karg.Configuration.usBIOSMajorRevision = + (ioc->biosVersion & 0xFF000000) >> 24; + karg.Configuration.usBIOSMinorRevision = + (ioc->biosVersion & 0x00FF0000) >> 16; + karg.Configuration.usBIOSBuildRevision = + (ioc->biosVersion & 0x0000FF00) >> 8; + karg.Configuration.usBIOSReleaseRevision = + (ioc->biosVersion & 0x000000FF); + karg.Configuration.uControllerFlags = CSMI_SAS_CNTLR_SAS_HBA | + CSMI_SAS_CNTLR_FWD_SUPPORT | CSMI_SAS_CNTLR_FWD_ONLINE | + CSMI_SAS_CNTLR_FWD_SRESET ; + + /* + * Enabling CSMI_SAS_CNTLR_SAS_RAID bit when IR fw detected + */ + if (ioc->ir_firmware) + karg.Configuration.uControllerFlags |= CSMI_SAS_CNTLR_SAS_RAID; + + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + + /* All Rrom entries will be zero. Skip them. */ + /* bReserved will also be zeros. */ + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return 0; +} + +/** + * Prototype Routine for the CSMI Sas Get Controller Status command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_get_cntlr_status(unsigned long arg) +{ + + CSMI_SAS_CNTLR_STATUS_BUFFER __user *uarg = (void __user *) arg; + MPT_ADAPTER *ioc = NULL; + CSMI_SAS_CNTLR_STATUS_BUFFER karg; + int iocnum; + int rc; + + if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in csmi_sas_get_cntlr_status_buffer struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + + /* Fill in the data and return the structure to the calling + * program + */ + + rc = mpt_GetIocState(ioc, 1); + switch (rc) { + case MPI_IOC_STATE_OPERATIONAL: + karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_GOOD; + karg.Status.uOfflineReason = 0; + break; + + case MPI_IOC_STATE_FAULT: + karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_FAILED; + karg.Status.uOfflineReason = 0; + break; + + case MPI_IOC_STATE_RESET: + case MPI_IOC_STATE_READY: + default: + karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_OFFLINE; + karg.Status.uOfflineReason = + CSMI_SAS_OFFLINE_REASON_INITIALIZING; + break; + } + + memset(&karg.Status.bReserved, 0, 28); + + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to write out csmi_sas_get_cntlr_status @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return 0; +} + +/** + * Prototype Routine for the CSMI Sas Get Phy Info command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_get_phy_info(unsigned long arg) +{ + CSMI_SAS_PHY_INFO_BUFFER __user *uarg = (void __user *) arg; + CSMI_SAS_PHY_INFO_BUFFER *karg; + MPT_ADAPTER *ioc = NULL; + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasIOUnitPage0_t *sasIoUnitPg0; + dma_addr_t sasIoUnitPg0_dma; + int sasIoUnitPg0_data_sz; + SasPhyPage0_t *sasPhyPg0; + dma_addr_t sasPhyPg0_dma; + int sasPhyPg0_data_sz; + u16 protocol; + int iocnum; + int rc; + int ii; + u64 sas_address; + struct mptsas_devinfo device_info; + int memory_pages; + + sasIoUnitPg0=NULL; + sasPhyPg0=NULL; + sasIoUnitPg0_data_sz=0; + sasPhyPg0_data_sz=0; + + memory_pages = get_order(sizeof(CSMI_SAS_PHY_INFO_BUFFER)); + karg = (CSMI_SAS_PHY_INFO_BUFFER *)__get_free_pages( + GFP_KERNEL, memory_pages); + if (!karg){ + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc CSMI_SAS_PHY_INFO_BUFFER " + "malloc_data_sz=%d memory_pages=%d\n", + __FILE__, __LINE__, __FUNCTION__, + (int)sizeof(CSMI_SAS_PHY_INFO_BUFFER), memory_pages); + return -ENOMEM; + } + + memset(karg, 0, sizeof(*karg)); + + if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_PHY_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in csmisas_get_phy_info_buffer struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + + /* Fill in the data and return the structure to the calling + * program + */ + + /* Issue a config request to get the number of phys + */ + hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + /* Don't check if this failed. Already in a + * failure case. + */ + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: HEADER\n")); + dcsmisasprintk(ioc, printk(": rc=%x\n",rc)); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } + + if (hdr.ExtPageLength == 0) { + /* Don't check if this failed. Already in a + * failure case. + */ + dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } + + sasIoUnitPg0_data_sz = hdr.ExtPageLength * 4; + rc = -ENOMEM; + + sasIoUnitPg0 = (SasIOUnitPage0_t *) pci_alloc_consistent(ioc->pcidev, + sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma); + + if (!sasIoUnitPg0) { + dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } + + memset((u8 *)sasIoUnitPg0, 0, sasIoUnitPg0_data_sz); + cfg.physAddr = sasIoUnitPg0_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + + /* Don't check if this failed. Already in a + * failure case. + */ + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: PAGE\n")); + dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } + + /* Number of Phys. */ + karg->Information.bNumberOfPhys = sasIoUnitPg0->NumPhys; + + /* Fill in information for each phy. */ + for (ii = 0; ii < karg->Information.bNumberOfPhys; ii++) { + +/* EDM : dump IO Unit Page 0 data*/ + dcsmisasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n")); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n", + le16_to_cpu(sasIoUnitPg0->PhyData[ii].AttachedDeviceHandle))); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n", + le16_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerDevHandle))); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n", + sasIoUnitPg0->PhyData[ii].Port)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n", + sasIoUnitPg0->PhyData[ii].PortFlags)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n", + sasIoUnitPg0->PhyData[ii].PhyFlags)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", + sasIoUnitPg0->PhyData[ii].NegotiatedLinkRate)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n", + le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo))); + dcsmisasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n", + le32_to_cpu(sasIoUnitPg0->PhyData[ii].DiscoveryStatus))); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); +/* EDM : debug data */ + + /* PHY stuff. */ + karg->Information.Phy[ii].bPortIdentifier = + sasIoUnitPg0->PhyData[ii].Port; + + /* Get the negotiated link rate for the phy. */ + switch (sasIoUnitPg0->PhyData[ii].NegotiatedLinkRate) { + + case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: + karg->Information.Phy[ii].bNegotiatedLinkRate = + CSMI_SAS_PHY_DISABLED; + break; + + case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: + karg->Information.Phy[ii].bNegotiatedLinkRate = + CSMI_SAS_LINK_RATE_FAILED; + break; + + case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: + break; + + case MPI_SAS_IOUNIT0_RATE_1_5: + karg->Information.Phy[ii].bNegotiatedLinkRate = + CSMI_SAS_LINK_RATE_1_5_GBPS; + break; + + case MPI_SAS_IOUNIT0_RATE_3_0: + karg->Information.Phy[ii].bNegotiatedLinkRate = + CSMI_SAS_LINK_RATE_3_0_GBPS; + break; + + case MPI_SAS_IOUNIT0_RATE_UNKNOWN: + default: + karg->Information.Phy[ii].bNegotiatedLinkRate = + CSMI_SAS_LINK_RATE_UNKNOWN; + break; + } + + if (sasIoUnitPg0->PhyData[ii].PortFlags & + MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS) { + karg->Information.Phy[ii].bAutoDiscover = + CSMI_SAS_DISCOVER_IN_PROGRESS; + } else { + karg->Information.Phy[ii].bAutoDiscover = + CSMI_SAS_DISCOVER_COMPLETE; + } + + /* Issue a config request to get + * phy information. + */ + hdr.PageVersion = MPI_SASPHY0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + cfg.pageAddr = ii; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n")); + dcsmisasprintk(ioc, printk(": rc=%x\n",rc)); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } + + if (hdr.ExtPageLength == 0) { + dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } + + sasPhyPg0_data_sz = hdr.ExtPageLength * 4; + rc = -ENOMEM; + + sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent( + ioc->pcidev, sasPhyPg0_data_sz, &sasPhyPg0_dma); + + if (! sasPhyPg0) { + dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } + + memset((u8 *)sasPhyPg0, 0, sasPhyPg0_data_sz); + cfg.physAddr = sasPhyPg0_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n")); + dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz, + (u8 *) sasPhyPg0, sasPhyPg0_dma); + goto sas_get_phy_info_exit; + } + +/* EDM : dump PHY Page 0 data*/ + memcpy(&sas_address, &sasPhyPg0->SASAddress, sizeof(u64)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n")); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n", + le16_to_cpu(sasPhyPg0->AttachedDevHandle))); + dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", + (unsigned long long)sas_address)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n", + sasPhyPg0->AttachedPhyIdentifier)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n", + le32_to_cpu(sasPhyPg0->AttachedDeviceInfo))); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", + sasPhyPg0->ProgrammedLinkRate)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n", + sasPhyPg0->HwLinkRate)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n", + sasPhyPg0->ChangeCount)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n", + le32_to_cpu(sasPhyPg0->PhyInfo))); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); +/* EDM : debug data */ + + /* save the data */ + + /* Set Max hardware link rate. + * This value is hard coded + * because the HW link rate + * is currently being + * overwritten in FW. + */ + + /* Set Max hardware link rate. */ + switch (sasPhyPg0->HwLinkRate & + MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { + + case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: + karg->Information.Phy[ii].bMaximumLinkRate = + CSMI_SAS_LINK_RATE_1_5_GBPS; + break; + + case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: + karg->Information.Phy[ii].bMaximumLinkRate = + CSMI_SAS_LINK_RATE_3_0_GBPS; + break; + default: + break; + } + + /* Set Max programmed link rate. */ + switch (sasPhyPg0->ProgrammedLinkRate & + MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { + + case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: + karg->Information.Phy[ii].bMaximumLinkRate |= + (CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS << 4); + break; + + case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: + karg->Information.Phy[ii].bMaximumLinkRate |= + (CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS << 4); + break; + default: + break; + } + + /* Set Min hardware link rate. */ + switch (sasPhyPg0->HwLinkRate & + MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { + + case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: + karg->Information.Phy[ii].bMinimumLinkRate = + CSMI_SAS_LINK_RATE_1_5_GBPS; + break; + + case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: + karg->Information.Phy[ii].bMinimumLinkRate = + CSMI_SAS_LINK_RATE_3_0_GBPS; + break; + default: + break; + } + + /* Set Min programmed link rate. */ + switch (sasPhyPg0->ProgrammedLinkRate & + MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { + + case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: + karg->Information.Phy[ii].bMinimumLinkRate |= + (CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS << 4); + break; + + case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: + karg->Information.Phy[ii].bMinimumLinkRate |= + (CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS << 4); + break; + default: + break; + } + + karg->Information.Phy[ii].bPhyChangeCount = sasPhyPg0->ChangeCount; + if( sasPhyPg0->PhyInfo & MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY ) + karg->Information.Phy[ii].bPhyFeatures = CSMI_SAS_PHY_VIRTUAL_SMP; + + /* Fill in Attached Device + * Initiator Port Protocol. + * Bits 6:3 + * More than one bit can be set. + */ + protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x78; + karg->Information.Phy[ii].Attached.bInitiatorPortProtocol = 0; + if (protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) + karg->Information.Phy[ii].Attached.bInitiatorPortProtocol = + CSMI_SAS_PROTOCOL_SSP; + if (protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR) + karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |= + CSMI_SAS_PROTOCOL_STP; + if (protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) + karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |= + CSMI_SAS_PROTOCOL_SMP; + if (protocol & MPI_SAS_DEVICE_INFO_SATA_HOST) + karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |= + CSMI_SAS_PROTOCOL_SATA; + + /* Fill in Phy Target Port + * Protocol. Bits 10:7 + * More than one bit can be set. + */ + protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x780; + karg->Information.Phy[ii].Attached.bTargetPortProtocol = 0; + if (protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET) + karg->Information.Phy[ii].Attached.bTargetPortProtocol |= + CSMI_SAS_PROTOCOL_SSP; + if (protocol & MPI_SAS_DEVICE_INFO_STP_TARGET) + karg->Information.Phy[ii].Attached.bTargetPortProtocol |= + CSMI_SAS_PROTOCOL_STP; + if (protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET) + karg->Information.Phy[ii].Attached.bTargetPortProtocol |= + CSMI_SAS_PROTOCOL_SMP; + if (protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE) + karg->Information.Phy[ii].Attached.bTargetPortProtocol |= + CSMI_SAS_PROTOCOL_SATA; + + + /* Fill in Attached device type */ + switch (le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & + MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { + + case MPI_SAS_DEVICE_INFO_NO_DEVICE: + karg->Information.Phy[ii].Attached.bDeviceType = + CSMI_SAS_NO_DEVICE_ATTACHED; + break; + + case MPI_SAS_DEVICE_INFO_END_DEVICE: + karg->Information.Phy[ii].Attached.bDeviceType = + CSMI_SAS_END_DEVICE; + break; + + case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: + karg->Information.Phy[ii].Attached.bDeviceType = + CSMI_SAS_EDGE_EXPANDER_DEVICE; + break; + + case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: + karg->Information.Phy[ii].Attached.bDeviceType = + CSMI_SAS_FANOUT_EXPANDER_DEVICE; + break; + } + + /* Identify Info. */ + switch (le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & + MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { + + case MPI_SAS_DEVICE_INFO_NO_DEVICE: + karg->Information.Phy[ii].Identify.bDeviceType = + CSMI_SAS_NO_DEVICE_ATTACHED; + break; + + case MPI_SAS_DEVICE_INFO_END_DEVICE: + karg->Information.Phy[ii].Identify.bDeviceType = + CSMI_SAS_END_DEVICE; + break; + + case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: + karg->Information.Phy[ii].Identify.bDeviceType = + CSMI_SAS_EDGE_EXPANDER_DEVICE; + break; + + case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: + karg->Information.Phy[ii].Identify.bDeviceType = + CSMI_SAS_FANOUT_EXPANDER_DEVICE; + break; + } + + /* Fill in Phy Initiator Port Protocol. Bits 6:3 + * More than one bit can be set, fall through cases. + */ + protocol = le32_to_cpu( + sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x78; + karg->Information.Phy[ii].Identify.bInitiatorPortProtocol = 0; + if( protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR ) + karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= + CSMI_SAS_PROTOCOL_SSP; + if( protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR ) + karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= + CSMI_SAS_PROTOCOL_STP; + if( protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR ) + karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= + CSMI_SAS_PROTOCOL_SMP; + if( protocol & MPI_SAS_DEVICE_INFO_SATA_HOST ) + karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= + CSMI_SAS_PROTOCOL_SATA; + + /* Fill in Phy Target Port Protocol. Bits 10:7 + * More than one bit can be set, fall through cases. + */ + protocol = le32_to_cpu( + sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x780; + karg->Information.Phy[ii].Identify.bTargetPortProtocol = 0; + if( protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET ) + karg->Information.Phy[ii].Identify.bTargetPortProtocol |= + CSMI_SAS_PROTOCOL_SSP; + if( protocol & MPI_SAS_DEVICE_INFO_STP_TARGET ) + karg->Information.Phy[ii].Identify.bTargetPortProtocol |= + CSMI_SAS_PROTOCOL_STP; + if( protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET ) + karg->Information.Phy[ii].Identify.bTargetPortProtocol |= + CSMI_SAS_PROTOCOL_SMP; + if( protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE ) + karg->Information.Phy[ii].Identify.bTargetPortProtocol |= + CSMI_SAS_PROTOCOL_SATA; + + /* Setup SAS Address for the attached device */ + if (sasPhyPg0->AttachedDevHandle) { + sas_address = reverse_byte_order64(sas_address); + memcpy(karg->Information.Phy[ii].Attached.bSASAddress, + &sas_address, sizeof(u64)); + karg->Information.Phy[ii].Attached.bPhyIdentifier = + sasPhyPg0->AttachedPhyIdentifier; + } + + /* Setup SAS Address for the parent device */ + csmisas_sas_device_pg0(ioc, &device_info, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + sasIoUnitPg0->PhyData[ii].ControllerDevHandle); + sas_address = reverse_byte_order64(device_info.sas_address); + memcpy(karg->Information.Phy[ii].Identify.bSASAddress, + &sas_address, sizeof(u64)); + karg->Information.Phy[ii].Identify.bPhyIdentifier = ii; + + pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz, + (u8 *) sasPhyPg0, sasPhyPg0_dma); + } + +sas_get_phy_info_exit: + + if (sasIoUnitPg0) + pci_free_consistent(ioc->pcidev, sasIoUnitPg0_data_sz, + (u8 *) sasIoUnitPg0, sasIoUnitPg0_dma); + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, karg, + sizeof(CSMI_SAS_PHY_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to write out csmisas_get_phy_info_buffer @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + + free_pages((unsigned long)karg, memory_pages); + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return 0; +} + +/** + * Prototype Routine for the CSMI SAS Set PHY Info command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_set_phy_info(unsigned long arg) +{ + CSMI_SAS_SET_PHY_INFO_BUFFER __user *uarg = (void __user *) arg; + CSMI_SAS_SET_PHY_INFO_BUFFER karg; + MPT_ADAPTER *ioc = NULL; + int iocnum; + + if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_set_phy_info struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + +/* TODO - implement IOCTL here */ + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE; + dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n")); + +// cim_set_phy_info_exit: + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_set_phy_info @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return 0; + +} + +/** + * Prototype Routine for the CSMI Sas Get SCSI Address command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_get_scsi_address(unsigned long arg) +{ + CSMI_SAS_GET_SCSI_ADDRESS_BUFFER __user *uarg = (void __user *) arg; + CSMI_SAS_GET_SCSI_ADDRESS_BUFFER karg; + MPT_ADAPTER *ioc = NULL; + int iocnum; + u64 sas_address; + struct sas_device_info *sas_info; + + if (copy_from_user(&karg, uarg, + sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_get_scsi_address struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + + /* reverse byte order the sas address */ + memcpy(&sas_address, karg.bSASAddress, sizeof(u64)); + sas_address = reverse_byte_order64(sas_address); + + /* Search the list for the matching SAS address. */ + karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_SCSI_ADDRESS; + karg.bPathId = 0; + karg.bTargetId = 0; + karg.bLun = 0; + + sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address); + if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume) + goto csmisas_get_scsi_address_exit; + + karg.bPathId = sas_info->os.channel; + karg.bTargetId = sas_info->os.id; + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + + csmisas_get_scsi_address_exit: + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_get_scsi_address @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return 0; +} + +/** + * Prototype Routine for the CSMI Sas Get SCSI Address command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_get_sata_signature(unsigned long arg) +{ + CSMI_SAS_SATA_SIGNATURE_BUFFER __user *uarg = (void __user *) arg; + CSMI_SAS_SATA_SIGNATURE_BUFFER karg; + MPT_ADAPTER *ioc = NULL; + int iocnum; + int rc, jj; + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasPhyPage0_t *sasPhyPg0; + dma_addr_t sasPhyPg0_dma; + int sasPhyPg0_data_sz; + SasDevicePage1_t *sasDevicePg1; + dma_addr_t sasDevicePg1_dma; + int sasDevicePg1_data_sz; + u8 phyId; + u64 sas_address; + + sasPhyPg0=NULL; + sasPhyPg0_data_sz=0; + sasDevicePg1=NULL; + sasDevicePg1_data_sz=0; + + if (copy_from_user(&karg, uarg, + sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_sata_signature struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + phyId = karg.Signature.bPhyIdentifier; + if (phyId >= ioc->num_ports) { + karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST; + dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n")); + goto cim_sata_signature_exit; + } + + /* Default to success.*/ + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + + /* Issue a config request to get the devHandle of the attached device + */ + + /* Issue a config request to get phy information. */ + hdr.PageVersion = MPI_SASPHY0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + cfg.pageAddr = phyId; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + /* Don't check if this failed. Already in a + * failure case. + */ + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n")); + dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } + + if (hdr.ExtPageLength == 0) { + /* Don't check if this failed. Already in a + * failure case. + */ + dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } + + + sasPhyPg0_data_sz = hdr.ExtPageLength * 4; + rc = -ENOMEM; + + sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent(ioc->pcidev, + sasPhyPg0_data_sz, &sasPhyPg0_dma); + + if (! sasPhyPg0) { + dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } + + memset((u8 *)sasPhyPg0, 0, sasPhyPg0_data_sz); + cfg.physAddr = sasPhyPg0_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + /* Don't check if this failed. Already in a + * failure case. + */ + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n")); + dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } + + /* Make sure a SATA device is attached. */ + if ((le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & + MPI_SAS_DEVICE_INFO_SATA_DEVICE) == 0) { + dcsmisasprintk(ioc, printk(KERN_WARNING ": NOT A SATA DEVICE\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_SATA_DEVICE; + goto cim_sata_signature_exit; + } + + /* Get device page 1 for FIS signature. */ + hdr.PageVersion = MPI_SASDEVICE1_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 1 /* page number 1 */; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + + cfg.pageAddr = ((MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT) | + le16_to_cpu(sasPhyPg0->AttachedDevHandle)); + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASDEVICE1_PAGEVERSION: HEADER\n")); + dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } + + if (hdr.ExtPageLength == 0) { + dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } + + sasDevicePg1_data_sz = hdr.ExtPageLength * 4; + rc = -ENOMEM; + + sasDevicePg1 = (SasDevicePage1_t *) pci_alloc_consistent + (ioc->pcidev, sasDevicePg1_data_sz, &sasDevicePg1_dma); + + if (! sasDevicePg1) { + dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } + + memset((u8 *)sasDevicePg1, 0, sasDevicePg1_data_sz); + cfg.physAddr = sasDevicePg1_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASDEVICE1_PAGEVERSION: PAGE\n")); + dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } + +/* EDM : dump Device Page 1 data*/ + dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 1 ---------\n")); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%x\n",sasDevicePg1->DevHandle)); + memcpy(&sas_address, &sasDevicePg1->SASAddress, sizeof(u64)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", + (unsigned long long)sas_address)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%x\n",sasDevicePg1->TargetID)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Bus=0x%x\n",sasDevicePg1->Bus)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Initial Reg Device FIS=")); + for(jj=0;jj<20;jj++) + dcsmisasprintk(ioc, printk("%02x ", + ((u8 *)&sasDevicePg1->InitialRegDeviceFIS)[jj])); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n")); +/* EDM : debug data */ + + memcpy(karg.Signature.bSignatureFIS, + sasDevicePg1->InitialRegDeviceFIS,20); + + cim_sata_signature_exit: + + if (sasPhyPg0) + pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz, + (u8 *) sasPhyPg0, sasPhyPg0_dma); + + if (sasDevicePg1) + pci_free_consistent(ioc->pcidev, sasDevicePg1_data_sz, + (u8 *) sasDevicePg1, sasDevicePg1_dma); + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_sata_signature @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return 0; +} + +/** + * Prototype Routine for the CSMI Sas Get SCSI Address command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_get_device_address(unsigned long arg) +{ + CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER __user *uarg = (void __user *) arg; + CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER karg; + MPT_ADAPTER *ioc = NULL; + int iocnum; + struct sas_device_info *sas_info; + u64 sas_address; + + if (copy_from_user(&karg, uarg, + sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_get_device_address_buffer struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + + karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_DEVICE_ADDRESS; + memset(karg.bSASAddress, 0, sizeof(u64)); + memset(karg.bSASLun, 0, sizeof(karg.bSASLun)); + + /* Search the list for the matching SAS address. */ + sas_info = csmisas_get_device_component_by_os(ioc, karg.bPathId, + karg.bTargetId); + if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume) + goto csmisas_get_device_address_exit; + + sas_address = reverse_byte_order64(sas_info->sas_address); + memcpy(karg.bSASAddress, &sas_address, sizeof(u64)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + + csmisas_get_device_address_exit: + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_get_device_address_buffer @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return 0; +} + +/** + * Prototype Routine for the CSMI Sas Get Link Errors command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_get_link_errors(unsigned long arg) +{ + CSMI_SAS_LINK_ERRORS_BUFFER __user *uarg = (void __user *) arg; + CSMI_SAS_LINK_ERRORS_BUFFER karg; + MPT_ADAPTER *ioc = NULL; + MPT_FRAME_HDR *mf = NULL; + MPIHeader_t *mpi_hdr; + int iocnum; + int rc; + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasPhyPage1_t *sasPhyPage1; + dma_addr_t sasPhyPage1_dma; + int sasPhyPage1_data_sz; + SasIoUnitControlRequest_t *sasIoUnitCntrReq; + SasIoUnitControlReply_t *sasIoUnitCntrReply; + u8 phyId; + u16 ioc_status; + u32 MsgContext; + + sasPhyPage1=NULL; + sasPhyPage1_data_sz=0; + + if (copy_from_user(&karg, uarg, + sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmisas_get_link_errors struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + phyId = karg.Information.bPhyIdentifier; + if (phyId >= ioc->num_ports) { + karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST; + dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n")); + goto cim_get_link_errors_exit; + } + + /* Default to success.*/ + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + + /* Issue a config request to get the devHandle of the attached device + */ + + /* Issue a config request to get phy information. */ + hdr.PageVersion = MPI_SASPHY1_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 1 /* page number 1*/; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + cfg.pageAddr = phyId; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + /* Don't check if this failed. Already in a + * failure case. + */ + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASPHY1_PAGEVERSION: HEADER\n")); + dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_link_errors_exit; + } + + if (hdr.ExtPageLength == 0) { + /* Don't check if this failed. Already in a + * failure case. + */ + dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_link_errors_exit; + } + + + sasPhyPage1_data_sz = hdr.ExtPageLength * 4; + rc = -ENOMEM; + + sasPhyPage1 = (SasPhyPage1_t *) pci_alloc_consistent(ioc->pcidev, + sasPhyPage1_data_sz, &sasPhyPage1_dma); + + if (! sasPhyPage1) { + dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_link_errors_exit; + } + + memset((u8 *)sasPhyPage1, 0, sasPhyPage1_data_sz); + cfg.physAddr = sasPhyPage1_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + /* Don't check if this failed. Already in a + * failure case. + */ + dcsmisasprintk(ioc, printk(KERN_ERR ": FAILED: MPI_SASPHY1_PAGEVERSION: PAGE\n")); + dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_link_errors_exit; + } + +/* EDM : dump PHY Page 1 data*/ + dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n")); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n", + sasPhyPage1->InvalidDwordCount)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n", + sasPhyPage1->RunningDisparityErrorCount)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n", + sasPhyPage1->LossDwordSynchCount)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n", + sasPhyPage1->PhyResetProblemCount)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n")); +/* EDM : debug data */ + + karg.Information.uInvalidDwordCount = + le32_to_cpu(sasPhyPage1->InvalidDwordCount); + karg.Information.uRunningDisparityErrorCount = + le32_to_cpu(sasPhyPage1->RunningDisparityErrorCount); + karg.Information.uLossOfDwordSyncCount = + le32_to_cpu(sasPhyPage1->LossDwordSynchCount); + karg.Information.uPhyResetProblemCount = + le32_to_cpu(sasPhyPage1->PhyResetProblemCount); + + if (karg.Information.bResetCounts == + CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS ) { + goto cim_get_link_errors_exit; + } + + /* Clear Error log + * + * Issue IOUNIT Control Reqeust Message + */ + + /* Get a MF for this command. + */ + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { + dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_link_errors_exit; + } + + mpi_hdr = (MPIHeader_t *) mf; + MsgContext = mpi_hdr->MsgContext; + sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; + memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t)); + sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; + sasIoUnitCntrReq->MsgContext = MsgContext; + sasIoUnitCntrReq->PhyNum = phyId; + sasIoUnitCntrReq->Operation = MPI_SAS_OP_PHY_CLEAR_ERROR_LOG; + + if (csmisas_send_command_wait(ioc, mf, karg.IoctlHeader.Timeout) != 0) { + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_link_errors_exit; + } + + /* process the completed Reply Message Frame */ + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { + + sasIoUnitCntrReply = + (SasIoUnitControlReply_t *)ioc->ioctl_cmds.reply; + ioc_status = le16_to_cpu(sasIoUnitCntrReply->IOCStatus) + & MPI_IOCSTATUS_MASK; + + if (ioc_status != MPI_IOCSTATUS_SUCCESS) { + dcsmisasprintk(ioc, printk(KERN_DEBUG ": SAS IO Unit Control: ")); + dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X\n", + sasIoUnitCntrReply->IOCStatus, + sasIoUnitCntrReply->IOCLogInfo)); + } + } + + cim_get_link_errors_exit: + + if (sasPhyPage1) + pci_free_consistent(ioc->pcidev, sasPhyPage1_data_sz, + (u8 *) sasPhyPage1, sasPhyPage1_dma); + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmisas_get_link_errors @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return 0; + +} + +/** + * Prototype Routine for the CSMI SAS SMP Passthru command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_smp_passthru(unsigned long arg) +{ + CSMI_SAS_SMP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg; + MPT_ADAPTER *ioc; + CSMI_SAS_SMP_PASSTHRU_BUFFER *karg; + pSmpPassthroughRequest_t smpReq; + pSmpPassthroughReply_t smpReply; + MPT_FRAME_HDR *mf = NULL; + MPIHeader_t *mpi_hdr; + char *psge; + int iocnum, flagsLength; + void * request_data; + dma_addr_t request_data_dma; + u32 request_data_sz; + void * response_data; + dma_addr_t response_data_dma; + u32 response_data_sz; + u16 ioc_status; + u64 sas_address; + u32 MsgContext; + int malloc_data_sz; + int memory_pages; + + malloc_data_sz = sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER); + memory_pages = get_order(malloc_data_sz); + karg = (CSMI_SAS_SMP_PASSTHRU_BUFFER *)__get_free_pages( + GFP_KERNEL, memory_pages); + if (!karg){ + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc CSMI_SAS_SMP_PASSTHRU_BUFFER " + "malloc_data_sz=%d memory_pages=%d\n", + __FILE__, __LINE__, __FUNCTION__, + malloc_data_sz, memory_pages); + return -ENOMEM; + } + + if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_smp_passthru struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + + request_data = NULL; + response_data = NULL; + response_data_sz = sizeof(CSMI_SAS_SMP_RESPONSE); + request_data_sz = karg->Parameters.uRequestLength; + + if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + + if (ioc->ioc_reset_in_progress) { + printk(KERN_ERR "%s@%d::%s - " + "Busy with IOC Reset \n", + __FILE__, __LINE__,__FUNCTION__); + free_pages((unsigned long)karg, memory_pages); + return -EBUSY; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + + /* Default to success.*/ + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + + /* Do some error checking on the request. */ + if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT; + goto cim_smp_passthru_exit; + } + + if ((request_data_sz > 0xFFFF) || (!request_data_sz)) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_smp_passthru_exit; + } + + /* Get a free request frame and save the message context. + */ + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { + dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_smp_passthru_exit; + } + + mpi_hdr = (MPIHeader_t *) mf; + MsgContext = mpi_hdr->MsgContext; + smpReq = (pSmpPassthroughRequest_t ) mf; + + memset(smpReq,0,ioc->req_sz); + + memcpy(&sas_address, karg->Parameters.bDestinationSASAddress, + sizeof(u64)); + sas_address = cpu_to_le64(reverse_byte_order64(sas_address)); + memcpy(&smpReq->SASAddress, &sas_address, sizeof(u64)); + + /* Fill in smp request. */ + smpReq->PhysicalPort = karg->Parameters.bPortIdentifier; + smpReq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; + smpReq->RequestDataLength = cpu_to_le16(request_data_sz); + smpReq->ConnectionRate = karg->Parameters.bConnectionRate; + smpReq->MsgContext = MsgContext; + smpReq->Reserved2 = 0; + smpReq->Reserved3 = 0; + + /* + * Prepare the necessary pointers to run + * through the SGL generation + */ + + psge = (char *)&smpReq->SGL; + + /* setup the *Request* payload SGE */ + flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_HOST_TO_IOC | + MPI_SGE_FLAGS_END_OF_BUFFER; + + flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; + flagsLength |= request_data_sz; + + request_data = pci_alloc_consistent( + ioc->pcidev, request_data_sz, &request_data_dma); + + if (!request_data) { + dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + mpt_free_msg_frame(ioc, mf); + goto cim_smp_passthru_exit; + } + + ioc->add_sge(psge, flagsLength, request_data_dma); + psge += ioc->SGE_size; + + memcpy(request_data, &karg->Parameters.Request, request_data_sz); + + /* setup the *Response* payload SGE */ + response_data = pci_alloc_consistent( + ioc->pcidev, response_data_sz, &response_data_dma); + + if (!response_data) { + dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + mpt_free_msg_frame(ioc, mf); + goto cim_smp_passthru_exit; + } + + flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_IOC_TO_HOST | + MPI_SGE_FLAGS_END_OF_BUFFER; + + flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; + flagsLength |= response_data_sz; + + ioc->add_sge(psge, flagsLength, response_data_dma); + + if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_smp_passthru_exit; + } + + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { + dcsmisasprintk(ioc, printk(KERN_DEBUG ": SMP Passthru: oh no, there is no reply!!")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_smp_passthru_exit; + } + + /* process the completed Reply Message Frame */ + smpReply = (pSmpPassthroughReply_t )ioc->ioctl_cmds.reply; + ioc_status = le16_to_cpu(smpReply->IOCStatus) & MPI_IOCSTATUS_MASK; + + if ((ioc_status != MPI_IOCSTATUS_SUCCESS) && + (ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN)) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + dcsmisasprintk(ioc, printk(KERN_DEBUG ": SMP Passthru: ")); + dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n", + le16_to_cpu(smpReply->IOCStatus), + le32_to_cpu(smpReply->IOCLogInfo), + smpReply->SASStatus)); + goto cim_smp_passthru_exit; + } + + karg->Parameters.bConnectionStatus = + map_sas_status_to_csmi(smpReply->SASStatus); + + + if (le16_to_cpu(smpReply->ResponseDataLength)) { + karg->Parameters.uResponseBytes = le16_to_cpu(smpReply->ResponseDataLength); + memcpy(&karg->Parameters.Response, + response_data, le16_to_cpu(smpReply->ResponseDataLength)); + } + + cim_smp_passthru_exit: + + if (request_data) + pci_free_consistent(ioc->pcidev, request_data_sz, + (u8 *)request_data, request_data_dma); + + if (response_data) + pci_free_consistent(ioc->pcidev, response_data_sz, + (u8 *)response_data, response_data_dma); + + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, karg, + sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_smp_passthru @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + + free_pages((unsigned long)karg, memory_pages); + dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n",__FUNCTION__)); + return 0; +} + +/** + * Prototype Routine for the CSMI SAS SSP Passthru command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int csmisas_ssp_passthru(unsigned long arg) +{ + CSMI_SAS_SSP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg; + CSMI_SAS_SSP_PASSTHRU_BUFFER karg_hdr, * karg; + MPT_ADAPTER *ioc = NULL; + pSCSIIORequest_t pScsiRequest; + pSCSIIOReply_t pScsiReply; + MPT_FRAME_HDR *mf = NULL; + MPIHeader_t *mpi_hdr; + int iocnum,ii; + u64 sas_address; + u16 req_idx; + char *psge; + int flagsLength; + void * request_data; + dma_addr_t request_data_dma; + u32 request_data_sz; + int malloc_data_sz; + int memory_pages; + u16 ioc_status; + u8 volume_id; + u8 volume_bus; + u8 is_hidden_raid_component; + u8 channel; + u8 id; + struct sas_device_info *sas_info; + u8 skey, asc, ascq; + u32 MsgContext; + + if (copy_from_user(&karg_hdr, uarg, sizeof(CSMI_SAS_SSP_PASSTHRU_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_ssp_passthru struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + request_data = NULL; + request_data_sz = karg_hdr.Parameters.uDataLength; + channel = 0; + id = 0; + volume_id = 0; + volume_bus = 0; + is_hidden_raid_component = 0; + + malloc_data_sz = (request_data_sz + + offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER, bDataBuffer)); + memory_pages = get_order(malloc_data_sz); + karg = (CSMI_SAS_SSP_PASSTHRU_BUFFER *)__get_free_pages( + GFP_KERNEL, memory_pages); + if (!karg){ + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc SAS_SSP_PASSTHRU_BUFFER " + "malloc_data_sz=%d memory_pages=%d\n", + __FILE__, __LINE__, __FUNCTION__, + malloc_data_sz, memory_pages); + return -ENOMEM; + } + + memset(karg, 0, sizeof(*karg)); + + if (copy_from_user(karg, uarg, request_data_sz + + offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER,bDataBuffer))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_ssp_passthru struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + + /* + * some checks of the incoming frame + */ + if ( offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER,bDataBuffer) + + request_data_sz - sizeof(IOCTL_HEADER) > + karg->IoctlHeader.Length ) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; + dcsmisasprintk(ioc, printk(KERN_ERR + "%s::%s()" + " @%d - expected datalen incorrect!\n", + __FILE__, __FUNCTION__, __LINE__)); + goto cim_ssp_passthru_exit; + } + + if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + goto cim_ssp_passthru_exit; + } + + if (ioc->ioc_reset_in_progress) { + printk(KERN_ERR "%s@%d::%s - " + "Busy with IOC Reset \n", + __FILE__, __LINE__,__FUNCTION__); + return -EBUSY; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; + printk(KERN_ERR "%s::%s()@%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + goto cim_ssp_passthru_exit; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + + /* Default to success. + */ + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + + /* Neither a phy nor a port has been selected. + */ + if ((karg->Parameters.bPhyIdentifier == CSMI_SAS_USE_PORT_IDENTIFIER) && + (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT)) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT; + dcsmisasprintk(ioc, printk(KERN_ERR + "%s::%s()" + " @%d - incorrect bPhyIdentifier and bPortIdentifier!\n", + __FILE__, __FUNCTION__, __LINE__)); + goto cim_ssp_passthru_exit; + } + + /* A phy has been selected. Verify that it's valid. + */ + if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) { + + /* Is the phy in range? */ + if (karg->Parameters.bPhyIdentifier >= ioc->num_ports) { + dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports (%d %d)\n", + karg->Parameters.bPhyIdentifier, + ioc->num_ports)); + karg->IoctlHeader.ReturnCode = + CSMI_SAS_PHY_DOES_NOT_EXIST; + goto cim_ssp_passthru_exit; + } + } + + if(karg->Parameters.bAdditionalCDBLength) { + /* TODO - SCSI IO (32) Request Message support + */ + dcsmisasprintk(ioc, printk(KERN_DEBUG ": greater than 16-byte cdb " + "is not supported!\n")); + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + goto cim_ssp_passthru_exit; + } + + /* we will use SAS address to resolve the scsi adddressing + */ + memcpy(&sas_address, karg->Parameters.bDestinationSASAddress, + sizeof(u64)); + sas_address = reverse_byte_order64(sas_address); + + /* Search the list for the matching SAS address. + */ + sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address); + if (!sas_info || sas_info->is_cached) { + /* + *Invalid SAS address + */ + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + dcsmisasprintk(ioc, printk(KERN_ERR + "%s::%s() @%d - couldn't find associated " + "SASAddress=%llX!\n", __FILE__, __FUNCTION__, __LINE__, + (unsigned long long)sas_address)); + goto cim_ssp_passthru_exit; + } + + id = sas_info->fw.id; + channel = sas_info->fw.channel; + + if (csmisas_is_phys_disk(ioc, channel, id)) { + id = csmisas_raid_id_to_num(ioc, channel, id); + channel = 0; + is_hidden_raid_component = 1; + } + + /* Get a free request frame and save the message context. + */ + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { + dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_ssp_passthru_exit; + } + + mpi_hdr = (MPIHeader_t *) mf; + MsgContext = mpi_hdr->MsgContext; + pScsiRequest = (pSCSIIORequest_t) mf; + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + + memset(pScsiRequest,0,sizeof(SCSIIORequest_t)); + + /* Fill in SCSI IO (16) request. + */ + + pScsiRequest->Function = (is_hidden_raid_component == 1) ? + MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH : MPI_FUNCTION_SCSI_IO_REQUEST; + pScsiRequest->TargetID = id; + pScsiRequest->Bus = channel; + memcpy(pScsiRequest->LUN, &karg->Parameters.bLun, 8); + pScsiRequest->CDBLength = karg->Parameters.bCDBLength; + pScsiRequest->DataLength = cpu_to_le32(request_data_sz); + pScsiRequest->MsgContext = MsgContext; + memcpy(pScsiRequest->CDB, karg->Parameters.bCDB, + pScsiRequest->CDBLength); + + dcsmisasprintk(ioc, printk(KERN_DEBUG "\tchannel = %d id = %d ", + sas_info->fw.channel, sas_info->fw.id)); + dcsmisasprintk(ioc, if(is_hidden_raid_component) + printk(KERN_DEBUG "num_id = %d ", id)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\tcdb_len = %d request_len = %d\n", + pScsiRequest->CDBLength, request_data_sz)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\t")); + dcsmisasprintk(ioc, for (ii = 0; ii < pScsiRequest->CDBLength; ++ii) + printk(" %02x", pScsiRequest->CDB[ii])); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); + + /* direction + */ + if (karg->Parameters.uFlags & CSMI_SAS_SSP_READ) { + pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ); + } else if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) { + pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_WRITE); + } else if ((karg->Parameters.uFlags & CSMI_SAS_SSP_UNSPECIFIED) && + (!karg->Parameters.uDataLength)) { + /* no data transfer + */ + pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_NODATATRANSFER); + } else { + /* no direction specified + */ + pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ); + pScsiRequest->MsgFlags = + MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR; + } + + pScsiRequest->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; + if (ioc->sg_addr_size == sizeof(u64)) + pScsiRequest->MsgFlags |= MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64; + + /* task attributes + */ + if((karg->Parameters.uFlags && 0xFF) == 0) { + pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ); + } else if (karg->Parameters.uFlags & + CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE) { + pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_HEADOFQ); + } else if (karg->Parameters.uFlags & + CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED) { + pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ORDEREDQ); + } else if (karg->Parameters.uFlags & + CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA) { + pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ACAQ); + } else { + pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_UNTAGGED); + } + + /* setup sense + */ + pScsiRequest->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; + pScsiRequest->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + + (req_idx * MPT_SENSE_BUFFER_ALLOC)); + + /* setup databuffer sg, assuming we fit everything one contiguous buffer + */ + psge = (char *)&pScsiRequest->SGL; + + if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) { + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; + } else if (karg->Parameters.uFlags & CSMI_SAS_SSP_READ) { + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; + }else { + flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_DIRECTION ) + << MPI_SGE_FLAGS_SHIFT; + } + flagsLength |= request_data_sz; + + if ( request_data_sz > 0) { + request_data = pci_alloc_consistent( + ioc->pcidev, request_data_sz, &request_data_dma); + + if (request_data == NULL) { + dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED " + "request_data_sz=%d\n", request_data_sz)); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + mpt_free_msg_frame(ioc, mf); + goto cim_ssp_passthru_exit; + } + + ioc->add_sge(psge, flagsLength, request_data_dma); + if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) + memcpy(request_data, karg->bDataBuffer, request_data_sz); + } else { + ioc->add_sge(psge, flagsLength, (dma_addr_t) -1); + } + + if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_ssp_passthru_exit; + } + + memset(&karg->Status,0,sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS)); + karg->Status.bConnectionStatus = CSMI_SAS_OPEN_ACCEPT; + karg->Status.bDataPresent = CSMI_SAS_SSP_NO_DATA_PRESENT; + karg->Status.bStatus = GOOD; + karg->Status.bResponseLength[0] = 0; + karg->Status.bResponseLength[1] = 0; + karg->Status.uDataBytes = request_data_sz; + + /* process the completed Reply Message Frame */ + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { + + pScsiReply = (pSCSIIOReply_t ) ioc->ioctl_cmds.reply; + karg->Status.bStatus = pScsiReply->SCSIStatus; + karg->Status.uDataBytes = min(le32_to_cpu(pScsiReply->TransferCount), + request_data_sz); + ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; + + if (pScsiReply->SCSIState == + MPI_SCSI_STATE_AUTOSENSE_VALID) { + karg->Status.bConnectionStatus = + CSMI_SAS_SSP_SENSE_DATA_PRESENT; + karg->Status.bResponseLength[0] = + (u8)le32_to_cpu(pScsiReply->SenseCount) & 0xFF; + memcpy(karg->Status.bResponse, + ioc->ioctl_cmds.sense, le32_to_cpu(pScsiReply->SenseCount)); + + skey = ioc->ioctl_cmds.sense[2] & 0x0F; + asc = ioc->ioctl_cmds.sense[12]; + ascq = ioc->ioctl_cmds.sense[13]; + + dcsmisasprintk(ioc, printk(KERN_DEBUG "\t [sense_key,asc,ascq]: " + "[0x%02x,0x%02x,0x%02x]\n", + skey, asc, ascq)); + + } else if(pScsiReply->SCSIState == + MPI_SCSI_STATE_RESPONSE_INFO_VALID) { + karg->Status.bDataPresent = + CSMI_SAS_SSP_RESPONSE_DATA_PRESENT; + karg->Status.bResponseLength[0] = + sizeof(pScsiReply->ResponseInfo); + for (ii=0;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 .... + */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + karg.IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_FAILED; + goto cim_get_task_managment_exit; + } +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) + if (mptctl_set_tm_flags(hd) != 0) { + karg.IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_FAILED; + goto cim_get_task_managment_exit; + } +#endif + /* Send request + */ + if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) { + dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + mpt_clear_taskmgmt_in_progress_flag(ioc); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) + mptctl_free_tm_flags(ioc); +#endif + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_task_managment_exit; + } + + mpi_hdr = (MPIHeader_t *) mf; + MsgContext = mpi_hdr->MsgContext; + pScsiTm = (pSCSITaskMgmt_t ) mf; + + memset(pScsiTm,0,sizeof(SCSITaskMgmt_t)); + pScsiTm->TaskType = taskType; + pScsiTm->Bus = channel; + pScsiTm->TargetID = id; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) + int_to_scsilun(karg.Parameters.bLun, + (struct scsi_lun *)pScsiTm->LUN); +#else + pScsiTm->LUN[1] = karg.Parameters.bLun; +#endif + pScsiTm->MsgContext = MsgContext; + pScsiTm->TaskMsgContext = TaskMsgContext; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + if (csmisas_send_handshake_wait(ioc, mf, + karg.IoctlHeader.Timeout) != 0) { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); +#endif + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_task_managment_exit; + } + + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { + + pScsiTmReply = + (pSCSITaskMgmtReply_t ) ioc->ioctl_cmds.reply; + + ioc_status = le16_to_cpu(pScsiTmReply->IOCStatus) + & MPI_IOCSTATUS_MASK; + + memset(&karg.Status,0, + sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS)); + + if(ioc_status == MPI_IOCSTATUS_SUCCESS) { + karg.IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_SUCCESS; + karg.Status.bSSPStatus = + CSMI_SAS_SSP_STATUS_COMPLETED; + }else if(ioc_status == MPI_IOCSTATUS_INSUFFICIENT_RESOURCES) { + karg.IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_SUCCESS; + karg.Status.bSSPStatus = + CSMI_SAS_SSP_STATUS_RETRY; + }else { + karg.IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_FAILED; + karg.Status.bSSPStatus = + CSMI_SAS_SSP_STATUS_FATAL_ERROR; + } + } else + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + + break; + + default: + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; + break; + } + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); +#endif + + cim_get_task_managment_exit: + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_SSP_TASK_IU_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_task_managment @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return 0; +} + +/** + * map_sas_status_to_csmi - Conversion for Connection Status + * @mpi_sas_status: Sas status returned by the firmware + * + * Returns converted connection status + * + **/ +static u8 +map_sas_status_to_csmi(u8 mpi_sas_status) +{ + u8 csmi_connect_status; + + switch (mpi_sas_status) { + + case MPI_SASSTATUS_SUCCESS: + csmi_connect_status = CSMI_SAS_OPEN_ACCEPT; + break; + + case MPI_SASSTATUS_UTC_BAD_DEST: + csmi_connect_status = CSMI_SAS_OPEN_REJECT_BAD_DESTINATION; + break; + + case MPI_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED: + csmi_connect_status = CSMI_SAS_OPEN_REJECT_RATE_NOT_SUPPORTED; + break; + + case MPI_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED: + csmi_connect_status = + CSMI_SAS_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED; + break; + + case MPI_SASSTATUS_UTC_STP_RESOURCES_BUSY: + csmi_connect_status = CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY; + break; + + case MPI_SASSTATUS_UTC_WRONG_DESTINATION: + csmi_connect_status = CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION; + break; + + case MPI_SASSTATUS_SDSF_NAK_RECEIVED: + csmi_connect_status = CSMI_SAS_OPEN_REJECT_RETRY; + break; + + case MPI_SASSTATUS_SDSF_CONNECTION_FAILED: + csmi_connect_status = CSMI_SAS_OPEN_REJECT_PATHWAY_BLOCKED; + break; + + case MPI_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT: + csmi_connect_status = CSMI_SAS_OPEN_REJECT_NO_DESTINATION; + break; + + case MPI_SASSTATUS_UNKNOWN_ERROR: + case MPI_SASSTATUS_INVALID_FRAME: + case MPI_SASSTATUS_UTC_BREAK_RECEIVED: + case MPI_SASSTATUS_UTC_PORT_LAYER_REQUEST: + case MPI_SASSTATUS_SHORT_INFORMATION_UNIT: + case MPI_SASSTATUS_LONG_INFORMATION_UNIT: + case MPI_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA: + case MPI_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR: + case MPI_SASSTATUS_XFER_RDY_NOT_EXPECTED: + case MPI_SASSTATUS_DATA_INCORRECT_DATA_LENGTH: + case MPI_SASSTATUS_DATA_TOO_MUCH_READ_DATA: + case MPI_SASSTATUS_DATA_OFFSET_ERROR: + csmi_connect_status = CSMI_SAS_OPEN_REJECT_RESERVE_STOP; + break; + + default: + csmi_connect_status = CSMI_SAS_OPEN_REJECT_RESERVE_STOP; + break; + } + + return csmi_connect_status; +} + +/** + * csmisas_phy_reset + * Issues a phy link reset or phy hard reset + * + * @ioc - Pointer to MPT_ADAPTER structure + * @PhyNum - phy number + * @opcode - {MPI_SAS_OP_PHY_LINK_RESET,MPI_SAS_OP_PHY_HARD_RESET} + * + * Returns: 0 for success, non-zero error + **/ +static int +csmisas_phy_reset(MPT_ADAPTER *ioc, u8 PhyNum, u8 opcode) +{ + SasIoUnitControlRequest_t *sasIoUnitCntrReq; + SasIoUnitControlReply_t *sasIoUnitCntrReply; + MPT_FRAME_HDR *mf = NULL; + MPIHeader_t *mpi_hdr; + u16 ioc_status; + u32 MsgContext; + + if ((opcode != MPI_SAS_OP_PHY_LINK_RESET) && + (opcode != MPI_SAS_OP_PHY_HARD_RESET)) + return -1; + + /* Get a MF for this command. + */ + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { + dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); + return -1; + } + + mpi_hdr = (MPIHeader_t *) mf; + MsgContext = mpi_hdr->MsgContext; + sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; + memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t)); + sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; + sasIoUnitCntrReq->MsgContext = MsgContext; + sasIoUnitCntrReq->Operation = opcode; + sasIoUnitCntrReq->PhyNum = PhyNum; + + if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0) + return -1; + + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) + return -1; + + /* process the completed Reply Message Frame */ + sasIoUnitCntrReply = (SasIoUnitControlReply_t *)ioc->ioctl_cmds.reply; + ioc_status = le16_to_cpu(sasIoUnitCntrReply->IOCStatus) + & MPI_IOCSTATUS_MASK; + if (ioc_status != MPI_IOCSTATUS_SUCCESS) { + printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", + __FUNCTION__, + sasIoUnitCntrReply->IOCStatus, + sasIoUnitCntrReply->IOCLogInfo); + return -1; + } + return 0; +} + +/** Prototype Routine for the CSMI SAS Phy Control command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_phy_control(unsigned long arg) +{ + CSMI_SAS_PHY_CONTROL_BUFFER __user *uarg = (void __user *) arg; + IOCTL_HEADER ioctl_header; + PCSMI_SAS_PHY_CONTROL_BUFFER karg; + SasIOUnitPage0_t *sasIoUnitPg0=NULL; + dma_addr_t sasIoUnitPg0_dma; + int sasIoUnitPg0_data_sz=0; + SasIOUnitPage1_t *sasIoUnitPg1=NULL; + dma_addr_t sasIoUnitPg1_dma; + int sasIoUnitPg1_data_sz=0; + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + MPT_ADAPTER *ioc = NULL; + int iocnum; + int csmi_sas_phy_control_buffer_sz; + int memory_pages; + + if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in IOCTL_HEADER" + "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + csmi_sas_phy_control_buffer_sz = ioctl_header.Length; + memory_pages = get_order(csmi_sas_phy_control_buffer_sz); + karg = (PCSMI_SAS_PHY_CONTROL_BUFFER)__get_free_pages( + GFP_KERNEL, memory_pages); + if (!karg){ + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc SAS_PHY_CONTROL_BUFFER " + "csmi_sas_phy_control_buffer_sz=%d memory_pages=%d\n", + __FILE__, __LINE__, __FUNCTION__, + csmi_sas_phy_control_buffer_sz, memory_pages); + return -ENOMEM; + } + memset(karg, 0, sizeof(*karg)); + + if (copy_from_user(karg, uarg, csmi_sas_phy_control_buffer_sz)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_phy_control_buffer " + "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(ioctl_header.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + + if (karg->bPhyIdentifier >= ioc->num_ports) { + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + goto cim_sas_phy_control_exit; + } + + /* + * Retreive SAS IOUNIT PAGE 0 + */ + + hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if (mpt_config(ioc, &cfg) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: READ MPI_SASIOUNITPAGE0: HEADER\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + + if (hdr.ExtPageLength == 0) { + dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + + sasIoUnitPg0_data_sz = hdr.ExtPageLength * 4; + sasIoUnitPg0 = (SasIOUnitPage0_t *) pci_alloc_consistent(ioc->pcidev, + sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma); + + if (!sasIoUnitPg0) { + dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + + memset((u8 *)sasIoUnitPg0, 0, sasIoUnitPg0_data_sz); + cfg.physAddr = sasIoUnitPg0_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if (mpt_config(ioc, &cfg) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: READ MPI_SASIOUNITPAGE0: CURRENT\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + + /* + * Retreive SAS IOUNIT PAGE 1 + */ + + hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 1; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if (mpt_config(ioc, &cfg) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: READ MPI_SASIOUNITPAGE1: HEADER\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + + if (hdr.ExtPageLength == 0) { + dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + + sasIoUnitPg1_data_sz = hdr.ExtPageLength * 4; + sasIoUnitPg1 = (SasIOUnitPage1_t *) pci_alloc_consistent(ioc->pcidev, + sasIoUnitPg1_data_sz, &sasIoUnitPg1_dma); + + if (!sasIoUnitPg1) { + dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + + memset((u8 *)sasIoUnitPg1, 0, sasIoUnitPg1_data_sz); + cfg.physAddr = sasIoUnitPg1_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if (mpt_config(ioc, &cfg) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: READ MPI_SASIOUNITPAGE1: CURRENT\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + + switch (karg->uFunction) { + + case CSMI_SAS_PC_LINK_RESET: + case CSMI_SAS_PC_HARD_RESET: + { + u8 opcode = (karg->uFunction==CSMI_SAS_PC_LINK_RESET) ? + MPI_SAS_OP_PHY_LINK_RESET : MPI_SAS_OP_PHY_HARD_RESET; + + if((karg->uLinkFlags & CSMI_SAS_PHY_ACTIVATE_CONTROL) && + (karg->usLengthOfControl >= sizeof(CSMI_SAS_PHY_CONTROL)) && + (karg->bNumberOfControls > 0)){ + if(karg->Control[0].bRate == + CSMI_SAS_LINK_RATE_1_5_GBPS) { + sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate = + MPI_SAS_IOUNIT1_MAX_RATE_1_5 | + MPI_SAS_IOUNIT1_MIN_RATE_1_5; + } + else if(karg->Control[0].bRate == + CSMI_SAS_LINK_RATE_3_0_GBPS) { + sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate = + MPI_SAS_IOUNIT1_MAX_RATE_3_0 | + MPI_SAS_IOUNIT1_MIN_RATE_3_0; + } + sasIoUnitPg1->PhyData[karg->bPhyIdentifier].PhyFlags &= + ~MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE; + cfg.dir = 1; + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM; + if (mpt_config(ioc, &cfg) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: WRITE MPI_SASIOUNITPAGE1 NVRAM\n")); + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + if (mpt_config(ioc, &cfg) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: WRITE MPI_SASIOUNITPAGE1 CURRENT\n")); + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + } + if (csmisas_phy_reset(ioc, + karg->bPhyIdentifier, opcode) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: csmisas_phy_reset\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + break; + + } + case CSMI_SAS_PC_PHY_DISABLE: + if(karg->usLengthOfControl || karg->bNumberOfControls) { + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + break; + } + sasIoUnitPg1->PhyData[karg->bPhyIdentifier].PhyFlags |= + MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE; + cfg.dir = 1; + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM; + if (mpt_config(ioc, &cfg) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: WRITE MPI_SASIOUNITPAGE1 NVRAM\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + if (mpt_config(ioc, &cfg) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: WRITE MPI_SASIOUNITPAGE1 CURRENT\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + if (csmisas_phy_reset(ioc, + karg->bPhyIdentifier, MPI_SAS_OP_PHY_HARD_RESET) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: csmisas_phy_reset\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } + break; + + case CSMI_SAS_PC_GET_PHY_SETTINGS: + if(karg->usLengthOfControl || karg->bNumberOfControls) { + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + break; + } + if(csmi_sas_phy_control_buffer_sz < + offsetof(CSMI_SAS_PHY_CONTROL_BUFFER,Control) + + (4* sizeof(CSMI_SAS_PHY_CONTROL))) { + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + break; + } + karg->usLengthOfControl = sizeof(CSMI_SAS_PHY_CONTROL); + karg->bNumberOfControls = 4; + karg->Control[0].bType = CSMI_SAS_SAS; + karg->Control[0].bRate = CSMI_SAS_LINK_RATE_1_5_GBPS; + karg->Control[1].bType = CSMI_SAS_SAS; + karg->Control[1].bRate = CSMI_SAS_LINK_RATE_3_0_GBPS; + karg->Control[2].bType = CSMI_SAS_SATA; + karg->Control[2].bRate = CSMI_SAS_LINK_RATE_1_5_GBPS; + karg->Control[3].bType = CSMI_SAS_SATA; + karg->Control[3].bRate = CSMI_SAS_LINK_RATE_3_0_GBPS; + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + break; + default: + break; + } + + cim_sas_phy_control_exit: + + if (sasIoUnitPg0) + pci_free_consistent(ioc->pcidev, sasIoUnitPg0_data_sz, + (u8 *) sasIoUnitPg0, sasIoUnitPg0_dma); + + if (sasIoUnitPg1) + pci_free_consistent(ioc->pcidev, sasIoUnitPg1_data_sz, + (u8 *) sasIoUnitPg1, sasIoUnitPg1_dma); + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, karg,csmi_sas_phy_control_buffer_sz)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_phy_control_buffer @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + free_pages((unsigned long)karg, memory_pages); + return 0; +} + +/** + * csmisas_get_manuf_pg_7 - Fetch Manufacturing config Page7. + * @ioc: Pointer to MPT_ADAPTER structure + * @mfgpage7_buffer: pointer to ManufacturingPage7_t that returns config + * page data + * @mfg_size - max size of buffer + * + * Return: 0 for success + * -ENOMEM if no memory available + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) + **/ +static int +csmisas_get_manuf_pg_7(MPT_ADAPTER *ioc, ManufacturingPage7_t *mfgpage7_buffer, int mfg_size) +{ + ConfigPageHeader_t hdr; + CONFIGPARMS cfg; + ManufacturingPage7_t *mfgPage7 = NULL; + dma_addr_t mfgPage7_dma; + int data_sz = 0; + int rc; + + /* Get Manufacturing Page 7 header */ + hdr.PageVersion = MPI_MANUFACTURING0_PAGEVERSION; + hdr.PageLength = 0; + hdr.PageNumber = 7; + hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.pageAddr = 0; + cfg.timeout = 0; + + if ((rc = mpt_config(ioc, &cfg)) != 0) + goto csmisas_get_manuf_pg_7_exit; + + if (hdr.PageLength == 0) { + rc = -EFAULT; + goto csmisas_get_manuf_pg_7_exit; + } + + data_sz = hdr.PageLength * 4; + mfgPage7 = pci_alloc_consistent(ioc->pcidev, data_sz, &mfgPage7_dma); + if (!mfgPage7) { + rc = -ENOMEM; + goto csmisas_get_manuf_pg_7_exit; + } + + memset((u8 *)mfgPage7, 0, data_sz); + cfg.physAddr = mfgPage7_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) + goto csmisas_get_manuf_pg_7_exit; + + /* copy buffer back to user */ + memcpy(mfgpage7_buffer, mfgPage7, min(data_sz, mfg_size)); + + csmisas_get_manuf_pg_7_exit: + + if (mfgPage7) + pci_free_consistent(ioc->pcidev, data_sz, (u8 *)mfgPage7, + mfgPage7_dma); + + return rc; +} + +/** + * Prototype Routine for the CSMI SAS Get Connector info command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + **/ +static int +csmisas_get_connector_info(unsigned long arg) +{ + CSMI_SAS_CONNECTOR_INFO_BUFFER __user *uarg = (void __user *) arg; + CSMI_SAS_CONNECTOR_INFO_BUFFER karg; + MPT_ADAPTER *ioc = NULL; + ManufacturingPage7_t *mfgPg7 = NULL; + int mfgPg7_sz; + int iocnum; + int i; + + if (copy_from_user(&karg, uarg, + sizeof(CSMI_SAS_CONNECTOR_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_connector_info_buffer" + " struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + + /* `32` is the sizeof MPI_MANPAGE7_CONNECTOR_INFO */ + for (i = 0; i < 32; i++) { + karg.Reference[i].uPinout = CSMI_SAS_CON_UNKNOWN; + strcpy(karg.Reference[i].bConnector,""); + karg.Reference[i].bLocation = CSMI_SAS_CON_UNKNOWN; + } + + mfgPg7_sz = offsetof(CONFIG_PAGE_MANUFACTURING_7,ConnectorInfo) + + (ioc->num_ports * sizeof(MPI_MANPAGE7_CONNECTOR_INFO)); + mfgPg7 = kmalloc(mfgPg7_sz, GFP_KERNEL); + if (!mfgPg7){ + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc @ %p\n", + __FILE__, __LINE__, __FUNCTION__, mfgPg7); + return -EFAULT; + } + memset(mfgPg7, 0, mfgPg7_sz); + + if (!csmisas_get_manuf_pg_7(ioc, mfgPg7, mfgPg7_sz)) { + for (i = 0; i < ioc->num_ports; i++) { + karg.Reference[i].uPinout = + le32_to_cpu(mfgPg7->ConnectorInfo[i].Pinout); + /*endian conversion , this is u8 * 16 ?? */ + strncpy(karg.Reference[i].bConnector, + mfgPg7->ConnectorInfo[i].Connector, 16); + karg.Reference[i].bLocation = + mfgPg7->ConnectorInfo[i].Location; + } + } + + kfree(mfgPg7); + + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_CONNECTOR_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_connector_info_buffer @" + "%p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return 0; +} + +/** + * csmisas_fill_location_data + * + * Outputs: None. + * Return: 0 if successful + **/ +static int +csmisas_fill_location_data(MPT_ADAPTER *ioc, u8 bus, u8 id, u8 opcode, + CSMI_SAS_LOCATION_IDENTIFIER * location_ident) +{ + + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + int rc; + SasDevicePage0_t *sasDevicePg0=NULL; + SasEnclosurePage0_t *sasEnclosurePg0=NULL; + dma_addr_t sasDevicePg0_dma,sasEnclosurePg0_dma; + int sasDevicePg0_data_sz=0; + int sasEnclosurePg0_data_sz=0; + u64 sas_address; + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + memset (location_ident, 0, sizeof(*location_ident)); + + /* SAS Device Page 0 */ + hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + rc=-1; + goto fill_location_data_exit; + } + + if (hdr.ExtPageLength == 0) { + rc=-1; + goto fill_location_data_exit; + } + + sasDevicePg0_data_sz = hdr.ExtPageLength * 4; + sasDevicePg0 = (SasDevicePage0_t *) pci_alloc_consistent( + ioc->pcidev, sasDevicePg0_data_sz, &sasDevicePg0_dma); + if (!sasDevicePg0) { + rc=-1; + goto fill_location_data_exit; + } + + memset((u8 *)sasDevicePg0, 0, sasDevicePg0_data_sz); + cfg.physAddr = sasDevicePg0_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = (bus << 8) + id + + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT); + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + rc=-1; + goto fill_location_data_exit; + } + + location_ident->bLocationFlags |= CSMI_SAS_LOCATE_SAS_ADDRESS_VALID; + memcpy(&sas_address, &sasDevicePg0->SASAddress, sizeof(u64)); + sas_address = reverse_byte_order64(sas_address); + memcpy(location_ident->bSASAddress, &sas_address, sizeof(u64)); + + location_ident->bLocationFlags |= CSMI_SAS_LOCATE_SAS_LUN_VALID; + memset(location_ident->bSASLun, 0, sizeof(location_ident->bSASLun)); + + /* SAS Enclosure Page 0 */ + hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + rc=0; + goto fill_location_data_exit; + } + + if (hdr.ExtPageLength == 0) { + rc=0; + goto fill_location_data_exit; + } + + sasEnclosurePg0_data_sz = hdr.ExtPageLength * 4; + sasEnclosurePg0 = (SasEnclosurePage0_t *) pci_alloc_consistent( + ioc->pcidev, sasEnclosurePg0_data_sz, &sasEnclosurePg0_dma); + if (!sasEnclosurePg0) { + rc=0; + goto fill_location_data_exit; + } + cfg.physAddr = sasEnclosurePg0_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = sasDevicePg0->EnclosureHandle + + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << MPI_SAS_ENCLOS_PGAD_FORM_SHIFT); + + if ((rc = mpt_config(ioc, &cfg)) != 0) { + rc=0; + goto fill_location_data_exit; + } + + location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID; + memcpy(&sas_address, &sasEnclosurePg0->EnclosureLogicalID, sizeof(u64)); + sas_address = reverse_byte_order64(sas_address); + if (sas_address) + memcpy(location_ident->bEnclosureIdentifier, &sas_address, sizeof(u64)); + else + strcpy(location_ident->bEnclosureIdentifier,"Internal"); + +// bBayPrefix - not supported + +// TODO - We need to look at sasEnclosurePg0-.Flags , to determine +// whether SEP BUS/TargetID is valid. Ifs its a SES device, then +// issue internal inquiry to (bus/id) to gather the Enclosure name. +// If the device is SMP, then issue SMP_MANUFACTURING to get enclosure name +// If its direct attached, there is no enclosure name + location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID; + strcpy(location_ident->bEnclosureName,"Not Supported"); + + location_ident->bLocationFlags |= CSMI_SAS_LOCATE_LOCATION_STATE_VALID; + location_ident->bLocationState = CSMI_SAS_LOCATE_UNKNOWN; + + location_ident->bLocationFlags |= CSMI_SAS_LOCATE_BAY_IDENTIFIER_VALID; + location_ident->bBayIdentifier = le16_to_cpu(sasDevicePg0->Slot); + + +// TODO - illuminating LEDs, +// karg->bIdentify = CSMI_SAS_LOCATE_FORCE_OFF, CSMI_SAS_LOCATE_FORCE_ON +// We can enable/disable LEDs by SCSI Enclosure Processor MPI request message +// printk("Flags=0x%x\n",sasEnclosurePg0->Flags); + +/* check sasEnclosurePg0->Flags - + * to validate whether we need to send the SEPRequest + * bit:5 should be set + * bit:3-0 any bit should be set. If zero, then SEPRequest will fail +*/ + +/* MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR + * Look in mpi_init.h + * SEPRequest_t = structure + * + * SEPRequest_t->Action should be set to MPI_SEP_REQ_ACTION_WRITE_STATUS + * + * SEPRequest_t->Flags should be set to + * MPI_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS, to pass along enclosure/slot ids + * + * SEPRequest_t->SlotStatus |= MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST - this + * will illuminate the LEDs + */ + +fill_location_data_exit: + + if (sasDevicePg0 != NULL) + pci_free_consistent(ioc->pcidev, sasDevicePg0_data_sz, + sasDevicePg0, sasDevicePg0_dma); + + if (sasEnclosurePg0 != NULL) + pci_free_consistent(ioc->pcidev, sasEnclosurePg0_data_sz, + sasEnclosurePg0, sasEnclosurePg0_dma); + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); + return rc; +} + +static int +csmisas_fill_location_data_raid(MPT_ADAPTER *ioc, PCSMI_SAS_GET_LOCATION_BUFFER karg, u8 VolumeBus, + u8 volumeID) +{ + pRaidVolumePage0_t pVolume0 = NULL; + pRaidPhysDiskPage0_t pPhysDisk0 = NULL; + CONFIGPARMS cfg; + ConfigPageHeader_t header; + u8 physDiskNumMax; + int volumepage0sz = 0, physdiskpage0sz = 0; + dma_addr_t volume0_dma, physdisk0_dma; + int csmi_sas_get_location_sz; + int rc = 0, i, idx; + int num_hotpares; + u64 totalMaxLBA, tmpTotalMaxLBA; + IOCPage5_t *iocPage5 = NULL; + u32 device_info = 0; + struct sas_device_info *sas_info; + + int sz; + + csmi_sas_get_location_sz = karg->IoctlHeader.Length; + physDiskNumMax = (csmi_sas_get_location_sz - + offsetof(CSMI_SAS_GET_LOCATION_BUFFER,Location)) + / sizeof(CSMI_SAS_LOCATION_IDENTIFIER); + karg->bNumberOfLocationIdentifiers=0; + + /* + * get RAID Volume Page 0 + */ + + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 0; + header.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; + cfg.cfghdr.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = (VolumeBus << 8) + volumeID; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + if (mpt_config(ioc, &cfg) != 0) { + rc = -1; + goto sas_fill_location_data_raid_exit; + } + + if (header.PageLength == 0) { + rc = -1; + goto sas_fill_location_data_raid_exit; + } + + volumepage0sz = header.PageLength * 4; + pVolume0 = pci_alloc_consistent(ioc->pcidev, volumepage0sz, + &volume0_dma); + if (!pVolume0) { + rc = -1; + goto sas_fill_location_data_raid_exit; + } + + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.physAddr = volume0_dma; + if (mpt_config(ioc, &cfg) != 0){ + rc = -1; + goto sas_fill_location_data_raid_exit; + } + + totalMaxLBA = (u64)le32_to_cpu(pVolume0->MaxLBA) | + ((u64)le32_to_cpu(pVolume0->MaxLBAHigh)) << 32; + + /* + * get RAID Physical Disk Page 0 + */ + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 0; + header.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; + cfg.cfghdr.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + if (mpt_config(ioc, &cfg) != 0) { + rc = -1; + goto sas_fill_location_data_raid_exit; + } + + if (header.PageLength == 0) { + rc = -1; + goto sas_fill_location_data_raid_exit; + } + + physdiskpage0sz = header.PageLength * 4; + pPhysDisk0 = pci_alloc_consistent(ioc->pcidev, physdiskpage0sz, + &physdisk0_dma); + if (!pPhysDisk0) { + rc = -1; + goto sas_fill_location_data_raid_exit; + } + cfg.physAddr = physdisk0_dma; + + for (i=0; i < min(pVolume0->NumPhysDisks, physDiskNumMax); i++) { + + /* obtain a refresh of pPhysDisk0 */ + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = pVolume0->PhysDisk[i].PhysDiskNum; + if (mpt_config(ioc, &cfg) != 0){ + rc = -1; + goto sas_fill_location_data_raid_exit; + } + + if((csmisas_fill_location_data(ioc, pPhysDisk0->PhysDiskBus, + pPhysDisk0->PhysDiskID, karg->bIdentify, + &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0) + karg->bNumberOfLocationIdentifiers++; + + if (device_info) + continue; + sas_info = csmisas_get_device_component_by_fw(ioc, + pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID); + if (!sas_info || sas_info->is_cached) + continue; + device_info = sas_info->device_info; + } + + if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS) + goto sas_fill_location_data_raid_exit; + + /* + * hot spare support + * + */ + + num_hotpares = csmisas_get_number_hotspares(ioc); + + if (num_hotpares) { + + sz = offsetof(IOCPage5_t, HotSpare) + + num_hotpares * sizeof(IOC_5_HOT_SPARE); + iocPage5 = kmalloc(sz, GFP_KERNEL); + + if (!iocPage5) + goto sas_fill_location_data_raid_exit; + memset(iocPage5, 0, sizeof(*iocPage5)); + + if (csmisas_get_ioc_pg5(ioc, iocPage5, sz) != 0) + goto sas_fill_location_data_raid_exit; + + for(i = 0, idx = pVolume0->NumPhysDisks ; i < num_hotpares; + i++, idx++) { + + if (idx >= physDiskNumMax) + break; + + /* obtain a refresh of pPhysDisk0 */ + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = iocPage5->HotSpare[i].PhysDiskNum; + if (mpt_config(ioc, &cfg) != 0) + goto sas_fill_location_data_raid_exit; + + /* Search the list for the matching SAS address. */ + sas_info = csmisas_get_device_component_by_fw(ioc, + pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID); + + if (!sas_info || sas_info->is_cached) + continue; + + /* don't mix SSP hot spare + * in SATA volume + */ + if (!csmisas_is_sata(pPhysDisk0) && + (device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE)) + continue; + + /* don't mix SATA hot spare + * in SSP volume + */ + if (csmisas_is_sata(pPhysDisk0) && + (device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET)) + continue; + + /* capacity check for IM volumes*/ + if ((pVolume0->VolumeType == + MPI_RAID_VOL_TYPE_IM) && + (totalMaxLBA + + (64*2*1024) /* metadata = 64MB*/ > + le32_to_cpu(pPhysDisk0->MaxLBA))) + continue; + + tmpTotalMaxLBA = totalMaxLBA; + do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks); + /* capacity check for IME volumes*/ + if ((pVolume0->VolumeType == + MPI_RAID_VOL_TYPE_IME) && + ((tmpTotalMaxLBA * 2) + + (64*2*1024 ) /*metadata = 64MB*/ > + le32_to_cpu(pPhysDisk0->MaxLBA))) + continue; + + if((csmisas_fill_location_data(ioc, + pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID, + karg->bIdentify, + &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0) + karg->bNumberOfLocationIdentifiers++; + } + } + + + sas_fill_location_data_raid_exit: + + kfree(iocPage5); + + if (pVolume0) + pci_free_consistent(ioc->pcidev, volumepage0sz, pVolume0, + volume0_dma); + + if(pPhysDisk0) + pci_free_consistent(ioc->pcidev, physdiskpage0sz, pPhysDisk0, + physdisk0_dma); + + return rc; +} + +/** + * Prototype Routine for the CSMI SAS Get location command. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + */ +static int +csmisas_get_location(unsigned long arg) +{ + CSMI_SAS_GET_LOCATION_BUFFER __user *uarg = (void __user *) arg; + PCSMI_SAS_GET_LOCATION_BUFFER karg; + IOCTL_HEADER ioctl_header; + MPT_ADAPTER *ioc = NULL; + int iocnum,i; + int csmi_sas_get_location_sz; + int memory_pages; + struct sas_device_info *sas_info; + + if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in IOCTL_HEADER" + "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + csmi_sas_get_location_sz = ioctl_header.Length; + memory_pages = get_order(csmi_sas_get_location_sz); + karg = (PCSMI_SAS_GET_LOCATION_BUFFER)__get_free_pages( + GFP_KERNEL, memory_pages); + if (!karg){ + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc GET_LOCATION_BUFFER " + "csmi_sas_get_location_sz=%d memory_pages=%d\n", + __FILE__, __LINE__, __FUNCTION__, + csmi_sas_get_location_sz, memory_pages); + return -ENOMEM; + } + memset(karg, 0, sizeof(*karg)); + + if (copy_from_user(karg, uarg, csmi_sas_get_location_sz)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_phy_control_buffer " + "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + + dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); + + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; + if(karg->bLengthOfLocationIdentifier != + sizeof(CSMI_SAS_LOCATION_IDENTIFIER)) + goto cim_sas_get_location_exit; + + sas_info = csmisas_get_device_component_by_os(ioc, karg->bPathId, + karg->bTargetId); + if (!sas_info) + goto cim_sas_get_location_exit; + + /* RAID SUPPORT */ + if (ioc->raid_data.pIocPg2 && sas_info->is_logical_volume) { + for (i=0; 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; +} Index: linux-2.6.18.i386/drivers/message/fusion/csmi/csmisas.h =================================================================== --- /dev/null +++ linux-2.6.18.i386/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_ Index: linux-2.6.18.i386/drivers/message/fusion/linux_compat.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/linux_compat.h +++ linux-2.6.18.i386/drivers/message/fusion/linux_compat.h @@ -1,9 +1,70 @@ /* drivers/message/fusion/linux_compat.h */ - #ifndef FUSION_LINUX_COMPAT_H #define FUSION_LINUX_COMPAT_H #include +#include #include +#include +#include + +#ifndef PCI_VENDOR_ID_ATTO +#define PCI_VENDOR_ID_ATTO 0x117c +#endif + +#ifndef PCI_VENDOR_ID_BROCADE +#define PCI_VENDOR_ID_BROCADE 0x1657 +#endif + +/* + * TODO Need to change 'shost_private' back to 'shost_priv' when suppying patchs + * upstream. Since Red Hat decided to backport this to rhel5.2 (2.6.18-92.el5) + * from the 2.6.23 kernel, it will make it difficult for us to add the proper + * glue in our driver. + */ +static inline void *shost_private(struct Scsi_Host *shost) +{ + return (void *)shost->hostdata; +} + +#ifndef spi_dv_pending +#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) +/** + * mpt_scsilun_to_int: convert a scsi_lun to an int + * @scsilun: struct scsi_lun to be converted. + * + * Description: + * Convert @scsilun from a struct scsi_lun to a four byte host byte-ordered + * integer, and return the result. The caller must check for + * truncation before using this function. + * + * Notes: + * The struct scsi_lun is assumed to be four levels, with each level + * effectively containing a SCSI byte-ordered (big endian) short; the + * addressing bits of each level are ignored (the highest two bits). + * For a description of the LUN format, post SCSI-3 see the SCSI + * Architecture Model, for SCSI-3 see the SCSI Controller Commands. + * + * Given a struct scsi_lun of: 0a 04 0b 03 00 00 00 00, this function returns + * the integer: 0x0b030a04 + **/ +static inline int mpt_scsilun_to_int(struct scsi_lun *scsilun) +{ + int i; + unsigned int lun; + lun = 0; + for (i = 0; i < sizeof(lun); i += 2) + lun = lun | (((scsilun->scsi_lun[i] << 8) | + scsilun->scsi_lun[i + 1]) << (i * 8)); + return lun; +} +#endif +#if (defined(CONFIG_SUSE_KERNEL) && !defined(scsi_is_sas_phy_local)) +#define SUSE_KERNEL_BASE 1 +#endif +/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* _LINUX_COMPAT_H */ Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2005 LSI Logic Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi.h * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * mpi.h Version: 01.05.11 + * mpi.h Version: 01.05.16 * * Version History * --------------- @@ -77,6 +77,11 @@ * 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT. * 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target. * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. + * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT. + * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT. + * 08-07-07 01.05.14 Bumped MPI_HEADER_VERSION_UNIT. + * 01-15-08 01.05.15 Bumped MPI_HEADER_VERSION_UNIT. + * 03-28-08 01.05.16 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -107,7 +112,7 @@ /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x0D) +#define MPI_HEADER_VERSION_UNIT (0x13) #define MPI_HEADER_VERSION_DEV (0x00) #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI_HEADER_VERSION_UNIT_SHIFT (8) Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_cnfg.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_cnfg.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_cnfg.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2005 LSI Logic Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_cnfg.h * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * mpi_cnfg.h Version: 01.05.12 + * mpi_cnfg.h Version: 01.05.18 * * Version History * --------------- @@ -276,6 +276,52 @@ * Added AdditionalControlFlags, MaxTargetPortConnectTime, * ReportDeviceMissingDelay, and IODeviceMissingDelay * fields to SAS IO Unit Page 1. + * 10-11-06 01.05.13 Added NumForceWWID field and ForceWWID array to + * Manufacturing Page 5. + * Added Manufacturing pages 8 through 10. + * Added defines for supported metadata size bits in + * CapabilitiesFlags field of IOC Page 6. + * Added defines for metadata size bits in VolumeSettings + * field of RAID Volume Page 0. + * Added SATA Link Reset settings, Enable SATA Asynchronous + * Notification bit, and HideNonZeroAttachedPhyIdentifiers + * bit to AdditionalControlFlags field of SAS IO Unit + * Page 1. + * Added defines for Enclosure Devices Unmapped and + * Device Limit Exceeded bits in Status field of SAS IO + * Unit Page 2. + * Added more AccessStatus values for SAS Device Page 0. + * Added bit for SATA Asynchronous Notification Support in + * Flags field of SAS Device Page 0. + * 02-28-07 01.05.14 Added ExtFlags field to Manufacturing Page 4. + * Added Disable SMART Polling for CapabilitiesFlags of + * IOC Page 6. + * Added Disable SMART Polling to DeviceSettings of BIOS + * Page 1. + * Added Multi-Port Domain bit for DiscoveryStatus field + * of SAS IO Unit Page. + * Added Multi-Port Domain Illegal flag for SAS IO Unit + * Page 1 AdditionalControlFlags field. + * 05-24-07 01.05.15 Added Hide Physical Disks with Non-Integrated RAID + * Metadata bit to Manufacturing Page 4 ExtFlags field. + * Added Internal Connector to End Device Present bit to + * Expander Page 0 Flags field. + * Fixed define for + * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED. + * 08-07-07 01.05.16 Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT + * define. + * Added BIOS Page 4 structure. + * Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID + * Physcial Disk Page 1. + * 01-15-07 01.05.17 Added additional bit defines for ExtFlags field of + * Manufacturing Page 4. + * Added Solid State Drives Supported bit to IOC Page 6 + * Capabilities Flags. + * Added new value for AccessStatus field of SAS Device + * Page 0 (_SATA_NEEDS_INITIALIZATION). + * 03-28-08 01.05.18 Defined new bits in Manufacturing Page 4 ExtFlags field + * to control coercion size and the mixing of SAS and SATA + * SSD drives. * -------------------------------------------------------------------------- */ @@ -622,7 +668,7 @@ typedef struct _CONFIG_PAGE_MANUFACTURIN U8 InfoSize1; /* 0Bh */ U8 InquirySize; /* 0Ch */ U8 Flags; /* 0Dh */ - U16 Reserved2; /* 0Eh */ + U16 ExtFlags; /* 0Eh */ U8 InquiryData[56]; /* 10h */ U32 ISVolumeSettings; /* 48h */ U32 IMEVolumeSettings; /* 4Ch */ @@ -641,7 +687,7 @@ typedef struct _CONFIG_PAGE_MANUFACTURIN } CONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4, ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t; -#define MPI_MANUFACTURING4_PAGEVERSION (0x04) +#define MPI_MANUFACTURING4_PAGEVERSION (0x05) /* defines for the Flags field */ #define MPI_MANPAGE4_FORCE_BAD_BLOCK_TABLE (0x80) @@ -653,18 +699,39 @@ typedef struct _CONFIG_PAGE_MANUFACTURIN #define MPI_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x02) #define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01) +/* defines for the ExtFlags field */ +#define MPI_MANPAGE4_EXTFLAGS_MASK_COERCION_SIZE (0x0180) +#define MPI_MANPAGE4_EXTFLAGS_SHIFT_COERCION_SIZE (7) +#define MPI_MANPAGE4_EXTFLAGS_1GB_COERCION_SIZE (0) +#define MPI_MANPAGE4_EXTFLAGS_128MB_COERCION_SIZE (1) + +#define MPI_MANPAGE4_EXTFLAGS_NO_MIX_SSD_SAS_SATA (0x0040) +#define MPI_MANPAGE4_EXTFLAGS_MIX_SSD_AND_NON_SSD (0x0020) +#define MPI_MANPAGE4_EXTFLAGS_DUAL_PORT_SUPPORT (0x0010) +#define MPI_MANPAGE4_EXTFLAGS_HIDE_NON_IR_METADATA (0x0008) +#define MPI_MANPAGE4_EXTFLAGS_SAS_CACHE_DISABLE (0x0004) +#define MPI_MANPAGE4_EXTFLAGS_SATA_CACHE_DISABLE (0x0002) +#define MPI_MANPAGE4_EXTFLAGS_LEGACY_MODE (0x0001) + + +#ifndef MPI_MANPAGE5_NUM_FORCEWWID +#define MPI_MANPAGE5_NUM_FORCEWWID (1) +#endif typedef struct _CONFIG_PAGE_MANUFACTURING_5 { CONFIG_PAGE_HEADER Header; /* 00h */ U64 BaseWWID; /* 04h */ U8 Flags; /* 0Ch */ - U8 Reserved1; /* 0Dh */ + U8 NumForceWWID; /* 0Dh */ U16 Reserved2; /* 0Eh */ + U32 Reserved3; /* 10h */ + U32 Reserved4; /* 14h */ + U64 ForceWWID[MPI_MANPAGE5_NUM_FORCEWWID]; /* 18h */ } CONFIG_PAGE_MANUFACTURING_5, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_5, ManufacturingPage5_t, MPI_POINTER pManufacturingPage5_t; -#define MPI_MANUFACTURING5_PAGEVERSION (0x01) +#define MPI_MANUFACTURING5_PAGEVERSION (0x02) /* defines for the Flags field */ #define MPI_MANPAGE5_TWO_WWID_PER_PHY (0x01) @@ -740,6 +807,36 @@ typedef struct _CONFIG_PAGE_MANUFACTURIN #define MPI_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) +typedef struct _CONFIG_PAGE_MANUFACTURING_8 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 ProductSpecificInfo;/* 04h */ +} CONFIG_PAGE_MANUFACTURING_8, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_8, + ManufacturingPage8_t, MPI_POINTER pManufacturingPage8_t; + +#define MPI_MANUFACTURING8_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_9 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 ProductSpecificInfo;/* 04h */ +} CONFIG_PAGE_MANUFACTURING_9, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_9, + ManufacturingPage9_t, MPI_POINTER pManufacturingPage9_t; + +#define MPI_MANUFACTURING9_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_10 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 ProductSpecificInfo;/* 04h */ +} CONFIG_PAGE_MANUFACTURING_10, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_10, + ManufacturingPage10_t, MPI_POINTER pManufacturingPage10_t; + +#define MPI_MANUFACTURING10_PAGEVERSION (0x00) + + /**************************************************************************** * IO Unit Config Pages ****************************************************************************/ @@ -1080,10 +1177,18 @@ typedef struct _CONFIG_PAGE_IOC_6 } CONFIG_PAGE_IOC_6, MPI_POINTER PTR_CONFIG_PAGE_IOC_6, IOCPage6_t, MPI_POINTER pIOCPage6_t; -#define MPI_IOCPAGE6_PAGEVERSION (0x00) +#define MPI_IOCPAGE6_PAGEVERSION (0x01) /* IOC Page 6 Capabilities Flags */ +#define MPI_IOCPAGE6_CAP_FLAGS_SSD_SUPPORT (0x00000020) +#define MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT (0x00000010) +#define MPI_IOCPAGE6_CAP_FLAGS_DISABLE_SMART_POLLING (0x00000008) + +#define MPI_IOCPAGE6_CAP_FLAGS_MASK_METADATA_SIZE (0x00000006) +#define MPI_IOCPAGE6_CAP_FLAGS_64MB_METADATA_SIZE (0x00000000) +#define MPI_IOCPAGE6_CAP_FLAGS_512MB_METADATA_SIZE (0x00000002) + #define MPI_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001) @@ -1150,6 +1255,7 @@ typedef struct _CONFIG_PAGE_BIOS_1 #define MPI_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) /* values for the DeviceSettings field */ +#define MPI_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010) #define MPI_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) #define MPI_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) #define MPI_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) @@ -1346,6 +1452,15 @@ typedef struct _CONFIG_PAGE_BIOS_2 #define MPI_BIOSPAGE2_FORM_SAS_WWN (0x05) #define MPI_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) +typedef struct _CONFIG_PAGE_BIOS_4 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U64 ReassignmentBaseWWID; /* 04h */ +} CONFIG_PAGE_BIOS_4, MPI_POINTER PTR_CONFIG_PAGE_BIOS_4, + BIOSPage4_t, MPI_POINTER pBIOSPage4_t; + +#define MPI_BIOSPAGE4_PAGEVERSION (0x00) + /**************************************************************************** * SCSI Port Config Pages @@ -2160,6 +2275,11 @@ typedef struct _RAID_VOL0_SETTINGS #define MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE (0x0004) #define MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC (0x0008) #define MPI_RAIDVOL0_SETTING_FAST_DATA_SCRUBBING_0102 (0x0020) /* obsolete */ + +#define MPI_RAIDVOL0_SETTING_MASK_METADATA_SIZE (0x00C0) +#define MPI_RAIDVOL0_SETTING_64MB_METADATA_SIZE (0x0000) +#define MPI_RAIDVOL0_SETTING_512MB_METADATA_SIZE (0x0040) + #define MPI_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0010) #define MPI_RAIDVOL0_SETTING_USE_DEFAULTS (0x8000) @@ -2203,7 +2323,7 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0 } CONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0, RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t; -#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x06) +#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x07) /* values for RAID Volume Page 0 InactiveStatus field */ #define MPI_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) @@ -2218,11 +2338,11 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0 typedef struct _CONFIG_PAGE_RAID_VOL_1 { CONFIG_PAGE_HEADER Header; /* 00h */ - U8 VolumeID; /* 01h */ - U8 VolumeBus; /* 02h */ - U8 VolumeIOC; /* 03h */ - U8 Reserved0; /* 04h */ - U8 GUID[24]; /* 05h */ + U8 VolumeID; /* 04h */ + U8 VolumeBus; /* 05h */ + U8 VolumeIOC; /* 06h */ + U8 Reserved0; /* 07h */ + U8 GUID[24]; /* 08h */ U8 Name[32]; /* 20h */ U64 WWID; /* 40h */ U32 Reserved1; /* 48h */ @@ -2277,7 +2397,7 @@ typedef struct _RAID_PHYS_DISK0_STATUS } RAID_PHYS_DISK0_STATUS, MPI_POINTER PTR_RAID_PHYS_DISK0_STATUS, RaidPhysDiskStatus_t, MPI_POINTER pRaidPhysDiskStatus_t; -/* RAID Volume 2 IM Physical Disk DiskStatus flags */ +/* RAID Physical Disk PhysDiskStatus flags */ #define MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x01) #define MPI_PHYSDISK0_STATUS_FLAG_QUIESCED (0x02) @@ -2332,6 +2452,15 @@ typedef struct _RAID_PHYS_DISK1_PATH #define MPI_RAID_PHYSDISK1_FLAG_BROKEN (0x0002) #define MPI_RAID_PHYSDISK1_FLAG_INVALID (0x0001) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength or NumPhysDiskPaths at runtime. + */ +#ifndef MPI_RAID_PHYS_DISK1_PATH_MAX +#define MPI_RAID_PHYS_DISK1_PATH_MAX (1) +#endif + typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_1 { CONFIG_PAGE_HEADER Header; /* 00h */ @@ -2339,7 +2468,7 @@ typedef struct _CONFIG_PAGE_RAID_PHYS_DI U8 PhysDiskNum; /* 05h */ U16 Reserved2; /* 06h */ U32 Reserved1; /* 08h */ - RAID_PHYS_DISK1_PATH Path[1]; /* 0Ch */ + RAID_PHYS_DISK1_PATH Path[MPI_RAID_PHYS_DISK1_PATH_MAX];/* 0Ch */ } CONFIG_PAGE_RAID_PHYS_DISK_1, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_1, RaidPhysDiskPage1_t, MPI_POINTER pRaidPhysDiskPage1_t; @@ -2481,6 +2610,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_ #define MPI_SAS_IOUNIT0_DS_TABLE_LINK (0x00000400) #define MPI_SAS_IOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800) #define MPI_SAS_IOUNIT0_DS_MAX_SATA_TARGETS (0x00001000) +#define MPI_SAS_IOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000) typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA @@ -2518,7 +2648,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_ } CONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1, SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t; -#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x06) +#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x07) /* values for SAS IO Unit Page 1 ControlFlags */ #define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) @@ -2544,7 +2674,14 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_ #define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) /* values for SAS IO Unit Page 1 AdditionalControlFlags */ -#define MPI_SAS_IOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) +#define MPI_SAS_IOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080) +#define MPI_SAS_IOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) +#define MPI_SAS_IOUNIT1_ACONTROL_HIDE_NONZERO_ATTACHED_PHY_IDENT (0x0020) +#define MPI_SAS_IOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010) +#define MPI_SAS_IOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008) +#define MPI_SAS_IOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004) +#define MPI_SAS_IOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002) +#define MPI_SAS_IOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) /* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */ #define MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F) @@ -2585,9 +2722,11 @@ 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 (0x05) +#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x06) /* values for SAS IO Unit Page 2 Status field */ +#define MPI_SAS_IOUNIT2_STATUS_DEVICE_LIMIT_EXCEEDED (0x08) +#define MPI_SAS_IOUNIT2_STATUS_ENCLOSURE_DEVICES_UNMAPPED (0x04) #define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02) #define MPI_SAS_IOUNIT2_STATUS_FULL_PERSISTENT_MAPPINGS (0x01) @@ -2663,6 +2802,7 @@ typedef struct _CONFIG_PAGE_SAS_EXPANDER #define MPI_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800) /* values for SAS Expander Page 0 Flags field */ +#define MPI_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x04) #define MPI_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x02) #define MPI_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x01) @@ -2703,7 +2843,7 @@ typedef struct _CONFIG_PAGE_SAS_EXPANDER /* see mpi_sas.h for values for SAS Expander Page 1 AttachedDeviceInfo values */ /* values for SAS Expander Page 1 DiscoveryInfo field */ -#define MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY DISABLED (0x04) +#define MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04) #define MPI_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) #define MPI_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) @@ -2739,24 +2879,39 @@ typedef struct _CONFIG_PAGE_SAS_DEVICE_0 } CONFIG_PAGE_SAS_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_0, SasDevicePage0_t, MPI_POINTER pSasDevicePage0_t; -#define MPI_SASDEVICE0_PAGEVERSION (0x04) +#define MPI_SASDEVICE0_PAGEVERSION (0x05) /* values for SAS Device Page 0 AccessStatus field */ -#define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) -#define MPI_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) -#define MPI_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) +#define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) +#define MPI_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) +#define MPI_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) +#define MPI_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03) +#define MPI_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04) +/* specific values for SATA Init failures */ +#define MPI_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F) /* values for SAS Device Page 0 Flags field */ -#define MPI_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) -#define MPI_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) -#define MPI_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) -#define MPI_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) -#define MPI_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) -#define MPI_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) -#define MPI_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) -#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT (0x0004) -#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED (0x0002) -#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) +#define MPI_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) +#define MPI_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) +#define MPI_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) +#define MPI_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) +#define MPI_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) +#define MPI_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) +#define MPI_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) +#define MPI_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) +#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT (0x0004) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED (0x0002) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) /* see mpi_sas.h for values for SAS Device Page 0 DeviceInfo values */ @@ -2810,11 +2965,11 @@ typedef struct _CONFIG_PAGE_SAS_PHY_0 U8 AttachedPhyIdentifier; /* 16h */ U8 Reserved2; /* 17h */ U32 AttachedDeviceInfo; /* 18h */ - U8 ProgrammedLinkRate; /* 20h */ - U8 HwLinkRate; /* 21h */ - U8 ChangeCount; /* 22h */ - U8 Flags; /* 23h */ - U32 PhyInfo; /* 24h */ + U8 ProgrammedLinkRate; /* 1Ch */ + U8 HwLinkRate; /* 1Dh */ + U8 ChangeCount; /* 1Eh */ + U8 Flags; /* 1Fh */ + U32 PhyInfo; /* 20h */ } CONFIG_PAGE_SAS_PHY_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_0, SasPhyPage0_t, MPI_POINTER pSasPhyPage0_t; Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_fc.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_fc.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_fc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 LSI Logic Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_fc.h Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_history.txt =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_history.txt +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_history.txt @@ -3,28 +3,28 @@ MPI Header File Change History ============================== - Copyright (c) 2000-2005 LSI Logic Corporation. + Copyright (c) 2000-2008 LSI Corporation. --------------------------------------- - Header Set Release Version: 01.05.13 - Header Set Release Date: 03-27-06 + Header Set Release Version: 01.05.19 + Header Set Release Date: 03-28-08 --------------------------------------- Filename Current version Prior version ---------- --------------- ------------- - mpi.h 01.05.11 01.05.10 - mpi_ioc.h 01.05.11 01.05.10 - mpi_cnfg.h 01.05.12 01.05.11 - mpi_init.h 01.05.07 01.05.06 - mpi_targ.h 01.05.06 01.05.05 + mpi.h 01.05.16 01.05.15 + mpi_ioc.h 01.05.16 01.05.15 + mpi_cnfg.h 01.05.18 01.05.17 + mpi_init.h 01.05.09 01.05.09 + mpi_targ.h 01.05.06 01.05.06 mpi_fc.h 01.05.01 01.05.01 mpi_lan.h 01.05.01 01.05.01 - mpi_raid.h 01.05.02 01.05.02 + mpi_raid.h 01.05.05 01.05.05 mpi_tool.h 01.05.03 01.05.03 mpi_inb.h 01.05.01 01.05.01 - mpi_sas.h 01.05.03 01.05.02 + mpi_sas.h 01.05.05 01.05.05 mpi_type.h 01.05.02 01.05.02 - mpi_history.txt 01.05.13 01.05.12 + mpi_history.txt 01.05.19 01.05.18 * Date Version Description @@ -94,6 +94,11 @@ mpi.h * 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT. * 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target. * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. + * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT. + * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT. + * 08-07-07 01.05.14 Bumped MPI_HEADER_VERSION_UNIT. + * 01-15-08 01.05.15 Bumped MPI_HEADER_VERSION_UNIT. + * 03-28-08 01.05.16 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- mpi_ioc.h @@ -182,6 +187,31 @@ mpi_ioc.h * Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event * data structure. * Added MPI_EXT_IMAGE_TYPE_INITIALIZATION. + * 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 notificaiton. + * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event + * data structure. + * Added new ImageType values for FWDownload and FWUpload + * requests. + * 02-28-07 01.05.13 Added MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT for SAS + * Broadcast Event Data (replacing _RESERVED2). + * For Discovery Error Event Data DiscoveryStatus field, + * replaced _MULTPL_PATHS with _UNSUPPORTED_DEVICE and + * added _MULTI_PORT_DOMAIN. + * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request. + * Added Common Boot Block type to FWUpload Request. + * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define. + * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and + * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data. + * Added SASAddress field to SAS Initiator Device Table + * Overflow event data structure. + * 03-28-08 01.05.16 Added two new ReasonCode values to SAS Device Status + * Change Event data to indicate completion of internally + * generated task management. + * Added MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE define. + * Added MPI_EVENT_SAS_INIT_RC_INACCESSIBLE define. * -------------------------------------------------------------------------- mpi_cnfg.h @@ -447,6 +477,52 @@ mpi_cnfg.h * Added AdditionalControlFlags, MaxTargetPortConnectTime, * ReportDeviceMissingDelay, and IODeviceMissingDelay * fields to SAS IO Unit Page 1. + * 10-11-06 01.05.13 Added NumForceWWID field and ForceWWID array to + * Manufacturing Page 5. + * Added Manufacturing pages 8 through 10. + * Added defines for supported metadata size bits in + * CapabilitiesFlags field of IOC Page 6. + * Added defines for metadata size bits in VolumeSettings + * field of RAID Volume Page 0. + * Added SATA Link Reset settings, Enable SATA Asynchronous + * Notification bit, and HideNonZeroAttachedPhyIdentifiers + * bit to AdditionalControlFlags field of SAS IO Unit + * Page 1. + * Added defines for Enclosure Devices Unmapped and + * Device Limit Exceeded bits in Status field of SAS IO + * Unit Page 2. + * Added more AccessStatus values for SAS Device Page 0. + * Added bit for SATA Asynchronous Notification Support in + * Flags field of SAS Device Page 0. + * 02-28-07 01.05.14 Added ExtFlags field to Manufacturing Page 4. + * Added Disable SMART Polling for CapabilitiesFlags of + * IOC Page 6. + * Added Disable SMART Polling to DeviceSettings of BIOS + * Page 1. + * Added Multi-Port Domain bit for DiscoveryStatus field + * of SAS IO Unit Page. + * Added Multi-Port Domain Illegal flag for SAS IO Unit + * Page 1 AdditionalControlFlags field. + * 05-24-07 01.05.15 Added Hide Physical Disks with Non-Integrated RAID + * Metadata bit to Manufacturing Page 4 ExtFlags field. + * Added Internal Connector to End Device Present bit to + * Expander Page 0 Flags field. + * Fixed define for + * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED. + * 08-07-07 01.05.16 Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT + * define. + * Added BIOS Page 4 structure. + * Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID + * Physcial Disk Page 1. + * 01-15-07 01.05.17 Added additional bit defines for ExtFlags field of + * Manufacturing Page 4. + * Added Solid State Drives Supported bit to IOC Page 6 + * Capabilities Flags. + * Added new value for AccessStatus field of SAS Device + * Page 0 (_SATA_NEEDS_INITIALIZATION). + * 03-28-08 01.05.18 Defined new bits in Manufacturing Page 4 ExtFlags field + * to control coercion size and the mixing of SAS and SATA + * SSD drives. * -------------------------------------------------------------------------- mpi_init.h @@ -490,6 +566,9 @@ mpi_init.h * 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them * unique in the first 32 characters. * 03-27-06 01.05.07 Added Task Management type of Clear ACA. + * 10-11-06 01.05.08 Shortened define for Task Management type of Clear ACA. + * 02-28-07 01.05.09 Defined two new MsgFlags bits for SCSI Task Management + * Request: Do Not Send Task IU and Soft Reset Option. * -------------------------------------------------------------------------- mpi_targ.h @@ -607,6 +686,11 @@ mpi_raid.h * 08-19-04 01.05.01 Original release for MPI v1.5. * 01-15-05 01.05.02 Added defines for the two new RAID Actions for * _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE. + * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and + * associated defines. + * 08-07-07 01.05.04 Added Disable Full Rebuild bit to the ActionDataWord + * for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME. + * 01-15-08 01.05.05 Added define for MPI_RAID_ACTION_SET_VOLUME_NAME. * -------------------------------------------------------------------------- mpi_tool.h @@ -638,6 +722,12 @@ mpi_sas.h * and Remove Device operations to SAS IO Unit Control. * Added DevHandle field to SAS IO Unit Control request and * reply. + * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO + * Unit Control request. + * 01-15-08 01.05.05 Added support for MPI_SAS_OP_SET_IOC_PARAMETER, + * including adding IOCParameter and IOCParameter value + * fields to SAS IO Unit Control Request. + * Added MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC define. * -------------------------------------------------------------------------- mpi_type.h @@ -653,20 +743,35 @@ mpi_type.h mpi_history.txt Parts list history -Filename 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09 ----------- -------- -------- -------- -------- -------- -mpi.h 01.05.11 01.05.10 01.05.09 01.05.08 01.05.07 -mpi_ioc.h 01.05.11 01.05.10 01.05.09 01.05.09 01.05.08 -mpi_cnfg.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08 -mpi_init.h 01.05.07 01.05.06 01.05.06 01.05.05 01.05.04 -mpi_targ.h 01.05.06 01.05.05 01.05.05 01.05.05 01.05.04 -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.02 01.05.02 01.05.02 01.05.02 01.05.02 -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.03 01.05.02 01.05.01 01.05.01 01.05.01 -mpi_type.h 01.05.02 01.05.02 01.05.01 01.05.01 01.05.01 +Filename 01.05.19 01.05.18 01.05.17 01.05.16 01.05.15 +---------- -------- -------- -------- -------- -------- +mpi.h 01.05.16 01.05.15 01.05.14 01.05.13 01.05.12 +mpi_ioc.h 01.05.16 01.05.15 01.05.15 01.05.14 01.05.13 +mpi_cnfg.h 01.05.18 01.05.17 01.05.16 01.05.15 01.05.14 +mpi_init.h 01.05.09 01.05.09 01.05.09 01.05.09 01.05.09 +mpi_targ.h 01.05.06 01.05.06 01.05.06 01.05.06 01.05.06 +mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_raid.h 01.05.05 01.05.05 01.05.04 01.05.03 01.05.03 +mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03 +mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_sas.h 01.05.05 01.05.05 01.05.04 01.05.04 01.05.04 +mpi_type.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02 + +Filename 01.05.14 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09 +---------- -------- -------- -------- -------- -------- -------- +mpi.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08 01.05.07 +mpi_ioc.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.09 01.05.08 +mpi_cnfg.h 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08 +mpi_init.h 01.05.08 01.05.07 01.05.06 01.05.06 01.05.05 01.05.04 +mpi_targ.h 01.05.06 01.05.06 01.05.05 01.05.05 01.05.05 01.05.04 +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.02 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02 +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.04 01.05.03 01.05.02 01.05.01 01.05.01 01.05.01 +mpi_type.h 01.05.02 01.05.02 01.05.02 01.05.01 01.05.01 01.05.01 Filename 01.05.08 01.05.07 01.05.06 01.05.05 01.05.04 01.05.03 ---------- -------- -------- -------- -------- -------- -------- Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_init.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_init.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_init.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2005 LSI Logic Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_init.h * Title: MPI initiator mode messages and structures * Creation Date: June 8, 2000 * - * mpi_init.h Version: 01.05.07 + * mpi_init.h Version: 01.05.09 * * Version History * --------------- @@ -53,6 +53,9 @@ * 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them * unique in the first 32 characters. * 03-27-06 01.05.07 Added Task Management type of Clear ACA. + * 10-11-06 01.05.08 Shortened define for Task Management type of Clear ACA. + * 02-28-07 01.05.09 Defined two new MsgFlags bits for SCSI Task Management + * Request: Do Not Send Task IU and Soft Reset Option. * -------------------------------------------------------------------------- */ @@ -428,13 +431,17 @@ typedef struct _MSG_SCSI_TASK_MGMT #define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) #define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) #define MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) -#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_ACA (0x08) +#define MPI_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) /* MsgFlags bits */ +#define MPI_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01) + #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00) #define MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION (0x02) #define MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION (0x04) +#define MPI_SCSITASKMGMT_MSGFLAGS_SOFT_RESET_OPTION (0x08) + /* SCSI Task Management Reply */ typedef struct _MSG_SCSI_TASK_MGMT_REPLY { Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_ioc.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_ioc.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_ioc.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2005 LSI Logic Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_ioc.h * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: August 11, 2000 * - * mpi_ioc.h Version: 01.05.11 + * mpi_ioc.h Version: 01.05.16 * * Version History * --------------- @@ -98,6 +98,31 @@ * Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event * data structure. * Added MPI_EXT_IMAGE_TYPE_INITIALIZATION. + * 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 notificaiton. + * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event + * data structure. + * Added new ImageType values for FWDownload and FWUpload + * requests. + * 02-28-07 01.05.13 Added MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT for SAS + * Broadcast Event Data (replacing _RESERVED2). + * For Discovery Error Event Data DiscoveryStatus field, + * replaced _MULTPL_PATHS with _UNSUPPORTED_DEVICE and + * added _MULTI_PORT_DOMAIN. + * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request. + * Added Common Boot Block type to FWUpload Request. + * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define. + * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and + * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data. + * Added SASAddress field to SAS Initiator Device Table + * Overflow event data structure. + * 03-28-08 01.05.16 Added two new ReasonCode values to SAS Device Status + * Change Event data to indicate completion of internally + * generated task management. + * Added MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE define. + * Added MPI_EVENT_SAS_INIT_RC_INACCESSIBLE define. * -------------------------------------------------------------------------- */ @@ -264,6 +289,7 @@ typedef struct _MSG_IOC_FACTS_REPLY #define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) #define MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) #define MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL (0x0008) +#define MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010) #define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01) #define MPI_IOCFACTS_FLAGS_REPLY_FIFO_HOST_SIGNAL (0x02) @@ -328,7 +354,8 @@ typedef struct _MSG_PORT_FACTS_REPLY U16 MaxPostedCmdBuffers; /* 1Ch */ U16 MaxPersistentIDs; /* 1Eh */ U16 MaxLanBuckets; /* 20h */ - U16 Reserved4; /* 22h */ + U8 MaxInitiators; /* 22h */ + U8 Reserved4; /* 23h */ U32 Reserved5; /* 24h */ } MSG_PORT_FACTS_REPLY, MPI_POINTER PTR_MSG_PORT_FACTS_REPLY, PortFactsReply_t, MPI_POINTER pPortFactsReply_t; @@ -487,6 +514,7 @@ typedef struct _MSG_EVENT_ACK_REPLY #define MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x00000018) #define MPI_EVENT_SAS_INIT_TABLE_OVERFLOW (0x00000019) #define MPI_EVENT_SAS_SMP_ERROR (0x0000001A) +#define MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE (0x0000001B) #define MPI_EVENT_LOG_ENTRY_ADDED (0x00000021) /* AckRequired field values */ @@ -593,6 +621,9 @@ typedef struct _EVENT_DATA_SAS_DEVICE_ST #define MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) #define MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) #define MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) +#define MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) +#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_INTERNAL_DEV_RESET (0x0E) +#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_TASK_ABORT_INTERNAL (0x0F) /* SCSI Event data for Queue Full event */ @@ -689,6 +720,8 @@ typedef struct _MPI_EVENT_DATA_IR2 #define MPI_EVENT_IR2_RC_PD_REMOVED (0x05) #define MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED (0x06) #define MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR (0x07) +#define MPI_EVENT_IR2_RC_DUAL_PORT_ADDED (0x08) +#define MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED (0x09) /* defines for logical disk states */ #define MPI_LD_STATE_OPTIMAL (0x00) @@ -780,7 +813,7 @@ typedef struct _EVENT_DATA_SAS_BROADCAST #define MPI_EVENT_PRIMITIVE_CHANGE (0x01) #define MPI_EVENT_PRIMITIVE_EXPANDER (0x03) -#define MPI_EVENT_PRIMITIVE_RESERVED2 (0x04) +#define MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04) #define MPI_EVENT_PRIMITIVE_RESERVED3 (0x05) #define MPI_EVENT_PRIMITIVE_RESERVED4 (0x06) #define MPI_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07) @@ -845,8 +878,10 @@ typedef struct _EVENT_DATA_DISCOVERY_ERR #define MPI_EVENT_DSCVRY_ERR_DS_SMP_CRC_ERROR (0x00000100) #define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_SUBTRACTIVE (0x00000200) #define MPI_EVENT_DSCVRY_ERR_DS_TABLE_TO_TABLE (0x00000400) -#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_PATHS (0x00000800) +#define MPI_EVENT_DSCVRY_ERR_DS_UNSUPPORTED_DEVICE (0x00000800) #define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000) +#define MPI_EVENT_DSCVRY_ERR_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE (0x00004000) /* SAS SMP Error Event data */ @@ -882,6 +917,8 @@ typedef struct _EVENT_DATA_SAS_INIT_DEV_ /* defines for the ReasonCode field of the SAS Initiator Device Status Change event */ #define MPI_EVENT_SAS_INIT_RC_ADDED (0x01) +#define MPI_EVENT_SAS_INIT_RC_REMOVED (0x02) +#define MPI_EVENT_SAS_INIT_RC_INACCESSIBLE (0x03) /* SAS Initiator Device Table Overflow Event data */ @@ -890,11 +927,60 @@ typedef struct _EVENT_DATA_SAS_INIT_TABL U8 MaxInit; /* 00h */ U8 CurrentInit; /* 01h */ U16 Reserved1; /* 02h */ + U64 SASAddress; /* 04h */ } EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, MPI_POINTER PTR_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, MpiEventDataSasInitTableOverflow_t, MPI_POINTER pMpiEventDataSasInitTableOverflow_t; +/* SAS Expander Status Change Event data */ + +typedef struct _EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE +{ + U8 ReasonCode; /* 00h */ + U8 Reserved1; /* 01h */ + U16 Reserved2; /* 02h */ + U8 PhysicalPort; /* 04h */ + U8 Reserved3; /* 05h */ + U16 EnclosureHandle; /* 06h */ + U64 SASAddress; /* 08h */ + U32 DiscoveryStatus; /* 10h */ + U16 DevHandle; /* 14h */ + U16 ParentDevHandle; /* 16h */ + U16 ExpanderChangeCount; /* 18h */ + U16 ExpanderRouteIndexes; /* 1Ah */ + U8 NumPhys; /* 1Ch */ + U8 SASLevel; /* 1Dh */ + U8 Flags; /* 1Eh */ + U8 Reserved4; /* 1Fh */ +} EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE, + MPI_POINTER PTR_EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE, + MpiEventDataSasExpanderStatusChange_t, + MPI_POINTER pMpiEventDataSasExpanderStatusChange_t; + +/* values for ReasonCode field of SAS Expander Status Change Event data */ +#define MPI_EVENT_SAS_EXP_RC_ADDED (0x00) +#define MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING (0x01) + +/* values for DiscoveryStatus field of SAS Expander Status Change Event data */ +#define MPI_EVENT_SAS_EXP_DS_LOOP_DETECTED (0x00000001) +#define MPI_EVENT_SAS_EXP_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI_EVENT_SAS_EXP_DS_MULTIPLE_PORTS (0x00000004) +#define MPI_EVENT_SAS_EXP_DS_EXPANDER_ERR (0x00000008) +#define MPI_EVENT_SAS_EXP_DS_SMP_TIMEOUT (0x00000010) +#define MPI_EVENT_SAS_EXP_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI_EVENT_SAS_EXP_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI_EVENT_SAS_EXP_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI_EVENT_SAS_EXP_DS_SMP_CRC_ERROR (0x00000100) +#define MPI_EVENT_SAS_EXP_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI_EVENT_SAS_EXP_DS_TABLE_LINK (0x00000400) +#define MPI_EVENT_SAS_EXP_DS_UNSUPPORTED_DEVICE (0x00000800) + +/* values for Flags field of SAS Expander Status Change Event data */ +#define MPI_EVENT_SAS_EXP_FLAGS_ROUTE_TABLE_CONFIG (0x02) +#define MPI_EVENT_SAS_EXP_FLAGS_CONFIG_IN_PROGRESS (0x01) + + /***************************************************************************** * @@ -926,6 +1012,11 @@ typedef struct _MSG_FW_DOWNLOAD #define MPI_FW_DOWNLOAD_ITYPE_BIOS (0x02) #define MPI_FW_DOWNLOAD_ITYPE_NVDATA (0x03) #define MPI_FW_DOWNLOAD_ITYPE_BOOTLOADER (0x04) +#define MPI_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06) +#define MPI_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) +#define MPI_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) +#define MPI_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) +#define MPI_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) typedef struct _FWDownloadTCSGE @@ -974,12 +1065,18 @@ typedef struct _MSG_FW_UPLOAD } MSG_FW_UPLOAD, MPI_POINTER PTR_MSG_FW_UPLOAD, FWUpload_t, MPI_POINTER pFWUpload_t; -#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM (0x00) -#define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01) -#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) -#define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03) -#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04) -#define MPI_FW_UPLOAD_ITYPE_FW_BACKUP (0x05) +#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM (0x00) +#define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01) +#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) +#define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03) +#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04) +#define MPI_FW_UPLOAD_ITYPE_FW_BACKUP (0x05) +#define MPI_FW_UPLOAD_ITYPE_MANUFACTURING (0x06) +#define MPI_FW_UPLOAD_ITYPE_CONFIG_1 (0x07) +#define MPI_FW_UPLOAD_ITYPE_CONFIG_2 (0x08) +#define MPI_FW_UPLOAD_ITYPE_MEGARAID (0x09) +#define MPI_FW_UPLOAD_ITYPE_COMPLETE (0x0A) +#define MPI_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) typedef struct _FWUploadTCSGE { Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_lan.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_lan.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_lan.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 LSI Logic Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_lan.h Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_log_fc.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_log_fc.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_log_fc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved. + * Copyright (c) 2000-2008 LSI Corporation. All rights reserved. * * NAME: fc_log.h * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_log_sas.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_log_sas.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_log_sas.h @@ -1,7 +1,6 @@ - /*************************************************************************** * * - * Copyright 2003 LSI Logic Corporation. All rights reserved. * + * Copyright (c) 2000-2008 LSI Corporation. All rights reserved. * * * * Description * * ------------ * @@ -14,7 +13,7 @@ #define IOPI_IOCLOGINFO_H_INCLUDED #define SAS_LOGINFO_NEXUS_LOSS 0x31170000 -#define SAS_LOGINFO_MASK 0xFFFF0000 +#define SAS_LOGINFO_MASK 0xFFFF0000 /****************************************************************************/ /* IOC LOGINFO defines, 0x00000000 - 0x0FFFFFFF */ @@ -43,129 +42,178 @@ /****************************************************************************/ /* IOP LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = IOP */ /****************************************************************************/ -#define IOP_LOGINFO_CODE_INVALID_SAS_ADDRESS (0x00010000) -#define IOP_LOGINFO_CODE_UNUSED2 (0x00020000) -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x00030000) -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_RT (0x00030100) /* Route Table Entry not found */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PN (0x00030200) /* Invalid Page Number */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x00030300) /* Invalid FORM */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x00030400) /* Invalid Page Type */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DNM (0x00030500) /* Device Not Mapped */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PERSIST (0x00030600) /* Persistent Page not found */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT (0x00030700) /* Default Page not found */ - -#define IOP_LOGINFO_CODE_DIAG_MSG_ERROR (0x00040000) /* Error handling diag msg - or'd with diag status */ - -#define IOP_LOGINFO_CODE_TASK_TERMINATED (0x00050000) - -#define IOP_LOGINFO_CODE_ENCL_MGMT_READ_ACTION_ERR0R (0x00060001) /* Read Action not supported for SEP msg */ -#define IOP_LOGINFO_CODE_ENCL_MGMT_INVALID_BUS_ID_ERR0R (0x00060002) /* Invalid Bus/ID in SEP msg */ - -#define IOP_LOGINFO_CODE_TARGET_ASSIST_TERMINATED (0x00070001) -#define IOP_LOGINFO_CODE_TARGET_STATUS_SEND_TERMINATED (0x00070002) -#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_ALL_IO (0x00070003) -#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO (0x00070004) -#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ (0x00070005) +#define IOP_LOGINFO_CODE_INVALID_SAS_ADDRESS (0x00010000) +#define IOP_LOGINFO_CODE_UNUSED2 (0x00020000) +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x00030000) +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_RT (0x00030100) /* Route Table Entry not found */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PN (0x00030200) /* Invalid Page Number */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x00030300) /* Invalid FORM */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x00030400) /* Invalid Page Type */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DNM (0x00030500) /* Device Not Mapped */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PERSIST (0x00030600) /* Persistent Page not found */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT (0x00030700) /* Default Page not found */ + +#define IOP_LOGINFO_CODE_FWUPLOAD_NO_FLASH_AVAILABLE (0x0003E000) /* Tried to upload from flash, but there is none */ +#define IOP_LOGINFO_CODE_FWUPLOAD_UNKNOWN_IMAGE_TYPE (0x0003E001) /* ImageType field contents were invalid */ +#define IOP_LOGINFO_CODE_FWUPLOAD_WRONG_IMAGE_SIZE (0x0003E002) /* ImageSize field in TCSGE was bad/offset in MfgPg 4 was wrong */ +#define IOP_LOGINFO_CODE_FWUPLOAD_ENTIRE_FLASH_UPLOAD_FAILED (0x0003E003) /* Error occured while attempting to upload the entire flash */ +#define IOP_LOGINFO_CODE_FWUPLOAD_REGION_UPLOAD_FAILED (0x0003E004) /* Error occured while attempting to upload single flash region */ +#define IOP_LOGINFO_CODE_FWUPLOAD_DMA_FAILURE (0x0003E005) /* Problem occured while DMAing FW to host memory */ + +#define IOP_LOGINFO_CODE_DIAG_MSG_ERROR (0x00040000) /* Error handling diag msg - or'd with diag status */ + +#define IOP_LOGINFO_CODE_TASK_TERMINATED (0x00050000) + +#define IOP_LOGINFO_CODE_ENCL_MGMT_READ_ACTION_ERR0R (0x00060001) /* Read Action not supported for SEP msg */ +#define IOP_LOGINFO_CODE_ENCL_MGMT_INVALID_BUS_ID_ERR0R (0x00060002) /* Invalid Bus/ID in SEP msg */ + +#define IOP_LOGINFO_CODE_TARGET_ASSIST_TERMINATED (0x00070001) +#define IOP_LOGINFO_CODE_TARGET_STATUS_SEND_TERMINATED (0x00070002) +#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_ALL_IO (0x00070003) +#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO (0x00070004) +#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ (0x00070005) + +#define IOP_LOGINFO_CODE_LOG_TIMESTAMP_EVENT (0x00080000) /****************************************************************************/ /* PL LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = PL */ /****************************************************************************/ -#define PL_LOGINFO_CODE_OPEN_FAILURE (0x00010000) -#define PL_LOG_INFO_CODE_OPEN_FAILURE_NO_DEST_TIME_OUT (0x00010001) -#define PL_LOGINFO_CODE_OPEN_FAILURE_BAD_DESTINATION (0x00010011) -#define PL_LOGINFO_CODE_OPEN_FAILURE_PROTOCOL_NOT_SUPPORTED (0x00010013) -#define PL_LOGINFO_CODE_OPEN_FAILURE_STP_RESOURCES_BSY (0x00010018) -#define PL_LOGINFO_CODE_OPEN_FAILURE_WRONG_DESTINATION (0x00010019) -#define PL_LOGINFO_CODE_OPEN_FAILURE_ORR_TIMEOUT (0X0001001A) -#define PL_LOGINFO_CODE_OPEN_FAILURE_PATHWAY_BLOCKED (0x0001001B) -#define PL_LOGINFO_CODE_OPEN_FAILURE_AWT_MAXED (0x0001001C) -#define PL_LOGINFO_CODE_INVALID_SGL (0x00020000) -#define PL_LOGINFO_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00030000) -#define PL_LOGINFO_CODE_FRAME_XFER_ERROR (0x00040000) -#define PL_LOGINFO_CODE_TX_FM_CONNECTED_LOW (0x00050000) -#define PL_LOGINFO_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00060000) -#define PL_LOGINFO_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00070000) -#define PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00080000) -#define PL_LOGINFO_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00090000) -#define PL_LOGINFO_CODE_RX_FM_INVALID_MESSAGE (0x000A0000) -#define PL_LOGINFO_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x000B0000) -#define PL_LOGINFO_CODE_RX_FM_CURRENT_FRAME_ERROR (0x000C0000) -#define PL_LOGINFO_CODE_SATA_LINK_DOWN (0x000D0000) -#define PL_LOGINFO_CODE_DISCOVERY_SATA_INIT_W_IOS (0x000E0000) -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x000F0000) -#define PL_LOGINFO_CODE_CONFIG_PL_NOT_INITIALIZED (0x000F0001) /* PL not yet initialized, can't do config page req. */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x000F0100) /* Invalid Page Type */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NUM_PHYS (0x000F0200) /* Invalid Number of Phys */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NOT_IMP (0x000F0300) /* Case Not Handled */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_DEV (0x000F0400) /* No Device Found */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x000F0500) /* Invalid FORM */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PHY (0x000F0600) /* Invalid Phy */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_OWNER (0x000F0700) /* No Owner Found */ -#define PL_LOGINFO_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00100000) -#define PL_LOGINFO_CODE_RESET (0x00110000) /* See Sub-Codes below */ -#define PL_LOGINFO_CODE_ABORT (0x00120000) /* See Sub-Codes below */ -#define PL_LOGINFO_CODE_IO_NOT_YET_EXECUTED (0x00130000) -#define PL_LOGINFO_CODE_IO_EXECUTED (0x00140000) -#define PL_LOGINFO_CODE_PERS_RESV_OUT_NOT_AFFIL_OWNER (0x00150000) -#define PL_LOGINFO_CODE_OPEN_TXDMA_ABORT (0x00160000) -#define PL_LOGINFO_CODE_IO_DEVICE_MISSING_DELAY_RETRY (0x00170000) -#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE (0x00000100) -#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_NO_DEST_TIMEOUT (0x00000101) -#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ORR_TIMEOUT (0x0000011A) /* Open Reject (Retry) Timeout */ -#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_PATHWAY_BLOCKED (0x0000011B) -#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_AWT_MAXED (0x0000011C) /* Arbitration Wait Timer Maxed */ - -#define PL_LOGINFO_SUB_CODE_TARGET_BUS_RESET (0x00000120) -#define PL_LOGINFO_SUB_CODE_TRANSPORT_LAYER (0x00000130) /* Leave lower nibble (1-f) reserved. */ -#define PL_LOGINFO_SUB_CODE_PORT_LAYER (0x00000140) /* Leave lower nibble (1-f) reserved. */ - - -#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) -#define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500) -#define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600) -#define PL_LOGINFO_SUB_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00000700) -#define PL_LOGINFO_SUB_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00000800) -#define PL_LOGINFO_SUB_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00000900) -#define PL_LOGINFO_SUB_CODE_RX_FM_INVALID_MESSAGE (0x00000A00) -#define PL_LOGINFO_SUB_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x00000B00) -#define PL_LOGINFO_SUB_CODE_RX_FM_CURRENT_FRAME_ERROR (0x00000C00) -#define PL_LOGINFO_SUB_CODE_SATA_LINK_DOWN (0x00000D00) -#define PL_LOGINFO_SUB_CODE_DISCOVERY_SATA_INIT_W_IOS (0x00000E00) -#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_CODE_ENCL_MGMT_SMP_FRAME_FAILURE (0x00200000) /* Can't get SMP Frame */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occured on SMP Read */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR (0x00200020) /* Error occured on SMP Write */ -#define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL (0x00200040) /* Encl Mgmt services not available for this WWID */ -#define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED (0x00200050) /* Address Mode not suppored */ -#define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM (0x00200060) /* Invalid Slot Number in SEP Msg */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SGPIO_NOT_PRESENT (0x00200070) /* SGPIO not present/enabled */ -#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_NOT_CONFIGURED (0x00200080) /* GPIO not configured */ -#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_FRAME_ERROR (0x00200090) /* GPIO can't allocate a frame */ -#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_CONFIG_PAGE_ERROR (0x002000A0) /* GPIO failed config page request */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SES_FRAME_ALLOC_ERROR (0x002000B0) /* Can't get frame for SES command */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SES_IO_ERROR (0x002000C0) /* I/O execution error */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SES_RETRIES_EXHAUSTED (0x002000D0) /* SEP I/O retries exhausted */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_ALLOC_ERROR (0x002000E0) /* Can't get frame for SMP command */ - -#define PL_LOGINFO_DA_SEP_NOT_PRESENT (0x00200100) /* SEP not present when msg received */ -#define PL_LOGINFO_DA_SEP_SINGLE_THREAD_ERROR (0x00200101) /* Can only accept 1 msg at a time */ -#define PL_LOGINFO_DA_SEP_ISTWI_INTR_IN_IDLE_STATE (0x00200102) /* ISTWI interrupt recvd. while IDLE */ -#define PL_LOGINFO_DA_SEP_RECEIVED_NACK_FROM_SLAVE (0x00200103) /* SEP NACK'd, it is busy */ -#define PL_LOGINFO_DA_SEP_DID_NOT_RECEIVE_ACK (0x00200104) /* SEP didn't rcv. ACK (Last Rcvd Bit = 1) */ -#define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM (0x00200105) /* SEP stopped or sent bad chksum in Hdr */ -#define PL_LOGINFO_DA_SEP_STOP_ON_DATA (0x00200106) /* SEP stopped while transfering data */ -#define PL_LOGINFO_DA_SEP_STOP_ON_SENSE_DATA (0x00200107) /* SEP stopped while transfering sense data */ -#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1 (0x00200108) /* SEP returned unknown scsi status */ -#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2 (0x00200109) /* SEP returned unknown scsi status */ -#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP (0x0020010A) /* SEP returned bad chksum after STOP */ -#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP_GETDATA (0x0020010B) /* SEP returned bad chksum after STOP while gettin data*/ -#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND (0x0020010C) /* SEP doesn't support CDB opcode */ +#define PL_LOGINFO_CODE_OPEN_FAILURE (0x00010000) /* see SUB_CODE_OPEN_FAIL_ below */ + +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_NO_DEST_TIME_OUT (0x00000001) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PATHWAY_BLOCKED (0x00000002) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_CONTINUE0 (0x00000003) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_CONTINUE1 (0x00000004) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_INITIALIZE0 (0x00000005) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_INITIALIZE1 (0x00000006) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_STOP0 (0x00000007) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_STOP1 (0x00000008) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RETRY (0x00000009) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_BREAK (0x0000000A) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0B (0x0000000B) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_OPEN_TIMEOUT_EXP (0x0000000C) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0D (0x0000000D) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_DVTBLE_ACCSS_FAIL (0x0000000E) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_BAD_DEST (0x00000011) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RATE_NOT_SUPP (0x00000012) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PROT_NOT_SUPP (0x00000013) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON0 (0x00000014) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON1 (0x00000015) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON2 (0x00000016) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON3 (0x00000017) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_STP_RESOURCES_BSY (0x00000018) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_WRONG_DESTINATION (0x00000019) + +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PATH_BLOCKED (0x0000001B) /* Retry Timeout */ +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_AWT_MAXED (0x0000001C) /* Retry Timeout */ + + + +#define PL_LOGINFO_CODE_INVALID_SGL (0x00020000) +#define PL_LOGINFO_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00030000) +#define PL_LOGINFO_CODE_FRAME_XFER_ERROR (0x00040000) +#define PL_LOGINFO_CODE_TX_FM_CONNECTED_LOW (0x00050000) +#define PL_LOGINFO_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00060000) +#define PL_LOGINFO_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00070000) +#define PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00080000) +#define PL_LOGINFO_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00090000) +#define PL_LOGINFO_CODE_RX_FM_INVALID_MESSAGE (0x000A0000) +#define PL_LOGINFO_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x000B0000) +#define PL_LOGINFO_CODE_RX_FM_CURRENT_FRAME_ERROR (0x000C0000) +#define PL_LOGINFO_CODE_SATA_LINK_DOWN (0x000D0000) +#define PL_LOGINFO_CODE_DISCOVERY_SATA_INIT_W_IOS (0x000E0000) +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x000F0000) +#define PL_LOGINFO_CODE_CONFIG_PL_NOT_INITIALIZED (0x000F0001) /* PL not yet initialized, can't do config page req. */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x000F0100) /* Invalid Page Type */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NUM_PHYS (0x000F0200) /* Invalid Number of Phys */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NOT_IMP (0x000F0300) /* Case Not Handled */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_DEV (0x000F0400) /* No Device Found */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x000F0500) /* Invalid FORM */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PHY (0x000F0600) /* Invalid Phy */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_OWNER (0x000F0700) /* No Owner Found */ +#define PL_LOGINFO_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00100000) +#define PL_LOGINFO_CODE_RESET (0x00110000) /* See Sub-Codes below (PL_LOGINFO_SUB_CODE) */ +#define PL_LOGINFO_CODE_ABORT (0x00120000) /* See Sub-Codes below (PL_LOGINFO_SUB_CODE)*/ +#define PL_LOGINFO_CODE_IO_NOT_YET_EXECUTED (0x00130000) +#define PL_LOGINFO_CODE_IO_EXECUTED (0x00140000) +#define PL_LOGINFO_CODE_PERS_RESV_OUT_NOT_AFFIL_OWNER (0x00150000) +#define PL_LOGINFO_CODE_OPEN_TXDMA_ABORT (0x00160000) +#define PL_LOGINFO_CODE_IO_DEVICE_MISSING_DELAY_RETRY (0x00170000) +#define PL_LOGINFO_CODE_IO_CANCELLED_DUE_TO_R_ERR (0x00180000) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE (0x00000100) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_NO_DEST_TIMEOUT (0x00000101) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_SATA_NEG_RATE_2HI (0x00000102) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_RATE_NOT_SUPPORTED (0x00000103) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_BREAK (0x00000104) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ZONE_VIOLATION (0x00000114) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON0 (0x00000114) /* Open Reject (Zone Violation) - available on SAS-2 devices */ +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON1 (0x00000115) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON2 (0x00000116) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON3 (0x00000117) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ORR_TIMEOUT (0x0000011A) /* Open Reject (Retry) Timeout */ +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_PATH_BLOCKED (0x0000011B) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_AWT_MAXED (0x0000011C) /* Arbitration Wait Timer Maxed */ + +#define PL_LOGINFO_SUB_CODE_TARGET_BUS_RESET (0x00000120) +#define PL_LOGINFO_SUB_CODE_TRANSPORT_LAYER (0x00000130) /* Leave lower nibble (1-f) reserved. */ +#define PL_LOGINFO_SUB_CODE_PORT_LAYER (0x00000140) /* Leave lower nibble (1-f) reserved. */ + + +#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_TX_FM_CONNECTED_LOW (0x00000500) +#define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600) +#define PL_LOGINFO_SUB_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00000700) +#define PL_LOGINFO_SUB_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00000800) +#define PL_LOGINFO_SUB_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00000900) +#define PL_LOGINFO_SUB_CODE_RX_FM_INVALID_MESSAGE (0x00000A00) +#define PL_LOGINFO_SUB_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x00000B00) +#define PL_LOGINFO_SUB_CODE_RX_FM_CURRENT_FRAME_ERROR (0x00000C00) +#define PL_LOGINFO_SUB_CODE_SATA_LINK_DOWN (0x00000D00) +#define PL_LOGINFO_SUB_CODE_DISCOVERY_SATA_INIT_W_IOS (0x00000E00) +#define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET (0x00000E01) +#define PL_LOGINFO_SUB_CODE_SECOND_OPEN (0x00000F00) +#define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00001000) +#define PL_LOGINFO_SUB_CODE_BREAK_ON_SATA_CONNECTION (0x00002000) /* not currently used in mainline */ +#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK (0x00003000) +#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK_AIP (0x00004000) +#define PL_LOGINFO_SUB_CODE_BREAK_ON_INCOMPLETE_BREAK_RCVD (0x00005000) + +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE (0x00200000) /* Can't get SMP Frame */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occured on SMP Read */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR (0x00200020) /* Error occured on SMP Write */ +#define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL (0x00200040) /* Encl Mgmt services not available for this WWID */ +#define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED (0x00200050) /* Address Mode not suppored */ +#define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM (0x00200060) /* Invalid Slot Number in SEP Msg */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SGPIO_NOT_PRESENT (0x00200070) /* SGPIO not present/enabled */ +#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_NOT_CONFIGURED (0x00200080) /* GPIO not configured */ +#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_FRAME_ERROR (0x00200090) /* GPIO can't allocate a frame */ +#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_CONFIG_PAGE_ERROR (0x002000A0) /* GPIO failed config page request */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SES_FRAME_ALLOC_ERROR (0x002000B0) /* Can't get frame for SES command */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SES_IO_ERROR (0x002000C0) /* I/O execution error */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SES_RETRIES_EXHAUSTED (0x002000D0) /* SEP I/O retries exhausted */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_ALLOC_ERROR (0x002000E0) /* Can't get frame for SMP command */ + +#define PL_LOGINFO_DA_SEP_NOT_PRESENT (0x00200100) /* SEP not present when msg received */ +#define PL_LOGINFO_DA_SEP_SINGLE_THREAD_ERROR (0x00200101) /* Can only accept 1 msg at a time */ +#define PL_LOGINFO_DA_SEP_ISTWI_INTR_IN_IDLE_STATE (0x00200102) /* ISTWI interrupt recvd. while IDLE */ +#define PL_LOGINFO_DA_SEP_RECEIVED_NACK_FROM_SLAVE (0x00200103) /* SEP NACK'd, it is busy */ +#define PL_LOGINFO_DA_SEP_DID_NOT_RECEIVE_ACK (0x00200104) /* SEP didn't rcv. ACK (Last Rcvd Bit = 1) */ +#define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM (0x00200105) /* SEP stopped or sent bad chksum in Hdr */ +#define PL_LOGINFO_DA_SEP_STOP_ON_DATA (0x00200106) /* SEP stopped while transfering data */ +#define PL_LOGINFO_DA_SEP_STOP_ON_SENSE_DATA (0x00200107) /* SEP stopped while transfering sense data */ +#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1 (0x00200108) /* SEP returned unknown scsi status */ +#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2 (0x00200109) /* SEP returned unknown scsi status */ +#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP (0x0020010A) /* SEP returned bad chksum after STOP */ +#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP_GETDATA (0x0020010B) /* SEP returned bad chksum after STOP while gettin data*/ +#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND (0x0020010C) /* SEP doesn't support CDB opcode f/w location 1 */ +#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND_2 (0x0020010D) /* SEP doesn't support CDB opcode f/w location 2 */ +#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND_3 (0x0020010E) /* SEP doesn't support CDB opcode f/w location 3 */ /****************************************************************************/ @@ -201,6 +249,8 @@ #define IR_LOGINFO_VOLUME_ACTIVATE_VOLUME_FAILED (0x00010014) /* Activation failed trying to import the volume */ #define IR_LOGINFO_VOLUME_ACTIVATING_IMPORT_VOLUME_FAILED (0x00010015) +/* Activation failed trying to import the volume */ +#define IR_LOGINFO_VOLUME_ACTIVATING_TOO_MANY_PHYS_DISKS (0x00010016) /* Phys Disk failed, too many phys disks */ #define IR_LOGINFO_PHYSDISK_CREATE_TOO_MANY_DISKS (0x00010020) @@ -243,6 +293,23 @@ /* Compatibility Error : IME size limited to < 2TB */ #define IR_LOGINFO_COMPAT_ERROR_IME_VOL_NOT_CURRENTLY_SUPPORTED (0x0001003D) +/* Device Firmware Update: DFU can only be started once */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DFU_IN_PROGRESS (0x00010050) +/* Device Firmware Update: Volume must be Optimal/Active/non-Quiesced */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DEVICE_IN_INVALID_STATE (0x00010051) +/* Device Firmware Update: DFU Timeout cannot be zero */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_INVALID_TIMEOUT (0x00010052) +/* Device Firmware Update: CREATE TIMER FAILED */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_NO_TIMERS (0x00010053) +/* Device Firmware Update: Failed to read SAS_IO_UNIT_PG_1 */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_READING_CFG_PAGE (0x00010054) +/* Device Firmware Update: Invalid SAS_IO_UNIT_PG_1 value(s) */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_PORT_IO_TIMEOUTS_REQUIRED (0x00010055) +/* Device Firmware Update: Unable to allocate memory for page */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_ALLOC_CFG_PAGE (0x00010056) +/* Device Firmware Update: */ +//#define IR_LOGINFO_DEV_FW_UPDATE_ERR_ (0x00010054) + /****************************************************************************/ /* Defines for convenience */ Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_raid.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_raid.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_raid.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2001-2005 LSI Logic Corporation. + * Copyright (c) 2001-2008 LSI Corporation. * * * Name: mpi_raid.h * Title: MPI RAID message and structures * Creation Date: February 27, 2001 * - * mpi_raid.h Version: 01.05.02 + * mpi_raid.h Version: 01.05.05 * * Version History * --------------- @@ -32,6 +32,11 @@ * 08-19-04 01.05.01 Original release for MPI v1.5. * 01-15-05 01.05.02 Added defines for the two new RAID Actions for * _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE. + * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and + * associated defines. + * 08-07-07 01.05.04 Added Disable Full Rebuild bit to the ActionDataWord + * for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME. + * 01-15-08 01.05.05 Added define for MPI_RAID_ACTION_SET_VOLUME_NAME. * -------------------------------------------------------------------------- */ @@ -90,6 +95,8 @@ typedef struct _MSG_RAID_ACTION #define MPI_RAID_ACTION_INACTIVATE_VOLUME (0x12) #define MPI_RAID_ACTION_SET_RESYNC_RATE (0x13) #define MPI_RAID_ACTION_SET_DATA_SCRUB_RATE (0x14) +#define MPI_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15) +#define MPI_RAID_ACTION_SET_VOLUME_NAME (0x16) /* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */ #define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC (0x00000001) @@ -102,6 +109,9 @@ typedef struct _MSG_RAID_ACTION #define MPI_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) #define MPI_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000002) +/* ActionDataWord defines for use with MPI_RAID_ACTION_DISABLE_VOLUME action */ +#define MPI_RAID_ACTION_ADATA_DISABLE_FULL_REBUILD (0x00000001) + /* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */ #define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL (0x00000001) @@ -111,6 +121,10 @@ typedef struct _MSG_RAID_ACTION /* ActionDataWord defines for use with MPI_RAID_ACTION_SET_DATA_SCRUB_RATE action */ #define MPI_RAID_ACTION_ADATA_DATA_SCRUB_RATE_MASK (0x000000FF) +/* ActionDataWord defines for use with MPI_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */ +#define MPI_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x00000001) +#define MPI_RAID_ACTION_ADATA_MASK_FW_UPDATE_TIMEOUT (0x0000FF00) +#define MPI_RAID_ACTION_ADATA_SHIFT_FW_UPDATE_TIMEOUT (8) /* RAID Action reply message */ Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_sas.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_sas.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_sas.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2004 LSI Logic Corporation. + * Copyright (c) 2004-2008 LSI Corporation. * * * Name: mpi_sas.h * Title: MPI Serial Attached SCSI structures and definitions * Creation Date: August 19, 2004 * - * mpi_sas.h Version: 01.05.03 + * mpi_sas.h Version: 01.05.05 * * Version History * --------------- @@ -21,6 +21,12 @@ * and Remove Device operations to SAS IO Unit Control. * Added DevHandle field to SAS IO Unit Control request and * reply. + * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO + * Unit Control request. + * 01-15-08 01.05.05 Added support for MPI_SAS_OP_SET_IOC_PARAMETER, + * including adding IOCParameter and IOCParameter value + * fields to SAS IO Unit Control Request. + * Added MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC define. * -------------------------------------------------------------------------- */ @@ -58,6 +64,8 @@ * Values for the SAS DeviceInfo field used in SAS Device Status Change Event * data and SAS IO Unit Configuration pages. */ +#define MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC (0xF0000000) + #define MPI_SAS_DEVICE_INFO_SEP (0x00004000) #define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) #define MPI_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) @@ -214,7 +222,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R U8 ChainOffset; /* 02h */ U8 Function; /* 03h */ U16 DevHandle; /* 04h */ - U8 Reserved3; /* 06h */ + U8 IOCParameter; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U8 TargetID; /* 0Ch */ @@ -223,7 +231,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R U8 PrimFlags; /* 0Fh */ U32 Primitive; /* 10h */ U64 SASAddress; /* 14h */ - U32 Reserved4; /* 1Ch */ + U32 IOCParameterValue; /* 1Ch */ } MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST, SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t; @@ -237,7 +245,10 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R #define MPI_SAS_OP_SEND_PRIMITIVE (0x0A) #define MPI_SAS_OP_FORCE_FULL_DISCOVERY (0x0B) #define MPI_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) -#define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D) +#define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D) /* obsolete name */ +#define MPI_SAS_OP_REMOVE_DEVICE (0x0D) +#define MPI_SAS_OP_SET_IOC_PARAMETER (0x0E) +#define MPI_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80) /* values for the PrimFlags field */ #define MPI_SAS_PRIMFLAGS_SINGLE (0x08) @@ -253,7 +264,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R U8 MsgLength; /* 02h */ U8 Function; /* 03h */ U16 DevHandle; /* 04h */ - U8 Reserved3; /* 06h */ + U8 IOCParameter; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U16 Reserved4; /* 0Ch */ Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_targ.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_targ.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_targ.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 LSI Logic Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_targ.h Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_tool.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_tool.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_tool.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2005 LSI Logic Corporation. + * Copyright (c) 2001-2008 LSI Corporation. * * * Name: mpi_tool.h Index: linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_type.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/lsi/mpi_type.h +++ linux-2.6.18.i386/drivers/message/fusion/lsi/mpi_type.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2004 LSI Logic Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_type.h * Title: MPI Basic type definitions * Creation Date: June 6, 2000 * - * mpi_type.h Version: 01.05.01 + * mpi_type.h Version: 01.05.02 * * Version History * --------------- @@ -20,6 +20,7 @@ * 08-08-01 01.02.01 Original release for v1.2 work. * 05-11-04 01.03.01 Original release for MPI v1.3. * 08-19-04 01.05.01 Original release for MPI v1.5. + * 08-30-05 01.05.02 Added PowerPC option to #ifdef's. * -------------------------------------------------------------------------- */ @@ -49,8 +50,18 @@ typedef signed short S16; typedef unsigned short U16; -typedef int32_t S32; -typedef u_int32_t U32; +#if defined(unix) || defined(__arm) || defined(ALPHA) || defined(__PPC__) || defined(__ppc) + + typedef signed int S32; + typedef unsigned int U32; + +#else + + typedef signed long S32; + typedef unsigned long U32; + +#endif + typedef struct _S64 { Index: linux-2.6.18.i386/drivers/message/fusion/mptbase.c =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/mptbase.c +++ linux-2.6.18.i386/drivers/message/fusion/mptbase.c @@ -2,11 +2,11 @@ * linux/drivers/message/fusion/mptbase.c * This is the Fusion MPT base driver which supports multiple * (SCSI + LAN) specialized protocol drivers. - * For use with LSI Logic PCI chip/adapter(s) - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI PCI chip/adapter(s) + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsi.com) + * Copyright (c) 1999-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -45,7 +45,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - +#include #include #include #include @@ -58,12 +58,15 @@ #include #include /* needed for in_interrupt() proto */ #include +#include #include #ifdef CONFIG_MTRR #include #endif #include "mptbase.h" +#include "linux_compat.h" /* linux-2.6 tweaks */ +#include "lsi/mpi_log_fc.h" /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #define my_NAME "Fusion MPT base driver" @@ -78,14 +81,45 @@ MODULE_VERSION(my_VERSION); /* * cmd line parameters */ -static int mpt_msi_enable; -module_param(mpt_msi_enable, int, 0); -MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)"); + +static int mpt_msi_enable_spi; +module_param(mpt_msi_enable_spi, int, 0); +MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI controllers (default=0)"); + +static int mpt_msi_enable_fc; +module_param(mpt_msi_enable_fc, int, 0); +MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC controllers (default=0)"); + +#if defined(SUSE_KERNEL_BASE) +static int mpt_msi_enable_sas = 0; +module_param(mpt_msi_enable_sas, int, 0); +MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS controllers (default=0)"); +#else +static int mpt_msi_enable_sas = 1; +module_param(mpt_msi_enable_sas, int, 0); +MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS controllers (default=1)"); +#endif + 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)"); +int mpt_debug_level; +static int mpt_set_debug_level(const char *val, struct kernel_param *kp); +module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int, + &mpt_debug_level, 0600); +MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)"); +EXPORT_SYMBOL(mpt_debug_level); + +int mpt_fwfault_debug; +module_param_call(mpt_fwfault_debug, param_set_int, param_get_int, + &mpt_fwfault_debug, 0600); +MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault" + " and halt Firmware on fault - (default=0)"); +EXPORT_SYMBOL(mpt_fwfault_debug); + + #ifdef MFCNT static int mfcounter = 0; #define PRINT_MF_COUNT 20000 @@ -95,9 +129,6 @@ static int mfcounter = 0; /* * Public data... */ -int mpt_lan_index = -1; -int mpt_stm_index = -1; - struct proc_dir_entry *mpt_proc_root_dir; #define WHOINIT_UNKNOWN 0xAA @@ -118,17 +149,21 @@ static MPT_EVHANDLER MptEvHandlers[MPT static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; -static int mpt_base_index = -1; -static int last_drv_idx = -1; - static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* + * Driver Callback Index's + */ +static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS; +static u8 last_drv_idx; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Forward protos... */ -static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r); -static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); +static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait, int sleepFlag); @@ -159,8 +194,8 @@ static int mpt_GetScsiPortSettings(MPT_A static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); -static void mpt_timer_expired(unsigned long data); -static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch); +static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc); +static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag); static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag); static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init); @@ -175,17 +210,15 @@ static int procmpt_iocinfo_read(char *bu #endif static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc); -//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers); -#ifdef MPT_DEBUG_REPLY static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); -#endif static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info); static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info); static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc); + /* module entry point */ static int __init fusion_init (void); static void __exit fusion_exit (void); @@ -216,6 +249,155 @@ 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); + MPT_ADAPTER *ioc; + + if (ret) + return ret; + + list_for_each_entry(ioc, &ioc_list, list) + ioc->debug_level = mpt_debug_level; + return 0; +} + +/** + * mpt_get_cb_idx - obtain cb_idx for registered driver + * @dclass: class driver enum + * + * Returns cb_idx, or zero means it wasn't found + **/ +static u8 +mpt_get_cb_idx(MPT_DRIVER_CLASS dclass) +{ + u8 cb_idx; + + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) + if (MptDriverClass[cb_idx] == dclass) + return cb_idx; + return 0; +} + +/** + * mpt_is_discovery_complete - determine if discovery has completed + * @ioc: per adatper instance + * + * Returns 1 when discovery completed, else zero. + */ +static int +mpt_is_discovery_complete(MPT_ADAPTER *ioc) +{ + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasIOUnitPage0_t *buffer; + dma_addr_t dma_handle; + int rc = 0; + + memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); + memset(&cfg, 0, sizeof(CONFIGPARMS)); + hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + cfg.cfghdr.ehdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if ((mpt_config(ioc, &cfg))) + goto out; + if (!hdr.ExtPageLength) + goto out; + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + &dma_handle); + if (!buffer) + goto out; + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((mpt_config(ioc, &cfg))) + goto out_free_consistent; + + if (!(buffer->PhyData[0].PortFlags & + MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS)) + rc = 1; + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + buffer, dma_handle); + out: + return rc; +} + +/** + * mpt_fault_reset_work - work performed on workq after ioc fault + * @work: input argument, used to derive ioc + * +**/ +static void +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) +mpt_fault_reset_work(struct work_struct *work) +{ + MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fault_reset_work.work); +#else +mpt_fault_reset_work(void *arg) +{ + MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; +#endif + u32 ioc_raw_state; + int rc; + unsigned long flags; + + if (ioc->ioc_reset_in_progress || !ioc->active) + goto out; + + ioc_raw_state = mpt_GetIocState(ioc, 0); + if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { + printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", + ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); + printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", + ioc->name, __FUNCTION__); + rc = mpt_HardResetHandler(ioc, CAN_SLEEP); + printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name, + __FUNCTION__, (rc == 0) ? "success" : "failed"); + ioc_raw_state = mpt_GetIocState(ioc, 0); + if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) + printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " + "reset (%04xh)\n", ioc->name, ioc_raw_state & + MPI_DOORBELL_DATA_MASK); + } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) { + if ((mpt_is_discovery_complete(ioc))) { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing " + "discovery_quiesce_io flag\n", ioc->name)); + ioc->sas_discovery_quiesce_io = 0; + } + } + + out: + /* + * Take turns polling alternate controller + */ + if (ioc->alt_ioc) + ioc = ioc->alt_ioc; + + /* rearm the timer */ + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->reset_work_q) + queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, + msecs_to_jiffies(MPT_POLLING_INTERVAL)); + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +} + /* * Process turbo (context) reply... */ @@ -224,10 +406,10 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa { MPT_FRAME_HDR *mf = NULL; MPT_FRAME_HDR *mr = NULL; - int req_idx = 0; - int cb_idx; + u16 req_idx = 0; + u8 cb_idx; - dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n", + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n", ioc->name, pa)); switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) { @@ -237,7 +419,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa mf = MPT_INDEX_2_MFPTR(ioc, req_idx); break; case MPI_CONTEXT_REPLY_TYPE_LAN: - cb_idx = mpt_lan_index; + cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER); /* * Blind set of mf to NULL here was fatal * after lan_reply says "freeme" @@ -258,7 +440,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); break; case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET: - cb_idx = mpt_stm_index; + cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER); mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); break; default: @@ -267,8 +449,8 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa } /* Check for (valid) IO callback! */ - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || - MptCallbacks[cb_idx] == NULL) { + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || + MptCallbacks[cb_idx] == NULL) { printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", __FUNCTION__, ioc->name, cb_idx); goto out; @@ -285,8 +467,8 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) { MPT_FRAME_HDR *mf; MPT_FRAME_HDR *mr; - int req_idx; - int cb_idx; + u16 req_idx; + u8 cb_idx; int freeme; u32 reply_dma_low; @@ -310,9 +492,10 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; mf = MPT_INDEX_2_MFPTR(ioc, req_idx); - dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n", + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n", ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function)); - DBG_DUMP_REPLY_FRAME(mr) + + DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr); /* Check/log IOC log info */ @@ -327,14 +510,15 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) mpt_sas_log_info(ioc, log_info); } -#ifdef MPT_DEBUG_REPLY + /* 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); -#endif /* Check for (valid) IO callback! */ - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || - MptCallbacks[cb_idx] == NULL) { + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || + MptCallbacks[cb_idx] == NULL) { printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", __FUNCTION__, ioc->name, cb_idx); freeme = 0; @@ -352,7 +536,6 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) mb(); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. * @irq: irq number (not used) @@ -369,9 +552,13 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) * This routine handles register-level access of the adapter but * dispatches (calls) a protocol-specific callback routine to handle * the protocol-specific details of the MPT request completion. - */ + **/ static irqreturn_t +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) +mpt_interrupt(int irq, void *bus_id) +#else mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) +#endif { MPT_ADAPTER *ioc = bus_id; u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); @@ -395,9 +582,9 @@ mpt_interrupt(int irq, void *bus_id, str /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_base_reply - MPT base driver's callback routine + * mptbase_reply - MPT base driver's callback routine * @ioc: Pointer to MPT_ADAPTER structure - * @mf: Pointer to original MPT request frame + * @req: Pointer to original MPT request frame * @reply: Pointer to MPT reply frame (NULL if TurboReply) * * MPT base driver's callback routine; all base driver @@ -408,121 +595,49 @@ mpt_interrupt(int irq, void *bus_id, str * should be freed, or 0 if it shouldn't. */ static int -mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) +mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { + EventNotificationReply_t *pEventReply; + u8 event; + int evHandlers; int freereq = 1; - u8 func; - - dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name)); - -#if defined(MPT_DEBUG_MSG_FRAME) - if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) { - dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf)); - DBG_DUMP_REQUEST_FRAME_HDR(mf) - } -#endif - - func = reply->u.hdr.Function; - dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n", - ioc->name, func)); - - if (func == MPI_FUNCTION_EVENT_NOTIFICATION) { - EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply; - int evHandlers = 0; - int results; - - results = ProcessEventNotification(ioc, pEvReply, &evHandlers); - if (results != evHandlers) { - /* CHECKME! Any special handling needed here? */ - devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n", - ioc->name, evHandlers, results)); - } - /* - * Hmmm... It seems that EventNotificationReply is an exception - * to the rule of one reply per request. - */ - if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) { + switch (reply->u.hdr.Function) { + case MPI_FUNCTION_EVENT_NOTIFICATION: + pEventReply = (EventNotificationReply_t *)reply; + evHandlers = 0; + ProcessEventNotification(ioc, pEventReply, &evHandlers); + event = le32_to_cpu(pEventReply->Event) & 0xFF; + if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) freereq = 0; - } else { - devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n", - ioc->name, pEvReply)); - } - -#ifdef CONFIG_PROC_FS -// LogEvent(ioc, pEvReply); -#endif - - } else if (func == MPI_FUNCTION_EVENT_ACK) { - dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n", - ioc->name)); - } else if (func == MPI_FUNCTION_CONFIG) { - CONFIGPARMS *pCfg; - unsigned long flags; - - dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n", - ioc->name, mf, reply)); - - pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *))); - - if (pCfg) { - /* disable timer and remove from linked list */ - del_timer(&pCfg->timer); - - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_del(&pCfg->linkage); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - /* - * If IOC Status is SUCCESS, save the header - * and set the status code to GOOD. - */ - pCfg->status = MPT_CONFIG_ERROR; - if (reply) { - ConfigReply_t *pReply = (ConfigReply_t *)reply; - u16 status; - - status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; - dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n", - status, le32_to_cpu(pReply->IOCLogInfo))); - - pCfg->status = status; - if (status == MPI_IOCSTATUS_SUCCESS) { - if ((pReply->Header.PageType & - MPI_CONFIG_PAGETYPE_MASK) == - MPI_CONFIG_PAGETYPE_EXTENDED) { - pCfg->cfghdr.ehdr->ExtPageLength = - le16_to_cpu(pReply->ExtPageLength); - pCfg->cfghdr.ehdr->ExtPageType = - pReply->ExtPageType; - } - pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; - - /* If this is a regular header, save PageLength. */ - /* LMP Do this better so not using a reserved field! */ - pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; - pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; - pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; - } - } - - /* - * Wake up the original calling thread - */ - pCfg->wait_done = 1; - wake_up(&mpt_waitq); - } - } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) { - /* we should be always getting a reply frame */ - memcpy(ioc->persist_reply_frame, reply, - min(MPT_DEFAULT_FRAME_SIZE, - 4*reply->u.reply.MsgLength)); - del_timer(&ioc->persist_timer); - ioc->persist_wait_done = 1; - wake_up(&mpt_waitq); - } else { - printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n", - ioc->name, func); + if (event != MPI_EVENT_EVENT_CHANGE) + break; + case MPI_FUNCTION_CONFIG: + case MPI_FUNCTION_SAS_IO_UNIT_CONTROL: + ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + if (reply) { + ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->mptbase_cmds.reply, reply, + min(MPT_DEFAULT_FRAME_SIZE, + 4 * reply->u.reply.MsgLength)); + } + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->mptbase_cmds.done); + } else + freereq = 0; + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF) + freereq = 1; + break; + case MPI_FUNCTION_EVENT_ACK: + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "EventAck reply received\n", ioc->name)); + break; + default: + printk(MYIOC_s_ERR_FMT + "Unexpected msg function (=%02Xh) reply received!\n", + ioc->name, reply->u.hdr.Function); + break; } /* @@ -532,7 +647,6 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRA return freereq; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_register - Register protocol-specific main callback handler. * @cbfunc: callback function pointer @@ -547,28 +661,27 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRA * in order to register separate callbacks; one for "normal" SCSI IO; * one for MptScsiTaskMgmt requests; one for Scan/DV requests. * - * Returns a positive integer valued "handle" in the - * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful. - * Any non-positive return value (including zero!) should be considered - * an error by the caller. - */ -int + * Returns u8 valued "handle" in the range (and S.O.D. order) + * {N,...,7,6,5,...,1} if successful. + * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be + * considered an error by the caller. + **/ +u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) { - int i; - - last_drv_idx = -1; + u8 cb_idx; + last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS; /* * Search for empty callback slot in this order: {N,...,7,6,5,...,1} * (slot/handle 0 is reserved!) */ - for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) { - if (MptCallbacks[i] == NULL) { - MptCallbacks[i] = cbfunc; - MptDriverClass[i] = dclass; - MptEvHandlers[i] = NULL; - last_drv_idx = i; + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptCallbacks[cb_idx] == NULL) { + MptCallbacks[cb_idx] = cbfunc; + MptDriverClass[cb_idx] = dclass; + MptEvHandlers[cb_idx] = NULL; + last_drv_idx = cb_idx; break; } } @@ -576,18 +689,17 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DR return last_drv_idx; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_deregister - Deregister a protocol drivers resources. * @cb_idx: previously registered callback handle * * Each protocol-specific driver should call this routine when its * module is unloaded. - */ + **/ void -mpt_deregister(int cb_idx) +mpt_deregister(u8 cb_idx) { - if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) { + if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) { MptCallbacks[cb_idx] = NULL; MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; MptEvHandlers[cb_idx] = NULL; @@ -596,7 +708,6 @@ mpt_deregister(int cb_idx) } } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_event_register - Register protocol-specific event callback * handler. @@ -607,18 +718,17 @@ mpt_deregister(int cb_idx) * if/when they choose to be notified of MPT events. * * Returns 0 for success. - */ + **/ int -mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc) +mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc) { - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return -1; MptEvHandlers[cb_idx] = ev_cbfunc; return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_event_deregister - Deregister protocol-specific event callback * handler. @@ -627,17 +737,16 @@ mpt_event_register(int cb_idx, MPT_EVHAN * Each protocol-specific driver should call this routine * when it does not (or can no longer) handle events, * or when its module is unloaded. - */ + **/ void -mpt_event_deregister(int cb_idx) +mpt_event_deregister(u8 cb_idx) { - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return; MptEvHandlers[cb_idx] = NULL; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_reset_register - Register protocol-specific IOC reset handler. * @cb_idx: previously registered (via mpt_register) callback handle @@ -647,18 +756,17 @@ mpt_event_deregister(int cb_idx) * if/when they choose to be notified of IOC resets. * * Returns 0 for success. - */ + **/ int -mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func) +mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func) { - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return -1; MptResetHandlers[cb_idx] = reset_func; return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_reset_deregister - Deregister protocol-specific IOC reset handler. * @cb_idx: previously registered callback handle @@ -666,56 +774,56 @@ mpt_reset_register(int cb_idx, MPT_RESET * Each protocol-specific driver should call this routine * when it does not (or can no longer) handle IOC reset handling, * or when its module is unloaded. - */ + **/ void -mpt_reset_deregister(int cb_idx) +mpt_reset_deregister(u8 cb_idx) { - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return; MptResetHandlers[cb_idx] = NULL; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_device_driver_register - Register device driver hooks * @dd_cbfunc: driver callbacks struct * @cb_idx: MPT protocol driver index - */ + **/ int -mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx) +mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx) { MPT_ADAPTER *ioc; const struct pci_device_id *id; - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return -EINVAL; MptDeviceDriverHandlers[cb_idx] = dd_cbfunc; /* call per pci device probe entry point */ list_for_each_entry(ioc, &ioc_list, list) { + if (!pci_get_drvdata(ioc->pcidev)) + continue; id = ioc->pcidev->driver ? ioc->pcidev->driver->id_table : NULL; if (dd_cbfunc->probe) dd_cbfunc->probe(ioc->pcidev, id); - } + } return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_device_driver_deregister - DeRegister device driver hooks * @cb_idx: MPT protocol driver index - */ + **/ void -mpt_device_driver_deregister(int cb_idx) +mpt_device_driver_deregister(u8 cb_idx) { struct mpt_pci_driver *dd_cbfunc; MPT_ADAPTER *ioc; - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return; dd_cbfunc = MptDeviceDriverHandlers[cb_idx]; @@ -728,19 +836,17 @@ mpt_device_driver_deregister(int cb_idx) MptDeviceDriverHandlers[cb_idx] = NULL; } - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024) * allocated per MPT adapter. - * @handle: Handle of registered MPT protocol driver + * @cb_idx: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * * Returns pointer to a MPT request frame or %NULL if none are available * or IOC is not active. - */ + **/ MPT_FRAME_HDR* -mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc) +mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc) { MPT_FRAME_HDR *mf; unsigned long flags; @@ -750,7 +856,8 @@ mpt_get_msg_frame(int handle, MPT_ADAPTE #ifdef MFCNT if (!ioc->active) - printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n"); + printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame " + "returning NULL!\n", ioc->name); #endif /* If interrupts are not attached, do not return a request frame */ @@ -765,13 +872,13 @@ mpt_get_msg_frame(int handle, MPT_ADAPTE u.frame.linkage.list); list_del(&mf->u.frame.linkage.list); mf->u.frame.linkage.arg1 = 0; - mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ req_offset = (u8 *)mf - (u8 *)ioc->req_frames; - /* u16! */ req_idx = req_offset / ioc->req_sz; mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; - ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */ + /* Default, will be changed if necessary in SG generation */ + ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; #ifdef MFCNT ioc->mfcnt++; #endif @@ -782,68 +889,86 @@ mpt_get_msg_frame(int handle, MPT_ADAPTE #ifdef MFCNT if (mf == NULL) - printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth); + printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! " + "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt, + ioc->req_depth); mfcounter++; if (mfcounter == PRINT_MF_COUNT) - printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth); + printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name, + ioc->mfcnt, ioc->req_depth); #endif - dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n", - ioc->name, handle, ioc->id, mf)); + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n", + ioc->name, cb_idx, ioc->id, mf)); return mf; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_put_msg_frame - Send a protocol specific MPT request frame * to a IOC. - * @handle: Handle of registered MPT protocol driver + * @cb_idx: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * @mf: Pointer to MPT request frame * * This routine posts a MPT request frame to the request post FIFO of a * specific MPT adapter. - */ + **/ void -mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) +mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { u32 mf_dma_addr; int req_offset; u16 req_idx; /* Request index */ /* ensure values are reset properly! */ - mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ req_offset = (u8 *)mf - (u8 *)ioc->req_frames; - /* u16! */ req_idx = req_offset / ioc->req_sz; mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; -#ifdef MPT_DEBUG_MSG_FRAME - { - u32 *m = mf->u.frame.hwhdr.__hdr; - int ii, n; - - printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ", - ioc->name, m); - n = ioc->req_sz/4 - 1; - while (m[n] == 0) - n--; - for (ii=0; ii<=n; ii++) { - if (ii && ((ii%8)==0)) - printk("\n" KERN_INFO " "); - printk(" %08x", le32_to_cpu(m[ii])); - } - printk("\n"); - } -#endif + DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf); - mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx]; - dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, 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])); CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame + * to a IOC using hi priority request queue. + * @cb_idx: Handle of registered MPT protocol driver + * @ioc: Pointer to MPT adapter structure + * @mf: Pointer to MPT request frame + * + * This routine posts a MPT request frame to the request post FIFO of a + * specific MPT adapter. + **/ +void +mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) +{ + u32 mf_dma_addr; + int req_offset; + u16 req_idx; /* Request index */ + + /* ensure values are reset properly! */ + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; + req_offset = (u8 *)mf - (u8 *)ioc->req_frames; + req_idx = req_offset / ioc->req_sz; + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); + mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; + + DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf); + + mf_dma_addr = (ioc->req_frames_low_dma + req_offset); + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n", + ioc->name, mf_dma_addr, req_idx)); + CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr); +} + /** * mpt_free_msg_frame - Place MPT request frame back on FreeQ. * @handle: Handle of registered MPT protocol driver @@ -852,7 +977,7 @@ mpt_put_msg_frame(int handle, MPT_ADAPTE * * This routine places a MPT request frame back on the MPT adapter's * FreeQ. - */ + **/ void mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { @@ -860,47 +985,148 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT /* Put Request back on FreeQ! */ spin_lock_irqsave(&ioc->FreeQlock, flags); - mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */ + if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf) + goto out; + mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf); /* signature to know if this mf is freed */ list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); #ifdef MFCNT ioc->mfcnt--; #endif + out: spin_unlock_irqrestore(&ioc->FreeQlock, flags); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_add_sge - Place a simple SGE at address pAddr. + * mpt_add_sge - Place a simple 32 bit SGE at address pAddr. * @pAddr: virtual address for SGE * @flagslength: SGE flags and data transfer length * @dma_addr: Physical address * * This routine places a MPT request frame back on the MPT adapter's * FreeQ. - */ -void + **/ +static void mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) { - if (sizeof(dma_addr_t) == sizeof(u64)) { - SGESimple64_t *pSge = (SGESimple64_t *) pAddr; - u32 tmp = dma_addr & 0xFFFFFFFF; + SGESimple32_t *pSge = (SGESimple32_t *) pAddr; + pSge->FlagsLength = cpu_to_le32(flagslength); + pSge->Address = cpu_to_le32(dma_addr); +} - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address.Low = cpu_to_le32(tmp); - tmp = (u32) ((u64)dma_addr >> 32); - pSge->Address.High = cpu_to_le32(tmp); - } else { - SGESimple32_t *pSge = (SGESimple32_t *) pAddr; - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address = cpu_to_le32(dma_addr); +/** + * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr. + * @pAddr: virtual address for SGE + * @flagslength: SGE flags and data transfer length + * @dma_addr: Physical address + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. + **/ +static void +mpt_add_sge_64bit(char *pAddr, u32 flagslength, dma_addr_t dma_addr) +{ + SGESimple64_t *pSge = (SGESimple64_t *) pAddr; + u32 tmp; + + tmp = dma_addr & 0xFFFFFFFF; + pSge->Address.Low = cpu_to_le32(tmp); + tmp = (u32) ((u64)dma_addr >> 32); + pSge->Address.High = cpu_to_le32(tmp); + pSge->FlagsLength = cpu_to_le32( + (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); +} + + +/** + * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr + * (1078 workaround). + * @pAddr: virtual address for SGE + * @flagslength: SGE flags and data transfer length + * @dma_addr: Physical address + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. + **/ +static void +mpt_add_sge_64bit_1078(char *pAddr, u32 flagslength, dma_addr_t dma_addr) +{ + SGESimple64_t *pSge = (SGESimple64_t *) pAddr; + u32 tmp; + + tmp = dma_addr & 0xFFFFFFFF; + pSge->Address.Low = cpu_to_le32(tmp); + tmp = (u32) ((u64)dma_addr >> 32); + + /* + * 1078 errata workaround for the 36GB limitation + */ + if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) { + flagslength |= + MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS); + tmp |= (1<<31); + if (mpt_debug_level & MPT_DEBUG_36GB_MEM) + printk(KERN_DEBUG "1078 P0M2 addressing for " + "addr = 0x%llx len = %d\n", + (unsigned long long)dma_addr, + MPI_SGE_LENGTH(flagslength)); } + + pSge->Address.High = cpu_to_le32(tmp); + pSge->FlagsLength = cpu_to_le32( + (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_add_chain - Place a 32 bit chain SGE at address pAddr. + * @pAddr: virtual address for SGE + * @next: nextChainOffset value (u32's) + * @length: length of next SGL segment + * @dma_addr: Physical address + * + */ +static void +mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) +{ + SGEChain32_t *pChain = (SGEChain32_t *) pAddr; + pChain->Length = cpu_to_le16(length); + pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; + pChain->NextChainOffset = next; + pChain->Address = cpu_to_le32(dma_addr); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr. + * @pAddr: virtual address for SGE + * @next: nextChainOffset value (u32's) + * @length: length of next SGL segment + * @dma_addr: Physical address + * + */ +static void +mpt_add_chain_64bit(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) +{ + SGEChain64_t *pChain = (SGEChain64_t *) pAddr; + u32 tmp = dma_addr & 0xFFFFFFFF; + + pChain->Length = cpu_to_le16(length); + pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT | + MPI_SGE_FLAGS_64_BIT_ADDRESSING); + + pChain->NextChainOffset = next; + + pChain->Address.Low = cpu_to_le32(tmp); + tmp = (u32) ((u64)dma_addr >> 32); + pChain->Address.High = cpu_to_le32(tmp); } + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_send_handshake_request - Send MPT request via doorbell handshake method. - * @handle: Handle of registered MPT protocol driver + * @cb_idx: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * @reqBytes: Size of the request in bytes * @req: Pointer to MPT request frame @@ -913,11 +1139,11 @@ mpt_add_sge(char *pAddr, u32 flagslength * request which are greater than 1 byte in size. * * Returns 0 for success, non-zero for failure. - */ + **/ int -mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) +mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) { - int r = 0; + int r = 0; u8 *req_as_bytes; int ii; @@ -932,10 +1158,10 @@ mpt_send_handshake_request(int handle, M * 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 = handle; + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; } /* Make sure there are no doorbells */ @@ -954,7 +1180,7 @@ mpt_send_handshake_request(int handle, M if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) return -5; - dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n", + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n", ioc->name, ii)); CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); @@ -990,7 +1216,6 @@ mpt_send_handshake_request(int handle, M return r; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_host_page_access_control - control the IOC's Host Page Buffer access * @ioc: Pointer to MPT adapter structure @@ -1007,8 +1232,7 @@ mpt_send_handshake_request(int handle, M * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER } * * Returns 0 for success, non-zero for failure. - */ - + **/ static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag) { @@ -1033,7 +1257,6 @@ mpt_host_page_access_control(MPT_ADAPTER return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_host_page_alloc - allocate system memory for the fw * @ioc: Pointer to pointer to IOC adapter @@ -1041,7 +1264,7 @@ mpt_host_page_access_control(MPT_ADAPTER * * If we already allocated memory in past, then resend the same pointer. * Returns 0 for success, non-zero for failure. - */ + **/ static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init) { @@ -1065,7 +1288,7 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pI host_page_buffer_sz, &ioc->HostPageBuffer_dma)) != NULL) { - dinitprintk((MYIOC_s_INFO_FMT + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n", ioc->name, ioc->HostPageBuffer, (u32)ioc->HostPageBuffer_dma, @@ -1089,21 +1312,16 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pI psge = (char *)&ioc_init->HostPageBufferSGE; flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_SYSTEM_ADDRESS | - MPI_SGE_FLAGS_32_BIT_ADDRESSING | MPI_SGE_FLAGS_HOST_TO_IOC | MPI_SGE_FLAGS_END_OF_BUFFER; - if (sizeof(dma_addr_t) == sizeof(u64)) { - flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING; - } flags_length = flags_length << MPI_SGE_FLAGS_SHIFT; flags_length |= ioc->HostPageBuffer_sz; - mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma); + ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma); ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE; return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure. * @iocid: IOC unique identifier (integer) @@ -1114,7 +1332,7 @@ return 0; * * Returns iocid and sets iocpp if iocid is found. * Returns -1 if iocid is not found. - */ + **/ int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) { @@ -1131,7 +1349,365 @@ mpt_verify_adapter(int iocid, MPT_ADAPTE return -1; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_get_product_name - returns product string + * @vendor: pci vendor id + * @device: pci device id + * @revision: pci revision id + * @prod_name: string returned + * + * Returns product string displayed when driver loads, + * in /proc/mpt/summary and /sysfs/class/scsi_host/host/version_product + * + **/ +static void +mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name) +{ + char *product_str = NULL; + + if (vendor == PCI_VENDOR_ID_BROCADE) { + switch (device) + { + case MPI_MANUFACTPAGE_DEVICEID_FC949E: + switch (revision) + { + case 0x00: + product_str = "BRE040 A0"; + break; + case 0x01: + product_str = "BRE040 A1"; + break; + default: + product_str = "BRE040"; + break; + } + break; + } + goto out; + } + + switch (device) + { + case MPI_MANUFACTPAGE_DEVICEID_FC909: + product_str = "LSIFC909 B1"; + break; + case MPI_MANUFACTPAGE_DEVICEID_FC919: + product_str = "LSIFC919 B0"; + break; + case MPI_MANUFACTPAGE_DEVICEID_FC929: + product_str = "LSIFC929 B0"; + break; + case MPI_MANUFACTPAGE_DEVICEID_FC919X: + if (revision < 0x80) + product_str = "LSIFC919X A0"; + else + product_str = "LSIFC919XL A1"; + break; + case MPI_MANUFACTPAGE_DEVICEID_FC929X: + if (revision < 0x80) + product_str = "LSIFC929X A0"; + else + product_str = "LSIFC929XL A1"; + break; + case MPI_MANUFACTPAGE_DEVICEID_FC939X: + product_str = "LSIFC939X A1"; + break; + case MPI_MANUFACTPAGE_DEVICEID_FC949X: + product_str = "LSIFC949X A1"; + break; + case MPI_MANUFACTPAGE_DEVICEID_FC949E: + switch (revision) + { + case 0x00: + product_str = "LSIFC949E A0"; + break; + case 0x01: + product_str = "LSIFC949E A1"; + break; + default: + product_str = "LSIFC949E"; + break; + } + break; + case MPI_MANUFACTPAGE_DEVID_53C1030: + switch (revision) + { + case 0x00: + product_str = "LSI53C1030 A0"; + break; + case 0x01: + product_str = "LSI53C1030 B0"; + break; + case 0x03: + product_str = "LSI53C1030 B1"; + break; + case 0x07: + product_str = "LSI53C1030 B2"; + break; + case 0x08: + product_str = "LSI53C1030 C0"; + break; + case 0x80: + product_str = "LSI53C1030T A0"; + break; + case 0x83: + product_str = "LSI53C1030T A2"; + break; + case 0x87: + product_str = "LSI53C1030T A3"; + break; + case 0xc1: + product_str = "LSI53C1020A A1"; + break; + default: + product_str = "LSI53C1030"; + break; + } + break; + case MPI_MANUFACTPAGE_DEVID_1030_53C1035: + switch (revision) + { + case 0x03: + product_str = "LSI53C1035 A2"; + break; + case 0x04: + product_str = "LSI53C1035 B0"; + break; + default: + product_str = "LSI53C1035"; + break; + } + break; + case MPI_MANUFACTPAGE_DEVID_SAS1064: + switch (revision) + { + case 0x00: + product_str = "LSISAS1064 A1"; + break; + case 0x01: + product_str = "LSISAS1064 A2"; + break; + case 0x02: + product_str = "LSISAS1064 A3"; + break; + case 0x03: + product_str = "LSISAS1064 A4"; + break; + default: + product_str = "LSISAS1064"; + break; + } + break; + case MPI_MANUFACTPAGE_DEVID_SAS1064E: + switch (revision) + { + case 0x00: + product_str = "LSISAS1064E A0"; + break; + case 0x01: + product_str = "LSISAS1064E B0"; + break; + case 0x02: + product_str = "LSISAS1064E B1"; + break; + case 0x04: + product_str = "LSISAS1064E B2"; + break; + case 0x08: + product_str = "LSISAS1064E B3"; + break; + default: + product_str = "LSISAS1064E"; + break; + } + break; + case MPI_MANUFACTPAGE_DEVID_SAS1068: + switch (revision) + { + case 0x00: + product_str = "LSISAS1068 A0"; + break; + case 0x01: + product_str = "LSISAS1068 B0"; + break; + case 0x02: + product_str = "LSISAS1068 B1"; + break; + default: + product_str = "LSISAS1068"; + break; + } + break; + case MPI_MANUFACTPAGE_DEVID_SAS1068E: + switch (revision) + { + case 0x00: + product_str = "LSISAS1068E A0"; + break; + case 0x01: + product_str = "LSISAS1068E B0"; + break; + case 0x02: + product_str = "LSISAS1068E B1"; + break; + case 0x04: + product_str = "LSISAS1068E B2"; + break; + case 0x08: + product_str = "LSISAS1068E B3"; + break; + default: + product_str = "LSISAS1068E"; + break; + } + break; + case MPI_MANUFACTPAGE_DEVID_SAS1078: + switch (revision) + { + case 0x00: + product_str = "LSISAS1078 A0"; + break; + case 0x01: + product_str = "LSISAS1078 B0"; + break; + case 0x02: + product_str = "LSISAS1078 C0"; + break; + case 0x03: + product_str = "LSISAS1078 C1"; + break; + case 0x04: + product_str = "LSISAS1078 C2"; + break; + default: + product_str = "LSISAS1078"; + break; + } + break; + } + + out: + if (product_str) + sprintf(prod_name, "%s", product_str); +} + +/** + * mpt_mapresources - map in memory mapped io + * @ioc: Pointer to pointer to IOC adapter + * + **/ +static int +mpt_mapresources(MPT_ADAPTER *ioc) +{ + u8 __iomem *mem; + int ii; + unsigned long mem_phys; + unsigned long port; + u32 msize; + u32 psize; + int r = -ENODEV; + struct pci_dev *pdev; + + pdev = ioc->pcidev; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) + if (pci_enable_device(pdev)) { + printk(MYIOC_s_WARN_FMT "pci_enable_device: failed\n", + ioc->name); + return r; + } +#else + ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); + if (pci_enable_device_bars(pdev, ioc->bars)) { + printk(MYIOC_s_ERR_FMT "pci_enable_device_bars() with MEM " + "failed\n",ioc->name); + return r; + } + if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) { + printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with " + "MEM failed\n",ioc->name); + return r; + } +#endif + if (sizeof(dma_addr_t) > 4) { + const uint64_t required_mask = dma_get_required_mask(&pdev->dev); + if (required_mask > DMA_32BIT_MASK + && !pci_set_dma_mask(pdev, DMA_64BIT_MASK) + && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { + ioc->dma_mask = DMA_64BIT_MASK; + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", + ioc->name)); + } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK) + && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + ioc->dma_mask = DMA_32BIT_MASK; + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", + ioc->name)); + } else { + printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", + ioc->name, pci_name(pdev)); + return r; + } + + } else { + if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK) + && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + ioc->dma_mask = DMA_32BIT_MASK; + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", + ioc->name)); + } else { + printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", + ioc->name, pci_name(pdev)); + return r; + } + } + + mem_phys = msize = 0; + port = psize = 0; + for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) { + if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) { + if (psize) + continue; + /* Get I/O space! */ + port = pci_resource_start(pdev, ii); + psize = pci_resource_len(pdev,ii); + } else { + if (msize) + continue; + /* Get memmap */ + mem_phys = pci_resource_start(pdev, ii); + msize = pci_resource_len(pdev,ii); + } + } + ioc->mem_size = msize; + + mem = NULL; + /* Get logical ptr for PciMem0 space */ + /*mem = ioremap(mem_phys, msize);*/ + mem = ioremap(mem_phys, msize); + if (mem == NULL) { + printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter memory!\n", ioc->name); + return -EINVAL; + } + ioc->memmap = mem; + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", + ioc->name, mem, mem_phys)); + + ioc->mem_phys = mem_phys; + ioc->chip = (SYSIF_REGS __iomem *)mem; + + /* Save Port IO values in case we need to do downloadboot */ + { + u8 *pmem = (u8*)port; + ioc->pio_mem_phys = port; + ioc->pio_chip = (SYSIF_REGS __iomem *)pmem; + } + + return 0; +} + /** * mpt_attach - Install a PCI intelligent MPT adapter. * @pdev: Pointer to pci_dev structure @@ -1148,17 +1724,12 @@ mpt_verify_adapter(int iocid, MPT_ADAPTE * Returns 0 for success, non-zero for failure. * * TODO: Add support for polled controllers - */ + **/ int mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) { MPT_ADAPTER *ioc; - u8 __iomem *mem; - unsigned long mem_phys; - unsigned long port; - u32 msize; - u32 psize; - int ii; + u8 cb_idx; int r = -ENODEV; u8 revision; u8 pcixcmd; @@ -1167,39 +1738,60 @@ mpt_attach(struct pci_dev *pdev, const s struct proc_dir_entry *dent, *ent; #endif - if (pci_enable_device(pdev)) - return r; - - dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n")); - - if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { - dprintk((KERN_INFO MYNAM - ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n")); - } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { - printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); - return r; - } - - if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) - dprintk((KERN_INFO MYNAM - ": Using 64 bit consistent mask\n")); - else - dprintk((KERN_INFO MYNAM - ": Not using 64 bit consistent mask\n")); - ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC); if (ioc == NULL) { printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); return -ENOMEM; } + + ioc->id = mpt_ids++; + sprintf(ioc->name, "ioc%d", ioc->id); + dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n")); + + /* + * set initial debug level + * (refer to mptdebug.h) + */ + ioc->debug_level = mpt_debug_level; + if (mpt_debug_level) + printk("mpt_debug_level=%xh\n", mpt_debug_level); + + + ioc->pcidev = pdev; + if (mpt_mapresources(ioc)) { + kfree(ioc); + return r; + } + + /* + * Setting up proper handlers for scatter gather handling + */ + if (ioc->dma_mask == DMA_64BIT_MASK) { + if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) + ioc->add_sge = &mpt_add_sge_64bit_1078; + else + ioc->add_sge = &mpt_add_sge_64bit; + ioc->add_chain = &mpt_add_chain_64bit; + ioc->sg_addr_size = 8; + } else { + ioc->add_sge = &mpt_add_sge; + ioc->add_chain = &mpt_add_chain; + ioc->sg_addr_size = 4; + } + ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; + + ioc->alloc_total = sizeof(MPT_ADAPTER); ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ ioc->reply_sz = MPT_REPLY_FRAME_SIZE; - ioc->pcidev = pdev; - ioc->diagPending = 0; - spin_lock_init(&ioc->diagLock); - spin_lock_init(&ioc->initializing_hba_lock); + spin_lock_init(&ioc->taskmgmt_lock); + mutex_init(&ioc->internal_cmds.mutex); + init_completion(&ioc->internal_cmds.done); + mutex_init(&ioc->mptbase_cmds.mutex); + init_completion(&ioc->mptbase_cmds.done); + mutex_init(&ioc->taskmgmt_cmds.mutex); + init_completion(&ioc->taskmgmt_cmds.done); /* Initialize the event logging. */ @@ -1212,85 +1804,58 @@ mpt_attach(struct pci_dev *pdev, const s ioc->mfcnt = 0; #endif + ioc->sh = NULL; ioc->cached_fw = NULL; /* Initilize SCSI Config Data structure */ memset(&ioc->spi_data, 0, sizeof(SpiCfgData)); - /* Initialize the running configQ head. - */ - INIT_LIST_HEAD(&ioc->configQ); - /* Initialize the fc rport list head. */ INIT_LIST_HEAD(&ioc->fc_rports); /* Find lookup slot. */ INIT_LIST_HEAD(&ioc->list); - ioc->id = mpt_ids++; - - mem_phys = msize = 0; - port = psize = 0; - for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) { - if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) { - if (psize) - continue; - /* Get I/O space! */ - port = pci_resource_start(pdev, ii); - psize = pci_resource_len(pdev,ii); - } else { - if (msize) - continue; - /* Get memmap */ - mem_phys = pci_resource_start(pdev, ii); - msize = pci_resource_len(pdev,ii); - } - } - ioc->mem_size = msize; - - mem = NULL; - /* Get logical ptr for PciMem0 space */ - /*mem = ioremap(mem_phys, msize);*/ - mem = ioremap(mem_phys, msize); - if (mem == NULL) { - printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n"); - kfree(ioc); - return -EINVAL; - } - ioc->memmap = mem; - dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); - dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n", - &ioc->facts, &ioc->pfacts[0])); - - ioc->mem_phys = mem_phys; - ioc->chip = (SYSIF_REGS __iomem *)mem; - - /* Save Port IO values in case we need to do downloadboot */ - { - u8 *pmem = (u8*)port; - ioc->pio_mem_phys = port; - ioc->pio_chip = (SYSIF_REGS __iomem *)pmem; - } + /* Initialize work */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) + INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work); +#else + INIT_WORK(&ioc->fault_reset_work, mpt_fault_reset_work, (void *)ioc); +#endif - if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) { - ioc->prod_name = "LSIFC909"; - ioc->bus_type = FC; - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) { - ioc->prod_name = "LSIFC929"; - ioc->bus_type = FC; - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) { - ioc->prod_name = "LSIFC919"; - ioc->bus_type = FC; + /* Initialize workqueue */ + snprintf(ioc->reset_work_q_name, KOBJ_NAME_LEN, "mpt_poll_%d", ioc->id); + ioc->reset_work_q = + create_singlethread_workqueue(ioc->reset_work_q_name); + if (!ioc->reset_work_q) { + printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n", + ioc->name); + kfree(ioc); + return -ENOMEM; } - else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) { - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts @ %p, pfacts[0] @ %p\n", + ioc->name, &ioc->facts, &ioc->pfacts[0])); + + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name); + + switch (pdev->device) + { + case MPI_MANUFACTPAGE_DEVICEID_FC939X: + case MPI_MANUFACTPAGE_DEVICEID_FC949X: + ioc->errata_flag_1064 = 1; + case MPI_MANUFACTPAGE_DEVICEID_FC909: + case MPI_MANUFACTPAGE_DEVICEID_FC929: + case MPI_MANUFACTPAGE_DEVICEID_FC919: + case MPI_MANUFACTPAGE_DEVICEID_FC949E: ioc->bus_type = FC; + break; + + case MPI_MANUFACTPAGE_DEVICEID_FC929X: if (revision < XL_929) { - ioc->prod_name = "LSIFC929X"; /* 929X Chip Fix. Set Split transactions level * for PCIX. Set MOST bits to zero. */ @@ -1298,83 +1863,75 @@ mpt_attach(struct pci_dev *pdev, const s pcixcmd &= 0x8F; pci_write_config_byte(pdev, 0x6a, pcixcmd); } else { - ioc->prod_name = "LSIFC929XL"; /* 929XL Chip Fix. Set MMRBC to 0x08. */ pci_read_config_byte(pdev, 0x6a, &pcixcmd); pcixcmd |= 0x08; pci_write_config_byte(pdev, 0x6a, pcixcmd); } - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) { - ioc->prod_name = "LSIFC919X"; ioc->bus_type = FC; + break; + + case MPI_MANUFACTPAGE_DEVICEID_FC919X: /* 919X Chip Fix. Set Split transactions level * for PCIX. Set MOST bits to zero. */ pci_read_config_byte(pdev, 0x6a, &pcixcmd); pcixcmd &= 0x8F; pci_write_config_byte(pdev, 0x6a, pcixcmd); - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) { - ioc->prod_name = "LSIFC939X"; - ioc->bus_type = FC; - ioc->errata_flag_1064 = 1; - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) { - ioc->prod_name = "LSIFC949X"; ioc->bus_type = FC; - ioc->errata_flag_1064 = 1; - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) { - ioc->prod_name = "LSIFC949E"; - ioc->bus_type = FC; - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) { - ioc->prod_name = "LSI53C1030"; - ioc->bus_type = SPI; + break; + + + case MPI_MANUFACTPAGE_DEVID_53C1030: /* 1030 Chip Fix. Disable Split transactions * for PCIX. Set MOST bits to zero if Rev < C0( = 8). */ - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); if (revision < C0_1030) { pci_read_config_byte(pdev, 0x6a, &pcixcmd); pcixcmd &= 0x8F; pci_write_config_byte(pdev, 0x6a, pcixcmd); } - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) { - ioc->prod_name = "LSI53C1035"; + + case MPI_MANUFACTPAGE_DEVID_1030_53C1035: ioc->bus_type = SPI; - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) { - ioc->prod_name = "LSISAS1064"; - ioc->bus_type = SAS; - ioc->errata_flag_1064 = 1; - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) { - ioc->prod_name = "LSISAS1068"; - ioc->bus_type = SAS; + break; + + case MPI_MANUFACTPAGE_DEVID_SAS1064: + case MPI_MANUFACTPAGE_DEVID_SAS1068: ioc->errata_flag_1064 = 1; - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) { - ioc->prod_name = "LSISAS1064E"; ioc->bus_type = SAS; - } - else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) { - ioc->prod_name = "LSISAS1068E"; + break; + + case MPI_MANUFACTPAGE_DEVID_SAS1064E: + case MPI_MANUFACTPAGE_DEVID_SAS1068E: + case MPI_MANUFACTPAGE_DEVID_SAS1078: ioc->bus_type = SAS; + break; } - else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { - ioc->prod_name = "LSISAS1078"; - ioc->bus_type = SAS; + + switch (ioc->bus_type) { + + case SAS: + ioc->msi_enable = mpt_msi_enable_sas; + break; + + case SPI: + ioc->msi_enable = mpt_msi_enable_spi; + break; + + case FC: + ioc->msi_enable = mpt_msi_enable_fc; + break; + + default: + ioc->msi_enable = 0; + break; } if (ioc->errata_flag_1064) pci_disable_io_access(pdev); - sprintf(ioc->name, "ioc%d", ioc->id); - spin_lock_init(&ioc->FreeQlock); /* Disable all! */ @@ -1389,26 +1946,32 @@ mpt_attach(struct pci_dev *pdev, const s */ mpt_detect_bound_ports(ioc, pdev); + + INIT_LIST_HEAD(&ioc->fw_event_list); + spin_lock_init(&ioc->fw_event_lock); + snprintf(ioc->fw_event_q_name, KOBJ_NAME_LEN, "mpt/%d", ioc->id); + ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name); + if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0){ - printk(KERN_WARNING MYNAM - ": WARNING - %s did not initialize properly! (%d)\n", + printk(MYIOC_s_ERR_FMT + "didn't initialize properly! (%d)\n", ioc->name, r); list_del(&ioc->list); if (ioc->alt_ioc) ioc->alt_ioc->alt_ioc = NULL; - iounmap(mem); + iounmap(ioc->memmap); kfree(ioc); pci_set_drvdata(pdev, NULL); return r; } /* call per device driver probe entry point */ - for(ii=0; iiprobe) { - MptDeviceDriverHandlers[ii]->probe(pdev,id); + for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { + if(MptDeviceDriverHandlers[cb_idx] && + MptDeviceDriverHandlers[cb_idx]->probe) { + MptDeviceDriverHandlers[cb_idx]->probe(pdev,id); } } @@ -1431,21 +1994,40 @@ mpt_attach(struct pci_dev *pdev, const s } #endif + if (!ioc->alt_ioc) + queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, + msecs_to_jiffies(MPT_POLLING_INTERVAL)); return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_detach - Remove a PCI intelligent MPT adapter. * @pdev: Pointer to pci_dev structure - */ - + **/ void mpt_detach(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); char pname[32]; - int ii; + u8 cb_idx; + unsigned long flags; + struct workqueue_struct *wq; + + /* + * Stop polling ioc for fault condition + */ + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + wq = ioc->reset_work_q; + ioc->reset_work_q = NULL; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + cancel_delayed_work(&ioc->fault_reset_work); + destroy_workqueue(wq); + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + wq = ioc->fw_event_q; + ioc->fw_event_q = NULL; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + destroy_workqueue(wq); sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); remove_proc_entry(pname, NULL); @@ -1455,52 +2037,35 @@ mpt_detach(struct pci_dev *pdev) remove_proc_entry(pname, NULL); /* call per device driver remove entry point */ - for(ii=0; iiremove) { - MptDeviceDriverHandlers[ii]->remove(pdev); + for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { + if(MptDeviceDriverHandlers[cb_idx] && + MptDeviceDriverHandlers[cb_idx]->remove) { + MptDeviceDriverHandlers[cb_idx]->remove(pdev); } } - /* Disable interrupts! */ - CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); - - ioc->active = 0; - synchronize_irq(pdev->irq); - - /* Clear any lingering interrupt */ - CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - - CHIPREG_READ32(&ioc->chip->IntStatus); - mpt_adapter_dispose(ioc); - - pci_set_drvdata(pdev, NULL); } /************************************************************************** * Power Management */ #ifdef CONFIG_PM -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_suspend - Fusion MPT base driver suspend routine. * @pdev: Pointer to pci_dev structure * @state: new state to enter - */ + **/ int mpt_suspend(struct pci_dev *pdev, pm_message_t state) { u32 device_state; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - device_state=pci_choose_state(pdev, state); - - printk(MYIOC_s_INFO_FMT - "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n", - ioc->name, pdev, pci_name(pdev), device_state); - - pci_save_state(pdev); + device_state = pci_choose_state(pdev, state); + printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering " + "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), + device_state); /* put ioc into READY_STATE */ if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) { @@ -1511,63 +2076,98 @@ mpt_suspend(struct pci_dev *pdev, pm_mes /* disable interrupts */ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; - /* Clear any lingering interrupt */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + free_irq(ioc->pci_irq, ioc); + if (ioc->msi_enable) + pci_disable_msi(ioc->pcidev); + ioc->pci_irq = -1; + pci_save_state(pdev); pci_disable_device(pdev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) + pci_release_selected_regions(ioc->pcidev, ioc->bars); +#endif pci_set_power_state(pdev, device_state); - return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_resume - Fusion MPT base driver resume routine. * @pdev: Pointer to pci_dev structure - */ + **/ int mpt_resume(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); u32 device_state = pdev->current_state; int recovery_state; + int err; - printk(MYIOC_s_INFO_FMT - "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n", - ioc->name, pdev, pci_name(pdev), device_state); + printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous " + "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), + device_state); - pci_set_power_state(pdev, 0); + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, PCI_D0, 0); pci_restore_state(pdev); - pci_enable_device(pdev); + ioc->pcidev = pdev; + err = mpt_mapresources(ioc); + if (err) + return err; + + if (ioc->dma_mask == DMA_64BIT_MASK) { + if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) + ioc->add_sge = &mpt_add_sge_64bit_1078; + else + ioc->add_sge = &mpt_add_sge_64bit; + ioc->add_chain = &mpt_add_chain_64bit; + ioc->sg_addr_size = 8; + } else { - /* enable interrupts */ - CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); - ioc->active = 1; + ioc->add_sge = &mpt_add_sge; + ioc->add_chain = &mpt_add_chain; + ioc->sg_addr_size = 4; + } + ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; - printk(MYIOC_s_INFO_FMT - "pci-resume: ioc-state=0x%x,doorbell=0x%x\n", - ioc->name, - (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT), - CHIPREG_READ32(&ioc->chip->Doorbell)); - /* bring ioc to operational state */ - if ((recovery_state = mpt_do_ioc_recovery(ioc, - MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) { - printk(MYIOC_s_INFO_FMT - "pci-resume: Cannot recover, error:[%x]\n", - ioc->name, recovery_state); - } else { - printk(MYIOC_s_INFO_FMT - "pci-resume: success\n", ioc->name); + printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n", + ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT), + CHIPREG_READ32(&ioc->chip->Doorbell)); + + /* + * Errata workaround for SAS pci express: + * Upon returning to the D0 state, the contents of the doorbell will be + * stale data, and this will incorrectly signal to the host driver that + * the firmware is ready to process mpt commands. The workaround is + * to issue a diagnostic reset. + */ + if (ioc->bus_type == SAS && (pdev->device == + MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device == + MPI_MANUFACTPAGE_DEVID_SAS1064E)) { + if (KickStart(ioc, 1, CAN_SLEEP) < 0) { + printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n", + ioc->name); + goto out; + } } + /* bring ioc to operational state */ + printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name); + if ((recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) + printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, " + "error:[%x]\n", ioc->name, recovery_state); + else + printk(MYIOC_s_INFO_FMT + "pci-resume: success\n", ioc->name); + out: return 0; } #endif static int -mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase) +mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase) { if ((MptDriverClass[index] == MPTSPI_DRIVER && ioc->bus_type != SPI) || @@ -1581,7 +2181,6 @@ mpt_signal_reset(int index, MPT_ADAPTER return (MptResetHandlers[index])(ioc, reset_phase); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_do_ioc_recovery - Initialize or recover MPT adapter. * @ioc: Pointer to MPT adapter structure @@ -1600,7 +2199,7 @@ mpt_signal_reset(int index, MPT_ADAPTER * -2 if READY but IOCFacts Failed * -3 if READY but PrimeIOCFifos Failed * -4 if READY but IOCInit Failed - */ + **/ static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) { @@ -1609,20 +2208,20 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 int hard; int rc=0; int ii; - int handlers; int ret = 0; int reset_alt_ioc_active = 0; int irq_allocated = 0; + u8 *a; - printk(KERN_INFO MYNAM ": Initiating %s %s\n", - ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); + printk(MYIOC_s_DEBUG_FMT "Initiating %s\n", ioc->name, + reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); /* Disable reply interrupts (also blocks FreeQ) */ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; if (ioc->alt_ioc) { - if (ioc->alt_ioc->active) + if (ioc->alt_ioc->active || reason == MPT_HOSTEVENT_IOC_RECOVER) reset_alt_ioc_active = 1; /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */ @@ -1636,22 +2235,22 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) { if (hard_reset_done == -4) { - printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n", - ioc->name); + printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n", + ioc->name); if (reset_alt_ioc_active && ioc->alt_ioc) { /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ - dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", - ioc->alt_ioc->name)); + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": alt-ioc reply irq re-enabled\n", + ioc->alt_ioc->name)); CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); ioc->alt_ioc->active = 1; } } else { - printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n", - ioc->name); + printk(MYIOC_s_WARN_FMT "NOT READY WARNING!\n", ioc->name); } - return -1; + ret = -1; + goto out; } /* hard_reset_done = 0 if a soft reset was performed @@ -1661,9 +2260,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; else - printk(KERN_WARNING MYNAM - ": alt-%s: Not ready WARNING!\n", - ioc->alt_ioc->name); + printk(MYIOC_s_WARN_FMT + ": alt-ioc Not ready WARNING!\n", ioc->alt_ioc->name); } for (ii=0; ii<5; ii++) { @@ -1674,7 +2272,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 if (ii == 5) { - dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Retry IocFacts failed rc=%x\n", ioc->name, rc)); ret = -2; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc); @@ -1682,13 +2281,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 if (alt_ioc_ready) { if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { - dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc)); /* Retry - alt IOC was initialized once */ rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); } if (rc) { - dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc)); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { @@ -1696,6 +2297,20 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 } } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) + if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) && + (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) { + pci_release_selected_regions(ioc->pcidev, ioc->bars); + ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM | + IORESOURCE_IO); + if (pci_enable_device_bars(ioc->pcidev, ioc->bars)) + return -5; + if (pci_request_selected_regions(ioc->pcidev, ioc->bars, + "mpt")) + return -5; + } +#endif + /* * Device is reset now. It must have de-asserted the interrupt line * (if it was asserted) and it should be safe to register for the @@ -1704,25 +2319,35 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { ioc->pci_irq = -1; if (ioc->pcidev->irq) { - if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev)) + if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev)) printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", ioc->name); + else + ioc->msi_enable = 0; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) + rc = request_irq(ioc->pcidev->irq, mpt_interrupt, + IRQF_SHARED, ioc->name, ioc); +#else rc = request_irq(ioc->pcidev->irq, mpt_interrupt, - IRQF_SHARED, ioc->name, ioc); + SA_SHIRQ, ioc->name, ioc); +#endif if (rc < 0) { printk(MYIOC_s_ERR_FMT "Unable to allocate " "interrupt %d!\n", ioc->name, ioc->pcidev->irq); - if (mpt_msi_enable) + if (ioc->msi_enable) pci_disable_msi(ioc->pcidev); - return -EBUSY; + ret = -EBUSY; + goto out; } irq_allocated = 1; ioc->pci_irq = ioc->pcidev->irq; pci_set_master(ioc->pcidev); /* ?? */ pci_set_drvdata(ioc->pcidev, ioc); - dprintk((KERN_INFO MYNAM ": %s installed at interrupt " - "%d\n", ioc->name, ioc->pcidev->irq)); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + "installed at interrupt %d\n", ioc->name, + ioc->pcidev->irq)); } } @@ -1731,17 +2356,21 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 * init as upper addresses are needed for init. * If fails, continue with alt-ioc processing */ + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n", + ioc->name)); if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0)) ret = -3; /* May need to check/upload firmware & data here! * If fails, continue with alt-ioc processing */ + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n", + ioc->name)); if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0)) ret = -4; // NEW! if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { - printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n", + printk(MYIOC_s_WARN_FMT ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n", ioc->alt_ioc->name, rc); alt_ioc_ready = 0; reset_alt_ioc_active = 0; @@ -1751,15 +2380,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { alt_ioc_ready = 0; reset_alt_ioc_active = 0; - printk(KERN_WARNING MYNAM - ": alt-%s: (%d) init failure WARNING!\n", + printk(MYIOC_s_WARN_FMT + ": alt-ioc: (%d) init failure WARNING!\n", ioc->alt_ioc->name, rc); } } if (reason == MPT_HOSTEVENT_IOC_BRINGUP){ if (ioc->upload_fw) { - ddlprintk((MYIOC_s_INFO_FMT + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "firmware upload required!\n", ioc->name)); /* Controller is not operational, cannot do upload @@ -1775,40 +2404,47 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 * chips (mpt_adapter_disable, * mpt_diag_reset) */ - ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n", - ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw)); - ioc->alt_ioc->cached_fw = NULL; + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "mpt_upload: alt_%s has cached_fw=%p \n", + ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw)); + ioc->cached_fw = NULL; } } else { - printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); + printk(MYIOC_s_WARN_FMT + "firmware upload failure!\n", ioc->name); ret = -5; } } } } + /* Enable MPT base driver management of EventNotification + * and EventAck handling. + */ + if ((ret == 0) && (!ioc->facts.EventState)) { + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendEventNotification\n", + ioc->name)); + ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */ + } + + if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) + rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag); + if (ret == 0) { /* Enable! (reply interrupt) */ CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); ioc->active = 1; } - - if (reset_alt_ioc_active && ioc->alt_ioc) { - /* (re)Enable alt-IOC! (reply interrupt) */ - dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", + if (rc == 0) { /* alt ioc */ + if (reset_alt_ioc_active && ioc->alt_ioc) { + /* (re)Enable alt-IOC! (reply interrupt) */ + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc reply irq re-enabled\n", ioc->alt_ioc->name)); - CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); - ioc->alt_ioc->active = 1; + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); + ioc->alt_ioc->active = 1; + } } - /* Enable MPT base driver management of EventNotification - * and EventAck handling. - */ - if ((ret == 0) && (!ioc->facts.EventState)) - (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */ - - if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) - (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */ /* Add additional "reason" check before call to GetLanConfigPages * (combined with GetIoUnitPage2 call). This prevents a somewhat @@ -1824,8 +2460,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 init_MUTEX(&ioc->raid_data.inactive_list_mutex); INIT_LIST_HEAD(&ioc->raid_data.inactive_list); - if (ioc->bus_type == SAS) { + switch (ioc->bus_type) { + case SAS: /* clear persistency table */ if(ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) { @@ -1839,23 +2476,31 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 */ mpt_findImVolumes(ioc); - } else if (ioc->bus_type == FC) { - if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) && + /* Check, and possibly reset, the coalescing value + */ + mpt_read_ioc_pg_1(ioc); + + break; + + case FC: + if ((ioc->pfacts[0].ProtocolFlags & + MPI_PORTFACTS_PROTOCOL_LAN) && (ioc->lan_cnfg_page0.Header.PageLength == 0)) { /* * Pre-fetch the ports LAN MAC address! * (LANPage1_t stuff) */ (void) GetLanConfigPages(ioc); -#ifdef MPT_DEBUG - { - u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; - dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", - ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] )); - } -#endif + a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "LanAddr = %02X:%02X:%02X" + ":%02X:%02X:%02X\n", + ioc->name, a[5], a[4], + a[3], a[2], a[1], a[0])); } - } else { + break; + + case SPI: /* Get NVRAM and adapter maximums from SPP 0 and 2 */ mpt_GetScsiPortSettings(ioc, 0); @@ -1874,47 +2519,24 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 mpt_read_ioc_pg_1(ioc); mpt_read_ioc_pg_4(ioc); + + break; } GetIoUnitPage2(ioc); - } - - /* - * Call each currently registered protocol IOC reset handler - * with post-reset indication. - * NOTE: If we're doing _IOC_BRINGUP, there can be no - * MptResetHandlers[] registered yet. - */ - if (hard_reset_done) { - rc = handlers = 0; - for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { - if ((ret == 0) && MptResetHandlers[ii]) { - dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n", - ioc->name, ii)); - rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET); - handlers++; - } - - if (alt_ioc_ready && MptResetHandlers[ii]) { - drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, ii)); - rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET); - handlers++; - } - } - /* FIXME? Examine results here? */ + mpt_get_manufacturing_pg_0(ioc); } out: + if ((ret != 0) && irq_allocated) { free_irq(ioc->pci_irq, ioc); - if (mpt_msi_enable) + if (ioc->msi_enable) pci_disable_msi(ioc->pcidev); } return ret; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_detect_bound_ports - Search for matching PCI bus/dev_function * @ioc: Pointer to MPT adapter structure @@ -1926,7 +2548,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 * * If match on PCI dev_function +/-1 is found, bind the two MPT adapters * using alt_ioc pointer fields in their %MPT_ADAPTER structures. - */ + **/ static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) { @@ -1935,7 +2557,7 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, unsigned int func = PCI_FUNC(pdev->devfn); MPT_ADAPTER *ioc_srch; - dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x," + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x," " searching for devfn match on %x or %x\n", ioc->name, pci_name(pdev), pdev->bus->number, pdev->devfn, func-1, func+1)); @@ -1952,16 +2574,16 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, if (_pcidev == peer) { /* Paranoia checks */ if (ioc->alt_ioc != NULL) { - printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n", - ioc->name, ioc->alt_ioc->name); + printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n", + ioc->name, ioc->name, ioc->alt_ioc->name); break; } else if (ioc_srch->alt_ioc != NULL) { - printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n", - ioc_srch->name, ioc_srch->alt_ioc->name); + printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n", + ioc_srch->name, ioc_srch->name, ioc_srch->alt_ioc->name); break; } - dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n", - ioc->name, ioc_srch->name)); + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FOUND! binding %s <==> %s\n", + ioc->name, ioc->name, ioc_srch->name)); ioc_srch->alt_ioc = ioc; ioc->alt_ioc = ioc_srch; } @@ -1969,11 +2591,10 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, pci_dev_put(peer); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_adapter_disable - Disable misbehaving MPT adapter. * @ioc: Pointer to MPT adapter structure - */ + **/ static void mpt_adapter_disable(MPT_ADAPTER *ioc) { @@ -1981,22 +2602,42 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) int ret; if (ioc->cached_fw != NULL) { - ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n")); - if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) { - printk(KERN_WARNING MYNAM - ": firmware downloadboot failure (%d)!\n", ret); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_adapter_disable: " + "Pushing FW onto adapter\n", ioc->name)); + if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *) + ioc->cached_fw, CAN_SLEEP)) < 0) { + printk(MYIOC_s_WARN_FMT + ": firmware downloadboot failure (%d)!\n", ioc->name, ret); } } + /* + * Put the controller into ready state (if its not already) + */ + if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) { + if(!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, + CAN_SLEEP)) { + if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) + printk(MYIOC_s_ERR_FMT "%s: IOC msg unit " + "reset failed to put ioc in ready state!\n", + ioc->name, __FUNCTION__); + } else + printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset " + "failed!\n", ioc->name, __FUNCTION__); + } + /* Disable adapter interrupts! */ + synchronize_irq(ioc->pcidev->irq); CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; + /* Clear any lingering interrupt */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + CHIPREG_READ32(&ioc->chip->IntStatus); if (ioc->alloc != NULL) { sz = ioc->alloc_sz; - dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n", + dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free @ %p, sz=%d bytes\n", ioc->name, ioc->alloc, ioc->alloc_sz)); pci_free_consistent(ioc->pcidev, sz, ioc->alloc, ioc->alloc_dma); @@ -2021,24 +2662,20 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) ioc->alloc_total -= sz; } - if (ioc->cached_fw != NULL) { - sz = ioc->facts.FWImageSize; - pci_free_consistent(ioc->pcidev, sz, - ioc->cached_fw, ioc->cached_fw_dma); - ioc->cached_fw = NULL; - ioc->alloc_total -= sz; - } + mpt_free_fw_memory(ioc); kfree(ioc->spi_data.nvram); 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; - pci_free_consistent(ioc->pcidev, sz, + pci_free_consistent(ioc->pcidev, sz, ioc->spi_data.pIocPg4, ioc->spi_data.IocPg4_dma); ioc->spi_data.pIocPg4 = NULL; @@ -2057,11 +2694,11 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) if (ioc->HostPageBuffer != NULL) { if((ret = mpt_host_page_access_control(ioc, MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) { - printk(KERN_ERR MYNAM + printk(MYIOC_s_ERR_FMT ": %s: host page buffers free failed (%d)!\n", - __FUNCTION__, ret); + ioc->name, __FUNCTION__, ret); } - dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n", + dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HostPageBuffer free @ %p, sz=%d bytes\n", ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz)); pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz, ioc->HostPageBuffer, @@ -2070,16 +2707,17 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) ioc->HostPageBuffer_sz = 0; ioc->alloc_total -= ioc->HostPageBuffer_sz; } + + pci_set_drvdata(ioc->pcidev, NULL); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_adapter_dispose - Free all resources associated with an MPT adapter * @ioc: Pointer to MPT adapter structure * * This routine unregisters h/w resources and frees all alloc'd memory * associated with a MPT adapter structure. - */ + **/ static void mpt_adapter_dispose(MPT_ADAPTER *ioc) { @@ -2094,7 +2732,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) if (ioc->pci_irq != -1) { free_irq(ioc->pci_irq, ioc); - if (mpt_msi_enable) + if (ioc->msi_enable) pci_disable_msi(ioc->pcidev); ioc->pci_irq = -1; } @@ -2104,10 +2742,15 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) ioc->memmap = NULL; } + pci_disable_device(ioc->pcidev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) + pci_release_selected_regions(ioc->pcidev, ioc->bars); +#endif + #if defined(CONFIG_MTRR) && 0 if (ioc->mtrr_reg > 0) { mtrr_del(ioc->mtrr_reg, 0, 0); - dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name)); + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region de-registered\n", ioc->name)); } #endif @@ -2115,7 +2758,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) list_del(&ioc->list); sz_last = ioc->alloc_total; - dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n", + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free'd %d of %d bytes\n", ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); if (ioc->alt_ioc) @@ -2124,19 +2767,18 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) kfree(ioc); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * MptDisplayIocCapabilities - Disply IOC's capabilities. * @ioc: Pointer to MPT adapter structure - */ + **/ static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc) { int i = 0; printk(KERN_INFO "%s: ", ioc->name); - if (ioc->prod_name && strlen(ioc->prod_name) > 3) - printk("%s: ", ioc->prod_name+3); + if (ioc->prod_name) + printk("%s: ", ioc->prod_name); printk("Capabilities={"); if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) { @@ -2167,7 +2809,6 @@ MptDisplayIocCapabilities(MPT_ADAPTER *i printk("}\n"); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * MakeIocReady - Get IOC to a READY state, using KickStart if needed. * @ioc: Pointer to MPT_ADAPTER structure @@ -2181,7 +2822,7 @@ MptDisplayIocCapabilities(MPT_ADAPTER *i * -2 - Msg Unit Reset Failed * -3 - IO Unit Reset Failed * -4 - IOC owned by a PEER - */ + **/ static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) { @@ -2195,7 +2836,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force /* Get current [raw] IOC state */ ioc_state = mpt_GetIocState(ioc, 0); - dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state)); + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MakeIocReady, [raw] state=%08x\n", ioc->name, ioc_state)); /* * Check to see if IOC got left/stuck in doorbell handshake @@ -2208,8 +2849,11 @@ MakeIocReady(MPT_ADAPTER *ioc, int force } /* Is it already READY? */ - if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) + if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) { + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "IOC is in READY state\n", + ioc->name)); return 0; + } /* * Check to see if IOC is in FAULT state. @@ -2226,7 +2870,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force * Hmmm... Did it get left operational? */ if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) { - dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n", ioc->name)); /* Check WhoInit. @@ -2235,9 +2879,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force * Else, fall through to KickStart case */ whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT; - dinitprintk((KERN_INFO MYNAM - ": whoinit 0x%x statefault %d force %d\n", - whoinit, statefault, force)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "whoinit 0x%x statefault %d force %d\n", + ioc->name, whoinit, statefault, force)); if (whoinit == MPI_WHOINIT_PCI_PEER) return -4; else { @@ -2282,15 +2926,15 @@ MakeIocReady(MPT_ADAPTER *ioc, int force ii++; cntdn--; if (!cntdn) { - printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n", - ioc->name, (int)((ii+5)/HZ)); + printk(MYIOC_s_ERR_FMT "Wait IOC_READY state (0x%x) timeout(%d)!\n", + ioc->name, ioc_state, (int)((ii+5)/HZ)); return -ETIME; } if (sleepFlag == CAN_SLEEP) { msleep(1); } else { - mdelay (1); /* 1 msec delay */ + mdelay(1); /* 1 msec delay */ } } @@ -2304,7 +2948,6 @@ MakeIocReady(MPT_ADAPTER *ioc, int force return hard_reset_done; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_GetIocState - Get the current state of a MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure @@ -2312,7 +2955,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force * * Returns all IOC Doorbell register bits if cooked==0, else just the * Doorbell bits in MPI_IOC_STATE_MASK. - */ + **/ u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked) { @@ -2320,7 +2963,6 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int co /* Get! */ s = CHIPREG_READ32(&ioc->chip->Doorbell); -// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s)); sc = s & MPI_IOC_STATE_MASK; /* Save! */ @@ -2329,7 +2971,6 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int co return cooked ? sc : s; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * GetIocFacts - Send IOCFacts request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure @@ -2337,7 +2978,7 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int co * @reason: If recovery, only update facts. * * Returns 0 for success, non-zero for failure. - */ + **/ static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) { @@ -2371,7 +3012,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF get_facts.Function = MPI_FUNCTION_IOC_FACTS; /* Assert: All other get_facts fields are zero! */ - dinitprintk((MYIOC_s_INFO_FMT + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending get IocFacts request req_sz=%d reply_sz=%d\n", ioc->name, req_sz, reply_sz)); @@ -2401,6 +3042,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); @@ -2416,7 +3059,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF * Old: u16{Major(4),Minor(4),SubMinor(8)} * New: u32{Major(8),Minor(8),Unit(8),Dev(8)} */ - if (facts->MsgVersion < 0x0102) { + if (facts->MsgVersion < MPI_VERSION_01_02) { /* * Handle old FC f/w style, convert to new... */ @@ -2428,9 +3071,11 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word); facts->ProductID = le16_to_cpu(facts->ProductID); + if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ioc->ir_firmware = 1; + facts->CurrentHostMfaHighAddr = le32_to_cpu(facts->CurrentHostMfaHighAddr); facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits); @@ -2446,7 +3091,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF * to 14 in MPI-1.01.0x. */ if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 && - facts->MsgVersion > 0x0100) { + facts->MsgVersion > MPI_VERSION_01_00) { facts->FWImageSize = le32_to_cpu(facts->FWImageSize); } @@ -2473,8 +3118,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF sz = sz >> 1; } ioc->NBShiftFactor = shiftFactor; - dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n", - ioc->name, vv, shiftFactor, r)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n", + ioc->name, vv, shiftFactor, r)); if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { /* @@ -2486,9 +3132,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF ioc->reply_sz = MPT_REPLY_FRAME_SIZE; ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth); - dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n", ioc->name, ioc->reply_sz, ioc->reply_depth)); - dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n", ioc->name, ioc->req_sz, ioc->req_depth)); /* Get port facts! */ @@ -2506,7 +3152,6 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * GetPortFacts - Send PortFacts request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure @@ -2514,7 +3159,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF * @sleepFlag: Specifies whether the process can sleep * * Returns 0 for success, non-zero for failure. - */ + **/ static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) { @@ -2527,9 +3172,8 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn /* IOC *must* NOT be in RESET state! */ if (ioc->last_state == MPI_IOC_STATE_RESET) { - printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n", - ioc->name, - ioc->last_state ); + printk(MYIOC_s_ERR_FMT "Can't get PortFacts, " + " NOT READY! (%08x)\n", ioc->name, ioc->last_state ); return -4; } @@ -2547,14 +3191,14 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn get_pfacts.PortNumber = portnum; /* Assert: All other get_pfacts fields are zero! */ - dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n", - ioc->name, portnum)); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n", + ioc->name, portnum)); /* No non-zero fields in the get_pfacts request are greater than * 1 byte in size, so we can just fire it off as is. */ ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts, - reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag); + reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag); if (ii != 0) return ii; @@ -2571,19 +3215,8 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs); pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets); - switch (ioc->bus_type) { - case SAS: - max_id = pfacts->PortSCSIID; - break; - case FC: - max_id = pfacts->MaxDevices; - break; - case SPI: - default: - max_id = MPT_MAX_SCSI_DEVICES; - break; - } - + max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID : + pfacts->MaxDevices; ioc->devices_per_bus = (max_id > 255) ? 256 : max_id; ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256; @@ -2600,7 +3233,6 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * SendIocInit - Send IOCInit request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure @@ -2609,7 +3241,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state. * * Returns 0 for success, non-zero for failure. - */ + **/ static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) { @@ -2634,12 +3266,13 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF ioc->upload_fw = 1; else ioc->upload_fw = 0; - ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n", + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n", ioc->name, ioc->upload_fw, ioc->facts.Flags)); ioc_init.MaxDevices = (U8)ioc->devices_per_bus; ioc_init.MaxBuses = (U8)ioc->number_of_buses; - dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n", + + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n", ioc->name, ioc->facts.MsgVersion)); if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) { // set MsgVersion and HeaderVersion host driver was built with @@ -2653,7 +3286,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF } ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ - if (sizeof(dma_addr_t) == sizeof(u64)) { + if (ioc->sg_addr_size == sizeof(u64)) { /* Save the upper 32-bits of the request * (reply) and sense buffers. */ @@ -2670,7 +3303,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF ioc->facts.MaxDevices = ioc_init.MaxDevices; ioc->facts.MaxBuses = ioc_init.MaxBuses; - dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n", + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init)); r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init, @@ -2684,7 +3317,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF * since we don't even look at its contents. */ - dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n", + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n", ioc->name, &ioc_init)); if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) { @@ -2715,14 +3348,13 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF state = mpt_GetIocState(ioc, 1); count++; } - dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n", ioc->name, count)); ioc->aen_event_read_flag=0; return r; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * SendPortEnable - Send PortEnable request to MPT adapter port. * @ioc: Pointer to MPT_ADAPTER structure @@ -2732,7 +3364,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF * Send PortEnable to bring IOC to OPERATIONAL state. * * Returns 0 for success, non-zero for failure. - */ + **/ static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) { @@ -2755,7 +3387,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int por /* port_enable.MsgFlags = 0; */ /* port_enable.MsgContext = 0; */ - dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", ioc->name, portnum, &port_enable)); /* RAID FW may take a long time to enable @@ -2779,46 +3411,62 @@ SendPortEnable(MPT_ADAPTER *ioc, int por * * If memory has already been allocated, the same (cached) value * is returned. - */ -void + * + * Return 0 if successfull, or non-zero for failure + **/ +int mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) { - if (ioc->cached_fw) - return; /* use already allocated memory */ - if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { + int rc; + + if (ioc->cached_fw) { + rc = 0; /* use already allocated memory */ + goto out; + } + else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */ ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma; - ioc->alloc_total += size; - ioc->alt_ioc->alloc_total -= size; + rc = 0; + goto out; + } + ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma); + if (!ioc->cached_fw) { + printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n", + ioc->name); + rc = -1; } else { - if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) ) - ioc->alloc_total += size; + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size)); + ioc->alloc_total += size; + rc = 0; } + out: + return rc; } + /** * mpt_free_fw_memory - free firmware memory * @ioc: Pointer to MPT_ADAPTER structure * * If alt_img is NULL, delete from ioc structure. * Else, delete a secondary image in same format. - */ + **/ void mpt_free_fw_memory(MPT_ADAPTER *ioc) { int sz; + if (!ioc->cached_fw) + return; + sz = ioc->facts.FWImageSize; - dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", - ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); - pci_free_consistent(ioc->pcidev, sz, - ioc->cached_fw, ioc->cached_fw_dma); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); + pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma); + ioc->alloc_total -= sz; ioc->cached_fw = NULL; - - return; } - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port. * @ioc: Pointer to MPT_ADAPTER structure @@ -2831,96 +3479,91 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc) * on the bound IOC, the second image is discarded * and memory is free'd. Both channels must upload to prevent * IOC from running in degraded mode. - */ + **/ static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) { - u8 request[ioc->req_sz]; u8 reply[sizeof(FWUploadReply_t)]; FWUpload_t *prequest; FWUploadReply_t *preply; FWUploadTCSGE_t *ptcsge; - int sgeoffset; u32 flagsLength; - int ii, sz, reply_sz; + int ii, reply_sz; int cmdStatus; + int request_size; /* If the image size is 0, we are done. */ - if ((sz = ioc->facts.FWImageSize) == 0) + if (!ioc->facts.FWImageSize) return 0; - mpt_alloc_fw_memory(ioc, sz); - - dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n", - ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); + if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0) + return -ENOMEM; - if (ioc->cached_fw == NULL) { - /* Major Failure. - */ + prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) : + kzalloc(ioc->req_sz, GFP_KERNEL); + if (!prequest) { + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed " + "while allocating memory \n", ioc->name)); + mpt_free_fw_memory(ioc); return -ENOMEM; } - prequest = (FWUpload_t *)&request; preply = (FWUploadReply_t *)&reply; - /* Destination... */ - memset(prequest, 0, ioc->req_sz); - reply_sz = sizeof(reply); memset(preply, 0, reply_sz); prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM; prequest->Function = MPI_FUNCTION_FW_UPLOAD; - ptcsge = (FWUploadTCSGE_t *) &prequest->SGL; ptcsge->DetailsLength = 12; ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; - ptcsge->ImageSize = cpu_to_le32(sz); - - sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t); - - flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz; - mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma); + ptcsge->ImageSize = cpu_to_le32(ioc->facts.FWImageSize); + ptcsge++; - sgeoffset += sizeof(u32) + sizeof(dma_addr_t); - dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n", - prequest, sgeoffset)); - DBG_DUMP_FW_REQUEST_FRAME(prequest) + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | ioc->facts.FWImageSize; + ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma); + request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) + + ioc->SGE_size; + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload " + " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest, + ioc->facts.FWImageSize, request_size)); + DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest); - ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest, - reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); + ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32*)prequest, + reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); - dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed " + "rc=%x \n", ioc->name, ii)); cmdStatus = -EFAULT; if (ii == 0) { /* Handshake transfer was complete and successful. * Check the Reply Frame. */ - int status, transfer_sz; - status = le16_to_cpu(preply->IOCStatus); - if (status == MPI_IOCSTATUS_SUCCESS) { - transfer_sz = le32_to_cpu(preply->ActualImageSize); - if (transfer_sz == sz) - cmdStatus = 0; - } + int status; + status = le16_to_cpu(preply->IOCStatus) & + MPI_IOCSTATUS_MASK; + if (status == MPI_IOCSTATUS_SUCCESS && + ioc->facts.FWImageSize == + le32_to_cpu(preply->ActualImageSize)); + cmdStatus = 0; } - dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n", - ioc->name, cmdStatus)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "do_upload cmdStatus=%d \n", + ioc->name, cmdStatus)); if (cmdStatus) { - - ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n", - ioc->name)); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, " + "freeing image \n", ioc->name)); mpt_free_fw_memory(ioc); } + kfree(prequest); return cmdStatus; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_downloadboot - DownloadBoot code * @ioc: Pointer to MPT_ADAPTER structure @@ -2933,7 +3576,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee * -1 FW Image size is 0 * -2 No valid cached_fw Pointer * <0 for fw upload failure. - */ + **/ static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag) { @@ -2945,10 +3588,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw u32 diagRwData; u32 nextImage; u32 load_addr; - u32 ioc_state=0; + u32 doorbell; - ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n", - ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader)); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n", + ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader)); CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); @@ -2960,11 +3603,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM)); /* wait 1 msec */ - if (sleepFlag == CAN_SLEEP) { + if (sleepFlag == CAN_SLEEP) msleep(1); - } else { - mdelay (1); - } + else + mdelay(1); diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); @@ -2972,20 +3614,19 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw for (count = 0; count < 30; count ++) { diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { - ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n", + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n", ioc->name, count)); break; } /* wait .1 sec */ - if (sleepFlag == CAN_SLEEP) { + if (sleepFlag == CAN_SLEEP) msleep (100); - } else { + else mdelay (100); - } } if ( count == 30 ) { - ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! " + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! " "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n", ioc->name, diag0val)); return -3; @@ -2999,6 +3640,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; @@ -3011,14 +3653,13 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw pci_enable_io_access(ioc->pcidev); CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress); - ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n", - ioc->name, pFwHeader->LoadStartAddress)); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n", + ioc->name, pFwHeader->LoadStartAddress)); - ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n", - ioc->name, fwSize*4, ptrFw)); - while (fwSize--) { + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n", + ioc->name, fwSize*4, ptrFw)); + while (fwSize--) CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); - } nextImage = pFwHeader->NextImageHeaderOffset; while (nextImage) { @@ -3029,22 +3670,23 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw fwSize = (pExtImage->ImageSize + 3) >> 2; ptrFw = (u32 *)pExtImage; - ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n", - ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr)); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n", + ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr)); CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr); - while (fwSize--) { + while (fwSize--) CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); - } nextImage = pExtImage->NextImageHeaderOffset; } /* Write the IopResetVectorRegAddr */ - ddlprintk((MYIOC_s_INFO_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((MYIOC_s_INFO_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, @@ -3061,72 +3703,75 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); - } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ { - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | - MPI_DIAG_CLEAR_FLASH_BAD_SIG); - - /* wait 1 msec */ - if (sleepFlag == CAN_SLEEP) { - msleep (1); - } else { - mdelay (1); - } } if (ioc->errata_flag_1064) pci_disable_io_access(ioc->pcidev); diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, " - "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n", - ioc->name, diag0val)); - diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE); - ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n", - ioc->name, diag0val)); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "diag0val=%x, turning off" + " PREVENT_IOC_BOOT and DISABLE_ARM\n", ioc->name, diag0val)); + diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "diag0val=%x\n", + ioc->name, diag0val)); CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); - /* Write 0xFF to reset the sequencer */ - CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); + if (ioc->bus_type == SAS ) { + /* wait 1 sec */ + if (sleepFlag == CAN_SLEEP) + msleep(1000); + else + mdelay(1000); - if (ioc->bus_type == SAS) { - ioc_state = mpt_GetIocState(ioc, 0); - if ( (GetIocFacts(ioc, sleepFlag, - MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) { - ddlprintk((MYIOC_s_INFO_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((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n", - ioc->name)); + ddlprintk(ioc, printk(MYIOC_s_WARN_FMT + "SendIocInit failed\n", ioc->name)); return -EFAULT; } - ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n", - ioc->name)); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "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((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n", - ioc->name, ioc_state)); + ddlprintk(ioc, printk(MYIOC_s_WARN_FMT "downloadboot failed! count=%d\n", ioc->name, count)); return -EFAULT; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * KickStart - Perform hard reset of MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure @@ -3151,7 +3796,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw * OR reset but failed to come READY * -2 - no reset, could not enter DIAG mode * -3 - reset but bad FW bit - */ + **/ static int KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) { @@ -3159,7 +3804,7 @@ KickStart(MPT_ADAPTER *ioc, int force, i u32 ioc_state=0; int cnt,cntdn; - dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": KickStart\n", ioc->name)); if (ioc->bus_type == SPI) { /* Always issue a Msg Unit Reset first. This will clear some * SCSI bus hang conditions. @@ -3177,14 +3822,15 @@ KickStart(MPT_ADAPTER *ioc, int force, i if (hard_reset_done < 0) return hard_reset_done; - dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n", + /* may not have worked but hard_reset_done doesn't always signal failure */ + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Diagnostic reset completed!\n", ioc->name)); cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */ for (cnt=0; cntname, cnt)); return hard_reset_done; } @@ -3195,12 +3841,11 @@ KickStart(MPT_ADAPTER *ioc, int force, i } } - printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n", - ioc->name, ioc_state); + dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n", + ioc->name, mpt_GetIocState(ioc, 0))); return -1; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_diag_reset - Perform hard reset of the adapter. * @ioc: Pointer to MPT_ADAPTER structure @@ -3218,43 +3863,63 @@ KickStart(MPT_ADAPTER *ioc, int force, i * 0 no reset performed because reset history bit set * -2 enabling diagnostic mode failed * -3 diagnostic reset failed - */ + **/ static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) { - MPT_ADAPTER *iocp=NULL; u32 diag0val; - u32 doorbell; + u32 doorbell = 0; int hard_reset_done = 0; int count = 0; -#ifdef MPT_DEBUG u32 diag1val = 0; -#endif + MpiFwHeader_t *cached_fw; /* Pointer to FW */ + u8 cb_idx; /* Clear any existing interrupts */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { - drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " - "address=%p\n", ioc->name, __FUNCTION__, - &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); + + if (!ignore) + return 0; + + drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " + "address=%p\n", ioc->name, __FUNCTION__, &ioc->chip->Doorbell, + &ioc->chip->Reset_1078)); CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); if (sleepFlag == CAN_SLEEP) msleep(1); else mdelay(1); + /* + * Call each currently registered protocol IOC reset handler + * with pre-reset indication. + * NOTE: If we're doing _IOC_BRINGUP, there can be no + * MptResetHandlers[] registered yet. + */ + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) + (*(MptResetHandlers[cb_idx]))(ioc, MPT_IOC_PRE_RESET); + } + for (count = 0; count < 60; count ++) { doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); doorbell &= MPI_IOC_STATE_MASK; - drsprintk((MYIOC_s_INFO_FMT + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "looking for READY STATE: doorbell=%x" " count=%d\n", ioc->name, doorbell, count)); - if (doorbell == MPI_IOC_STATE_READY) { + + 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) @@ -3262,18 +3927,22 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign else mdelay(1000); } + + if (doorbell != MPI_IOC_STATE_READY) + printk(MYIOC_s_ERR_FMT "Failed to come READY after " + "reset! IocState=%x", ioc->name, doorbell); return -1; } /* Use "Diagnostic reset" method! (only thing available!) */ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); -#ifdef MPT_DEBUG - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n", + if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n", ioc->name, diag0val, diag1val)); -#endif + } /* Do the reset if we are told to ignore the reset history * or if the reset history is 0 @@ -3291,11 +3960,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); /* wait 100 msec */ - if (sleepFlag == CAN_SLEEP) { + if (sleepFlag == CAN_SLEEP) msleep (100); - } else { + else mdelay (100); - } count++; if (count > 20) { @@ -3307,16 +3975,16 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n", + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n", ioc->name, diag0val)); } -#ifdef MPT_DEBUG - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n", + if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n", ioc->name, diag0val, diag1val)); -#endif + } /* * Disable the ARM (Bug fix) * @@ -3330,7 +3998,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign */ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); hard_reset_done = 1; - dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n", + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n", ioc->name)); /* @@ -3339,55 +4007,44 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign * NOTE: If we're doing _IOC_BRINGUP, there can be no * MptResetHandlers[] registered yet. */ - { - int ii; - int r = 0; - - for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { - if (MptResetHandlers[ii]) { - dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n", - ioc->name, ii)); - r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET); - if (ioc->alt_ioc) { - dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, ii)); - r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET); - } + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { + mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); + if (ioc->alt_ioc) { + mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET); } } - /* FIXME? Examine results here? */ } if (ioc->cached_fw) - iocp = ioc; + cached_fw = (MpiFwHeader_t *)ioc->cached_fw; else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) - iocp = ioc->alt_ioc; - if (iocp) { + cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw; + else + cached_fw = NULL; + if (cached_fw) { /* If the DownloadBoot operation fails, the * IOC will be left unusable. This is a fatal error * case. _diag_reset will return < 0 */ for (count = 0; count < 30; count ++) { - diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic); + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { break; } - dprintk((MYIOC_s_INFO_FMT "cached_fw: diag0val=%x count=%d\n", - iocp->name, diag0val, count)); + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n", + ioc->name, diag0val, count)); /* wait 1 sec */ - if (sleepFlag == CAN_SLEEP) { + if (sleepFlag == CAN_SLEEP) msleep (1000); - } else { + else mdelay (1000); - } } - if ((count = mpt_downloadboot(ioc, - (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) { - printk(KERN_WARNING MYNAM - ": firmware downloadboot failure (%d)!\n", count); + if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) { + printk(MYIOC_s_WARN_FMT + "firmware downloadboot failure (%d)!\n", ioc->name, count); } - } else { /* Wait for FW to reload and for board * to go to the READY state. @@ -3399,27 +4056,40 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); doorbell &= MPI_IOC_STATE_MASK; - if (doorbell == MPI_IOC_STATE_READY) { + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "looking for READY STATE: doorbell=%x" + " count=%d\n", ioc->name, doorbell, count)); + + if (doorbell == MPI_IOC_STATE_READY) + break; + + /* + * Early out for hard fault + */ + if (count && doorbell == MPI_IOC_STATE_FAULT) break; - } /* wait 1 sec */ - if (sleepFlag == CAN_SLEEP) { + if (sleepFlag == CAN_SLEEP) msleep (1000); - } else { + else mdelay (1000); - } } + + if (doorbell != MPI_IOC_STATE_READY) + printk(MYIOC_s_ERR_FMT "Failed to come READY " + "after reset! IocState=%x", ioc->name, + doorbell); } } diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); -#ifdef MPT_DEBUG - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -#endif + if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); + } /* Clear RESET_HISTORY bit! Place board in the * diagnostic mode to update the diag register. @@ -3438,11 +4108,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); /* wait 100 msec */ - if (sleepFlag == CAN_SLEEP) { + if (sleepFlag == CAN_SLEEP) msleep (100); - } else { + else mdelay (100); - } count++; if (count > 20) { @@ -3473,12 +4142,12 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign return -3; } -#ifdef MPT_DEBUG - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -#endif + if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); + } /* * Reset flag that says we've enabled event notification @@ -3491,7 +4160,6 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign return hard_reset_done; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * SendIocReset - Send IOCReset request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure @@ -3502,7 +4170,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign * Send IOCReset request to the MPT adapter. * * Returns 0 for success, non-zero for failure. - */ + **/ static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) { @@ -3510,10 +4178,10 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_ u32 state; int cntdn, count; - drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n", + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n", ioc->name, reset_type)); CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<name, (int)((count+5)/HZ)); + printk(MYIOC_s_ERR_FMT "Wait IOC_READY state (0x%x) timeout(%d)!\n", + ioc->name, state, (int)((count+5)/HZ)); return -ETIME; } if (sleepFlag == CAN_SLEEP) { msleep(1); } else { - mdelay (1); /* 1 msec delay */ + mdelay(1); /* 1 msec delay */ } } @@ -3550,14 +4218,13 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_ return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * initChainBuffers - Allocate memory for and initialize chain buffers * @ioc: Pointer to MPT_ADAPTER structure * * Allocates memory for and initializes chain buffers, * chain buffer control arrays and spinlock. - */ + **/ static int initChainBuffers(MPT_ADAPTER *ioc) { @@ -3575,14 +4242,14 @@ initChainBuffers(MPT_ADAPTER *ioc) return -1; ioc->ReqToChain = (int *) mem; - dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n", ioc->name, mem, sz)); mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) return -1; ioc->RequestNB = (int *) mem; - dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n", ioc->name, mem, sz)); } for (ii = 0; ii < ioc->req_depth; ii++) { @@ -3594,29 +4261,35 @@ initChainBuffers(MPT_ADAPTER *ioc) * index = chain_idx * * Calculate the number of chain buffers needed(plus 1) per I/O - * then multiply the the maximum number of simultaneous cmds + * then multiply the maximum number of simultaneous cmds * * num_sge = num sge in request frame + last chain buffer * scale = num sge per chain buffer if no chain element */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) - num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); + scale = ioc->req_sz/ ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) + num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size; else - num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + num_sge = 1+ scale + (ioc->req_sz - 64) / ioc->SGE_size; - if (sizeof(dma_addr_t) == sizeof(u64)) { + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + (ioc->req_sz - 64) / ioc->SGE_size; } - dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n", ioc->name, num_sge, numSGE)); - if ( numSGE > MPT_SCSI_SG_DEPTH ) - numSGE = MPT_SCSI_SG_DEPTH; + if (ioc->bus_type == FC) { + if (numSGE > MPT_SCSI_FC_SG_DEPTH) + numSGE = MPT_SCSI_FC_SG_DEPTH; + } + else { + if (numSGE > MPT_SCSI_SG_DEPTH) + numSGE = MPT_SCSI_SG_DEPTH; + } num_chain = 1; while (numSGE - num_sge > 0) { @@ -3625,7 +4298,7 @@ initChainBuffers(MPT_ADAPTER *ioc) } num_chain++; - dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n", ioc->name, numSGE, num_sge, num_chain)); if (ioc->bus_type == SPI) @@ -3642,7 +4315,7 @@ initChainBuffers(MPT_ADAPTER *ioc) return -1; ioc->ChainToChain = (int *) mem; - dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n", ioc->name, mem, sz)); } else { mem = (u8 *) ioc->ChainToChain; @@ -3651,7 +4324,6 @@ initChainBuffers(MPT_ADAPTER *ioc) return num_chain; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * PrimeIocFifos - Initialize IOC request and reply FIFOs. * @ioc: Pointer to MPT_ADAPTER structure @@ -3661,7 +4333,7 @@ initChainBuffers(MPT_ADAPTER *ioc) * reply frames. * * Returns 0 for success, non-zero for failure. - */ + **/ static int PrimeIocFifos(MPT_ADAPTER *ioc) { @@ -3670,30 +4342,53 @@ PrimeIocFifos(MPT_ADAPTER *ioc) dma_addr_t alloc_dma; u8 *mem; int i, reply_sz, sz, total_size, num_chain; + u64 dma_mask; - /* Prime reply FIFO... */ + dma_mask = 0; + /* Prime reply FIFO... */ if (ioc->reply_frames == NULL) { if ( (num_chain = initChainBuffers(ioc)) < 0) return -1; + /* + * 1078 errata workaround for the 36GB limitation + */ + if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 && + ioc->dma_mask > MPT_DMA_35BIT_MASK) { + if (!pci_set_dma_mask(ioc->pcidev, DMA_32BIT_MASK) + && !pci_set_consistent_dma_mask(ioc->pcidev, + DMA_32BIT_MASK)) { + dma_mask = MPT_DMA_35BIT_MASK; + d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "setting 35 bit addressing for " + "Request/Reply/Chain and Sense Buffers\n", + ioc->name)); + } else { + d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "failed setting 35 bit addressing for " + "Request/Reply/Chain and Sense Buffers\n", + ioc->name)); + } + } + total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth); - dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n", ioc->name, ioc->reply_sz, ioc->reply_depth)); - dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n", ioc->name, reply_sz, reply_sz)); sz = (ioc->req_sz * ioc->req_depth); - dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n", ioc->name, ioc->req_sz, ioc->req_depth)); - dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n", ioc->name, sz, sz)); total_size += sz; sz = num_chain * ioc->req_sz; /* chain buffer pool size */ - dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n", ioc->name, ioc->req_sz, num_chain)); - dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n", ioc->name, sz, sz, num_chain)); total_size += sz; @@ -3704,7 +4399,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) goto out_fail; } - dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n", + 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)); memset(mem, 0, total_size); @@ -3715,7 +4410,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) ioc->reply_frames = (MPT_FRAME_HDR *) mem; ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); - dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n", ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); alloc_dma += reply_sz; @@ -3726,7 +4421,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) ioc->req_frames = (MPT_FRAME_HDR *) mem; ioc->req_frames_dma = alloc_dma; - dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n", ioc->name, mem, (void *)(ulong)alloc_dma)); ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); @@ -3740,7 +4435,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma, sz, MTRR_TYPE_WRCOMB, 1); - dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n", + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n", ioc->name, ioc->req_frames_dma, sz)); #endif @@ -3752,7 +4447,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) ioc->ChainBuffer = mem; ioc->ChainBufferDMA = alloc_dma; - dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n", ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA)); /* Initialize the free chain Q. @@ -3797,7 +4492,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF); ioc->alloc_total += sz; - dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n", ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma)); } @@ -3805,7 +4500,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) /* Post Reply frames to FIFO */ alloc_dma = ioc->alloc_dma; - dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n", + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n", ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); for (i = 0; i < ioc->reply_depth; i++) { @@ -3814,9 +4509,16 @@ PrimeIocFifos(MPT_ADAPTER *ioc) alloc_dma += ioc->reply_sz; } + if (dma_mask == MPT_DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev, + ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev, + ioc->dma_mask)) + d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "restoring 64 bit addressing\n", ioc->name)); + return 0; out_fail: + if (ioc->alloc != NULL) { sz = ioc->alloc_sz; pci_free_consistent(ioc->pcidev, @@ -3833,10 +4535,16 @@ out_fail: ioc->sense_buf_pool, ioc->sense_buf_pool_dma); ioc->sense_buf_pool = NULL; } + + if (dma_mask == MPT_DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev, + DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(ioc->pcidev, + DMA_64BIT_MASK)) + d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "restoring 64 bit addressing\n", ioc->name)); + return -1; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_handshake_req_reply_wait - Send MPT request to and receive reply * from IOC via doorbell handshake method. @@ -3854,7 +4562,7 @@ out_fail: * greater than 1 byte in size. * * Returns 0 for success, non-zero for failure. - */ + **/ static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait, int sleepFlag) @@ -3886,7 +4594,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; - dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n", + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n", ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); /* Read doorbell and check for active bit */ @@ -3921,10 +4629,10 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER failcnt++; } - dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req)); - DBG_DUMP_REQUEST_FRAME_HDR(req) + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req)); + DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req); - dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n", + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n", ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : "")); /* @@ -3933,7 +4641,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0) failcnt++; - dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n", + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n", ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : "")); /* @@ -3948,7 +4656,6 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER return -failcnt; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge * @ioc: Pointer to MPT_ADAPTER structure @@ -3960,7 +4667,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER * bit in its IntStatus register being clear. * * Returns a negative value on failure, else wait loop count. - */ + **/ static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag) { @@ -3989,7 +4696,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int } if (cntdn) { - dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n", + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n", ioc->name, count)); return count; } @@ -3999,7 +4706,6 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int return -1; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit * @ioc: Pointer to MPT_ADAPTER structure @@ -4010,7 +4716,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register. * * Returns a negative value on failure, else wait loop count. - */ + **/ static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) { @@ -4021,24 +4727,24 @@ 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++; } } if (cntdn) { - dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n", + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n", ioc->name, count, howlong)); return count; } @@ -4048,7 +4754,6 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int return -1; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * WaitForDoorbellReply - Wait for and capture an IOC handshake reply. * @ioc: Pointer to MPT_ADAPTER structure @@ -4060,7 +4765,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int * of 128 bytes of reply data. * * Returns a negative value on failure, else size of reply in WORDS. - */ + **/ static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) { @@ -4090,7 +4795,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i } } - dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n", + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n", ioc->name, t, le32_to_cpu(*(u32 *)hs_reply), failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); @@ -4126,15 +4831,14 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i } #endif - dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name)); - DBG_DUMP_REPLY_FRAME(mptReply) + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name)); + DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply); - dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n", + dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n", ioc->name, t, u16cnt/2)); return u16cnt/2; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * GetLanConfigPages - Fetch LANConfig pages. * @ioc: Pointer to MPT_ADAPTER structure @@ -4144,7 +4848,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i * -EPERM if not allowed due to ISR context * -EAGAIN if no msg frames currently available * -EFAULT for non-successful reply or no reply (timeout) - */ + **/ static int GetLanConfigPages(MPT_ADAPTER *ioc) { @@ -4245,7 +4949,6 @@ GetLanConfigPages(MPT_ADAPTER *ioc) return rc; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table * @ioc: Pointer to MPT_ADAPTER structure @@ -4258,9 +4961,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc) * NOTE: Don't use not this function during interrupt time. * * Returns 0 for success, non-zero error - */ - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + **/ int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) { @@ -4268,7 +4969,14 @@ mptbase_sas_persist_operation(MPT_ADAPTE SasIoUnitControlReply_t *sasIoUnitCntrReply; MPT_FRAME_HDR *mf = NULL; MPIHeader_t *mpi_hdr; + int ret = 0; + unsigned long timeleft; + + mutex_lock(&ioc->mptbase_cmds.mutex); + /* init the internal cmd struct */ + memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); + INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) /* insure garbage is not sent to fw */ switch(persist_opcode) { @@ -4278,8 +4986,8 @@ mptbase_sas_persist_operation(MPT_ADAPTE break; default: - return -1; - break; + ret = -1; + goto out; } printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode); @@ -4288,7 +4996,8 @@ mptbase_sas_persist_operation(MPT_ADAPTE */ if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { printk("%s: no msg frames!\n",__FUNCTION__); - return -1; + ret = -1; + goto out; } mpi_hdr = (MPIHeader_t *) mf; @@ -4298,31 +5007,44 @@ mptbase_sas_persist_operation(MPT_ADAPTE sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext; sasIoUnitCntrReq->Operation = persist_opcode; - init_timer(&ioc->persist_timer); - ioc->persist_timer.data = (unsigned long) ioc; - ioc->persist_timer.function = mpt_timer_expired; - ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */; - ioc->persist_wait_done=0; - add_timer(&ioc->persist_timer); mpt_put_msg_frame(mpt_base_index, ioc, mf); - wait_event(mpt_waitq, ioc->persist_wait_done); + timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ); + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + printk("%s: failed\n", __FUNCTION__); + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", + ioc->name, __FUNCTION__); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + } + goto out; + } + + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + ret = -1; + goto out; + } sasIoUnitCntrReply = - (SasIoUnitControlReply_t *)ioc->persist_reply_frame; + (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply; if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { - printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", - __FUNCTION__, - sasIoUnitCntrReply->IOCStatus, - sasIoUnitCntrReply->IOCLogInfo); - return -1; - } + printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", __FUNCTION__, + sasIoUnitCntrReply->IOCStatus, sasIoUnitCntrReply->IOCLogInfo); + printk("%s: failed\n",__FUNCTION__); + ret = -1; + } else + printk("%s: success\n",__FUNCTION__); + out: - printk("%s: success\n",__FUNCTION__); - return 0; + CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) + mutex_unlock(&ioc->mptbase_cmds.mutex); + return ret; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - static void mptbase_raid_process_event_data(MPT_ADAPTER *ioc, MpiEventDataRaid_t * pRaidEventData) @@ -4453,7 +5175,6 @@ mptbase_raid_process_event_data(MPT_ADAP } } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * GetIoUnitPage2 - Retrieve BIOS version and boot order information. * @ioc: Pointer to MPT_ADAPTER structure @@ -4463,7 +5184,7 @@ mptbase_raid_process_event_data(MPT_ADAP * -EPERM if not allowed due to ISR context * -EAGAIN if no msg frames currently available * -EFAULT for non-successful reply or no reply (timeout) - */ + **/ static int GetIoUnitPage2(MPT_ADAPTER *ioc) { @@ -4511,7 +5232,6 @@ GetIoUnitPage2(MPT_ADAPTER *ioc) return rc; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2 * @ioc: Pointer to a Adapter Strucutre @@ -4531,7 +5251,7 @@ GetIoUnitPage2(MPT_ADAPTER *ioc) * Both valid * Return 0 * CHECK - what type of locking mechanisms should be used???? - */ + **/ static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) { @@ -4554,7 +5274,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc ioc->spi_data.nvram = (int *) mem; - dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n", + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n", ioc->name, ioc->spi_data.nvram, sz)); } @@ -4590,8 +5310,9 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc ioc->spi_data.minSyncFactor = MPT_ASYNC; ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN; rc = 1; - ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n", - ioc->name, ioc->spi_data.minSyncFactor)); + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Unable to read PortPage0 minSyncFactor=%x\n", + ioc->name, ioc->spi_data.minSyncFactor)); } else { /* Save the Port Page 0 data */ @@ -4601,7 +5322,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) { ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; - ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n", + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "noQas due to Capabilities=%x\n", ioc->name, pPP0->Capabilities)); } ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; @@ -4610,7 +5331,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc ioc->spi_data.maxSyncOffset = (u8) (data >> 16); data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK; ioc->spi_data.minSyncFactor = (u8) (data >> 8); - ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n", + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PortPage0 minSyncFactor=%x\n", ioc->name, ioc->spi_data.minSyncFactor)); } else { ioc->spi_data.maxSyncOffset = 0; @@ -4626,7 +5347,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc if (ioc->spi_data.minSyncFactor < MPT_ULTRA) { ioc->spi_data.minSyncFactor = MPT_ULTRA; - ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n", + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HVD or SE detected, minSyncFactor=%x\n", ioc->name, ioc->spi_data.minSyncFactor)); } } @@ -4662,6 +5383,38 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc /* Nvram data is left with INVALID mark */ rc = 1; + } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) { + + /* This is an ATTO adapter, read Page2 accordingly + */ + ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf; + ATTODeviceInfo_t *pdevice = NULL; + u16 ATTOFlags; + + /* Save the Port Page 2 data + * (reformat into a 32bit quantity) + */ + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { + pdevice = &pPP2->DeviceSettings[ii]; + ATTOFlags = le16_to_cpu(pdevice->ATTOFlags); + data = 0; + + /* Translate ATTO device flags to LSI format + */ + if (ATTOFlags & ATTOFLAG_DISC) + data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE); + if (ATTOFlags & ATTOFLAG_ID_ENB) + data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE); + if (ATTOFlags & ATTOFLAG_LUN_ENB) + data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE); + if (ATTOFlags & ATTOFLAG_TAGGED) + data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE); + if (!(ATTOFlags & ATTOFLAG_WIDE_ENB)) + data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE); + + data = (data << 16) | (pdevice->Period << 8) | 10; + ioc->spi_data.nvram[ii] = data; + } } else { SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf; MpiDeviceInfo_t *pdevice = NULL; @@ -4699,7 +5452,6 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc return rc; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_readScsiDevicePageHeaders - save version and length of SDP1 * @ioc: Pointer to a Adapter Strucutre @@ -4707,7 +5459,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc * * Return: -EFAULT if read of config page header fails * or 0 if success. - */ + **/ static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) { @@ -4742,21 +5494,81 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTE ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion; ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength; - dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n", + dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n", ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length)); - dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n", + dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n", ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length)); return 0; } +static void +mpt_read_ioc_pg_6(MPT_ADAPTER *ioc) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t header; + IOCPage6_t *pIoc6=NULL; + dma_addr_t ioc6_dma; + int iocpage6sz; + void *mem; + + /* Free the old page + */ + if (ioc->raid_data.pIocPg6) { + kfree(ioc->raid_data.pIocPg6); + ioc->raid_data.pIocPg6 = NULL; + } + + /* There is at least one physical disk. + * Read and save IOC Page 3 + */ + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 6; + header.PageType = MPI_CONFIG_PAGETYPE_IOC; + cfg.cfghdr.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.timeout = 0; + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (header.PageLength == 0) + goto out; + + /* Read Header good, alloc memory + */ + iocpage6sz = header.PageLength * 4; + pIoc6 = pci_alloc_consistent(ioc->pcidev, iocpage6sz, &ioc6_dma); + if (!pIoc6) + goto out; + + /* Read the Page and save the data + * into malloc'd memory. + */ + cfg.physAddr = ioc6_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + if (mpt_config(ioc, &cfg) != 0) + goto out; + + mem = kmalloc(iocpage6sz, GFP_ATOMIC); + if (!mem) + goto out; + + memcpy(mem, pIoc6, iocpage6sz); + ioc->raid_data.pIocPg6 = mem; + + out: + if (pIoc6) + pci_free_consistent(ioc->pcidev, iocpage6sz, pIoc6, ioc6_dma); +} + /** - * mpt_inactive_raid_list_free - * - * This clears this link list. - * - * @ioc - pointer to per adapter structure - * + * mpt_inactive_raid_list_free - This clears this link list. + * @ioc : pointer to per adapter structure + * **/ static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc) @@ -4776,15 +5588,13 @@ mpt_inactive_raid_list_free(MPT_ADAPTER } /** - * mpt_inactive_raid_volumes - * - * This sets up link list of phy_disk_nums for devices belonging in an inactive volume - * - * @ioc - pointer to per adapter structure - * @channel - volume channel - * @id - volume target id - * - * + * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums + * for devices belonging in an inactive volume + * + * @ioc : pointer to per adapter structure + * @channel : volume channel + * @id : volume target id + * **/ static void mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id) @@ -4793,10 +5603,12 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i ConfigPageHeader_t hdr; dma_addr_t dma_handle; pRaidVolumePage0_t buffer = NULL; - int i; + int i, j; RaidPhysDiskPage0_t phys_disk; + RaidPhysDiskPage1_t *phys_disk_1; struct inactive_raid_component_info *component_info; int handle_inactive_volumes; + int num_paths, device_is_online; memset(&cfg, 0 , sizeof(CONFIGPARMS)); memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); @@ -4841,8 +5653,31 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) continue; + if (phys_disk.PhysDiskStatus.State != + MPI_PHYSDISK0_STATUS_ONLINE) + continue; + + /* check to see if device is online by checking phys_disk_pg1 */ + device_is_online = 0; + num_paths = mpt_raid_phys_disk_get_num_paths(ioc, + buffer->PhysDisk[i].PhysDiskNum); + if (num_paths < 2) + continue; + phys_disk_1 = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk_1) + continue; + mpt_raid_phys_disk_pg1(ioc, buffer->PhysDisk[i].PhysDiskNum, + phys_disk_1); + for (j = 0; j < num_paths && !device_is_online; j++) + if (!phys_disk_1->Path[j].Flags) + device_is_online = 1; + kfree(phys_disk_1); + if (!device_is_online) + continue; + if ((component_info = kmalloc(sizeof (*component_info), - GFP_KERNEL)) == NULL) + GFP_KERNEL)) == NULL) continue; component_info->volumeID = id; @@ -4875,7 +5710,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i * -ENOMEM if pci_alloc failed **/ int -mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk) +mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, RaidPhysDiskPage0_t *phys_disk) { CONFIGPARMS cfg; ConfigPageHeader_t hdr; @@ -4885,7 +5720,9 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, memset(&cfg, 0 , sizeof(CONFIGPARMS)); memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t)); + hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION; hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; cfg.cfghdr.hdr = &hdr; cfg.physAddr = -1; @@ -4932,6 +5769,181 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, } /** + * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num + * @ioc: Pointer to a Adapter Structure + * @phys_disk_num: io unit unique phys disk num generated by the ioc + * + * Return: + * returns number paths + **/ +int +mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidPhysDiskPage1_t buffer = NULL; + int rc; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + + hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; + hdr.PageNumber = 1; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if (mpt_config(ioc, &cfg) != 0) { + rc = 0; + goto out; + } + + if (!hdr.PageLength) { + rc = 0; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) { + rc = 0; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = phys_disk_num; + + if (mpt_config(ioc, &cfg) != 0) { + rc = 0; + goto out; + } + + rc = buffer->NumPhysDiskPaths; + out: + + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); + + return rc; +} + +/** + * mpt_raid_phys_disk_pg1 - returns phys disk page 1 + * @ioc: Pointer to a Adapter Structure + * @phys_disk_num: io unit unique phys disk num generated by the ioc + * @phys_disk: requested payload data returned + * + * Return: + * 0 on success + * -EFAULT if read of config page header fails or data pointer not NULL + * -ENOMEM if pci_alloc failed + **/ +int +mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, RaidPhysDiskPage1_t *phys_disk) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidPhysDiskPage1_t buffer = NULL; + int rc; + int i; + __le64 sas_address; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + rc = 0; + + hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; + hdr.PageNumber = 1; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if (mpt_config(ioc, &cfg) != 0) { + rc = -EFAULT; + goto out; + } + + if (!hdr.PageLength) { + rc = -EFAULT; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) { + rc = -ENOMEM; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = phys_disk_num; + + if (mpt_config(ioc, &cfg) != 0) { + rc = -EFAULT; + goto out; + } + + phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths; + phys_disk->PhysDiskNum = phys_disk_num; + for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) { + phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID; + phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus; + phys_disk->Path[i].OwnerIdentifier = buffer->Path[i].OwnerIdentifier; + phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags); + memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); + memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64)); + memcpy(&sas_address, &buffer->Path[i].OwnerWWID, sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); + memcpy(&phys_disk->Path[i].OwnerWWID, &sas_address, sizeof(__le64)); + } + + out: + + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); + + return rc; +} + +/** + * mpt_sort_ioc_pg2 - compare function for sorting volumes + * in ascending order + * @a: ioc_pg2 raid volume page + * @b: ioc_pg2 raid volume page + * + * Return: + * 0 same, 1 (a is bigger), -1 (b is bigger) + **/ +static int +mpt_sort_ioc_pg2(const void *a, const void *b) +{ + ConfigPageIoc2RaidVol_t * volume_a = (ConfigPageIoc2RaidVol_t *)a; + ConfigPageIoc2RaidVol_t * volume_b = (ConfigPageIoc2RaidVol_t *)b; + + if (volume_a->VolumeBus == volume_b->VolumeBus) { + if (volume_a->VolumeID == volume_b->VolumeID) + return 0; + if (volume_a->VolumeID < volume_b->VolumeID) + return -1; + return 1; + } + if (volume_a->VolumeBus < volume_b->VolumeBus) + return -1; + return 1; +} + +/** * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes * @ioc: Pointer to a Adapter Strucutre * @portnum: IOC port number @@ -4994,16 +6006,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); @@ -5162,12 +6180,15 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) cfg.physAddr = ioc1_dma; 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); - dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n", + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n", ioc->name, tmp)); if (tmp > MPT_COALESCING_TIMEOUT) { @@ -5178,26 +6199,26 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) cfg.dir = 1; cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; if (mpt_config(ioc, &cfg) == 0) { - dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n", + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n", ioc->name, MPT_COALESCING_TIMEOUT)); cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM; if (mpt_config(ioc, &cfg) == 0) { - dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n", + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset NVRAM Coalescing Timeout to = %d\n", ioc->name, MPT_COALESCING_TIMEOUT)); } else { - dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n", + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset NVRAM Coalescing Timeout Failed\n", ioc->name)); } } else { - dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n", + dprintk(ioc, printk(MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n", ioc->name)); } } } else { - dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name)); + dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name)); } } @@ -5206,55 +6227,94 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) return; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static void +mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t buf_dma; + ManufacturingPage0_t *pbuf = NULL; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + + hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.timeout = 10; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (!cfg.cfghdr.hdr->PageLength) + goto out; + + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma); + if (!pbuf) + goto out; + + cfg.physAddr = buf_dma; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name)); + memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly)); + memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer)); + + out: + + if (pbuf) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); +} + /** * SendEventNotification - Send EventNotification (on or off) request to adapter * @ioc: Pointer to MPT_ADAPTER structure * @EvSwitch: Event switch flags - */ + * @sleepFlag: Specifies whether the process can sleep + **/ static int -SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch) +SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag) { - EventNotification_t *evnp; - - evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc); - if (evnp == NULL) { - devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n", - ioc->name)); - return 0; - } - memset(evnp, 0, sizeof(*evnp)); + EventNotification_t evn; + MPIDefaultReply_t reply_buf; - devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp)); + memset(&evn, 0, sizeof(EventNotification_t)); + memset(&reply_buf, 0, sizeof(MPIDefaultReply_t)); - evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION; - evnp->ChainOffset = 0; - evnp->MsgFlags = 0; - evnp->Switch = EvSwitch; + evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION; + evn.Switch = EvSwitch; + evn.MsgContext = cpu_to_le32(mpt_base_index << 16); - mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp); + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Sending EventNotification (%d) request %p\n", + ioc->name, EvSwitch, &evn)); - return 0; + return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t), + (u32*)&evn, sizeof(MPIDefaultReply_t), (u16*)&reply_buf, 30, + sleepFlag); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * SendEventAck - Send EventAck request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @evnp: Pointer to original EventNotification request - */ + **/ static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) { EventAck_t *pAck; if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { - dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n", + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", ioc->name,__FUNCTION__)); return -1; } - devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name)); + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name)); pAck->Function = MPI_FUNCTION_EVENT_ACK; pAck->ChainOffset = 0; @@ -5269,7 +6329,6 @@ SendEventAck(MPT_ADAPTER *ioc, EventNoti return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_config - Generic function to issue config message * @ioc: Pointer to an adapter structure @@ -5282,35 +6341,62 @@ SendEventAck(MPT_ADAPTER *ioc, EventNoti * -EPERM if not allowed due to ISR context * -EAGAIN if no msg frames currently available * -EFAULT for non-successful reply or no reply (timeout) - */ + **/ int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) { Config_t *pReq; + ConfigReply_t *pReply; ConfigExtendedPageHeader_t *pExtHdr = NULL; MPT_FRAME_HDR *mf; - unsigned long flags; - int ii, rc; + int ii; int flagsLength; - int in_isr; + long timeout; + int ret; + u8 page_type = 0, extend_page; + unsigned long timeleft; + unsigned long flags; + u8 issue_hard_reset = 0; + u8 retry_count = 0; - /* Prevent calling wait_event() (below), if caller happens - * to be in ISR context, because that is fatal! - */ - in_isr = in_interrupt(); - if (in_isr) { - dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n", - ioc->name)); + if (in_interrupt()) return -EPERM; + + /* don't send a config page during diag reset */ + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: busy with host reset\n", ioc->name, __FUNCTION__)); + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return -EBUSY; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + /* don't send if no chance of success */ + if (!ioc->active || + mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) { + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: ioc not operational, %d, %xh\n", + ioc->name, __FUNCTION__, ioc->active, + mpt_GetIocState(ioc, 0))); + return -EFAULT; } + retry_config: + mutex_lock(&ioc->mptbase_cmds.mutex); + /* init the internal cmd struct */ + memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); + INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) + /* Get and Populate a free Frame */ if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { - dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n", - ioc->name)); - return -EAGAIN; + dcprintk(ioc, printk(MYIOC_s_WARN_FMT + "mpt_config: no msg frames!\n", ioc->name)); + ret = -EAGAIN; + goto out; } + pReq = (Config_t *)mf; pReq->Action = pCfg->action; pReq->Reserved = 0; @@ -5336,7 +6422,9 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS pReq->ExtPageType = pExtHdr->ExtPageType; pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; - /* Page Length must be treated as a reserved field for the extended header. */ + /* Page Length must be treated as a reserved field for the + * extended header. + */ pReq->Header.PageLength = 0; } @@ -5349,126 +6437,126 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS else flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; - if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) { + if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == + MPI_CONFIG_PAGETYPE_EXTENDED) { flagsLength |= pExtHdr->ExtPageLength * 4; - - dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n", - ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action)); - } - else { + page_type = pReq->ExtPageType; + extend_page = 1; + } else { flagsLength |= pCfg->cfghdr.hdr->PageLength * 4; - - dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n", - ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action)); + page_type = pReq->Header.PageType; + extend_page = 0; } - mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); - - /* Append pCfg pointer to end of mf - */ - *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg; - - /* Initalize the timer - */ - init_timer(&pCfg->timer); - pCfg->timer.data = (unsigned long) ioc; - pCfg->timer.function = mpt_timer_expired; - pCfg->wait_done = 0; - - /* Set the timer; ensure 10 second minimum */ - if (pCfg->timeout < 10) - pCfg->timer.expires = jiffies + HZ*10; - else - pCfg->timer.expires = jiffies + HZ*pCfg->timeout; - - /* Add to end of Q, set timer and then issue this command */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_add_tail(&pCfg->linkage, &ioc->configQ); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); + dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Sending Config request type 0x%x, page 0x%x and action %d\n", + ioc->name, page_type, pReq->Header.PageNumber, pReq->Action)); - add_timer(&pCfg->timer); + ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); + timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout; mpt_put_msg_frame(mpt_base_index, ioc, mf); - wait_event(mpt_waitq, pCfg->wait_done); - - /* mf has been freed - do not access */ - - rc = pCfg->status; + timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, timeout); + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Failed Sending Config request type 0x%x, page 0x%x," + " action %d, status %xh, time left %ld\n\n", + ioc->name, page_type, pReq->Header.PageNumber, + pReq->Action, ioc->mptbase_cmds.status, timeleft)); + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) + issue_hard_reset = 1; + goto out; + } - return rc; -} + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + ret = -1; + goto out; + } + pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply; + ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; + if (ret == MPI_IOCSTATUS_SUCCESS) { + if (extend_page) { + pCfg->cfghdr.ehdr->ExtPageLength = + le16_to_cpu(pReply->ExtPageLength); + pCfg->cfghdr.ehdr->ExtPageType = + pReply->ExtPageType; + } + pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; + pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; + pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; + pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mpt_timer_expired - Callback for timer process. - * Used only internal config functionality. - * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long - */ -static void -mpt_timer_expired(unsigned long data) -{ - MPT_ADAPTER *ioc = (MPT_ADAPTER *) data; + } - dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name)); + if (retry_count) + printk(MYIOC_s_INFO_FMT "Retry completed ret=0x%x timeleft=%ld\n", + ioc->name, ret, timeleft); - /* Perform a FW reload */ - if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) - printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name); + dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n", + ret, le32_to_cpu(pReply->IOCLogInfo))); - /* No more processing. - * Hard reset clean-up will wake up - * process and free all resources. - */ - dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name)); + out: - return; + CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) + mutex_unlock(&ioc->mptbase_cmds.mutex); + if (issue_hard_reset) { + issue_hard_reset = 0; + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", + ioc->name, __FUNCTION__); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + /* attempt one retry for a timed out command */ + if (!retry_count) { + printk(MYIOC_s_INFO_FMT + "Attempting Retry Config request type 0x%x, page 0x%x," + " action %d\n", ioc->name, page_type, + pCfg->cfghdr.hdr->PageNumber, pCfg->action); + retry_count++; + goto retry_config; + } + } + return ret; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_ioc_reset - Base cleanup for hard reset * @ioc: Pointer to the adapter structure * @reset_phase: Indicates pre- or post-reset functionality * - * Remark: Frees resources with internally generated commands. - */ -static int -mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) -{ - CONFIGPARMS *pCfg; - unsigned long flags; - - dprintk((KERN_WARNING MYNAM - ": IOC %s_reset routed to MPT base driver!\n", - reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - - if (reset_phase == MPT_IOC_SETUP_RESET) { - ; - } else if (reset_phase == MPT_IOC_PRE_RESET) { - /* If the internal config Q is not empty - - * delete timer. MF resources will be freed when - * the FIFO's are primed. - */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_for_each_entry(pCfg, &ioc->configQ, linkage) - del_timer(&pCfg->timer); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - } else { - CONFIGPARMS *pNext; - - /* Search the configQ for internal commands. - * Flush the Q, and wake up all suspended threads. - */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) { - list_del(&pCfg->linkage); - - pCfg->status = MPT_CONFIG_ERROR; - pCfg->wait_done = 1; - wake_up(&mpt_waitq); + * Remark: Frees resources with internally generated commands. + **/ +static int +mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) +{ + switch(reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); + ioc->taskmgmt_quiesce_io = 1; + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); +/* wake up mptbase_cmds */ + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->mptbase_cmds.done); + } +/* wake up taskmgmt_cmds */ + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->taskmgmt_cmds.done); } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); + break; + default: + break; } return 1; /* currently means nothing really */ @@ -5476,16 +6564,11 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int rese #ifdef CONFIG_PROC_FS /* { */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff... - */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries. * * Returns 0 for success, non-zero for failure. - */ + **/ static int procmpt_create(void) { @@ -5506,12 +6589,11 @@ procmpt_create(void) return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries. * * Returns 0 for success, non-zero for failure. - */ + **/ static void procmpt_destroy(void) { @@ -5520,7 +6602,6 @@ procmpt_destroy(void) remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * procmpt_summary_read - Handle read request of a summary file * @buf: Pointer to area to write information @@ -5532,7 +6613,7 @@ procmpt_destroy(void) * * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary. * Returns number of characters written to process performing the read. - */ + **/ static int procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -5564,7 +6645,6 @@ procmpt_summary_read(char *buf, char **s MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * procmpt_version_read - Handle read request from /proc/mpt/version. * @buf: Pointer to area to write information @@ -5575,11 +6655,11 @@ procmpt_summary_read(char *buf, char **s * @data: Pointer * * Returns number of characters written to process performing the read. - */ + **/ static int procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - int ii; + u8 cb_idx; int scsi, fc, sas, lan, ctl, targ, dmp; char *drvname; int len; @@ -5588,10 +6668,10 @@ procmpt_version_read(char *buf, char **s len += sprintf(buf+len, " Fusion MPT base driver\n"); scsi = fc = sas = lan = ctl = targ = dmp = 0; - for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { drvname = NULL; - if (MptCallbacks[ii]) { - switch (MptDriverClass[ii]) { + if (MptCallbacks[cb_idx]) { + switch (MptDriverClass[cb_idx]) { case MPTSPI_DRIVER: if (!scsi++) drvname = "SPI host"; break; @@ -5620,7 +6700,6 @@ procmpt_version_read(char *buf, char **s MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info. * @buf: Pointer to area to write information @@ -5631,7 +6710,7 @@ procmpt_version_read(char *buf, char **s * @data: Pointer * * Returns number of characters written to process performing the read. - */ + **/ static int procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -5717,7 +6796,6 @@ procmpt_iocinfo_read(char *buf, char **s #endif /* CONFIG_PROC_FS } */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc) { @@ -5733,7 +6811,6 @@ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTE } } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer. * @ioc: Pointer to MPT_ADAPTER structure @@ -5744,7 +6821,7 @@ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTE * * This routine writes (english readable) ASCII text, which represents * a summary of IOC information, to a buffer. - */ + **/ void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan) { @@ -5785,6 +6862,220 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, /* * Reset Handling */ + +/** + * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment + * @ioc: Pointer to MPT_ADAPTER structure + * + * Returns 0 for SUCCESS or -1 if FAILED. + * + * If -1 is return, then it was not possible to set the flags + **/ +int +mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) +{ + unsigned long flags; + int retval; + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress || + (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) { + retval = -1; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + goto out; + } + retval = 0; + ioc->taskmgmt_in_progress = 1; + ioc->taskmgmt_quiesce_io = 1; + if (ioc->alt_ioc) { + ioc->alt_ioc->taskmgmt_in_progress = 1; + ioc->alt_ioc->taskmgmt_quiesce_io = 1; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + out: + return retval; +} + +/** + * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +void +mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + ioc->taskmgmt_in_progress = 0; + ioc->taskmgmt_quiesce_io = 0; + if (ioc->alt_ioc) { + ioc->alt_ioc->taskmgmt_in_progress = 0; + ioc->alt_ioc->taskmgmt_quiesce_io = 0; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +} + +/** + * mpt_halt_firmware - Halts the firmware if it is operational and panic + * the kernel + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +void +mpt_halt_firmware(MPT_ADAPTER *ioc) +{ + u32 ioc_raw_state; + + ioc_raw_state = mpt_GetIocState(ioc, 0); + + if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { + printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n", + ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); + if(mpt_fwfault_debug == 2) + for(;;); + else + panic("%s: IOC Fault (%04xh)!!!\n",ioc->name, + ioc_raw_state & MPI_DOORBELL_DATA_MASK); + } else { + CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00); + if(mpt_fwfault_debug == 2) { + printk("%s: Firmware is halted due to command timeout\n" + ,ioc->name); + for(;;); + } + else + panic("%s: Firmware is halted due to command timeout\n", + ioc->name); + } +} + +/** + * mpt_SoftResetHandler - Issues a less expensive reset + * @ioc: Pointer to MPT_ADAPTER structure + * @sleepFlag: Indicates if sleep or schedule must be called. + + * + * Returns 0 for SUCCESS or -1 if FAILED. + * + * Message Unit Reset - instructs the IOC to reset the Reply Post and + * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded. + * All posted buffers are freed, and event notification is turned off. + * IOC doesnt reply to any outstanding request. This will transfer IOC + * to READY state. + **/ +int +mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag) +{ + int rc; + int ii; + u8 cb_idx; + unsigned long flags; + u32 ioc_state; + unsigned long time_count; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n", ioc->name)); + + ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK; + + if(mpt_fwfault_debug) + mpt_halt_firmware(ioc); + + if (ioc_state == MPI_IOC_STATE_FAULT || ioc_state == MPI_IOC_STATE_RESET) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "skipping, either in FAULT or RESET state!\n", ioc->name)); + return -1; + } + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return -1; + } + ioc->ioc_reset_in_progress = 1; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + rc = -1; + + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) + mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); + } + + /* Disable reply interrupts (also blocks FreeQ) */ + CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); + ioc->active = 0; + time_count = jiffies; + + rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); + + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) + mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); + } + + if (rc) + goto out; + + ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK; + if (ioc_state != MPI_IOC_STATE_READY) + goto out; + + for (ii = 0; ii < 5; ii++) { + /* Get IOC facts! Allow 5 retries */ + if ((rc = GetIocFacts(ioc, sleepFlag, + MPT_HOSTEVENT_IOC_RECOVER)) == 0) + break; + if (sleepFlag == CAN_SLEEP) { + msleep(100); + } else { + mdelay(100); + } + } + if (ii == 5) + goto out; + + if ((rc = PrimeIocFifos(ioc)) != 0) + goto out; + + if ((rc = SendIocInit(ioc, sleepFlag)) != 0) + goto out; + + if ((rc = SendEventNotification(ioc, 1, sleepFlag)) != 0) + goto out; + + if (ioc->hard_resets < -1) + ioc->hard_resets++; + + /* + * At this point, we know soft reset succeeded. + */ + + ioc->active = 1; + CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); + + out: + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + ioc->ioc_reset_in_progress = 0; + ioc->taskmgmt_quiesce_io = 0; + ioc->taskmgmt_in_progress = 0; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + if (ioc->active) { /* otherwise, hard reset coming */ + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) + mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); + } + } + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler: completed (%d seconds): %s\n", + ioc->name, jiffies_to_msecs(jiffies - time_count)/1000, + ((rc == 0) ? "SUCCESS" : "FAILED"))); + + return rc; +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_HardResetHandler - Generic reset handler @@ -5801,81 +7092,97 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, * FW reload/initialization failed. * * Returns 0 for SUCCESS or -1 if FAILED. - */ + **/ int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) { - int rc; + int rc; + u8 cb_idx; unsigned long flags; + unsigned long time_count; - dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name)); #ifdef MFCNT printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name); printk("MF count 0x%x !\n", ioc->mfcnt); #endif + if(mpt_fwfault_debug) + mpt_halt_firmware(ioc); + /* Reset the adapter. Prevent more than 1 call to * mpt_do_ioc_recovery at any instant in time. */ - spin_lock_irqsave(&ioc->diagLock, flags); - if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){ - spin_unlock_irqrestore(&ioc->diagLock, flags); + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); return 0; - } else { - ioc->diagPending = 1; } - spin_unlock_irqrestore(&ioc->diagLock, flags); + ioc->ioc_reset_in_progress = 1; + if (ioc->alt_ioc) + ioc->alt_ioc->ioc_reset_in_progress = 1; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - /* FIXME: If do_ioc_recovery fails, repeat.... - */ /* The SCSI driver needs to adjust timeouts on all current * commands prior to the diagnostic reset being issued. * Prevents timeouts occurring during a diagnostic reset...very bad. * For all other protocol drivers, this is a no-op. */ - { - int ii; - int r = 0; - - for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { - if (MptResetHandlers[ii]) { - dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n", - ioc->name, ii)); - r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET); - if (ioc->alt_ioc) { - dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, ii)); - r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET); - } - } + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { + mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); + if (ioc->alt_ioc) + mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET); } } + time_count = jiffies; if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) { printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name); + } else { + if (ioc->hard_resets < -1) + ioc->hard_resets++; } - ioc->reload_fw = 0; - if (ioc->alt_ioc) - ioc->alt_ioc->reload_fw = 0; - spin_lock_irqsave(&ioc->diagLock, flags); - ioc->diagPending = 0; - if (ioc->alt_ioc) - ioc->alt_ioc->diagPending = 0; - spin_unlock_irqrestore(&ioc->diagLock, flags); + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + ioc->ioc_reset_in_progress = 0; + ioc->taskmgmt_quiesce_io = 0; + ioc->taskmgmt_in_progress = 0; + if (ioc->alt_ioc) { + ioc->alt_ioc->ioc_reset_in_progress = 0; + ioc->alt_ioc->taskmgmt_quiesce_io = 0; + ioc->alt_ioc->taskmgmt_in_progress = 0; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc)); + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { + mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); + if (ioc->alt_ioc) + mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET); + } + } + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler: completed (%d seconds): %s\n", + ioc->name, jiffies_to_msecs(jiffies - time_count)/1000, + ((rc == 0) ? "SUCCESS" : "FAILED"))); return rc; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#ifdef CONFIG_FUSION_LOGGING static void -EventDescriptionStr(u8 event, u32 evData0, char *evStr) +mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply) { char *ds = NULL; + u32 evData0; + int ii; + u8 event; + char *evStr = ioc->evStr; + + event = le32_to_cpu(pEventReply->Event) & 0xFF; + evData0 = le32_to_cpu(pEventReply->Data[0]); switch(event) { case MPI_EVENT_NONE: @@ -5909,9 +7216,9 @@ EventDescriptionStr(u8 event, u32 evData if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) ds = "Loop State(LIP) Change"; else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) - ds = "Loop State(LPE) Change"; /* ??? */ + ds = "Loop State(LPE) Change"; else - ds = "Loop State(LPB) Change"; /* ??? */ + ds = "Loop State(LPB) Change"; break; case MPI_EVENT_LOGOUT: ds = "Logout"; @@ -6007,6 +7314,11 @@ EventDescriptionStr(u8 event, u32 evData "SAS Device Status Change: Internal Device " "Reset : id=%d channel=%d", id, channel); break; + case MPI_EVENT_SAS_DEV_STAT_RC_CMPL_INTERNAL_DEV_RESET: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Internal Device " + "Reset Completed: id=%d channel=%d", id, channel); + break; case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: snprintf(evStr, EVENT_DESCR_STR_SZ, "SAS Device Status Change: Internal Task " @@ -6027,6 +7339,11 @@ EventDescriptionStr(u8 event, u32 evData "SAS Device Status Change: Internal Query " "Task : id=%d channel=%d", id, channel); break; + case MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Async Notification " + "Task : id=%d channel=%d", id, channel); + break; default: snprintf(evStr, EVENT_DESCR_STR_SZ, "SAS Device Status Change: Unknown: " @@ -6111,28 +7428,65 @@ EventDescriptionStr(u8 event, u32 evData } case MPI_EVENT_IR2: { + u8 id = (u8)(evData0); + u8 channel = (u8)(evData0 >> 8); + u8 phys_num = (u8)(evData0 >> 24); u8 ReasonCode = (u8)(evData0 >> 16); + switch (ReasonCode) { case MPI_EVENT_IR2_RC_LD_STATE_CHANGED: - ds = "IR2: LD State Changed"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: LD State Changed: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_PD_STATE_CHANGED: - ds = "IR2: PD State Changed"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: PD State Changed " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL: - ds = "IR2: Bad Block Table Full"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Bad Block Table Full: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_PD_INSERTED: - ds = "IR2: PD Inserted"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: PD Inserted: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_PD_REMOVED: - ds = "IR2: PD Removed"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: PD Removed: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: - ds = "IR2: Foreign CFG Detected"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Foreign CFG Detected: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR: - ds = "IR2: Rebuild Medium Error"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Rebuild Medium Error: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Dual Port Added: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Dual Port Removed: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; default: ds = "IR2"; @@ -6156,25 +7510,46 @@ EventDescriptionStr(u8 event, u32 evData { u8 phy_num = (u8)(evData0); u8 port_num = (u8)(evData0 >> 8); - u8 port_width = (u8)(evData0 >> 16); + u8 num_phys = (u8)(evData0 >> 16); u8 primative = (u8)(evData0 >> 24); + char *primative_str = NULL; + + switch (primative) { + case MPI_EVENT_PRIMITIVE_CHANGE: + primative_str = "change"; + break; + case MPI_EVENT_PRIMITIVE_EXPANDER: + primative_str = "expander"; + break; + case MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT: + primative_str = "asyn event"; + break; + default: + primative_str = "reserved"; + break; + } snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Broadcase Primative: phy=%d port=%d " - "width=%d primative=0x%02x", - phy_num, port_num, port_width, primative); + "SAS Broadcast Primative: phy=%d port=%d " + "num_phys=%d primative=%s (0x%02x)", + phy_num, port_num, num_phys, primative_str, primative); break; } case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: { u8 reason = (u8)(evData0); - u8 port_num = (u8)(evData0 >> 8); - u16 handle = le16_to_cpu(evData0 >> 16); - snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Initiator Device Status Change: reason=0x%02x " - "port=%d handle=0x%04x", - reason, port_num, handle); + switch (reason) { + case MPI_EVENT_SAS_INIT_RC_ADDED: + ds = "SAS Initiator Status Change: Added"; + break; + case MPI_EVENT_SAS_INIT_RC_REMOVED: + ds = "SAS Initiator Status Change: Deleted"; + break; + default: + ds = "SAS Initiator Status Change"; + break; + } break; } @@ -6222,6 +7597,24 @@ EventDescriptionStr(u8 event, u32 evData break; } + case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: + { + u8 reason = (u8)(evData0); + + switch (reason) { + case MPI_EVENT_SAS_EXP_RC_ADDED: + ds = "Expander Status Change: Added"; + break; + case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING: + ds = "Expander Status Change: Deleted"; + break; + default: + ds = "Expander Status Change"; + break; + } + break; + } + /* * MPT base "custom" events may be added here... */ @@ -6231,9 +7624,21 @@ EventDescriptionStr(u8 event, u32 evData } if (ds) strncpy(evStr, ds, EVENT_DESCR_STR_SZ); + + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "MPT event:(%02Xh) : %s\n", + ioc->name, event, evStr)); + + devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM + ": Event data:\n")); + for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++) + devtverboseprintk(ioc, printk(" %08x", + le32_to_cpu(pEventReply->Data[ii]))); + devtverboseprintk(ioc, printk(KERN_DEBUG "\n")); } +#endif -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * ProcessEventNotification - Route EventNotificationReply to all event handlers * @ioc: Pointer to MPT_ADAPTER structure @@ -6243,40 +7648,30 @@ EventDescriptionStr(u8 event, u32 evData * Routes a received EventNotificationReply to all currently registered * event handlers. * Returns sum of event handlers return values. - */ + **/ static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers) { u16 evDataLen; u32 evData0 = 0; -// u32 evCtx; int ii; + u8 cb_idx; int r = 0; int handlers = 0; - char evStr[EVENT_DESCR_STR_SZ]; u8 event; + /* * Do platform normalization of values */ event = le32_to_cpu(pEventReply->Event) & 0xFF; -// evCtx = le32_to_cpu(pEventReply->EventContext); evDataLen = le16_to_cpu(pEventReply->EventDataLength); - if (evDataLen) { + if (evDataLen) evData0 = le32_to_cpu(pEventReply->Data[0]); - } - - EventDescriptionStr(event, evData0, evStr); - devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n", - ioc->name, - event, - evStr)); -#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS) - printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO); - for (ii = 0; ii < evDataLen; ii++) - printk(" %08x", le32_to_cpu(pEventReply->Data[ii])); - printk("\n"); +#ifdef CONFIG_FUSION_LOGGING + if (evDataLen) + mpt_display_event_info(ioc, pEventReply); #endif /* @@ -6329,11 +7724,11 @@ ProcessEventNotification(MPT_ADAPTER *io /* * Call each currently registered protocol event handler. */ - for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { - if (MptEvHandlers[ii]) { - devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n", - ioc->name, ii)); - r += (*(MptEvHandlers[ii]))(ioc, pEventReply); + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptEvHandlers[cb_idx]) { + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Routing Event to event handler #%d\n", ioc->name, cb_idx)); + r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply); handlers++; } } @@ -6343,10 +7738,10 @@ ProcessEventNotification(MPT_ADAPTER *io * If needed, send (a single) EventAck. */ if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) { - devtverboseprintk((MYIOC_s_WARN_FMT + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "EventAck required\n",ioc->name)); if ((ii = SendEventAck(ioc, pEventReply)) != 0) { - devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n", + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n", ioc->name, ii)); } } @@ -6366,17 +7761,39 @@ ProcessEventNotification(MPT_ADAPTER *io static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) { - static char *subcl_str[8] = { - "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer", - "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info" - }; - u8 subcl = (log_info >> 24) & 0x7; + char *desc = "unknown"; + + switch (log_info & 0xFF000000) { + case MPI_IOCLOGINFO_FC_INIT_BASE: + desc = "FCP Initiator"; + break; + case MPI_IOCLOGINFO_FC_TARGET_BASE: + desc = "FCP Target"; + break; + case MPI_IOCLOGINFO_FC_LAN_BASE: + desc = "LAN"; + break; + case MPI_IOCLOGINFO_FC_MSG_BASE: + desc = "MPI Message Layer"; + break; + case MPI_IOCLOGINFO_FC_LINK_BASE: + desc = "FC Link"; + break; + case MPI_IOCLOGINFO_FC_CTX_BASE: + desc = "Context Manager"; + break; + case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET: + desc = "Invalid Field Offset"; + break; + case MPI_IOCLOGINFO_FC_STATE_CHANGE: + desc = "State Change Info"; + break; + } - printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n", - ioc->name, log_info, subcl_str[subcl]); + printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n", + ioc->name, log_info, desc, (log_info & 0xFFFFFF)); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_spi_log_info - Log information returned from SCSI Parallel IOC. * @ioc: Pointer to MPT_ADAPTER structure @@ -6384,7 +7801,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 lo * @log_info: U32 LogInfo word from the IOC * * Refer to lsi/sp_log.h. - */ + **/ static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) { @@ -6394,8 +7811,6 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l switch (info) { case 0x00010000: desc = "bug! MID not found"; - if (ioc->reload_fw == 0) - ioc->reload_fw++; break; case 0x00020000: @@ -6590,7 +8005,6 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */ }; -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_sas_log_info - Log information returned from SAS IOC. * @ioc: Pointer to MPT_ADAPTER structure @@ -6670,12 +8084,10 @@ union loginfo_type { sas_loginfo.dw.code, sas_loginfo.dw.subcode); } -#ifdef MPT_DEBUG_REPLY -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_iocstatus_info_config - IOCSTATUS information for config pages * @ioc: Pointer to MPT_ADAPTER structure - * ioc_status: U32 IOCStatus word from IOC + * @ioc_status: U32 IOCStatus word from IOC * @mf: Pointer to MPT request frame * * Refer to lsi/mpi.h. @@ -6746,8 +8158,8 @@ mpt_iocstatus_info_config(MPT_ADAPTER *i if (!desc) return; - printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n", - ioc->name, ioc_status, desc, extend_desc); + dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n", + ioc->name, ioc_status, desc, extend_desc)); } /** @@ -6973,9 +8385,8 @@ mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 if (!desc) return; - printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc); + dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc)); } -#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ EXPORT_SYMBOL(mpt_attach); @@ -6996,55 +8407,54 @@ EXPORT_SYMBOL(mpt_device_driver_register EXPORT_SYMBOL(mpt_device_driver_deregister); EXPORT_SYMBOL(mpt_get_msg_frame); EXPORT_SYMBOL(mpt_put_msg_frame); +EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri); EXPORT_SYMBOL(mpt_free_msg_frame); -EXPORT_SYMBOL(mpt_add_sge); EXPORT_SYMBOL(mpt_send_handshake_request); EXPORT_SYMBOL(mpt_verify_adapter); EXPORT_SYMBOL(mpt_GetIocState); EXPORT_SYMBOL(mpt_print_ioc_summary); -EXPORT_SYMBOL(mpt_lan_index); -EXPORT_SYMBOL(mpt_stm_index); EXPORT_SYMBOL(mpt_HardResetHandler); +EXPORT_SYMBOL(mpt_SoftResetHandler); EXPORT_SYMBOL(mpt_config); EXPORT_SYMBOL(mpt_findImVolumes); EXPORT_SYMBOL(mpt_alloc_fw_memory); EXPORT_SYMBOL(mpt_free_fw_memory); EXPORT_SYMBOL(mptbase_sas_persist_operation); EXPORT_SYMBOL(mpt_raid_phys_disk_pg0); +EXPORT_SYMBOL(mpt_raid_phys_disk_pg1); +EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths); +EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag); +EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag); +EXPORT_SYMBOL(mpt_halt_firmware); -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * fusion_init - Fusion MPT base driver initialization routine. * * Returns 0 for success, non-zero for failure. - */ + **/ static int __init fusion_init(void) { - int i; + u8 cb_idx; show_mptmod_ver(my_NAME, my_VERSION); printk(KERN_INFO COPYRIGHT "\n"); - for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) { - MptCallbacks[i] = NULL; - MptDriverClass[i] = MPTUNKNOWN_DRIVER; - MptEvHandlers[i] = NULL; - MptResetHandlers[i] = NULL; + for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { + MptCallbacks[cb_idx] = NULL; + MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; + MptEvHandlers[cb_idx] = NULL; + MptResetHandlers[cb_idx] = NULL; } /* Register ourselves (mptbase) in order to facilitate * EventNotification handling. */ - mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER); + mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER); /* Register for hard reset handling callbacks. */ - if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) { - dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n")); - } else { - /* FIXME! */ - } + mpt_reset_register(mpt_base_index, mpt_ioc_reset); #ifdef CONFIG_PROC_FS (void) procmpt_create(); @@ -7052,19 +8462,15 @@ fusion_init(void) return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * fusion_exit - Perform driver unload cleanup. * * This routine frees all resources associated with each MPT adapter * and removes all %MPT_PROCFS_MPTBASEDIR entries. - */ + **/ static void __exit fusion_exit(void) { - - dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n")); - mpt_reset_deregister(mpt_base_index); #ifdef CONFIG_PROC_FS Index: linux-2.6.18.i386/drivers/message/fusion/mptbase.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/mptbase.h +++ linux-2.6.18.i386/drivers/message/fusion/mptbase.h @@ -3,10 +3,10 @@ * High performance SCSI + LAN / Fibre Channel device drivers. * For use with PCI chip/adapter(s): * LSIFC9xx/LSI409xx Fibre Channel - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsi.com) + * Copyright (c) 1999-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -49,9 +49,6 @@ #define MPTBASE_H_INCLUDED /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -#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 */ @@ -68,16 +65,20 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #ifndef MODULEAUTHOR -#define MODULEAUTHOR "LSI Logic Corporation" +#define MODULEAUTHOR "LSI Corporation" #endif #ifndef COPYRIGHT -#define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR +#define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.04" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.04" +#define MPT_LINUX_VERSION_COMMON "4.00.43.00" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-4.00.43.00" #define WHAT_MAGIC_STRING "@" "(" "#" ")" +#define MPT_LINUX_MAJOR_VERSION 4 +#define MPT_LINUX_MINOR_VERSION 00 +#define MPT_LINUX_BUILD_VERSION 43 +#define MPT_LINUX_RELEASE_VERSION 00 #define show_mptmod_ver(s,ver) \ printk(KERN_INFO "%s %s\n", s, ver); @@ -86,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 */ @@ -133,6 +136,8 @@ #define MPT_COALESCING_TIMEOUT 0x10 +#define MPT_DMA_35BIT_MASK 0x00000007ffffffffULL + /* * SCSI transfer rate defines. */ @@ -172,8 +177,21 @@ #define MPT_SCSI_SG_DEPTH 40 #endif +#ifdef CONFIG_FUSION_MAX_FC_SGE +#if CONFIG_FUSION_MAX_FC_SGE < 16 +#define MPT_SCSI_FC_SG_DEPTH 16 +#elif CONFIG_FUSION_MAX_FC_SGE > 256 +#define MPT_SCSI_FC_SG_DEPTH 256 +#else +#define MPT_SCSI_FC_SG_DEPTH CONFIG_FUSION_MAX_FC_SGE +#endif +#else +#define MPT_SCSI_FC_SG_DEPTH 40 +#endif + /* debug print string length used for events and iocstatus */ -# define EVENT_DESCR_STR_SZ 100 +# define EVENT_DESCR_STR_SZ 100 + #ifdef __KERNEL__ /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -186,6 +204,8 @@ * MPT drivers. NOTE: Users of these macro defs must * themselves define their own MYNAM. */ +#define MYIOC_s_FMT MYNAM ": %s: " +#define MYIOC_s_DEBUG_FMT KERN_DEBUG MYNAM ": %s: " #define MYIOC_s_INFO_FMT KERN_INFO MYNAM ": %s: " #define MYIOC_s_NOTE_FMT KERN_NOTICE MYNAM ": %s: " #define MYIOC_s_WARN_FMT KERN_WARNING MYNAM ": %s: WARNING - " @@ -193,6 +213,34 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* + * ATTO UL4D associated structures and defines + */ +#define ATTOFLAG_DISC 0x0001 +#define ATTOFLAG_TAGGED 0x0002 +#define ATTOFLAG_WIDE_ENB 0x0008 +#define ATTOFLAG_ID_ENB 0x0010 +#define ATTOFLAG_LUN_ENB 0x0060 + +typedef struct _ATTO_DEVICE_INFO +{ + u8 Offset; /* 00h */ + u8 Period; /* 01h */ + u16 ATTOFlags; /* 02h */ +} ATTO_DEVICE_INFO, MPI_POINTER PTR_ATTO_DEVICE_INFO, + ATTODeviceInfo_t, MPI_POINTER pATTODeviceInfo_t; + +typedef struct _ATTO_CONFIG_PAGE_SCSI_PORT_2 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + u16 PortFlags; /* 04h */ + u16 Unused1; /* 06h */ + u32 Unused2; /* 08h */ + ATTO_DEVICE_INFO DeviceSettings[16]; /* 0Ch */ +} 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... */ typedef enum { @@ -306,7 +354,8 @@ typedef struct _SYSIF_REGS u32 Reserved2[2]; /* 38-3F reserved for future use */ u32 RequestFifo; /* 40 Request Post/Free FIFO */ u32 ReplyFifo; /* 44 Reply Post/Free FIFO */ - u32 Reserved3[2]; /* 48-4F reserved for future use */ + u32 RequestHiPriFifo; /* 48 Hi Priority Request FIFO */ + u32 Reserved3; /* 4C-4F reserved for future use */ u32 HostIndex; /* 50 Host Index register */ u32 Reserved4[15]; /* 54-8F */ u32 Fubar; /* 90 For Fubar usage */ @@ -337,8 +386,8 @@ typedef struct _VirtTarget { struct scsi_target *starget; u8 tflags; u8 ioc_id; - u8 id; - u8 channel; + u8 id; /* logical target id */ + u8 channel; /* logical channel number */ u8 minSyncFactor; /* 0xFF is async */ u8 maxOffset; /* 0 if async */ u8 maxWidth; /* 0 if narrow, 1 if wide */ @@ -346,7 +395,7 @@ typedef struct _VirtTarget { u8 raidVolume; /* set, if RAID Volume */ u8 type; /* byte 0 of Inquiry data */ u8 deleted; /* target in process of being removed */ - u32 num_luns; + int num_luns; } VirtTarget; typedef struct _VirtDevice { @@ -392,42 +441,33 @@ do { \ } while (0) -/* - * IOCTL structure and associated defines - */ - -#define MPT_IOCTL_STATUS_DID_IOCRESET 0x01 /* IOC Reset occurred on the current*/ -#define MPT_IOCTL_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */ -#define MPT_IOCTL_STATUS_TIMER_ACTIVE 0x04 /* The timer is running */ -#define MPT_IOCTL_STATUS_SENSE_VALID 0x08 /* Sense data is valid */ -#define MPT_IOCTL_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */ -#define MPT_IOCTL_STATUS_TMTIMER_ACTIVE 0x20 /* The TM timer is running */ -#define MPT_IOCTL_STATUS_TM_FAILED 0x40 /* User TM request failed */ - -#define MPTCTL_RESET_OK 0x01 /* Issue Bus Reset */ - -typedef struct _MPT_IOCTL { - struct _MPT_ADAPTER *ioc; - u8 ReplyFrame[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */ - u8 sense[MPT_SENSE_BUFFER_ALLOC]; - int wait_done; /* wake-up value for this ioc */ - u8 rsvd; - u8 status; /* current command status */ - u8 reset; /* 1 if bus reset allowed */ - u8 id; /* target for reset */ - struct mutex ioctl_mutex; -} MPT_IOCTL; - -#define MPT_SAS_MGMT_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */ -#define MPT_SAS_MGMT_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */ -#define MPT_SAS_MGMT_STATUS_TM_FAILED 0x40 /* User TM request failed */ +#define MPT_MGMT_STATUS_RF_VALID 0x01 /* The Reply Frame is VALID */ +#define MPT_MGMT_STATUS_COMMAND_GOOD 0x02 /* Command Status GOOD */ +#define MPT_MGMT_STATUS_PENDING 0x04 /* command is pending */ +#define MPT_MGMT_STATUS_DID_IOCRESET 0x08 /* IOC Reset occurred on the current*/ +#define MPT_MGMT_STATUS_SENSE_VALID 0x10 /* valid sense info */ +#define MPT_MGMT_STATUS_TIMER_ACTIVE 0x20 /* obsolete */ +#define MPT_MGMT_STATUS_FREE_MF 0x40 /* free the mf from complete routine */ + + +#define INITIALIZE_MGMT_STATUS(status) \ + status = MPT_MGMT_STATUS_PENDING; +#define CLEAR_MGMT_STATUS(status) \ + status = 0; +#define CLEAR_MGMT_PENDING_STATUS(status) \ + status &= ~MPT_MGMT_STATUS_PENDING; +#define SET_MGMT_MSG_CONTEXT(msg_context, value) \ + msg_context = value; -typedef struct _MPT_SAS_MGMT { +typedef struct _MPT_MGMT { struct mutex mutex; struct completion done; u8 reply[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */ + u8 sense[MPT_SENSE_BUFFER_ALLOC]; u8 status; /* current command status */ -}MPT_SAS_MGMT; + int completion_code; + u32 msg_context; +}MPT_MGMT; /* * Event Structure and define @@ -436,7 +476,7 @@ typedef struct _MPT_SAS_MGMT { typedef struct _mpt_ioctl_events { u32 event; /* Specified by define above */ u32 eventContext; /* Index or counter */ - int data[2]; /* First 8 bytes of Event Data */ + u32 data[2]; /* First 8 bytes of Event Data */ } MPT_IOCTL_EVENTS; /* @@ -499,6 +539,7 @@ struct inactive_raid_component_info { typedef struct _RaidCfgData { IOCPage2_t *pIocPg2; /* table of Raid Volumes */ IOCPage3_t *pIocPg3; /* table of physical disks */ + 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 @@ -529,6 +570,9 @@ struct mptfc_rport_info u8 flags; }; +typedef void (*MPT_ADD_SGE)(char *pAddr, u32 flagslength, dma_addr_t dma_addr); +typedef void (*MPT_ADD_CHAIN)(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr); + /* * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS */ @@ -537,12 +581,23 @@ typedef struct _MPT_ADAPTER int id; /* Unique adapter id N {0,1,2,...} */ int pci_irq; /* This irq */ char name[MPT_NAME_LENGTH]; /* "iocN" */ - char *prod_name; /* "LSIFC9x9" */ + char prod_name[MPT_NAME_LENGTH]; /* "LSIFC9x9" */ +#ifdef CONFIG_FUSION_LOGGING + char evStr[EVENT_DESCR_STR_SZ]; /* used in mpt_display_event_info */ +#endif + char board_name[16]; + char board_assembly[16]; + char board_tracer[16]; + u16 nvdata_version_persistent; + u16 nvdata_version_default; + int debug_level; + u8 io_missing_delay; + u8 device_missing_delay; 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; @@ -557,6 +612,8 @@ typedef struct _MPT_ADAPTER int reply_depth; /* Num Allocated reply frames */ int reply_sz; /* Reply frame size */ int num_chain; /* Number of chain buffers */ + MPT_ADD_SGE add_sge; /* Pointer to add_sge function */ + MPT_ADD_CHAIN add_chain; /* Pointer to add_chain function */ /* Pool of buffers for chaining. ReqToChain * and ChainToChain track index of chain buffers. * ChainBuffer (DMA) virt/phys addresses. @@ -585,29 +642,29 @@ 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 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) + int bars; /* bitmask of BAR's that must be configured */ +#endif + int msi_enable; u8 __iomem *memmap; /* mmap address */ struct Scsi_Host *sh; /* Scsi Host pointer */ - SpiCfgData spi_data; /* Scsi config. data */ - RaidCfgData raid_data; /* Raid config. data */ - SasCfgData sas_data; /* Sas config. data */ - FcCfgData fc_data; /* Fc config. data */ - MPT_IOCTL *ioctl; /* ioctl data pointer */ + SpiCfgData spi_data; /* Scsi config. data */ + RaidCfgData raid_data; /* Raid config. data */ + SasCfgData sas_data; /* Sas config. data */ + FcCfgData fc_data; /* Fc config. data */ struct proc_dir_entry *ioc_dentry; struct _MPT_ADAPTER *alt_ioc; /* ptr to 929 bound adapter port */ - spinlock_t diagLock; /* diagnostic reset lock */ - int diagPending; u32 biosVersion; /* BIOS version from IO Unit Page 2 */ int eventTypes; /* Event logging parameters */ int eventContext; /* Next event context */ int eventLogSize; /* Max number of cached events */ struct _mpt_ioctl_events *events; /* pointer to event log */ u8 *cached_fw; /* Pointer to FW */ - dma_addr_t cached_fw_dma; - struct list_head configQ; /* linked list of config. requests */ + dma_addr_t cached_fw_dma; int hs_reply_idx; #ifndef MFCNT u32 pad0; @@ -620,13 +677,16 @@ typedef struct _MPT_ADAPTER IOCFactsReply_t facts; PortFactsReply_t pfacts[2]; FCPortPage0_t fc_port_page0[2]; - struct timer_list persist_timer; /* persist table timer */ - int persist_wait_done; /* persist completion flag */ - u8 persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */ LANPage0_t lan_cnfg_page0; LANPage1_t lan_cnfg_page1; +#if defined(CPQ_CIM) + u32 csmi_change_count; /* count to track all IR + events for CSMI */ + u8 pci_slot_number; /* ioc page 1 - pci slot number */ +#endif u8 ir_firmware; /* =1 if IR firmware detected */ + /* * Description: errata_flag_1064 * If a PCIX read occurs within 1 or 2 cycles after the chip receives @@ -637,32 +697,79 @@ typedef struct _MPT_ADAPTER int aen_event_read_flag; /* flag to indicate event log was read*/ u8 FirstWhoInit; u8 upload_fw; /* If set, do a fw upload */ - u8 reload_fw; /* Force a FW Reload on next reset */ u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */ - u8 pad1[4]; - int DoneCtx; - int TaskCtx; - int InternalCtx; - spinlock_t initializing_hba_lock; - int initializing_hba_lock_flag; + u8 DoneCtx; + u8 TaskCtx; + u8 InternalCtx; struct list_head list; struct net_device *netdev; struct list_head sas_topology; struct mutex sas_topology_mutex; - struct mutex sas_discovery_mutex; - u8 sas_discovery_runtime; - u8 sas_discovery_ignore_events; - u16 handle; - int sas_index; /* index refrencing */ - MPT_SAS_MGMT sas_mgmt; - struct work_struct sas_persist_task; + u8 disable_hotplug_remove; + struct workqueue_struct *fw_event_q; + struct list_head fw_event_list; + spinlock_t fw_event_lock; + u8 fw_events_off; /* if '1', then ignore events */ + char fw_event_q_name[KOBJ_NAME_LEN]; + + struct mptsas_portinfo *hba_port_info; /* port_info object for the host */ + u64 hba_port_sas_addr; + u16 hba_port_num_phy; + struct list_head sas_device_info_list; + struct semaphore sas_device_info_mutex; + u8 old_sas_discovery_protocal; + u8 sas_discovery_quiesce_io; + int sas_index; /* index refrencing */ + MPT_MGMT sas_mgmt; + MPT_MGMT internal_cmds; + MPT_MGMT mptbase_cmds; /* for sending config pages */ + MPT_MGMT taskmgmt_cmds; + MPT_MGMT ioctl_cmds; /* ioctl data pointer */ + spinlock_t taskmgmt_lock; /* diagnostic reset lock */ + int taskmgmt_in_progress; + u8 taskmgmt_quiesce_io; + u8 ioc_reset_in_progress; +#if defined(CPQ_CIM) + u8 num_ports; +#endif + + char reset_work_q_name[KOBJ_NAME_LEN]; + struct workqueue_struct *reset_work_q; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) + struct delayed_work fault_reset_work; +#else + struct work_struct fault_reset_work; +#endif struct work_struct fc_setup_reset_work; struct list_head fc_rports; + struct work_struct fc_lsc_work; + u8 fc_link_speed[2]; spinlock_t fc_rescan_work_lock; struct work_struct fc_rescan_work; char fc_rescan_work_q_name[KOBJ_NAME_LEN]; struct workqueue_struct *fc_rescan_work_q; + unsigned long hard_resets; /* driver forced bus resets count */ + unsigned long soft_resets; /* fw/external bus resets count */ + unsigned long timeouts; /* cmd timeouts */ + struct scsi_cmnd **ScsiLookup; + spinlock_t scsi_lookup_lock; + int sdev_queue_depth; /* sdev queue depth */ + u64 dma_mask; + u32 broadcast_aen_busy; +#if defined(DIAG_BUFFER_SUPPORT) + u8 *DiagBuffer[MPI_DIAG_BUF_TYPE_COUNT]; + u32 DataSize[MPI_DIAG_BUF_TYPE_COUNT]; + u32 DiagBuffer_sz[MPI_DIAG_BUF_TYPE_COUNT]; + dma_addr_t DiagBuffer_dma[MPI_DIAG_BUF_TYPE_COUNT]; + u8 TraceLevel[MPI_DIAG_BUF_TYPE_COUNT]; + u8 DiagBuffer_Status[MPI_DIAG_BUF_TYPE_COUNT]; + u32 UniqueId[MPI_DIAG_BUF_TYPE_COUNT]; + u32 ExtendedType[MPI_DIAG_BUF_TYPE_COUNT]; + u32 ProductSpecific[MPI_DIAG_BUF_TYPE_COUNT][4]; +#endif + u8 sg_addr_size; + u8 SGE_size; } MPT_ADAPTER; /* @@ -699,183 +806,18 @@ typedef struct _mpt_sge { dma_addr_t Address; } MptSge_t; -#define mpt_addr_size() \ - ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \ - MPI_SGE_FLAGS_32_BIT_ADDRESSING) - -#define mpt_msg_flags() \ - ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \ - MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32) +#define mpt_msg_flags(ioc) \ + (ioc->sg_addr_size == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \ + MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32 + +#define MPT_SGE_FLAGS_64_BIT_ADDRESSING \ + (MPI_SGE_FLAGS_64_BIT_ADDRESSING << MPI_SGE_FLAGS_SHIFT) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Funky (private) macros... */ -#ifdef MPT_DEBUG -#define dprintk(x) printk x -#else -#define dprintk(x) -#endif - -#ifdef MPT_DEBUG_INIT -#define dinitprintk(x) printk x -#define DBG_DUMP_FW_REQUEST_FRAME(mfp) \ - { int i, n = 10; \ - u32 *m = (u32 *)(mfp); \ - printk(KERN_INFO " "); \ - for (i=0; i> 16; \ - printk("TM_REPLY MessageLength=%d:\n", n); \ - for (i=0; ireq_frames + (ioc)->req_sz * (idx) ) @@ -886,58 +828,12 @@ typedef struct _mpt_sge { #define MPT_INDEX_2_RFPTR(ioc,idx) \ (MPT_FRAME_HDR*)( (u8*)(ioc)->reply_frames + (ioc)->req_sz * (idx) ) -#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME) -#define DBG_DUMP_REPLY_FRAME(mfp) \ - { u32 *m = (u32 *)(mfp); \ - int i, n = (le32_to_cpu(m[0]) & 0x00FF0000) >> 16; \ - printk(KERN_INFO " "); \ - for (i=0; i #include #include #include @@ -66,11 +67,20 @@ #include #include -#define COPYRIGHT "Copyright (c) 1999-2007 LSI Logic Corporation" -#define MODULEAUTHOR "LSI Logic Corporation" +#define COPYRIGHT "Copyright (c) 1999-2008 LSI Corporation" +#define MODULEAUTHOR "LSI Corporation" #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 @@ -83,7 +93,8 @@ MODULE_VERSION(my_VERSION); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int mptctl_id = -1; +static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS; static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait ); @@ -112,6 +123,42 @@ static int mptctl_do_reset(unsigned long static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd); static int mptctl_hp_targetinfo(unsigned long arg); +#if defined(CPQ_CIM) +/* csmisas proto's*/ +static int csmisas_get_driver_info(unsigned long arg); +static int csmisas_get_cntlr_status(unsigned long arg); +static int csmisas_get_cntlr_config(unsigned long arg); +static int csmisas_get_phy_info(unsigned long arg); +static int csmisas_get_scsi_address(unsigned long arg); +static int csmisas_get_link_errors(unsigned long arg); +static int csmisas_smp_passthru(unsigned long arg); +static int csmisas_firmware_download(unsigned long arg); +static int csmisas_get_raid_info(unsigned long arg); +static int csmisas_get_raid_config(unsigned long arg); +static int csmisas_get_raid_features(unsigned long arg); +static int csmisas_set_raid_control(unsigned long arg); +static int csmisas_get_raid_element(unsigned long arg); +static int csmisas_set_raid_operation(unsigned long arg); +static int csmisas_set_phy_info(unsigned long arg); +static int csmisas_ssp_passthru(unsigned long arg); +static int csmisas_stp_passthru(unsigned long arg); +static int csmisas_get_sata_signature(unsigned long arg); +static int csmisas_get_device_address(unsigned long arg); +static int csmisas_task_managment(unsigned long arg); +static int csmisas_phy_control(unsigned long arg); +static int csmisas_get_connector_info(unsigned long arg); +static int csmisas_get_location(unsigned long arg); +#endif // CPQ_CIM + +#if defined(DIAG_BUFFER_SUPPORT) +/* diag_buffer proto's */ +static int mptctl_register_diag_buffer(unsigned long arg); +static int mptctl_release_diag_buffer(unsigned long arg); +static int mptctl_unregister_diag_buffer(unsigned long arg); +static int mptctl_query_diag_buffer(unsigned long arg); +static int mptctl_read_diag_buffer(unsigned long arg); +#endif // DIAG_BUFFER_SUPPORT + static int mptctl_probe(struct pci_dev *, const struct pci_device_id *); static void mptctl_remove(struct pci_dev *); @@ -127,10 +174,6 @@ static MptSge_t *kbuf_alloc_2_sgl(int by struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc); static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc); -static void mptctl_timeout_expired (MPT_IOCTL *ioctl); -static int mptctl_bus_reset(MPT_IOCTL *ioctl); -static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd); -static void mptctl_free_tm_flags(MPT_ADAPTER *ioc); /* * Reset Handler cleanup function @@ -181,16 +224,14 @@ static inline int mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock) { int rc = 0; - dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock)); if (nonblock) { - if (!mutex_trylock(&ioc->ioctl->ioctl_mutex)) + if (!mutex_trylock(&ioc->ioctl_cmds.mutex)) rc = -EAGAIN; } else { - if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex)) + if (mutex_lock_interruptible(&ioc->ioctl_cmds.mutex)) rc = -ERESTARTSYS; } - dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc)); return rc; } @@ -204,119 +245,104 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, in static int mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { - char *sense_data; - int sz, req_index; - u16 iocStatus; - u8 cmd; - - dctlprintk(("mptctl_reply()!\n")); - if (req) - cmd = req->u.hdr.Function; - else - return 1; - - if (ioc->ioctl) { + char *sense_data; + int req_index; + int sz; - if (reply==NULL) { - - dctlprintk(("mptctl_reply() NULL Reply " - "Function=%x!\n", cmd)); - - ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; - ioc->ioctl->reset &= ~MPTCTL_RESET_OK; + if (!req) + return 0; - /* We are done, issue wake up - */ - ioc->ioctl->wait_done = 1; - wake_up (&mptctl_wait); - return 1; + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "completing mpi function " + "(0x%02X), req=%p, reply=%p\n", ioc->name, req->u.hdr.Function, + req, reply)); - } + /* + * Handling continuation of the same reply. Processing the first + * reply, and eating the other replys that come later. + */ + if (ioc->ioctl_cmds.msg_context != req->u.hdr.MsgContext) + goto out_continuation; - dctlprintk(("mptctl_reply() with req=%p " - "reply=%p Function=%x!\n", req, reply, cmd)); + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; - /* Copy the reply frame (which much exist - * for non-SCSI I/O) to the IOC structure. - */ - dctlprintk(("Copying Reply Frame @%p to ioc%d!\n", - reply, ioc->id)); - memcpy(ioc->ioctl->ReplyFrame, reply, - min(ioc->reply_sz, 4*reply->u.reply.MsgLength)); - ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID; + if (!reply) + goto out; - /* Set the command status to GOOD if IOC Status is GOOD - * OR if SCSI I/O cmd and data underrun or recovered error. - */ - iocStatus = le16_to_cpu(reply->u.reply.IOCStatus) & MPI_IOCSTATUS_MASK; - if (iocStatus == MPI_IOCSTATUS_SUCCESS) - ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; - - if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) || - (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { - ioc->ioctl->reset &= ~MPTCTL_RESET_OK; - - if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) || - (iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) { - ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; - } - } + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + sz = min(ioc->reply_sz, 4*reply->u.reply.MsgLength); + memcpy(ioc->ioctl_cmds.reply, reply, sz); + + if (reply->u.reply.IOCStatus || reply->u.reply.IOCLogInfo) + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "iocstatus (0x%04X), loginfo (0x%08X)\n", ioc->name, + le16_to_cpu(reply->u.reply.IOCStatus), + le32_to_cpu(reply->u.reply.IOCLogInfo))); + + if ((req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) || + (req->u.hdr.Function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + + if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState) + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "scsi_status (0x%02x), scsi_state (0x%02x), " + "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name, + reply->u.sreply.SCSIStatus, + reply->u.sreply.SCSIState, + le16_to_cpu(reply->u.sreply.TaskTag), + le32_to_cpu(reply->u.sreply.TransferCount))); - /* Copy the sense data - if present - */ - if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) && - (reply->u.sreply.SCSIState & - MPI_SCSI_STATE_AUTOSENSE_VALID)){ + if (reply->u.sreply.SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { sz = req->u.scsireq.SenseBufferLength; req_index = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx); - sense_data = - ((u8 *)ioc->sense_buf_pool + + sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); - memcpy(ioc->ioctl->sense, sense_data, sz); - ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID; + memcpy(ioc->ioctl_cmds.sense, sense_data, sz); + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_SENSE_VALID; } + } - if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT) - mptctl_free_tm_flags(ioc); - - /* We are done, issue wake up - */ - ioc->ioctl->wait_done = 1; - wake_up (&mptctl_wait); + out: + /* We are done, issue wake up + */ + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) { + if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) + mpt_clear_taskmgmt_in_progress_flag(ioc); + ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->ioctl_cmds.done); } + + out_continuation: + if (reply && (reply->u.reply.MsgFlags & + MPI_MSGFLAGS_CONTINUATION_REPLY)) + return 0; return 1; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptctl_timeout_expired - * - * Expecting an interrupt, however timed out. - * - */ -static void mptctl_timeout_expired (MPT_IOCTL *ioctl) +static int +mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) { - int rc = 1; + if (!mf) + return 0; - dctlprintk((KERN_NOTICE MYNAM ": Timeout Expired! Host %d\n", - ioctl->ioc->id)); - if (ioctl == NULL) - return; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n", + ioc->name, mf, mr)); - ioctl->wait_done = 0; - if (ioctl->reset & MPTCTL_RESET_OK) - rc = mptctl_bus_reset(ioctl); - - if (rc) { - /* Issue a reset for this device. - * The IOC is not responding. - */ - dctlprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n", - ioctl->ioc->name)); - mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP); - } - return; + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + if (!mr) + goto out; + + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->taskmgmt_cmds.reply, mr, + min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); + out: + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + mpt_clear_taskmgmt_in_progress_flag(ioc); + ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->taskmgmt_cmds.done); + return 1; + } + return 0; } /* mptctl_bus_reset @@ -324,125 +350,181 @@ static void mptctl_timeout_expired (MPT_ * Bus reset code. * */ -static int mptctl_bus_reset(MPT_IOCTL *ioctl) +static int +mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; - MPT_SCSI_HOST *hd; + SCSITaskMgmtReply_t *pScsiTmReply; int ii; int retval; - - - ioctl->reset &= ~MPTCTL_RESET_OK; - - if (ioctl->ioc->sh == NULL) + unsigned long timeout; + unsigned long time_count; + u16 iocstatus; + + /* bus reset is only good for SCSI IO, RAID PASSTHRU */ + if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) || + (function == MPI_FUNCTION_SCSI_IO_REQUEST)) { + dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, not SCSI_IO!!\n", + ioc->name)); return -EPERM; + } - hd = (MPT_SCSI_HOST *) ioctl->ioc->sh->hostdata; - if (hd == NULL) + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); return -EPERM; + } - /* Single threading .... - */ - if (mptctl_set_tm_flags(hd) != 0) - return -EPERM; + retval = 0; /* Send request */ - if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) { - dctlprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n", - ioctl->ioc->name)); - - mptctl_free_tm_flags(ioctl->ioc); - return -ENOMEM; + if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) { + dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n", + ioc->name)); + mpt_clear_taskmgmt_in_progress_flag(ioc); + retval = -ENOMEM; + goto mptctl_bus_reset_done; } - dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n", - ioctl->ioc->name, mf)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", + ioc->name, mf)); pScsiTm = (SCSITaskMgmt_t *) mf; - pScsiTm->TargetID = ioctl->id; - pScsiTm->Bus = hd->port; /* 0 */ - pScsiTm->ChainOffset = 0; + memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; - pScsiTm->Reserved = 0; pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; - pScsiTm->Reserved1 = 0; pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; - + pScsiTm->TargetID = 0; + pScsiTm->Bus = 0; + pScsiTm->ChainOffset = 0; + pScsiTm->Reserved = 0; + pScsiTm->Reserved1 = 0; + pScsiTm->TaskMsgContext = 0; for (ii= 0; ii < 8; ii++) pScsiTm->LUN[ii] = 0; - for (ii=0; ii < 7; ii++) pScsiTm->Reserved2[ii] = 0; - pScsiTm->TaskMsgContext = 0; - dtmprintk((MYIOC_s_INFO_FMT - "mptctl_bus_reset: issued.\n", ioctl->ioc->name)); + switch (ioc->bus_type) { + case FC: + timeout = 40; + break; + case SAS: + timeout = 30; + break; + case SPI: + default: + timeout = 2; + break; + } - DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n", + ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout)); - ioctl->wait_done=0; - if ((retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc, - sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) { - dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!" - " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, - hd->ioc, mf)); - goto mptctl_bus_reset_done; + 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); + 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 mptctl_bus_reset_done; + } } /* Now wait for the command to complete */ - ii = wait_event_timeout(mptctl_wait, - ioctl->wait_done == 1, - HZ*5 /* 5 second timeout */); - - if(ii <=0 && (ioctl->wait_done != 1 )) { - mpt_free_msg_frame(hd->ioc, mf); - ioctl->wait_done = 0; - retval = -1; /* return failure */ + ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt failed\n", ioc->name)); + mpt_free_msg_frame(ioc, mf); + mpt_clear_taskmgmt_in_progress_flag(ioc); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + retval = 0; + else + retval = -1; /* return failure */ + goto mptctl_bus_reset_done; } -mptctl_bus_reset_done: - - mptctl_free_tm_flags(ioctl->ioc); - return retval; -} - -static int -mptctl_set_tm_flags(MPT_SCSI_HOST *hd) { - unsigned long flags; - - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt failed\n", ioc->name)); + retval = -1; /* return failure */ + goto mptctl_bus_reset_done; + } - if (hd->tmState == TM_STATE_NONE) { - hd->tmState = TM_STATE_IN_PROGRESS; - hd->tmPending = 1; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - } else { - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - return -EBUSY; + pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, " + "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, " + "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus, + pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + le16_to_cpu(pScsiTmReply->IOCStatus), + le32_to_cpu(pScsiTmReply->IOCLogInfo), + pScsiTmReply->ResponseCode, + le32_to_cpu(pScsiTmReply->TerminationCount))); + + iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; + + if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || + iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED || + iocstatus == MPI_IOCSTATUS_SUCCESS) + retval = 0; + else { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt failed\n", ioc->name)); + retval = -1; /* return failure */ } - return 0; + + mptctl_bus_reset_done: + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + return retval; } static void -mptctl_free_tm_flags(MPT_ADAPTER *ioc) +mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { - MPT_SCSI_HOST * hd; unsigned long flags; - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; - if (hd == NULL) + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n", + ioc->name, __FUNCTION__)); + + if(mpt_fwfault_debug) + mpt_halt_firmware(ioc); + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) + mpt_free_msg_frame(ioc, mf); return; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmState = TM_STATE_NONE; - hd->tmPending = 0; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); + if (!mptctl_bus_reset(ioc, mf->u.hdr.Function)) + return; - return; + /* Issue a reset for this device. + * The IOC is not responding. + */ + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", + ioc->name)); + CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -455,22 +537,23 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc) static int mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - MPT_IOCTL *ioctl = ioc->ioctl; - dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n", - reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - - if(ioctl == NULL) - return 1; - switch(reset_phase) { case MPT_IOC_SETUP_RESET: - ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); break; case MPT_IOC_POST_RESET: - ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->ioctl_cmds.done); + } break; - case MPT_IOC_PRE_RESET: default: break; } @@ -487,7 +570,8 @@ mptctl_event_process(MPT_ADAPTER *ioc, E event = le32_to_cpu(pEvReply->Event) & 0xFF; - dctlprintk(("%s() called\n", __FUNCTION__)); + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n", + ioc->name, __FUNCTION__)); if(async_queue == NULL) return 1; @@ -497,8 +581,10 @@ mptctl_event_process(MPT_ADAPTER *ioc, E */ if (event == 0x21 ) { ioc->aen_event_read_flag=1; - dctlprintk(("Raised SIGIO to application\n")); - devtverboseprintk(("Raised SIGIO to application\n")); + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Raised SIGIO to application\n", + ioc->name)); + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Raised SIGIO to application\n", ioc->name)); kill_fasync(&async_queue, SIGIO, POLL_IN); return 1; } @@ -515,8 +601,10 @@ mptctl_event_process(MPT_ADAPTER *ioc, E */ if (ioc->events && (ioc->eventTypes & ( 1 << event))) { ioc->aen_event_read_flag=1; - dctlprintk(("Raised SIGIO to application\n")); - devtverboseprintk(("Raised SIGIO to application\n")); + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Raised SIGIO to application\n", ioc->name)); + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Raised SIGIO to application\n", ioc->name)); kill_fasync(&async_queue, SIGIO, POLL_IN); } return 1; @@ -530,14 +618,12 @@ mptctl_fasync(int fd, struct file *filep list_for_each_entry(ioc, &ioc_list, list) ioc->aen_event_read_flag=0; - dctlprintk(("%s() called\n", __FUNCTION__)); return fasync_helper(fd, filep, mode, &async_queue); } static int mptctl_release(struct inode *inode, struct file *filep) { - dctlprintk(("%s() called\n", __FUNCTION__)); return fasync_helper(-1, filep, 0, &async_queue); } @@ -558,10 +644,9 @@ __mptctl_ioctl(struct file *file, unsign int ret; MPT_ADAPTER *iocp = NULL; - dctlprintk(("mptctl_ioctl() called\n")); if (copy_from_user(&khdr, uhdr, sizeof(khdr))) { - printk(KERN_ERR "%s::mptctl_ioctl() @%d - " + printk(KERN_ERR MYNAM "%s::mptctl_ioctl() @%d - " "Unable to copy mpt_ioctl_header data @ %p\n", __FILE__, __LINE__, uhdr); return -EFAULT; @@ -574,17 +659,12 @@ __mptctl_ioctl(struct file *file, unsign iocnumX = khdr.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnumX)); + if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnumX); return -ENODEV; } - if (!iocp->active) { - printk(KERN_ERR "%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 @@ -604,6 +684,25 @@ __mptctl_ioctl(struct file *file, unsign return mptctl_eventreport(arg); } else if (cmd == MPTFWREPLACE) { return mptctl_replace_fw(arg); +#if defined(DIAG_BUFFER_SUPPORT) +/* diag_buffer static data calls*/ + } else if (cmd == MPTDIAGQUERY) { + return mptctl_query_diag_buffer(arg); + } else if (cmd == MPTDIAGUNREGISTER) { + return mptctl_unregister_diag_buffer(arg); +#endif + +#if defined(CPQ_CIM) +/* csmisas static data calls*/ + } else if (cmd == CC_CSMI_SAS_GET_DRIVER_INFO) { + return csmisas_get_driver_info(arg); + } else if (cmd == CC_CSMI_SAS_GET_CNTLR_STATUS) { + return csmisas_get_cntlr_status(arg); + } else if (cmd == CC_CSMI_SAS_GET_SCSI_ADDRESS) { + return csmisas_get_scsi_address(arg); + } else if (cmd == CC_CSMI_SAS_GET_DEVICE_ADDRESS){ + return csmisas_get_device_address(arg); +#endif // CPQ_CIM } /* All of these commands require an interrupt or @@ -612,7 +711,7 @@ __mptctl_ioctl(struct file *file, unsign if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) return ret; - dctlprintk((MYIOC_s_INFO_FMT ": mptctl_ioctl()\n", iocp->name)); +// dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT ": mptctl_ioctl()\n", iocp->name)); if (cmd == MPTFWDOWNLOAD) ret = mptctl_fw_download(arg); @@ -624,10 +723,61 @@ __mptctl_ioctl(struct file *file, unsign ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd)); else if (cmd == HP_GETTARGETINFO) ret = mptctl_hp_targetinfo(arg); +#if defined(CPQ_CIM) +/* csmisas requiring fw calls*/ + else if (cmd == CC_CSMI_SAS_GET_CNTLR_CONFIG) + ret = csmisas_get_cntlr_config(arg); + else if (cmd == CC_CSMI_SAS_GET_PHY_INFO) + ret = csmisas_get_phy_info(arg); + else if (cmd == CC_CSMI_SAS_GET_SATA_SIGNATURE) + ret = csmisas_get_sata_signature(arg); + else if (cmd == CC_CSMI_SAS_GET_LINK_ERRORS) + ret = csmisas_get_link_errors(arg); + else if (cmd == CC_CSMI_SAS_SMP_PASSTHRU) + ret = csmisas_smp_passthru(arg); + else if (cmd == CC_CSMI_SAS_SSP_PASSTHRU) + ret = csmisas_ssp_passthru(arg); + else if (cmd == CC_CSMI_SAS_FIRMWARE_DOWNLOAD) + ret = csmisas_firmware_download(arg); + else if (cmd == CC_CSMI_SAS_GET_RAID_INFO) + ret = csmisas_get_raid_info(arg); + else if (cmd == CC_CSMI_SAS_GET_RAID_CONFIG) + ret = csmisas_get_raid_config(arg); + else if (cmd == CC_CSMI_SAS_GET_RAID_FEATURES) + ret = csmisas_get_raid_features(arg); + else if (cmd == CC_CSMI_SAS_SET_RAID_CONTROL) + ret = csmisas_set_raid_control(arg); + else if (cmd == CC_CSMI_SAS_GET_RAID_ELEMENT) + ret = csmisas_get_raid_element(arg); + else if (cmd == CC_CSMI_SAS_SET_RAID_OPERATION) + ret = csmisas_set_raid_operation(arg); + else if (cmd == CC_CSMI_SAS_SET_PHY_INFO) + ret = csmisas_set_phy_info(arg); + else if (cmd == CC_CSMI_SAS_STP_PASSTHRU) + ret = csmisas_stp_passthru(arg); + else if (cmd == CC_CSMI_SAS_TASK_MANAGEMENT) + ret = csmisas_task_managment(arg); + else if (cmd == CC_CSMI_SAS_PHY_CONTROL) + ret = csmisas_phy_control(arg); + else if (cmd == CC_CSMI_SAS_GET_CONNECTOR_INFO) + ret = csmisas_get_connector_info(arg); + else if (cmd == CC_CSMI_SAS_GET_LOCATION) + ret = csmisas_get_location(arg); +#endif // CPQ_CIM + +#if defined(DIAG_BUFFER_SUPPORT) +/* diag_buffer requiring fw calls*/ + else if (cmd == MPTDIAGREGISTER) + ret = mptctl_register_diag_buffer(arg); + else if (cmd == MPTDIAGRELEASE) + ret = mptctl_release_diag_buffer(arg); + else if (cmd == MPTDIAGREADBUFFER) + ret = mptctl_read_diag_buffer(arg); +#endif // DIAG_BUFFER_SUPPORT else ret = -EINVAL; - mutex_unlock(&iocp->ioctl->ioctl_mutex); + mutex_unlock(&iocp->ioctl_cmds.mutex); return ret; } @@ -648,24 +798,26 @@ static int mptctl_do_reset(unsigned long struct mpt_ioctl_diag_reset krinfo; MPT_ADAPTER *iocp; - dctlprintk((KERN_INFO "mptctl_do_reset called.\n")); - if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) { - printk(KERN_ERR "%s@%d::mptctl_do_reset - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_do_reset - " "Unable to copy mpt_ioctl_diag_reset struct @ %p\n", __FILE__, __LINE__, urinfo); return -EFAULT; } if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) { - dctlprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n", - __FILE__, __LINE__, krinfo.hdr.iocnum)); + 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 */ } + dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "mptctl_do_reset called.\n", + iocp->name)); + if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) { - printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n", - __FILE__, __LINE__); + printk (MYIOC_s_ERR_FMT "%s@%d::mptctl_do_reset - reset failed.\n", + iocp->name, __FILE__, __LINE__); return -1; } @@ -695,9 +847,8 @@ mptctl_fw_download(unsigned long arg) struct mpt_fw_xfer __user *ufwdl = (void __user *) arg; struct mpt_fw_xfer kfwdl; - dctlprintk((KERN_INFO "mptctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) { - printk(KERN_ERR "%s@%d::_ioctl_fwdl - " + printk(KERN_ERR MYNAM "%s@%d::_ioctl_fwdl - " "Unable to copy mpt_fw_xfer struct @ %p\n", __FILE__, __LINE__, ufwdl); return -EFAULT; @@ -743,16 +894,11 @@ mptctl_do_fw_download(int ioc, char __us int sge_offset = 0; u16 iocstat; pFWDownloadReply_t ReplyMsg = NULL; - - dctlprintk(("mptctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id)); - - dctlprintk(("DbG: kfwdl.bufp = %p\n", ufwbuf)); - dctlprintk(("DbG: kfwdl.fwlen = %d\n", (int)fwlen)); - dctlprintk(("DbG: kfwdl.ioc = %04xh\n", ioc)); + unsigned long timeleft; if (mpt_verify_adapter(ioc, &iocp) < 0) { - dctlprintk(("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 { @@ -761,6 +907,16 @@ mptctl_do_fw_download(int ioc, char __us if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL) return -EAGAIN; } + + dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT + "mptctl_do_fwdl called. mptctl_id = %xh.\n", iocp->name, mptctl_id)); + dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.bufp = %p\n", + iocp->name, ufwbuf)); + dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.fwlen = %d\n", + iocp->name, (int)fwlen)); + dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.ioc = %04xh\n", + iocp->name, ioc)); + dlmsg = (FWDownload_t*) mf; ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL; sgOut = (char *) (ptsge + 1); @@ -823,13 +979,14 @@ mptctl_do_fw_download(int ioc, char __us * 64 4 */ maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) - / (sizeof(dma_addr_t) + sizeof(u32)); + / iocp->SGE_size; if (numfrags > maxfrags) { ret = -EMLINK; - goto fwdl_out; + goto fwdl_out; } - dctlprintk(("DbG: sgl buffer = %p, sgfrags = %d\n", sgl, numfrags)); + dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: sgl buffer = %p, sgfrags = %d\n", + iocp->name, sgl, numfrags)); /* * Parse SG list, copying sgl itself, @@ -850,45 +1007,48 @@ mptctl_do_fw_download(int ioc, char __us if (nib == 0 || nib == 3) { ; } else if (sgIn->Address) { - mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address); + iocp->add_sge(sgOut, sgIn->FlagsLength, sgIn->Address); n++; if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) { - printk(KERN_ERR "%s@%d::_ioctl_fwdl - " - "Unable to copy f/w buffer hunk#%d @ %p\n", - __FILE__, __LINE__, n, ufwbuf); + 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); goto fwdl_out; } fw_bytes_copied += bl->len; } sgIn++; bl++; - sgOut += (sizeof(dma_addr_t) + sizeof(u32)); + sgOut += iocp->SGE_size; } -#ifdef MPT_DEBUG - { - u32 *m = (u32 *)mf; - printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " "); - for (i=0; i < 7+numfrags*2; i++) - printk(" %08x", le32_to_cpu(m[i])); - printk("\n"); - } -#endif + DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags); /* * Finally, perform firmware download. */ ReplyMsg = NULL; + SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, dlmsg->MsgContext); + INITIALIZE_MGMT_STATUS(iocp->ioctl_cmds.status) mpt_put_msg_frame(mptctl_id, iocp, mf); /* Now wait for the command to complete */ - ret = wait_event_timeout(mptctl_wait, - iocp->ioctl->wait_done == 1, - HZ*60); - - if(ret <=0 && (iocp->ioctl->wait_done != 1 )) { - /* Now we need to reset the board */ - mptctl_timeout_expired(iocp->ioctl); + timeleft = wait_for_completion_timeout(&iocp->ioctl_cmds.done, HZ*60); + if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __FUNCTION__); + if (iocp->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(iocp, mf); + goto fwdl_out; + } + if (!timeleft) + mptctl_timeout_expired(iocp, mf); + goto fwdl_out; + } + + if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __FUNCTION__); + mpt_free_msg_frame(iocp, mf); ret = -ENODATA; goto fwdl_out; } @@ -896,30 +1056,34 @@ mptctl_do_fw_download(int ioc, char __us if (sgl) kfree_sgl(sgl, sgl_dma, buflist, iocp); - ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame; + ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply; iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; if (iocstat == MPI_IOCSTATUS_SUCCESS) { - printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\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(KERN_WARNING MYNAM ": ?Hmmm... %s says it doesn't support F/W download!?!\n", - iocp->name); - printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n"); + 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); return -EBADRQC; } else if (iocstat == MPI_IOCSTATUS_BUSY) { - printk(KERN_WARNING MYNAM ": Warning! %s says: IOC_BUSY!\n", iocp->name); - printk(KERN_WARNING MYNAM ": (try again later?)\n"); + 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(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR! %s returned [bad] status = %04xh\n", - iocp->name, iocstat); - printk(KERN_WARNING MYNAM ": (bad VooDoo)\n"); + printk(MYIOC_s_WARN_FMT "returned [bad] status = %04xh\n", + iocp->name, iocstat); + printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name); return -ENOMSG; } return 0; fwdl_out: - kfree_sgl(sgl, sgl_dma, buflist, iocp); + + CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status); + SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0); + kfree_sgl(sgl, sgl_dma, buflist, iocp); return ret; } @@ -963,10 +1127,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i * structures for the SG elements. */ i = MAX_SGL_BYTES / 8; - buflist = kmalloc(i, GFP_USER); - if (buflist == NULL) + buflist = kzalloc(i, GFP_USER); + if (!buflist) return NULL; - memset(buflist, 0, i); buflist_ent = 0; /* Allocate a single block of memory to store the sg elements and @@ -991,7 +1154,7 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i * */ sgl = sglbuf; - sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1; + sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1; while (bytes_allocd < bytes) { this_alloc = min(alloc_sz, bytes-bytes_allocd); buflist[buflist_ent].len = this_alloc; @@ -1001,10 +1164,10 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i if (buflist[buflist_ent].kptr == NULL) { alloc_sz = alloc_sz / 2; if (alloc_sz == 0) { - printk(KERN_WARNING MYNAM "-SG: No can do - " - "not enough memory! :-(\n"); - printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", - numfrags); + printk(MYIOC_s_WARN_FMT "-SG: No can do - " + "not enough memory! :-(\n", ioc->name); + printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n", + ioc->name, numfrags); goto free_and_fail; } continue; @@ -1012,7 +1175,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i dma_addr_t dma_addr; bytes_allocd += this_alloc; - sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc); + sgl->FlagsLength = (0x10000000|sgdir|this_alloc); + if (ioc->sg_addr_size == sizeof(u64)) + sgl->FlagsLength |= MPT_SGE_FLAGS_64_BIT_ADDRESSING; dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir); sgl->Address = dma_addr; @@ -1027,18 +1192,19 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i /* Need to chain? */ if (fragcnt == sg_spill) { - printk(KERN_WARNING MYNAM "-SG: No can do - " "Chain required! :-(\n"); - printk(KERN_WARNING MYNAM "(freeing %d frags)\n", numfrags); + 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; } /* overflow check... */ if (numfrags*8 > MAX_SGL_BYTES){ /* GRRRRR... */ - printk(KERN_WARNING MYNAM "-SG: No can do - " - "too many SG frags! :-(\n"); - printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", - numfrags); + printk(MYIOC_s_WARN_FMT "-SG: No can do - " + "too many SG frags! :-(\n", ioc->name); + printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n", + ioc->name, numfrags); goto free_and_fail; } } @@ -1049,20 +1215,16 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i *frags = numfrags; *blp = buflist; - dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " - "%d SG frags generated!\n", - numfrags)); - - dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " - "last (big) alloc_sz=%d\n", - alloc_sz)); + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - " + "%d SG frags generated!\n", ioc->name, numfrags)); + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - " + "last (big) alloc_sz=%d\n", ioc->name, alloc_sz)); return sglbuf; free_and_fail: if (sglbuf != NULL) { - int i; - for (i = 0; i < numfrags; i++) { dma_addr_t dma_addr; u8 *kptr; @@ -1139,7 +1301,8 @@ kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_ pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma); kfree(buflist); - dctlprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n)); + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: Free'd 1 SGL buf + %d kbufs!\n", + ioc->name, n)); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1164,9 +1327,8 @@ mptctl_getiocinfo (unsigned long arg, un int cim_rev; u8 revision; struct scsi_device *sdev; - VirtDevice *vdev; + VirtDevice *vdevice; - dctlprintk((": mptctl_getiocinfo called.\n")); /* Add of PCI INFO results in unaligned access for * IA64 and Sparc. Reset long to int. Return no PCI * data for obsolete format. @@ -1184,13 +1346,13 @@ mptctl_getiocinfo (unsigned long arg, un karg = kmalloc(data_size, GFP_KERNEL); if (karg == NULL) { - printk(KERN_ERR "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n", + printk(KERN_ERR MYNAM "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n", __FILE__, __LINE__); return -ENOMEM; } if (copy_from_user(karg, uarg, data_size)) { - printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_getiocinfo - " "Unable to read in mpt_ioctl_iocinfo struct @ %p\n", __FILE__, __LINE__, uarg); kfree(karg); @@ -1199,21 +1361,25 @@ mptctl_getiocinfo (unsigned long arg, un if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + 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); return -ENODEV; } /* Verify the data transfer size is correct. */ if (karg->hdr.maxDataSize != data_size) { - printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " - "Structure size mismatch. Command not completed.\n", - __FILE__, __LINE__); + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - " + "Structure size mismatch. Command not completed.\n", + ioc->name, __FILE__, __LINE__); kfree(karg); return -EFAULT; } + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_getiocinfo called.\n", + ioc->name)); + /* Fill in the data and return the structure to the calling * program */ @@ -1257,8 +1423,10 @@ mptctl_getiocinfo (unsigned long arg, un karg->numDevices = 0; if (ioc->sh) { shost_for_each_device(sdev, ioc->sh) { - vdev = sdev->hostdata; - if (vdev->vtarget->tflags & + vdevice = sdev->hostdata; + if (vdevice == NULL || vdevice->vtarget == NULL) + continue; + if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) continue; karg->numDevices++; @@ -1282,9 +1450,9 @@ mptctl_getiocinfo (unsigned long arg, un /* Copy the data from kernel memory to user memory */ if (copy_to_user((char __user *)arg, karg, data_size)) { - printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - " "Unable to write out mpt_ioctl_iocinfo struct @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); kfree(karg); return -EFAULT; } @@ -1309,7 +1477,7 @@ mptctl_gettargetinfo (unsigned long arg) struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg; struct mpt_ioctl_targetinfo karg; MPT_ADAPTER *ioc; - VirtDevice *vdev; + VirtDevice *vdevice; char *pmem; int *pdata; int iocnum; @@ -1320,9 +1488,8 @@ mptctl_gettargetinfo (unsigned long arg) u8 port; struct scsi_device *sdev; - dctlprintk(("mptctl_gettargetinfo called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) { - printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_gettargetinfo - " "Unable to read in mpt_ioctl_targetinfo struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1330,11 +1497,14 @@ mptctl_gettargetinfo (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + 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; } + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_gettargetinfo called.\n", + ioc->name)); /* Get the port number and set the maximum number of bytes * in the returned structure. * Ignore the port setting. @@ -1344,8 +1514,8 @@ mptctl_gettargetinfo (unsigned long arg) port = karg.hdr.port; if (maxWordsLeft <= 0) { - printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n", - __FILE__, __LINE__); + printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n", + ioc->name, __FILE__, __LINE__); return -ENOMEM; } @@ -1363,13 +1533,12 @@ mptctl_gettargetinfo (unsigned long arg) * 15- 8: Bus Number * 7- 0: Target ID */ - pmem = kmalloc(numBytes, GFP_KERNEL); - if (pmem == NULL) { - printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n", - __FILE__, __LINE__); + pmem = kzalloc(numBytes, GFP_KERNEL); + if (!pmem) { + printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n", + ioc->name, __FILE__, __LINE__); return -ENOMEM; } - memset(pmem, 0, numBytes); pdata = (int *) pmem; /* Get number of devices @@ -1378,13 +1547,15 @@ mptctl_gettargetinfo (unsigned long arg) shost_for_each_device(sdev, ioc->sh) { if (!maxWordsLeft) continue; - vdev = sdev->hostdata; - if (vdev->vtarget->tflags & + vdevice = sdev->hostdata; + if (vdevice == NULL || vdevice->vtarget == NULL) + continue; + if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) continue; - lun = (vdev->vtarget->raidVolume) ? 0x80 : vdev->lun; - *pdata = (((u8)lun << 16) + (vdev->vtarget->channel << 8) + - (vdev->vtarget->id )); + lun = (vdevice->vtarget->raidVolume) ? 0x80 : vdevice->lun; + *pdata = (((u8)lun << 16) + (vdevice->vtarget->channel << 8) + + (vdevice->vtarget->id )); pdata++; numDevices++; --maxWordsLeft; @@ -1396,9 +1567,9 @@ mptctl_gettargetinfo (unsigned long arg) */ if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_targetinfo))) { - printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - " "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); kfree(pmem); return -EFAULT; } @@ -1406,9 +1577,9 @@ mptctl_gettargetinfo (unsigned long arg) /* Copy the remaining data from kernel memory to user memory */ if (copy_to_user(uarg->targetInfo, pmem, numBytes)) { - printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - " "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", - __FILE__, __LINE__, pdata); + ioc->name, __FILE__, __LINE__, pdata); kfree(pmem); return -EFAULT; } @@ -1434,9 +1605,8 @@ mptctl_readtest (unsigned long arg) MPT_ADAPTER *ioc; int iocnum; - dctlprintk(("mptctl_readtest called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) { - printk(KERN_ERR "%s@%d::mptctl_readtest - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - " "Unable to read in mpt_ioctl_test struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1444,11 +1614,14 @@ mptctl_readtest (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + 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; } + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_readtest called.\n", + ioc->name)); /* Fill in the data and return the structure to the calling * program */ @@ -1466,9 +1639,9 @@ mptctl_readtest (unsigned long arg) /* Copy the data from kernel memory to user memory */ if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_test))) { - printk(KERN_ERR "%s@%d::mptctl_readtest - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_readtest - " "Unable to write out mpt_ioctl_test struct @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); return -EFAULT; } @@ -1494,9 +1667,8 @@ mptctl_eventquery (unsigned long arg) MPT_ADAPTER *ioc; int iocnum; - dctlprintk(("mptctl_eventquery called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) { - printk(KERN_ERR "%s@%d::mptctl_eventquery - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - " "Unable to read in mpt_ioctl_eventquery struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1504,20 +1676,23 @@ mptctl_eventquery (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + 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; } + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventquery called.\n", + ioc->name)); karg.eventEntries = MPTCTL_EVENT_LOG_SIZE; karg.eventTypes = ioc->eventTypes; /* Copy the data from kernel memory to user memory */ if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) { - printk(KERN_ERR "%s@%d::mptctl_eventquery - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventquery - " "Unable to write out mpt_ioctl_eventquery struct @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); return -EFAULT; } return 0; @@ -1532,9 +1707,8 @@ mptctl_eventenable (unsigned long arg) MPT_ADAPTER *ioc; int iocnum; - dctlprintk(("mptctl_eventenable called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) { - printk(KERN_ERR "%s@%d::mptctl_eventenable - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - " "Unable to read in mpt_ioctl_eventenable struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1542,21 +1716,24 @@ mptctl_eventenable (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + 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; } + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventenable called.\n", + ioc->name)); if (ioc->events == NULL) { /* Have not yet allocated memory - do so now. */ int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); - ioc->events = kmalloc(sz, GFP_KERNEL); - if (ioc->events == NULL) { - printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); + ioc->events = kzalloc(sz, GFP_KERNEL); + if (!ioc->events) { + printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n", + ioc->name); return -ENOMEM; } - memset(ioc->events, 0, sz); ioc->alloc_total += sz; ioc->eventContext = 0; @@ -1579,9 +1756,8 @@ mptctl_eventreport (unsigned long arg) int iocnum; int numBytes, maxEvents, max; - dctlprintk(("mptctl_eventreport called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) { - printk(KERN_ERR "%s@%d::mptctl_eventreport - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_eventreport - " "Unable to read in mpt_ioctl_eventreport struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1589,11 +1765,14 @@ mptctl_eventreport (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + 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); @@ -1613,9 +1792,9 @@ mptctl_eventreport (unsigned long arg) */ numBytes = max * sizeof(MPT_IOCTL_EVENTS); if (copy_to_user(uarg->eventData, ioc->events, numBytes)) { - printk(KERN_ERR "%s@%d::mptctl_eventreport - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventreport - " "Unable to write out mpt_ioctl_eventreport struct @ %p\n", - __FILE__, __LINE__, ioc->events); + ioc->name, __FILE__, __LINE__, ioc->events); return -EFAULT; } @@ -1632,9 +1811,8 @@ mptctl_replace_fw (unsigned long arg) int iocnum; int newFwSize; - dctlprintk(("mptctl_replace_fw called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) { - printk(KERN_ERR "%s@%d::mptctl_replace_fw - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_replace_fw - " "Unable to read in mpt_ioctl_replace_fw struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1642,11 +1820,14 @@ mptctl_replace_fw (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + 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; } + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_replace_fw called.\n", + ioc->name)); /* If caching FW, Free the old FW image */ if (ioc->cached_fw == NULL) @@ -1670,9 +1851,9 @@ mptctl_replace_fw (unsigned long arg) /* Copy the data from user memory to kernel space */ if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) { - printk(KERN_ERR "%s@%d::mptctl_replace_fw - " - "Unable to read in mpt_ioctl_replace_fw image " - "@ %p\n", __FILE__, __LINE__, uarg); + 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); mpt_free_fw_memory(ioc); return -EFAULT; } @@ -1704,10 +1885,9 @@ mptctl_mpt_command (unsigned long arg) int iocnum; int rc; - dctlprintk(("mptctl_command called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) { - printk(KERN_ERR "%s@%d::mptctl_mpt_command - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_mpt_command - " "Unable to read in mpt_ioctl_command struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -1715,8 +1895,9 @@ mptctl_mpt_command (unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + 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; } @@ -1753,41 +1934,46 @@ mptctl_do_mpt_command (struct mpt_ioctl_ int sz, rc = 0; int msgContext; u16 req_idx; - ulong timeout; + unsigned long timeout; + unsigned long timeleft; struct scsi_device *sdev; + unsigned long flags; + u8 function; - dctlprintk(("mptctl_do_mpt_command called.\n")); + /* bufIn and bufOut are used for user to kernel space transfers + */ bufIn.kptr = bufOut.kptr = NULL; + bufIn.len = bufOut.len = 0; if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); return -ENODEV; } - if (!ioc->ioctl) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " - "No memory available during driver init.\n", - __FILE__, __LINE__); - return -ENOMEM; - } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " - "Busy with IOC Reset \n", __FILE__, __LINE__); + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - " + "Busy with diagnostic reset\n", __FILE__, __LINE__); return -EBUSY; } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); /* Verify that the final request frame will not be too large. */ sz = karg.dataSgeOffset * 4; if (karg.dataInSize > 0) - sz += sizeof(dma_addr_t) + sizeof(u32); + sz += ioc->SGE_size; if (karg.dataOutSize > 0) - sz += sizeof(dma_addr_t) + sizeof(u32); + sz += ioc->SGE_size; if (sz > ioc->req_sz) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Request frame too large (%d) maximum (%d)\n", - __FILE__, __LINE__, sz, ioc->req_sz); + ioc->name, __FILE__, __LINE__, sz, ioc->req_sz); return -EFAULT; } @@ -1805,24 +1991,40 @@ mptctl_do_mpt_command (struct mpt_ioctl_ * Request frame in user space */ if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to read MF from mpt_ioctl_command struct @ %p\n", - __FILE__, __LINE__, mfPtr); + ioc->name, __FILE__, __LINE__, mfPtr); + function = -1; rc = -EFAULT; goto done_free_mem; } hdr->MsgContext = cpu_to_le32(msgContext); - + function = hdr->Function; /* Verify that this request is allowed. */ - switch (hdr->Function) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n", + ioc->name, function, mf)); + + switch (function) { case MPI_FUNCTION_IOC_FACTS: case MPI_FUNCTION_PORT_FACTS: karg.dataOutSize = karg.dataInSize = 0; break; case MPI_FUNCTION_CONFIG: + { + Config_t *config_frame; + config_frame = (Config_t *)mf; + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\ttype=0x%02x ext_type=0x%02x " + "number=0x%02x action=0x%02x\n", ioc->name, + config_frame->Header.PageType, + config_frame->ExtPageType, + config_frame->Header.PageNumber, + config_frame->Action)); + break; + } + case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND: case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND: case MPI_FUNCTION_FW_UPLOAD: @@ -1843,23 +2045,23 @@ mptctl_do_mpt_command (struct mpt_ioctl_ id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus; if (pScsiReq->TargetID > id) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Target ID out of bounds. \n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -ENODEV; goto done_free_mem; } if (pScsiReq->Bus >= ioc->number_of_buses) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Target Bus out of bounds. \n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -ENODEV; goto done_free_mem; } pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; - pScsiReq->MsgFlags |= mpt_msg_flags(); + pScsiReq->MsgFlags |= mpt_msg_flags(ioc); /* verify that app has not requested @@ -1881,6 +2083,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_ struct scsi_target *starget = scsi_target(sdev); VirtTarget *vtarget = starget->hostdata; + if (vtarget == NULL) + continue; if ((pScsiReq->TargetID == vtarget->id) && (pScsiReq->Bus == vtarget->channel) && (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)) @@ -1901,13 +2105,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_ pScsiReq->Control = cpu_to_le32(scsidir | qtag); pScsiReq->DataLength = cpu_to_le32(dataSize); - ioc->ioctl->reset = MPTCTL_RESET_OK; - ioc->ioctl->id = pScsiReq->TargetID; - } else { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } @@ -1916,7 +2117,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ case MPI_FUNCTION_SMP_PASSTHROUGH: /* Check mf->PassthruFlags to determine if * transfer is ImmediateMode or not. - * Immediate mode returns data in the ReplyFrame. + * Immediate mode returns data in the reply. * Else, we are sending request and response data * in two SGLs at the end of the mf. */ @@ -1924,9 +2125,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_ case MPI_FUNCTION_SATA_PASSTHROUGH: if (!ioc->sh) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } @@ -1945,7 +2146,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ int dataSize; pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; - pScsiReq->MsgFlags |= mpt_msg_flags(); + pScsiReq->MsgFlags |= mpt_msg_flags(ioc); /* verify that app has not requested @@ -1980,32 +2181,25 @@ mptctl_do_mpt_command (struct mpt_ioctl_ pScsiReq->Control = cpu_to_le32(scsidir | qtag); pScsiReq->DataLength = cpu_to_le32(dataSize); - ioc->ioctl->reset = MPTCTL_RESET_OK; - ioc->ioctl->id = pScsiReq->TargetID; } else { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } break; case MPI_FUNCTION_SCSI_TASK_MGMT: - { - MPT_SCSI_HOST *hd = NULL; - if ((ioc->sh == NULL) || ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " - "SCSI driver not loaded or SCSI host not found. \n", - __FILE__, __LINE__); - rc = -EFAULT; - goto done_free_mem; - } else if (mptctl_set_tm_flags(hd) != 0) { - rc = -EPERM; - goto done_free_mem; - } - } + { + SCSITaskMgmt_t *pScsiTm; + pScsiTm = (SCSITaskMgmt_t *)mf; + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tTaskType=0x%x MsgFlags=0x%x " + "TaskMsgContext=0x%x id=%d channel=%d\n", ioc->name, pScsiTm->TaskType, + le32_to_cpu(pScsiTm->TaskMsgContext), pScsiTm->MsgFlags, + pScsiTm->TargetID, pScsiTm->Bus)); break; + } case MPI_FUNCTION_IOC_INIT: { @@ -2015,7 +2209,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ /* Verify that all entries in the IOC INIT match * existing setup (and in LE format). */ - if (sizeof(dma_addr_t) == sizeof(u64)) { + if (ioc->sg_addr_size == sizeof(u64)) { high_addr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32)); sense_high= cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32)); } else { @@ -2023,14 +2217,19 @@ 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)) || (pInit->HostMfaHighAddr != high_addr) || (pInit->SenseBufferHighAddr != sense_high)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n", - __FILE__, __LINE__); + ioc->name, __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } @@ -2061,9 +2260,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_ MPI_FUNCTION_LAN_RESET */ - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Illegal request (function 0x%x) \n", - __FILE__, __LINE__, hdr->Function); + ioc->name, __FILE__, __LINE__, function); rc = -EFAULT; goto done_free_mem; } @@ -2076,11 +2275,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_ psge = (char *) (((int *) mf) + karg.dataSgeOffset); flagsLength = 0; - /* bufIn and bufOut are used for user to kernel space transfers - */ - bufIn.kptr = bufOut.kptr = NULL; - bufIn.len = bufOut.len = 0; - if (karg.dataOutSize > 0) sgSize ++; @@ -2094,8 +2288,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ if (karg.dataInSize > 0) { flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_DIRECTION | - mpt_addr_size() ) + MPI_SGE_FLAGS_DIRECTION ) << MPI_SGE_FLAGS_SHIFT; } else { flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; @@ -2112,19 +2305,19 @@ mptctl_do_mpt_command (struct mpt_ioctl_ /* Set up this SGE. * Copy to MF and to sglbuf */ - mpt_add_sge(psge, flagsLength, dma_addr_out); - psge += (sizeof(u32) + sizeof(dma_addr_t)); + ioc->add_sge(psge, flagsLength, dma_addr_out); + psge += ioc->SGE_size; /* Copy user data to kernel space. */ if (copy_from_user(bufOut.kptr, karg.dataOutBufPtr, bufOut.len)) { - printk(KERN_ERR + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - Unable " "to read user data " "struct @ %p\n", - __FILE__, __LINE__,karg.dataOutBufPtr); + ioc->name, __FILE__, __LINE__,karg.dataOutBufPtr); rc = -EFAULT; goto done_free_mem; } @@ -2146,70 +2339,86 @@ mptctl_do_mpt_command (struct mpt_ioctl_ /* Set up this SGE * Copy to MF and to sglbuf */ - mpt_add_sge(psge, flagsLength, dma_addr_in); + ioc->add_sge(psge, flagsLength, dma_addr_in); } } } else { /* Add a NULL SGE */ - mpt_add_sge(psge, flagsLength, (dma_addr_t) -1); + ioc->add_sge(psge, flagsLength, (dma_addr_t) -1); } - ioc->ioctl->wait_done = 0; - if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { - - DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf); + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) + if (function == MPI_FUNCTION_SCSI_TASK_MGMT) { - if (mpt_send_handshake_request(mptctl_id, ioc, - sizeof(SCSITaskMgmt_t), (u32*)mf, - CAN_SLEEP) != 0) { - dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!" - " (ioc %p, mf %p) \n", ioc->name, - ioc, mf)); - mptctl_free_tm_flags(ioc); - rc = -ENODATA; + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); goto done_free_mem; } + DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); + + if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && + (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); + if (rc != 0) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "send_handshake FAILED! (ioc %p, mf %p)\n", + ioc->name, ioc, mf)); + mpt_clear_taskmgmt_in_progress_flag(ioc); + rc = -ENODATA; + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + goto done_free_mem; + } + } } else mpt_put_msg_frame(mptctl_id, ioc, mf); /* Now wait for the command to complete */ timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT; - timeout = wait_event_timeout(mptctl_wait, - ioc->ioctl->wait_done == 1, - HZ*timeout); - - if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) { - /* Now we need to reset the board */ - - if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) - mptctl_free_tm_flags(ioc); - - mptctl_timeout_expired(ioc->ioctl); - rc = -ENODATA; + timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*timeout); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -ETIME; + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n", + ioc->name, __FUNCTION__)); + if (function == MPI_FUNCTION_SCSI_TASK_MGMT) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + goto done_free_mem; + } + if (!timeleft) { + mptctl_timeout_expired(ioc, mf); + mf = NULL; + } goto done_free_mem; } + if (function == MPI_FUNCTION_SCSI_TASK_MGMT) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + mf = NULL; /* If a valid reply frame, copy to the user. * Offset 2: reply length in U32's */ - if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) { + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { if (karg.maxReplyBytes < ioc->reply_sz) { - sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]); + sz = min(karg.maxReplyBytes, 4*ioc->ioctl_cmds.reply[2]); } else { - sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]); + sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]); } - if (sz > 0) { if (copy_to_user(karg.replyFrameBufPtr, - &ioc->ioctl->ReplyFrame, sz)){ - printk(KERN_ERR + ioc->ioctl_cmds.reply, sz)){ + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to write out reply frame %p\n", - __FILE__, __LINE__, karg.replyFrameBufPtr); + ioc->name, __FILE__, __LINE__, karg.replyFrameBufPtr); rc = -ENODATA; goto done_free_mem; } @@ -2218,13 +2427,13 @@ mptctl_do_mpt_command (struct mpt_ioctl_ /* If valid sense data, copy to user. */ - if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) { + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) { sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE); if (sz > 0) { - if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + 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", - __FILE__, __LINE__, + ioc->name, __FILE__, __LINE__, karg.senseDataPtr); rc = -ENODATA; goto done_free_mem; @@ -2235,14 +2444,13 @@ mptctl_do_mpt_command (struct mpt_ioctl_ /* If the overall status is _GOOD and data in, copy data * to user. */ - if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) && - (karg.dataInSize > 0) && (bufIn.kptr)) { - + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) && + (karg.dataInSize > 0) && (bufIn.kptr)) { if (copy_to_user(karg.dataInBufPtr, bufIn.kptr, karg.dataInSize)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to write data to user %p\n", - __FILE__, __LINE__, + ioc->name, __FILE__, __LINE__, karg.dataInBufPtr); rc = -ENODATA; } @@ -2250,9 +2458,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_ done_free_mem: - ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_COMMAND_GOOD | - MPT_IOCTL_STATUS_SENSE_VALID | - MPT_IOCTL_STATUS_RF_VALID ); + CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); /* Free the allocated memory. */ @@ -2292,18 +2499,18 @@ 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; - dctlprintk((": mptctl_hp_hostinfo called.\n")); /* Reset long to int. Should affect IA64 and SPARC only */ if (data_size == sizeof(hp_host_info_t)) @@ -2314,7 +2521,7 @@ mptctl_hp_hostinfo(unsigned long arg, un return -EFAULT; if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) { - printk(KERN_ERR "%s@%d::mptctl_hp_host_info - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_host_info - " "Unable to read in hp_host_info struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -2322,11 +2529,14 @@ mptctl_hp_hostinfo(unsigned long arg, un if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + 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 */ @@ -2366,42 +2576,9 @@ mptctl_hp_hostinfo(unsigned long arg, un karg.fw_version[10] = (ioc->facts.FWVersion.Struct.Dev % 10 ) + '0'; karg.fw_version[11] = '\0'; - /* Issue a config request to get the device serial number - */ - hdr.PageVersion = 0; - hdr.PageLength = 0; - hdr.PageNumber = 0; - hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING; - cfg.cfghdr.hdr = &hdr; - cfg.physAddr = -1; - cfg.pageAddr = 0; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.dir = 0; /* read */ - cfg.timeout = 10; + strncpy(karg.serial_number, ioc->board_tracer, 16); - strncpy(karg.serial_number, " ", 24); - if (mpt_config(ioc, &cfg) == 0) { - if (cfg.cfghdr.hdr->PageLength > 0) { - /* Issue the second config page request */ - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma); - if (pbuf) { - cfg.physAddr = buf_dma; - if (mpt_config(ioc, &cfg) == 0) { - ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf; - if (strlen(pdata->BoardTracerNumber) > 1) { - strncpy(karg.serial_number, pdata->BoardTracerNumber, 24); - karg.serial_number[24-1]='\0'; - } - } - pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); - pbuf = NULL; - } - } - } - rc = mpt_GetIocState(ioc, 1); - switch (rc) { + switch (mpt_GetIocState(ioc, 1)) { case MPI_IOC_STATE_OPERATIONAL: karg.ioc_status = HP_STATUS_OK; break; @@ -2431,9 +2608,9 @@ mptctl_hp_hostinfo(unsigned long arg, un MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; if (hd && (cim_rev == 1)) { - karg.hard_resets = hd->hard_resets; - karg.soft_resets = hd->soft_resets; - karg.timeouts = hd->timeouts; + karg.hard_resets = ioc->hard_resets; + karg.soft_resets = ioc->soft_resets; + karg.timeouts = ioc->timeouts; } } @@ -2441,17 +2618,19 @@ 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((MYIOC_s_WARN_FMT "%s, no msg frames!!\n", + 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); @@ -2461,24 +2640,26 @@ mptctl_hp_hostinfo(unsigned long arg, un IstwiRWRequest->DeviceAddr = 0xB0; pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma); - if (!pbuf) + if (!pbuf) { + retval = -ENOMEM; goto out; - mpt_add_sge((char *)&IstwiRWRequest->SGL, - (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma); + } + ioc->add_sge((char *)&IstwiRWRequest->SGL, (MPT_SGE_FLAGS_SSIMPLE_READ|4),buf_dma); - ioc->ioctl->wait_done = 0; + retval = 0; + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, IstwiRWRequest->MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) mpt_put_msg_frame(mptctl_id, ioc, mf); - - rc = wait_event_timeout(mptctl_wait, - ioc->ioctl->wait_done == 1, - HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */); - - if(rc <=0 && (ioc->ioctl->wait_done != 1 )) { - /* - * Now we need to reset the board - */ - mpt_free_msg_frame(ioc, mf); - mptctl_timeout_expired(ioc->ioctl); + timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*MPT_IOCTL_DEFAULT_TIMEOUT); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + retval = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __FUNCTION__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; + } + if (!timeleft) + mptctl_timeout_expired(ioc, mf); goto out; } @@ -2491,23 +2672,26 @@ mptctl_hp_hostinfo(unsigned long arg, un * bays have drives in them * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3) */ - if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) karg.rsvd = *(u32 *)pbuf; out: + CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); + if (pbuf) pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma); /* Copy the data from kernel memory to user memory */ if (copy_to_user((char __user *)arg, &karg, sizeof(hp_host_info_t))) { - printk(KERN_ERR "%s@%d::mptctl_hpgethostinfo - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hpgethostinfo - " "Unable to write out hp_host_info @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); return -EFAULT; } - return 0; + return retval; } @@ -2538,9 +2722,8 @@ mptctl_hp_targetinfo(unsigned long arg) ConfigPageHeader_t hdr; int tmp, np, rc = 0; - dctlprintk((": mptctl_hp_targetinfo called.\n")); if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) { - printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - " + printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_targetinfo - " "Unable to read in hp_host_targetinfo struct @ %p\n", __FILE__, __LINE__, uarg); return -EFAULT; @@ -2548,11 +2731,14 @@ mptctl_hp_targetinfo(unsigned long arg) if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dctlprintk((KERN_ERR "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + 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)); /* There is nothing to do for FCP parts. */ if ((ioc->bus_type == SAS) || (ioc->bus_type == FC)) @@ -2651,9 +2837,9 @@ mptctl_hp_targetinfo(unsigned long arg) /* Copy the data from kernel memory to user memory */ if (copy_to_user((char __user *)arg, &karg, sizeof(hp_target_info_t))) { - printk(KERN_ERR "%s@%d::mptctl_hp_target_info - " + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hp_target_info - " "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", - __FILE__, __LINE__, uarg); + ioc->name, __FILE__, __LINE__, uarg); return -EFAULT; } @@ -2662,7 +2848,7 @@ mptctl_hp_targetinfo(unsigned long arg) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static const struct file_operations mptctl_fops = { +static struct file_operations mptctl_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .release = mptctl_release, @@ -2694,7 +2880,6 @@ compat_mptfwxfer_ioctl(struct file *filp int nonblock = (filp->f_flags & O_NONBLOCK); int ret; - dctlprintk((KERN_INFO MYNAM "::compat_mptfwxfer_ioctl() called\n")); if (copy_from_user(&kfw32, (char __user *)arg, sizeof(kfw32))) return -EFAULT; @@ -2703,21 +2888,24 @@ compat_mptfwxfer_ioctl(struct file *filp iocnumX = kfw32.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - dctlprintk((KERN_ERR MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n", - __LINE__, iocnumX)); + if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n", + __LINE__, iocnumX); return -ENODEV; } if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) return ret; + dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mptfwxfer_ioctl() called\n", + iocp->name)); kfw.iocnum = iocnum; kfw.fwlen = kfw32.fwlen; kfw.bufp = compat_ptr(kfw32.bufp); ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); - mutex_unlock(&iocp->ioctl->ioctl_mutex); + mutex_unlock(&iocp->ioctl_cmds.mutex); return ret; } @@ -2734,8 +2922,6 @@ compat_mpt_command(struct file *filp, un int nonblock = (filp->f_flags & O_NONBLOCK); int ret; - dctlprintk((KERN_INFO MYNAM "::compat_mpt_command() called\n")); - if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) return -EFAULT; @@ -2743,14 +2929,17 @@ compat_mpt_command(struct file *filp, un iocnumX = karg32.hdr.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - dctlprintk((KERN_ERR MYNAM "::compat_mpt_command @%d - ioc%d not found!\n", - __LINE__, iocnumX)); + if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n", + __LINE__, iocnumX); return -ENODEV; } if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) return ret; + dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mpt_command() called\n", + iocp->name)); /* Copy data to karg */ karg.hdr.iocnum = karg32.hdr.iocnum; karg.hdr.port = karg32.hdr.port; @@ -2771,7 +2960,7 @@ compat_mpt_command(struct file *filp, un */ ret = mptctl_do_mpt_command (karg, &uarg->MF); - mutex_unlock(&iocp->ioctl->ioctl_mutex); + mutex_unlock(&iocp->ioctl_cmds.mutex); return ret; } @@ -2791,6 +2980,31 @@ static long compat_mpctl_ioctl(struct fi case MPTHARDRESET: case HP_GETHOSTINFO: case HP_GETTARGETINFO: +#if defined(CPQ_CIM) + case CC_CSMI_SAS_GET_DRIVER_INFO: + case CC_CSMI_SAS_GET_CNTLR_CONFIG: + case CC_CSMI_SAS_GET_CNTLR_STATUS: + case CC_CSMI_SAS_GET_SCSI_ADDRESS: + case CC_CSMI_SAS_GET_DEVICE_ADDRESS: + case CC_CSMI_SAS_GET_PHY_INFO: + case CC_CSMI_SAS_GET_SATA_SIGNATURE: + case CC_CSMI_SAS_GET_LINK_ERRORS: + case CC_CSMI_SAS_SMP_PASSTHRU: + case CC_CSMI_SAS_SSP_PASSTHRU: + case CC_CSMI_SAS_FIRMWARE_DOWNLOAD: + case CC_CSMI_SAS_GET_RAID_INFO: + case CC_CSMI_SAS_GET_RAID_CONFIG: + case CC_CSMI_SAS_GET_RAID_FEATURES: + case CC_CSMI_SAS_SET_RAID_CONTROL: + case CC_CSMI_SAS_GET_RAID_ELEMENT: + case CC_CSMI_SAS_SET_RAID_OPERATION: + case CC_CSMI_SAS_SET_PHY_INFO: + case CC_CSMI_SAS_STP_PASSTHRU: + case CC_CSMI_SAS_TASK_MANAGEMENT: + case CC_CSMI_SAS_PHY_CONTROL: + case CC_CSMI_SAS_GET_CONNECTOR_INFO: + case CC_CSMI_SAS_GET_LOCATION: +#endif /* CPQ_CIM */ case MPTTEST: ret = __mptctl_ioctl(f, cmd, arg); break; @@ -2823,31 +3037,12 @@ static long compat_mpctl_ioctl(struct fi static int mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - int err; - int sz; - u8 *mem; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - /* - * Allocate and inite a MPT_IOCTL structure - */ - sz = sizeof (MPT_IOCTL); - mem = kmalloc(sz, GFP_KERNEL); - if (mem == NULL) { - err = -ENOMEM; - goto out_fail; - } + mutex_init(&ioc->ioctl_cmds.mutex); + init_completion(&ioc->ioctl_cmds.done); - memset(mem, 0, sz); - ioc->ioctl = (MPT_IOCTL *) mem; - ioc->ioctl->ioc = ioc; - mutex_init(&ioc->ioctl->ioctl_mutex); return 0; - -out_fail: - - mptctl_remove(pdev); - return err; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2860,9 +3055,22 @@ out_fail: static void mptctl_remove(struct pci_dev *pdev) { +#if defined(DIAG_BUFFER_SUPPORT) MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + int i; - kfree ( ioc->ioctl ); + /* + * Cleanup diag buffer allocated memory + */ + for (i = 0; i < MPI_DIAG_BUF_TYPE_COUNT; i++) { + if (ioc->DiagBuffer[i] == NULL) + continue; + pci_free_consistent(ioc->pcidev, ioc->DiagBuffer_sz[i], + ioc->DiagBuffer[i], ioc->DiagBuffer_dma[i]); + ioc->DiagBuffer[i] = NULL; + ioc->DiagBuffer_Status[i] = 0; + } +#endif } static struct mpt_pci_driver mptctl_driver = { @@ -2878,11 +3086,7 @@ static int __init mptctl_init(void) show_mptmod_ver(my_NAME, my_VERSION); - if(mpt_device_driver_register(&mptctl_driver, - MPTCTL_DRIVER) != 0 ) { - dprintk((KERN_INFO MYNAM - ": failed to register dd callbacks\n")); - } + mpt_device_driver_register(&mptctl_driver, MPTCTL_DRIVER); /* Register this device */ err = misc_register(&mptctl_miscdev); @@ -2898,23 +3102,17 @@ static int __init mptctl_init(void) * Install our handler */ ++where; - if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) { + mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER); + if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) { printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); misc_deregister(&mptctl_miscdev); err = -EBUSY; goto out_fail; } - if (mpt_reset_register(mptctl_id, mptctl_ioc_reset) == 0) { - dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); - } else { - /* FIXME! */ - } - - if (mpt_event_register(mptctl_id, mptctl_event_process) == 0) { - devtverboseprintk((KERN_INFO MYNAM - ": Registered for IOC event notifications\n")); - } + mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER); + mpt_reset_register(mptctl_id, mptctl_ioc_reset); + mpt_event_register(mptctl_id, mptctl_event_process); return 0; @@ -2934,17 +3132,23 @@ static void mptctl_exit(void) /* De-register reset handler from base module */ mpt_reset_deregister(mptctl_id); - dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n")); + mpt_reset_deregister(mptctl_taskmgmt_id); /* De-register callback handler from base module */ mpt_deregister(mptctl_id); - printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n"); 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); Index: linux-2.6.18.i386/drivers/message/fusion/mptctl.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/mptctl.h +++ linux-2.6.18.i386/drivers/message/fusion/mptctl.h @@ -1,12 +1,12 @@ /* - * 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 - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsi.com) + * Copyright (c) 1999-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -460,8 +460,5 @@ typedef struct _hp_target_info { /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - #endif Index: linux-2.6.18.i386/drivers/message/fusion/mptdebug.h =================================================================== --- /dev/null +++ linux-2.6.18.i386/drivers/message/fusion/mptdebug.h @@ -0,0 +1,298 @@ +/* + * linux/drivers/message/fusion/mptdebug.h + * 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) + * + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#ifndef MPTDEBUG_H_INCLUDED +#define MPTDEBUG_H_INCLUDED + +/* + * debug level can be programmed on the fly via SysFS (hex values) + * + * 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 + * + * -------------------------------------------------------- + * mpt_debug_level - command line parameter + * this allow enabling debug at driver load time (for all iocs) + * + * Example (programming for MPT_DEBUG_EVENTS) + * + * insmod mptbase.ko mpt_debug_level=8 + * + * -------------------------------------------------------- + * CONFIG_FUSION_LOGGING - enables compiling debug into driver + * this can be enabled in the driver Makefile + * + * + * -------------------------------------------------------- + * Please note most debug prints are set to logging priority = debug + * This is the lowest level, and most verbose. Please refer to manual + * pages for syslogd or syslogd-ng on how to configure this. + */ + +#define MPT_DEBUG 0x00000001 +#define MPT_DEBUG_MSG_FRAME 0x00000002 +#define MPT_DEBUG_SG 0x00000004 +#define MPT_DEBUG_EVENTS 0x00000008 +#define MPT_DEBUG_VERBOSE_EVENTS 0x00000010 +#define MPT_DEBUG_INIT 0x00000020 +#define MPT_DEBUG_EXIT 0x00000040 +#define MPT_DEBUG_FAIL 0x00000080 +#define MPT_DEBUG_TM 0x00000100 +#define MPT_DEBUG_DV 0x00000200 +#define MPT_DEBUG_REPLY 0x00000400 +#define MPT_DEBUG_HANDSHAKE 0x00000800 +#define MPT_DEBUG_CONFIG 0x00001000 +#define MPT_DEBUG_DL 0x00002000 +#define MPT_DEBUG_RESET 0x00008000 +#define MPT_DEBUG_SCSI 0x00010000 +#define MPT_DEBUG_IOCTL 0x00020000 +#define MPT_DEBUG_CSMISAS 0x00040000 +#define MPT_DEBUG_FC 0x00080000 +#define MPT_DEBUG_SAS 0x00100000 +#define MPT_DEBUG_SAS_WIDE 0x00200000 +#define MPT_DEBUG_36GB_MEM 0x00400000 + +/* + * CONFIG_FUSION_LOGGING - enabled in Kconfig + */ + +#ifdef CONFIG_FUSION_LOGGING +#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \ +{ \ + if (IOC->debug_level & BITS) \ + CMD; \ +} +#else +#define MPT_CHECK_LOGGING(IOC, CMD, BITS) +#endif + + +/* + * debug macros + */ + +#define dprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG) + +#define dsgprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG) + +#define devtprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS) + +#define devtverboseprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_VERBOSE_EVENTS) + +#define dinitprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT) + +#define dexitprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT) + +#define dfailprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL) + +#define dtmprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM) + +#define ddvprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DV) + +#define dreplyprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY) + +#define dhsprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE) + +#define dcprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG) + +#define ddlprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL) + +#define drsprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET) + +#define dsprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI) + +#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) + +#define dsasprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS) + +#define dsaswideprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE) + +#define d36memprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_36GB_MEM) + +/* + * Verbose logging + */ +#if defined(MPT_DEBUG_VERBOSE) && defined(CONFIG_FUSION_LOGGING) +static inline void +DBG_DUMP_FW_DOWNLOAD(MPT_ADAPTER *ioc, u32 *mfp, int numfrags) +{ + int i; + + if (!(ioc->debug_level & MPT_DEBUG)) + return; + printk(KERN_DEBUG "F/W download request:\n"); + for (i=0; i < 7+numfrags*2; i++) + printk(" %08x", le32_to_cpu(mfp[i])); + printk("\n"); +} + +static inline void +DBG_DUMP_PUT_MSG_FRAME(MPT_ADAPTER *ioc, u32 *mfp) +{ + int ii, n; + + if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME)) + return; + printk(KERN_DEBUG "%s: About to Put msg frame @ %p:\n", + ioc->name, mfp); + n = ioc->req_sz/4 - 1; + while (mfp[n] == 0) + n--; + for (ii=0; ii<=n; ii++) { + if (ii && ((ii%8)==0)) + printk("\n"); + printk(" %08x", le32_to_cpu(mfp[ii])); + } + printk("\n"); +} + +static inline void +DBG_DUMP_FW_REQUEST_FRAME(MPT_ADAPTER *ioc, u32 *mfp) +{ + int i, n; + + if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME)) + return; + n = 10; + printk(KERN_INFO " "); + for (i = 0; i < n; i++) + printk(" %08x", le32_to_cpu(mfp[i])); + printk("\n"); +} + +static inline void +DBG_DUMP_REQUEST_FRAME(MPT_ADAPTER *ioc, u32 *mfp) +{ + int i, n; + + if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME)) + return; + n = 24; + for (i=0; idebug_level & MPT_DEBUG_MSG_FRAME)) + return; + n = (le32_to_cpu(mfp[0]) & 0x00FF0000) >> 16; + printk(KERN_INFO " "); + for (i=0; idebug_level & MPT_DEBUG_MSG_FRAME)) + return; + n = 3; + printk(KERN_INFO " "); + for (i=0; idebug_level & MPT_DEBUG_TM)) + return; + n = 13; + printk(KERN_DEBUG "TM_REQUEST:\n"); + for (i=0; idebug_level & MPT_DEBUG_TM)) + return; + n = (le32_to_cpu(mfp[0]) & 0x00FF0000) >> 16; + printk(KERN_DEBUG "TM_REPLY MessageLength=%d:\n", n); + for (i=0; i #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 @@ -63,6 +65,7 @@ #include #include +#include "linux_compat.h" /* linux-2.6 tweaks */ #include "mptbase.h" #include "mptscsih.h" @@ -85,15 +88,23 @@ MODULE_PARM_DESC(mptfc_dev_loss_tmo, " I " return following a device loss event." " Default=60."); +static int mpt_sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH; +static int mptfc_set_sdev_queue_depth(const char *val, struct kernel_param *kp); +module_param_call(mpt_sdev_queue_depth, mptfc_set_sdev_queue_depth, + param_get_int, &mpt_sdev_queue_depth, 0600); +MODULE_PARM_DESC(mpt_sdev_queue_depth, + " Max Device Queue Depth (default=" + __MODULE_STRING(MPT_SCSI_CMD_PER_DEV_HIGH) ")"); + /* scsi-mid layer global parmeter is max_report_luns, which is 511 */ #define MPTFC_MAX_LUN (16895) static int max_lun = MPTFC_MAX_LUN; module_param(max_lun, int, 0); MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); -static int mptfcDoneCtx = -1; -static int mptfcTaskCtx = -1; -static int mptfcInternalCtx = -1; /* Used only for internal commands */ +static u8 mptfcDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptfcTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; static int mptfc_target_alloc(struct scsi_target *starget); static int mptfc_slave_alloc(struct scsi_device *sdev); @@ -131,6 +142,7 @@ static struct scsi_host_template mptfc_d .max_sectors = 8192, .cmd_per_lun = 7, .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = mptscsih_host_attrs, }; /**************************************************************************** @@ -154,6 +166,8 @@ static struct pci_device_id mptfc_pci_ta PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E, PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_BROCADE, MPI_MANUFACTPAGE_DEVICEID_FC949E, + PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, mptfc_pci_table); @@ -181,46 +195,75 @@ static struct fc_function_template mptfc .show_host_symbolic_name = 1, }; +/** + * mptfc_set_sdev_queue_depth - global setting of the mpt_sdev_queue_depth + * found via /sys/module/mptfc/parameters/mpt_sdev_queue_depth + * @val: + * @kp: + * + * Returns + **/ +static int +mptfc_set_sdev_queue_depth(const char *val, struct kernel_param *kp) +{ + int ret = param_set_int(val, kp); + MPT_ADAPTER *ioc; + struct scsi_device *sdev; + + if (ret) + return ret; + + list_for_each_entry(ioc, &ioc_list, list) { + if (ioc->bus_type != FC) + continue; + shost_for_each_device(sdev, ioc->sh) + mptscsih_change_queue_depth(sdev, mpt_sdev_queue_depth); + ioc->sdev_queue_depth = mpt_sdev_queue_depth; + } + return 0; +} + static int mptfc_block_error_handler(struct scsi_cmnd *SCpnt, int (*func)(struct scsi_cmnd *SCpnt), const char *caller) { + MPT_SCSI_HOST *hd; struct scsi_device *sdev = SCpnt->device; struct Scsi_Host *shost = sdev->host; struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); unsigned long flags; int ready; + MPT_ADAPTER *ioc; + hd = shost_private(SCpnt->device->host); + ioc = hd->ioc; spin_lock_irqsave(shost->host_lock, flags); while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) { spin_unlock_irqrestore(shost->host_lock, flags); - dfcprintk ((MYIOC_s_INFO_FMT + dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "mptfc_block_error_handler.%d: %d:%d, port status is " "DID_IMM_RETRY, deferring %s recovery.\n", - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, - SCpnt->device->id,SCpnt->device->lun,caller)); + ioc->name, ioc->sh->host_no, + SCpnt->device->id, SCpnt->device->lun, caller)); msleep(1000); spin_lock_irqsave(shost->host_lock, flags); } spin_unlock_irqrestore(shost->host_lock, flags); if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) { - dfcprintk ((MYIOC_s_INFO_FMT + dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "%s.%d: %d:%d, failing recovery, " - "port state %d, vdev %p.\n", caller, - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, - SCpnt->device->id,SCpnt->device->lun,ready, + "port state %d, vdevice %p.\n", caller, + ioc->name, ioc->sh->host_no, + SCpnt->device->id, SCpnt->device->lun, ready, SCpnt->device->hostdata)); return FAILED; } - dfcprintk ((MYIOC_s_INFO_FMT + dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "%s.%d: %d:%d, executing recovery.\n", caller, - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, - ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, - SCpnt->device->id,SCpnt->device->lun)); + ioc->name, ioc->sh->host_no, + SCpnt->device->id, SCpnt->device->lun)); return (*func)(SCpnt); } @@ -466,13 +509,14 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int /* * if already mapped, remap here. If not mapped, * target_alloc will allocate vtarget and map, - * slave_alloc will fill in vdev from vtarget. + * slave_alloc will fill in vdevice from vtarget. */ if (ri->starget) { vtarget = ri->starget->hostdata; if (vtarget) { vtarget->id = pg0->CurrentTargetID; vtarget->channel = pg0->CurrentBus; + vtarget->deleted = 0; } } *((struct mptfc_rport_info **)rport->dd_data) = ri; @@ -481,7 +525,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; - dfcprintk ((MYIOC_s_INFO_FMT + dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, " "rport tid %d, tmo %d\n", ioc->name, @@ -510,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); @@ -559,6 +604,35 @@ mptfc_target_alloc(struct scsi_target *s } /* + * mptfc_dump_lun_info + * @ioc + * @rport + * @sdev + * + */ +static void +mptfc_dump_lun_info(MPT_ADAPTER *ioc, struct fc_rport *rport, struct scsi_device *sdev, + VirtTarget *vtarget) +{ + u64 nn, pn; + struct mptfc_rport_info *ri; + + ri = *((struct mptfc_rport_info **)rport->dd_data); + pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; + nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; + dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT + "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, " + "CurrentTargetID %d, %x %llx %llx\n", + ioc->name, + sdev->host->host_no, + vtarget->num_luns, + sdev->id, ri->pg0.CurrentTargetID, + ri->pg0.PortIdentifier, + (unsigned long long)pn, + (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. * Return non-zero if allocation fails. @@ -569,10 +643,10 @@ mptfc_slave_alloc(struct scsi_device *sd { MPT_SCSI_HOST *hd; VirtTarget *vtarget; - VirtDevice *vdev; + VirtDevice *vdevice; struct scsi_target *starget; struct fc_rport *rport; - + MPT_ADAPTER *ioc; starget = scsi_target(sdev); rport = starget_to_rport(starget); @@ -580,50 +654,29 @@ mptfc_slave_alloc(struct scsi_device *sd if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; - hd = (MPT_SCSI_HOST *)sdev->host->hostdata; - - vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); - if (!vdev) { + hd = shost_private(sdev->host); + ioc = hd->ioc; + vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); + if (!vdevice) { printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", - hd->ioc->name, sizeof(VirtDevice)); + ioc->name, sizeof(VirtDevice)); return -ENOMEM; } - sdev->hostdata = vdev; + sdev->hostdata = vdevice; vtarget = starget->hostdata; if (vtarget->num_luns == 0) { - vtarget->ioc_id = hd->ioc->id; + vtarget->ioc_id = ioc->id; vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; } - vdev->vtarget = vtarget; - vdev->lun = sdev->lun; + vdevice->vtarget = vtarget; + vdevice->lun = sdev->lun; vtarget->num_luns++; - - -#ifdef DMPT_DEBUG_FC - { - u64 nn, pn; - struct mptfc_rport_info *ri; - ri = *((struct mptfc_rport_info **)rport->dd_data); - pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; - nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; - dfcprintk ((MYIOC_s_INFO_FMT - "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, " - "CurrentTargetID %d, %x %llx %llx\n", - hd->ioc->name, - sdev->host->host_no, - vtarget->num_luns, - sdev->id, ri->pg0.CurrentTargetID, - ri->pg0.PortIdentifier, - (unsigned long long)pn, - (unsigned long long)nn)); - } -#endif - + mptfc_dump_lun_info(ioc, rport, sdev, vtarget); return 0; } @@ -633,9 +686,9 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void struct mptfc_rport_info *ri; struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); int err; - VirtDevice *vdev = SCpnt->device->hostdata; + VirtDevice *vdevice = SCpnt->device->hostdata; - if (!vdev || !vdev->vtarget) { + if (!vdevice || !vdevice->vtarget) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; @@ -651,27 +704,56 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void /* dd_data is null until finished adding target */ ri = *((struct mptfc_rport_info **)rport->dd_data); if (unlikely(!ri)) { - dfcprintk ((MYIOC_s_INFO_FMT - "mptfc_qcmd.%d: %d:%d, dd_data is null.\n", - ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name, - ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no, - SCpnt->device->id,SCpnt->device->lun)); SCpnt->result = DID_IMM_RETRY << 16; done(SCpnt); return 0; } - err = mptscsih_qcmd(SCpnt,done); -#ifdef DMPT_DEBUG_FC - if (unlikely(err)) { - dfcprintk ((MYIOC_s_INFO_FMT - "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero, (%x).\n", - ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name, - ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no, - SCpnt->device->id,SCpnt->device->lun,err)); + return mptscsih_qcmd(SCpnt,done); +} + +/* + * mptfc_display_port_link_speed - displaying link speed + * @ioc: Pointer to MPT_ADAPTER structure + * @portnum: IOC Port number + * @pp0dest: port page0 data payload + * + */ +static void +mptfc_display_port_link_speed(MPT_ADAPTER *ioc, int portnum, FCPortPage0_t *pp0dest) +{ + u8 old_speed, new_speed, state; + char *old, *new; + + if (portnum >= 2) + return; + + old_speed = ioc->fc_link_speed[portnum]; + new_speed = pp0dest->CurrentSpeed; + state = pp0dest->PortState; + + if (state != MPI_FCPORTPAGE0_PORTSTATE_OFFLINE && + new_speed != MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN) { + + old = old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" : + old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" : + old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" : + "Unknown"; + new = new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" : + new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" : + new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" : + "Unknown"; + if (old_speed == 0) + printk(MYIOC_s_NOTE_FMT + "FC Link Established, Speed = %s\n", + ioc->name, new); + else if (old_speed != new_speed) + printk(MYIOC_s_WARN_FMT + "FC Link Speed Change, Old Speed = %s, New Speed = %s\n", + ioc->name, old, new); + + ioc->fc_link_speed[portnum] = new_speed; } -#endif - return err; } /* @@ -773,6 +855,7 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, i " complete.\n", ioc->name); } + mptfc_display_port_link_speed(ioc, portnum, pp0dest); } pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma); @@ -899,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) @@ -911,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) @@ -923,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; } @@ -1023,11 +1109,39 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,in } static void +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) +mptfc_link_status_change(struct work_struct *work) +{ + MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fc_rescan_work); +#else +mptfc_link_status_change(void *arg) +{ + MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; +#endif + int ii; + + for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) + (void) mptfc_GetFcPortPage0(ioc, ii); + +} + +static void +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) +mptfc_setup_reset(struct work_struct *work) +{ + MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fc_setup_reset_work); +#else mptfc_setup_reset(void *arg) { MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; +#endif 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) { @@ -1035,10 +1149,16 @@ mptfc_setup_reset(void *arg) 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; - dfcprintk ((MYIOC_s_INFO_FMT + dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "mptfc_setup_reset.%d: %llx deleted\n", ioc->name, ioc->sh->host_no, @@ -1048,12 +1168,33 @@ mptfc_setup_reset(void *arg) } static void +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) +mptfc_rescan_devices(struct work_struct *work) +{ + MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fc_rescan_work); +#else mptfc_rescan_devices(void *arg) { MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; +#endif 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) { @@ -1081,10 +1222,16 @@ mptfc_rescan_devices(void *arg) 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; - dfcprintk ((MYIOC_s_INFO_FMT + dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "mptfc_rescan.%d: %llx deleted\n", ioc->name, ioc->sh->host_no, @@ -1159,8 +1306,15 @@ mptfc_probe(struct pci_dev *pdev, const } spin_lock_init(&ioc->fc_rescan_work_lock); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) + INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices); + INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset); + INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change); +#else INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc); INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset, (void *)ioc); + INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change, (void *)ioc); +#endif spin_lock_irqsave(&ioc->FreeQlock, flags); @@ -1180,6 +1334,8 @@ mptfc_probe(struct pci_dev *pdev, const sh->this_id = ioc->pfacts[0].PortSCSIID; + ioc->sdev_queue_depth = mpt_sdev_queue_depth; + /* Required entry. */ sh->unique_id = ioc->id; @@ -1193,22 +1349,20 @@ mptfc_probe(struct pci_dev *pdev, const * A slightly different algorithm is required for * 64bit SGEs. */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) { + scale = ioc->req_sz/ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 64) / ioc->SGE_size; } if (numSGE < sh->sg_tablesize) { /* Reset this value */ - dprintk((MYIOC_s_INFO_FMT + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Resetting sg_tablesize to %d from %d\n", ioc->name, numSGE, sh->sg_tablesize)); sh->sg_tablesize = numSGE; @@ -1216,52 +1370,29 @@ mptfc_probe(struct pci_dev *pdev, const spin_unlock_irqrestore(&ioc->FreeQlock, flags); - hd = (MPT_SCSI_HOST *) sh->hostdata; + hd = shost_private(sh); hd->ioc = ioc; /* SCSI needs scsi_cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ - hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); - if (!hd->ScsiLookup) { + ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); + if (!ioc->ScsiLookup) { error = -ENOMEM; goto out_mptfc_probe; } + spin_lock_init(&ioc->scsi_lookup_lock); - dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", - ioc->name, hd->ScsiLookup)); + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", + ioc->name, ioc->ScsiLookup)); - /* Clear the TM flags - */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; - hd->abortSCpnt = NULL; - - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; - - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; - - init_waitqueue_head(&hd->scandv_waitq); - hd->scandv_wait_done = 0; hd->last_queue_full = 0; sh->transportt = mptfc_transport_template; error = scsi_add_host (sh, &ioc->pcidev->dev); if(error) { - dprintk((KERN_ERR MYNAM - "scsi_add_host failed\n")); + dprintk(ioc, printk(MYIOC_s_ERR_FMT + "scsi_add_host failed\n", ioc->name)); goto out_mptfc_probe; } @@ -1281,7 +1412,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 - @@ -1319,11 +1449,8 @@ mptfc_event_process(MPT_ADAPTER *ioc, Ev unsigned long flags; int rc=1; - devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", - ioc->name, event)); - if (ioc->sh == NULL || - ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) + ((hd = shost_private(ioc->sh)) == NULL)) return 1; switch (event) { @@ -1335,6 +1462,14 @@ mptfc_event_process(MPT_ADAPTER *ioc, Ev } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); break; + case MPI_EVENT_LINK_STATUS_CHANGE: + spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); + if (ioc->fc_rescan_work_q) { + queue_work(ioc->fc_rescan_work_q, + &ioc->fc_lsc_work); + } + spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); + break; default: rc = mptscsih_event_process(ioc,pEvReply); break; @@ -1349,45 +1484,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((KERN_WARNING MYNAM - ": IOC %s_reset routed to FC host driver!\n", - 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) { @@ -1409,15 +1544,8 @@ mptfc_init(void) mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER); mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER); - if (mpt_event_register(mptfcDoneCtx, mptfc_event_process) == 0) { - devtverboseprintk((KERN_INFO MYNAM - ": Registered for IOC event notifications\n")); - } - - if (mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset) == 0) { - dprintk((KERN_INFO MYNAM - ": Registered for IOC reset notifications\n")); - } + mpt_event_register(mptfcDoneCtx, mptfc_event_process); + mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset); error = pci_register_driver(&mptfc_driver); if (error) @@ -1426,12 +1554,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) { @@ -1441,6 +1568,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); @@ -1482,13 +1611,7 @@ mptfc_exit(void) fc_release_transport(mptfc_transport_template); mpt_reset_deregister(mptfcDoneCtx); - dprintk((KERN_INFO MYNAM - ": Deregistered for IOC reset notifications\n")); - mpt_event_deregister(mptfcDoneCtx); - dprintk((KERN_INFO MYNAM - ": Deregistered for IOC event notifications\n")); - mpt_deregister(mptfcInternalCtx); mpt_deregister(mptfcTaskCtx); mpt_deregister(mptfcDoneCtx); Index: linux-2.6.18.i386/drivers/message/fusion/mptlan.c =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/mptlan.c +++ linux-2.6.18.i386/drivers/message/fusion/mptlan.c @@ -1,12 +1,11 @@ /* * linux/drivers/message/fusion/mptlan.c * IP Over Fibre Channel device driver. - * For use with LSI Logic Fibre Channel PCI chip/adapters - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. - * - * Copyright (c) 2000-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsi.com) + * For use with LSI Fibre Channel PCI chip/adapters + * running LSI Fusion MPT (Message Passing Technology) firmware. * + * Copyright (c) 2000-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -53,6 +52,7 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #include "mptlan.h" +#include #include #include #include @@ -114,7 +114,12 @@ struct mpt_lan_priv { u32 total_received; struct net_device_stats stats; /* Per device statistics */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) + struct delayed_work post_buckets_task; + struct net_device *dev; +#else struct work_struct post_buckets_task; +#endif unsigned long post_buckets_active; }; @@ -135,7 +140,11 @@ static int lan_reply (MPT_ADAPTER *ioc, static int mpt_lan_open(struct net_device *dev); static int mpt_lan_reset(struct net_device *dev); static int mpt_lan_close(struct net_device *dev); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) +static void mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv); +#else static void mpt_lan_post_receive_buckets(void *dev_id); +#endif static void mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority); static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg); @@ -153,7 +162,7 @@ static unsigned short mpt_lan_type_trans /* * Fusion MPT LAN private data */ -static int LanCtx = -1; +static u8 LanCtx = MPT_MAX_PROTOCOL_DRIVERS; static u32 max_buckets_out = 127; static u32 tx_max_out_p = 127 - 16; @@ -167,7 +176,6 @@ DEFINE_RWLOCK(bad_naa_lock); /* * Fusion MPT LAN external data */ -extern int mpt_lan_index; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** @@ -195,8 +203,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)) { @@ -348,7 +355,11 @@ mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i; spin_unlock_irqrestore(&priv->rxfidx_lock, flags); } else { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) + mpt_lan_post_receive_buckets(priv); +#else mpt_lan_post_receive_buckets(dev); +#endif netif_wake_queue(dev); } @@ -444,7 +455,12 @@ mpt_lan_open(struct net_device *dev) dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n")); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) + mpt_lan_post_receive_buckets(priv); +#else mpt_lan_post_receive_buckets(dev); +#endif + printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n", IOC_AND_NETDEV_NAMES_s_s(dev)); @@ -713,6 +729,9 @@ mpt_lan_sdu_send (struct sk_buff *skb, s LANSendRequest_t *pSendReq; SGETransaction32_t *pTrans; SGESimple64_t *pSimple; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) + const unsigned char *mac; +#endif dma_addr_t dma; unsigned long flags; int ctx; @@ -752,7 +771,11 @@ mpt_lan_sdu_send (struct sk_buff *skb, s /* Set the mac.raw pointer, since this apparently isn't getting * done before we get the skb. Pull the data pointer past the mac data. */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) + skb_reset_mac_header(skb); +#else skb->mac.raw = skb->data; +#endif skb_pull(skb, 12); dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len, @@ -783,6 +806,10 @@ mpt_lan_sdu_send (struct sk_buff *skb, s // IOC_AND_NETDEV_NAMES_s_s(dev), // ctx, skb, skb->data)); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) + mac = skb_mac_header(skb); +#endif + #ifdef QLOGIC_NAA_WORKAROUND { struct NAA_Hosed *nh; @@ -792,12 +819,21 @@ mpt_lan_sdu_send (struct sk_buff *skb, s drops. */ read_lock_irq(&bad_naa_lock); for (nh = mpt_bad_naa; nh != NULL; nh=nh->next) { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) + 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])) { +#else if ((nh->ieee[0] == skb->mac.raw[0]) && (nh->ieee[1] == skb->mac.raw[1]) && (nh->ieee[2] == skb->mac.raw[2]) && (nh->ieee[3] == skb->mac.raw[3]) && (nh->ieee[4] == skb->mac.raw[4]) && (nh->ieee[5] == skb->mac.raw[5])) { +#endif cur_naa = nh->NAA; dlprintk ((KERN_INFO "mptlan/sdu_send: using NAA value " "= %04x.\n", cur_naa)); @@ -808,6 +844,16 @@ mpt_lan_sdu_send (struct sk_buff *skb, s } #endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) + pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) | + (mac[0] << 8) | + (mac[1] << 0)); + pTrans->TransactionDetails[1] = cpu_to_le32((mac[2] << 24) | + (mac[3] << 16) | + (mac[4] << 8) | + (mac[5] << 0)); +#else pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) | (skb->mac.raw[0] << 8) | (skb->mac.raw[1] << 0)); @@ -815,6 +861,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s (skb->mac.raw[3] << 16) | (skb->mac.raw[4] << 8) | (skb->mac.raw[5] << 0)); +#endif pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2]; @@ -831,7 +878,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; @@ -857,7 +904,7 @@ mpt_lan_wake_post_buckets_task(struct ne if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { if (priority) { - schedule_work(&priv->post_buckets_task); + schedule_delayed_work(&priv->post_buckets_task, 0); } else { schedule_delayed_work(&priv->post_buckets_task, 1); dioprintk((KERN_INFO MYNAM ": post_buckets queued on " @@ -929,7 +976,11 @@ mpt_lan_receive_post_turbo(struct net_de pci_dma_sync_single_for_cpu(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) + skb_copy_from_linear_data(old_skb, skb_put(skb, len), len); +#else memcpy(skb_put(skb, len), old_skb->data, len); +#endif pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); @@ -1090,7 +1141,11 @@ mpt_lan_receive_post_reply(struct net_de priv->RcvCtl[ctx].dma, priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) + skb_copy_from_linear_data(old_skb, skb_put(skb, l), l); +#else memcpy(skb_put(skb, l), old_skb->data, l); +#endif pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, @@ -1119,8 +1174,11 @@ mpt_lan_receive_post_reply(struct net_de priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) + skb_copy_from_linear_data(old_skb, skb_put(skb, len), len); +#else memcpy(skb_put(skb, len), old_skb->data, len); - +#endif pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, priv->RcvCtl[ctx].len, @@ -1191,10 +1249,16 @@ mpt_lan_receive_post_reply(struct net_de /* Simple SGE's only at the moment */ static void +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) +mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) +{ + struct net_device *dev = priv->dev; +#else mpt_lan_post_receive_buckets(void *dev_id) { struct net_device *dev = dev_id; struct mpt_lan_priv *priv = dev->priv; +#endif MPT_ADAPTER *mpt_dev = priv->mpt_dev; MPT_FRAME_HDR *mf; LANReceivePostRequest_t *pRecvReq; @@ -1228,6 +1292,8 @@ mpt_lan_post_receive_buckets(void *dev_i } pRecvReq = (LANReceivePostRequest_t *) mf; + i = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + mpt_dev->RequestNB[i] = 0; count = buckets; if (count > max) count = max; @@ -1297,7 +1363,7 @@ mpt_lan_post_receive_buckets(void *dev_i 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; @@ -1338,6 +1404,15 @@ out: clear_bit(0, &priv->post_buckets_active); } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) +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)); +} +#endif + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static struct net_device * mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) @@ -1353,11 +1428,20 @@ mpt_register_lan_device (MPT_ADAPTER *mp priv = netdev_priv(dev); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) + priv->dev = dev; +#endif priv->mpt_dev = mpt_dev; priv->pnum = pnum; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) + memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task)); + INIT_DELAYED_WORK(&priv->post_buckets_task, + mpt_lan_post_receive_buckets_work); +#else memset(&priv->post_buckets_task, 0, sizeof(struct work_struct)); INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev); +#endif priv->post_buckets_active = 0; dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n", @@ -1416,7 +1500,9 @@ mpt_register_lan_device (MPT_ADAPTER *mp dlprintk((KERN_INFO MYNAM ": Finished registering dev " "and setting initial values\n")); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) SET_MODULE_OWNER(dev); +#endif if (register_netdev(dev) != 0) { free_netdev(dev); @@ -1499,9 +1585,6 @@ static int __init mpt_lan_init (void) return -EBUSY; } - /* Set the callback index to be used by driver core for turbo replies */ - mpt_lan_index = LanCtx; - dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx)); if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) { @@ -1513,8 +1596,7 @@ static int __init mpt_lan_init (void) dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); - if (mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER)) - dprintk((KERN_INFO MYNAM ": failed to register dd callbacks\n")); + mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER); return 0; } @@ -1523,10 +1605,9 @@ static void __exit mpt_lan_exit(void) mpt_device_driver_deregister(MPTLAN_DRIVER); mpt_reset_deregister(LanCtx); - if (LanCtx >= 0) { + if (LanCtx) { mpt_deregister(LanCtx); - LanCtx = -1; - mpt_lan_index = 0; + LanCtx = MPT_MAX_PROTOCOL_DRIVERS; } } @@ -1540,7 +1621,11 @@ mpt_lan_type_trans(struct sk_buff *skb, struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data; struct fcllc *fcllc; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) + skb_reset_mac_header(skb); +#else skb->mac.raw = skb->data; +#endif skb_pull(skb, sizeof(struct mpt_lan_ohdr)); if (fch->dtype == htons(0xffff)) { Index: linux-2.6.18.i386/drivers/message/fusion/mptlan.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/mptlan.h +++ linux-2.6.18.i386/drivers/message/fusion/mptlan.h @@ -1,12 +1,11 @@ /* * linux/drivers/message/fusion/mptlan.h * IP Over Fibre Channel device driver. - * For use with LSI Logic Fibre Channel PCI chip/adapters - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. - * - * Copyright (c) 2000-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsi.com) + * For use with LSI Fibre Channel PCI chip/adapters + * running LSI Fusion MPT (Message Passing Technology) firmware. * + * Copyright (c) 2000-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -55,6 +54,7 @@ #include #endif +#include #include #include // #include @@ -73,9 +73,10 @@ #include #include +#include /* Override mptbase.h by pre-defining these! */ -#define MODULEAUTHOR "LSI Logic Corporation" +#define MODULEAUTHOR "LSI Corporation" #include "mptbase.h" Index: linux-2.6.18.i386/drivers/message/fusion/mptsas.c =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/mptsas.c +++ linux-2.6.18.i386/drivers/message/fusion/mptsas.c @@ -1,11 +1,10 @@ /* * linux/drivers/message/fusion/mptsas.c - * For use with LSI Logic PCI chip/adapter(s) - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI PCI chip/adapter(s) + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsi.com) - * Copyright (c) 2005-2007 Dell + * Copyright (c) 1999-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -43,14 +42,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - +#include "linux_compat.h" /* linux-2.6 tweaks */ +#include #include #include #include #include -#include +#include #include +#include #include /* for mdelay */ +#include #include #include @@ -59,9 +61,19 @@ #include #include +#include "linux_compat.h" /* linux-2.6 tweaks */ #include "mptbase.h" #include "mptscsih.h" +/* The glue to get a single driver working in both + * SLES10 and RHEL5 environments + */ +#if (defined(CONFIG_SUSE_KERNEL) && defined(scsi_is_sas_phy_local)) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +#define MPT_WIDE_PORT_API 1 +#define MPT_WIDE_PORT_API_PLUS 1 +#endif + +#include "mptsas.h" #define my_NAME "Fusion MPT SAS Host driver" #define my_VERSION MPT_LINUX_VERSION_COMMON @@ -70,7 +82,13 @@ /* * Reserved channel for integrated raid */ +#if defined(MPT_WIDE_PORT_API) #define MPTSAS_RAID_CHANNEL 1 +#else +#define MPTSAS_RAID_CHANNEL 8 +#endif + +#define SAS_CONFIG_PAGE_TIMEOUT 30 MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); @@ -83,239 +101,357 @@ MODULE_PARM_DESC(mpt_pt_clear, " Clear persistency table: enable=1 " "(default=MPTSCSIH_PT_CLEAR=0)"); +static int mpt_cmd_retry_count = 144; +module_param(mpt_cmd_retry_count, int, 0); +MODULE_PARM_DESC(mpt_cmd_retry_count, + " Device discovery TUR command retry count: default=144"); + +static int mpt_disable_hotplug_remove = 0; +module_param(mpt_disable_hotplug_remove, int, 0); +MODULE_PARM_DESC(mpt_disable_hotplug_remove, + " Disable hotpug remove events: default=0"); + +static int mpt_sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH; +static int mptsas_set_sdev_queue_depth(const char *val, + struct kernel_param *kp); +module_param_call(mpt_sdev_queue_depth, mptsas_set_sdev_queue_depth, + param_get_int, &mpt_sdev_queue_depth, 0600); +MODULE_PARM_DESC(mpt_sdev_queue_depth, + " Max Device Queue Depth (default=" + __MODULE_STRING(MPT_SCSI_CMD_PER_DEV_HIGH) ")"); + /* scsi-mid layer global parmeter is max_report_luns, which is 511 */ #define MPTSAS_MAX_LUN (16895) static int max_lun = MPTSAS_MAX_LUN; module_param(max_lun, int, 0); MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); -static int mptsasDoneCtx = -1; -static int mptsasTaskCtx = -1; -static int mptsasInternalCtx = -1; /* Used only for internal commands */ -static int mptsasMgmtCtx = -1; - -static void mptsas_hotplug_work(void *arg); - -struct mptsas_target_reset_event { - struct list_head list; - EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data; - u8 target_reset_issued; -}; - -enum mptsas_hotplug_action { - MPTSAS_ADD_DEVICE, - MPTSAS_DEL_DEVICE, - MPTSAS_ADD_RAID, - MPTSAS_DEL_RAID, - MPTSAS_ADD_INACTIVE_VOLUME, - MPTSAS_IGNORE_EVENT, -}; - -struct mptsas_hotplug_event { - struct work_struct work; - MPT_ADAPTER *ioc; - enum mptsas_hotplug_action event_type; - u64 sas_address; - u8 channel; - u8 id; - u32 device_info; - u16 handle; - u16 parent_handle; - u8 phy_id; - u8 phys_disk_num_valid; /* hrc (hidden raid component) */ - u8 phys_disk_num; /* hrc - unique index*/ - u8 hidden_raid_component; /* hrc - don't expose*/ -}; +static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ +static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; + +static struct mptsas_phyinfo * mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, + u64 sas_address); +static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, + u32 form, u32 form_specific); +static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, + u32 form, u32 form_specific); + +static int mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info); +static void mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info); +static void mptsas_expander_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info); +static int mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, + u32 form, u32 form_specific); +static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); +static void mptsas_not_responding_devices(MPT_ADAPTER *ioc); -struct mptsas_discovery_event { - struct work_struct work; - MPT_ADAPTER *ioc; -}; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) +static void mptsas_firmware_event_work(struct work_struct *work); +#else +static void mptsas_firmware_event_work(void *arg); +#endif -/* - * SAS topology structures +/** + * 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: * - * The MPT Fusion firmware interface spreads information about the - * SAS topology over many manufacture pages, thus we need some data - * structure to collect it and process it for the SAS transport class. - */ - -struct mptsas_devinfo { - u16 handle; /* unique id to address this device */ - u16 handle_parent; /* unique id to address parent device */ - u16 handle_enclosure; /* enclosure identifier of the enclosure */ - u16 slot; /* physical slot in enclosure */ - u8 phy_id; /* phy number of parent device */ - u8 port_id; /* sas physical port this device - is assoc'd with */ - u8 id; /* logical target id of this device */ - u32 phys_disk_num; /* phys disk id, for csmi-ioctls */ - u8 channel; /* logical bus number of this device */ - u64 sas_address; /* WWN of this device, - SATA is assigned by HBA,expander */ - u32 device_info; /* bitfield detailed info about this device */ -}; - -/* - * 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 */ - 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 */ - u8 negotiated_link_rate; /* nego'd link rate for this phy */ - 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 */ - struct mptsas_devinfo attached; /* point to attached device info */ - struct sas_phy *phy; /* transport layer phy object */ - struct mptsas_portinfo *portinfo; - struct mptsas_portinfo_details * port_details; -}; + * 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; -struct mptsas_portinfo { - struct list_head list; - u16 num_phys; /* number of phys */ - struct mptsas_phyinfo *phy_info; -}; + if (ret) + return ret; -struct mptsas_enclosure { - u64 enclosure_logical_id; /* The WWN for the enclosure */ - u16 enclosure_handle; /* unique id to address this */ - u16 flags; /* details enclosure management */ - u16 num_slot; /* num slots */ - u16 start_slot; /* first slot */ - u8 start_id; /* starting logical target id */ - u8 start_channel; /* starting logical channel id */ - u8 sep_id; /* SEP device logical target id */ - u8 sep_channel; /* SEP channel logical channel id */ -}; + list_for_each_entry(ioc, &ioc_list, list) { + if (ioc->bus_type != SAS) + continue; + shost_for_each_device(sdev, ioc->sh) + mptscsih_change_queue_depth(sdev, mpt_sdev_queue_depth); + ioc->sdev_queue_depth = mpt_sdev_queue_depth; + } + return 0; +} -#ifdef MPT_DEBUG_SAS -static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) +static void mptsas_print_phy_data(MPT_ADAPTER *ioc, + MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) { - printk("---- IO UNIT PAGE 0 ------------\n"); - printk("Handle=0x%X\n", - le16_to_cpu(phy_data->AttachedDeviceHandle)); - printk("Controller Handle=0x%X\n", - le16_to_cpu(phy_data->ControllerDevHandle)); - printk("Port=0x%X\n", phy_data->Port); - printk("Port Flags=0x%X\n", phy_data->PortFlags); - printk("PHY Flags=0x%X\n", phy_data->PhyFlags); - printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate); - printk("Controller PHY Device Info=0x%X\n", - le32_to_cpu(phy_data->ControllerPhyDeviceInfo)); - printk("DiscoveryStatus=0x%X\n", - le32_to_cpu(phy_data->DiscoveryStatus)); - printk("\n"); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "---- IO UNIT PAGE 0 ------------\n", ioc->name)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n", + ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n", + ioc->name, le16_to_cpu(phy_data->ControllerDevHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n", + ioc->name, phy_data->Port)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n", + ioc->name, phy_data->PortFlags)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n", + ioc->name, phy_data->PhyFlags)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n", + ioc->name, phy_data->NegotiatedLinkRate)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Controller PHY Device Info=0x%X\n", ioc->name, + le32_to_cpu(phy_data->ControllerPhyDeviceInfo))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n", + ioc->name, le32_to_cpu(phy_data->DiscoveryStatus))); } -static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0) +static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0) { __le64 sas_address; memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); - printk("---- SAS PHY PAGE 0 ------------\n"); - printk("Attached Device Handle=0x%X\n", - le16_to_cpu(pg0->AttachedDevHandle)); - printk("SAS Address=0x%llX\n", - (unsigned long long)le64_to_cpu(sas_address)); - printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier); - printk("Attached Device Info=0x%X\n", - le32_to_cpu(pg0->AttachedDeviceInfo)); - printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate); - printk("Change Count=0x%X\n", pg0->ChangeCount); - printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo)); - printk("\n"); -} - -static void mptsas_print_phy_pg1(SasPhyPage1_t *pg1) -{ - printk("---- SAS PHY PAGE 1 ------------\n"); - printk("Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount); - printk("Running Disparity Error Count=0x%x\n", - pg1->RunningDisparityErrorCount); - printk("Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount); - printk("PHY Reset Problem Count=0x%x\n", pg1->PhyResetProblemCount); - printk("\n"); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "---- SAS PHY PAGE 0 ------------\n", ioc->name)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Attached Device Handle=0x%X\n", ioc->name, + le16_to_cpu(pg0->AttachedDevHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n", + ioc->name, (unsigned long long)le64_to_cpu(sas_address))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Attached PHY Identifier=0x%X\n", ioc->name, + pg0->AttachedPhyIdentifier)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n", + ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n", + ioc->name, pg0->ProgrammedLinkRate)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n", + ioc->name, pg0->ChangeCount)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n", + ioc->name, le32_to_cpu(pg0->PhyInfo))); +} + +static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1) +{ + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "---- SAS PHY PAGE 1 ------------\n", ioc->name)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n", + ioc->name, pg1->InvalidDwordCount)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Running Disparity Error Count=0x%x\n", ioc->name, + pg1->RunningDisparityErrorCount)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Loss Dword Synch Count=0x%x\n", ioc->name, + pg1->LossDwordSynchCount)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "PHY Reset Problem Count=0x%x\n\n", ioc->name, + pg1->PhyResetProblemCount)); } -static void mptsas_print_device_pg0(SasDevicePage0_t *pg0) +static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0) { __le64 sas_address; memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); - printk("---- SAS DEVICE PAGE 0 ---------\n"); - printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)); - printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)); - printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)); - printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot)); - printk("SAS Address=0x%llX\n", (unsigned long long) - le64_to_cpu(sas_address)); - printk("Target ID=0x%X\n", pg0->TargetID); - printk("Bus=0x%X\n", pg0->Bus); - /* The PhyNum field specifies the PHY number of the parent - * device this device is linked to - */ - printk("Parent Phy Num=0x%X\n", pg0->PhyNum); - printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus)); - printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo)); - printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags)); - printk("Physical Port=0x%X\n", pg0->PhysicalPort); - printk("\n"); -} - -static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1) -{ - printk("---- SAS EXPANDER PAGE 1 ------------\n"); - - printk("Physical Port=0x%X\n", pg1->PhysicalPort); - printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier); - printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate); - printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate); - printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate); - printk("Owner Device Handle=0x%X\n", - le16_to_cpu(pg1->OwnerDevHandle)); - printk("Attached Device Handle=0x%X\n", - le16_to_cpu(pg1->AttachedDevHandle)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "---- SAS DEVICE PAGE 0 ---------\n", ioc->name)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n", + ioc->name, le16_to_cpu(pg0->DevHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n", + ioc->name, le16_to_cpu(pg0->ParentDevHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n", + ioc->name, le16_to_cpu(pg0->EnclosureHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n", + ioc->name, le16_to_cpu(pg0->Slot))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n", + ioc->name, (unsigned long long)le64_to_cpu(sas_address))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n", + ioc->name, pg0->TargetID)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n", + ioc->name, pg0->Bus)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n", + ioc->name, pg0->PhyNum)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n", + ioc->name, le16_to_cpu(pg0->AccessStatus))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n", + ioc->name, le32_to_cpu(pg0->DeviceInfo))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n", + ioc->name, le16_to_cpu(pg0->Flags))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n", + ioc->name, pg0->PhysicalPort)); +} + +static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1) +{ + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n", + ioc->name, pg1->PhysicalPort)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n", + ioc->name, pg1->PhyIdentifier)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n", + ioc->name, pg1->NegotiatedLinkRate)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n", + ioc->name, pg1->ProgrammedLinkRate)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n", + ioc->name, pg1->HwLinkRate)); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n", + ioc->name, le16_to_cpu(pg1->OwnerDevHandle))); + dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Attached Device Handle=0x%X\n\n", ioc->name, + le16_to_cpu(pg1->AttachedDevHandle))); +} + +/* inhibit sas firmware event handling */ +static void +mptsas_fw_event_off(MPT_ADAPTER *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + ioc->fw_events_off = 1; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + +} + +/* enable sas firmware event handling */ +static void +mptsas_fw_event_on(MPT_ADAPTER *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + ioc->fw_events_off = 0; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } + +/* queue a sas firmware event */ +static void +mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, + unsigned long delay) +{ + unsigned long flags; + +#if defined(CPQ_CIM) + ioc->csmi_change_count++; +#endif + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + list_add_tail(&fw_event->list, &ioc->fw_event_list); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) + INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); #else -#define mptsas_print_phy_data(phy_data) do { } while (0) -#define mptsas_print_phy_pg0(pg0) do { } while (0) -#define mptsas_print_phy_pg1(pg1) do { } while (0) -#define mptsas_print_device_pg0(pg0) do { } while (0) -#define mptsas_print_expander_pg1(pg1) do { } while (0) + INIT_WORK(&fw_event->work, mptsas_firmware_event_work, (void *)fw_event); #endif + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: add (fw_event=0x%p)\n", + ioc->name,__FUNCTION__, fw_event)); + queue_delayed_work(ioc->fw_event_q, &fw_event->work, + msecs_to_jiffies(delay)); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/* requeue a sas firmware event */ +static void +mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, + unsigned long delay) +{ + unsigned long flags; + spin_lock_irqsave(&ioc->fw_event_lock, flags); + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: reschedule task " + "(fw_event=0x%p)\n", ioc->name,__FUNCTION__, fw_event)); + fw_event->retries++; + queue_delayed_work(ioc->fw_event_q, &fw_event->work, + msecs_to_jiffies(delay)); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/* free memory assoicated to a sas firmware event */ +static void +mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: kfree (fw_event=0x%p)\n", + ioc->name,__FUNCTION__, fw_event)); + list_del(&fw_event->list); + kfree(fw_event); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/* walk the firmware event queue, and either stop or wait for outstanding events to complete */ +static void +mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) +{ + struct fw_event_work *fw_event, *next; + struct mptsas_target_reset_event *target_reset_list, *n; + u8 flush_q; + MPT_SCSI_HOST *hd = shost_private(ioc->sh); + + /* flush the target_reset_list */ + if (!list_empty(&hd->target_reset_list)) { + list_for_each_entry_safe(target_reset_list, n, + &hd->target_reset_list, list) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: removing target reset for id=%d\n", + ioc->name, __FUNCTION__, + target_reset_list->sas_event_data.TargetID)); + list_del(&target_reset_list->list); + kfree(target_reset_list); + } + } + + if (list_empty(&ioc->fw_event_list) || + !ioc->fw_event_q || in_interrupt()) + return; + + flush_q = 0; + list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { + if (cancel_delayed_work(&fw_event->work)) + mptsas_free_fw_event(ioc, fw_event); + else + flush_q = 1; + } + if (flush_q) + flush_workqueue(ioc->fw_event_q); +} + -static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) +/** + * phy_to_ioc - + * @phy: + * + * + **/ +static inline MPT_ADAPTER * +phy_to_ioc(struct sas_phy *phy) { struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; } -static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) +/** + * rphy_to_ioc - + * @rphy: + * + * + **/ +static inline MPT_ADAPTER * +rphy_to_ioc(struct sas_rphy *rphy) { struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; } -/* - * mptsas_find_portinfo_by_handle +/** + * mptsas_find_portinfo_by_handle - + * @ioc: Pointer to MPT_ADAPTER structure + * @handle: * - * This function should be called with the sas_topology_mutex already held - */ + * This function should be called with the sas_topology_mutex already held + * + **/ static struct mptsas_portinfo * mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) { @@ -332,9 +468,44 @@ mptsas_find_portinfo_by_handle(MPT_ADAPT return rc; } -/* - * Returns true if there is a scsi end device - */ +/** + * mptsas_find_portinfo_by_sas_address - + * @ioc: Pointer to MPT_ADAPTER structure + * @handle: + * + * This function should be called with the sas_topology_mutex already held + * + **/ +static struct mptsas_portinfo * +mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) +{ + struct mptsas_portinfo *port_info, *rc=NULL; + int i; + + if (sas_address >= ioc->hba_port_sas_addr && + sas_address < (ioc->hba_port_sas_addr + + ioc->hba_port_num_phy)) + return ioc->hba_port_info; + + mutex_lock(&ioc->sas_topology_mutex); + list_for_each_entry(port_info, &ioc->sas_topology, list) + for (i = 0; i < port_info->num_phys; i++) + if (port_info->phy_info[i].identify.sas_address == + sas_address) { + rc = port_info; + goto out; + } + out: + mutex_unlock(&ioc->sas_topology_mutex); + return rc; +} + +/** + * mptsas_is_end_device - + * @attached: + * + * Returns true if there is a scsi end device + **/ static inline int mptsas_is_end_device(struct mptsas_devinfo * attached) { @@ -352,9 +523,54 @@ mptsas_is_end_device(struct mptsas_devin return 0; } -/* no mutex */ +/** + * mptsas_get_rphy - + * @phy_info: + * + **/ +static inline struct sas_rphy * +mptsas_get_rphy(struct mptsas_phyinfo *phy_info) +{ + if (phy_info->port_details) + return phy_info->port_details->rphy; + else + return NULL; +} + +/** + * mptsas_set_rphy - + * @ioc: Pointer to MPT_ADAPTER structure + * @phy_info: + * @rphy: + * + **/ +static inline void +mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) +{ + if (phy_info->port_details) { + phy_info->port_details->rphy = rphy; + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "sas_rphy_add: rphy=%p\n", ioc->name, rphy)); + } + + if (rphy) { + dsaswideprintk(ioc, dev_printk(KERN_DEBUG, + &rphy->dev, MYIOC_s_FMT "add:", ioc->name)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n", + ioc->name, rphy, rphy->dev.release)); + } +} + +/** + * mptsas_port_delete - + * @ioc: Pointer to MPT_ADAPTER structure + * @port_details: + * + * (no mutex) + * + **/ static void -mptsas_port_delete(struct mptsas_portinfo_details * port_details) +mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details) { struct mptsas_portinfo *port_info; struct mptsas_phyinfo *phy_info; @@ -366,46 +582,51 @@ mptsas_port_delete(struct mptsas_portinf port_info = port_details->port_info; phy_info = port_info->phy_info; - dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d " - "bitmask=0x%016llX\n", __FUNCTION__, port_details, +#if defined(MPT_WIDE_PORT_API) + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d " + "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details, port_details->num_phys, (unsigned long long) port_details->phy_bitmask)); +#else + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: port=%02d num_phys=%02d " + "rphy=%02d bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details, + port_details->port_id, port_details->num_phys, + port_details->rphy_id, (unsigned long long) + port_details->phy_bitmask)); +#endif for (i = 0; i < port_info->num_phys; i++, phy_info++) { if(phy_info->port_details != port_details) continue; memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); + mptsas_set_rphy(ioc, phy_info, NULL); phy_info->port_details = NULL; } kfree(port_details); } -static inline struct sas_rphy * -mptsas_get_rphy(struct mptsas_phyinfo *phy_info) +#if !defined(MPT_WIDE_PORT_API) +/** + * mptsas_get_rphy_id - + * @phy_info: + * + **/ +static inline u8 +mptsas_get_rphy_id(struct mptsas_phyinfo *phy_info) { if (phy_info->port_details) - return phy_info->port_details->rphy; + return phy_info->port_details->rphy_id; else - return NULL; + return 0xFF; } - -static inline void -mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) -{ - if (phy_info->port_details) { - phy_info->port_details->rphy = rphy; - dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy)); - } - -#ifdef MPT_DEBUG_SAS_WIDE - if (rphy) { - dev_printk(KERN_DEBUG, &rphy->dev, "add:"); - printk("rphy=%p release=%p\n", - rphy, rphy->dev.release); - } #endif -} +#if defined(MPT_WIDE_PORT_API) +/** + * mptsas_get_port - + * @phy_info: + * + **/ static inline struct sas_port * mptsas_get_port(struct mptsas_phyinfo *phy_info) { @@ -415,21 +636,33 @@ 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(struct mptsas_phyinfo *phy_info, struct sas_port *port) +mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port) { if (phy_info->port_details) phy_info->port_details->port = port; -#ifdef MPT_DEBUG_SAS_WIDE if (port) { - dev_printk(KERN_DEBUG, &port->dev, "add: "); - printk("port=%p release=%p\n", - port, port->dev.release); + dsaswideprintk(ioc, dev_printk(KERN_DEBUG, + &port->dev, MYIOC_s_FMT "add:", ioc->name)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n", + ioc->name, port, port->dev.release)); } -#endif } +#endif +/** + * mptsas_get_starget - + * @phy_info: + * + **/ static inline struct scsi_target * mptsas_get_starget(struct mptsas_phyinfo *phy_info) { @@ -439,6 +672,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) @@ -447,105 +686,424 @@ starget) phy_info->port_details->starget = starget; } - -/* - * mptsas_setup_wide_ports +/** + * mptsas_add_device_component - + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: fw mapped id's + * @id: + * @sas_address: + * @device_info: * - * Updates for new and existing narrow/wide port configuration - * in the sas_topology - */ + **/ static void -mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) +mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id, + u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id) { - struct mptsas_portinfo_details * port_details; - struct mptsas_phyinfo *phy_info, *phy_info_cmp; - u64 sas_address; - int i, j; + struct sas_device_info *sas_info, *next; + struct scsi_device *sdev; + struct scsi_target *starget; + struct sas_rphy *rphy; + + /* + * Delete all matching devices out of the list + */ + down(&ioc->sas_device_info_mutex); + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + if (!sas_info->is_logical_volume && + (sas_info->sas_address == sas_address || + (sas_info->fw.channel == channel && + sas_info->fw.id == id))) { + list_del(&sas_info->list); + kfree(sas_info); + } + } - mutex_lock(&ioc->sas_topology_mutex); + if (!(sas_info = kzalloc(sizeof(struct sas_device_info), GFP_KERNEL))) + goto out; - phy_info = port_info->phy_info; - for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { - if (phy_info->attached.handle) - continue; - port_details = phy_info->port_details; - if (!port_details) - continue; - if (port_details->num_phys < 2) - continue; - /* - * Removing a phy from a port, letting the last - * phy be removed by firmware events. - */ - dsaswideprintk((KERN_DEBUG - "%s: [%p]: deleting phy = %d\n", - __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)); - sas_port_delete_phy(port_details->port, phy_info->phy); - phy_info->port_details = NULL; - } + /* + * Set Firmware mapping + */ + sas_info->fw.id = id; + sas_info->fw.channel = channel; + + sas_info->sas_address = sas_address; + sas_info->device_info = device_info; + sas_info->slot = slot; + sas_info->enclosure_logical_id = enclosure_logical_id; + INIT_LIST_HEAD(&sas_info->list); + list_add_tail(&sas_info->list, &ioc->sas_device_info_list); /* - * Populate and refresh the tree + * Set OS mapping */ - phy_info = port_info->phy_info; - for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { - sas_address = phy_info->attached.sas_address; - dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n", - i, (unsigned long long)sas_address)); - if (!sas_address) - continue; - port_details = phy_info->port_details; - /* - * Forming a port - */ - if (!port_details) { - port_details = kzalloc(sizeof(*port_details), - GFP_KERNEL); - if (!port_details) - goto out; - port_details->num_phys = 1; - port_details->port_info = port_info; - if (phy_info->phy_id < 64 ) - port_details->phy_bitmask |= - (1 << phy_info->phy_id); - phy_info->sas_port_add_phy=1; - dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t" - "phy_id=%d sas_address=0x%018llX\n", - i, (unsigned long long)sas_address)); - phy_info->port_details = port_details; + shost_for_each_device(sdev, ioc->sh) { + starget = scsi_target(sdev); + rphy = dev_to_rphy(starget->dev.parent); + if (rphy->identify.sas_address == sas_address) { + sas_info->os.id = starget->id; + sas_info->os.channel = starget->channel; } + } - if (i == port_info->num_phys - 1) - continue; - phy_info_cmp = &port_info->phy_info[i + 1]; - for (j = i + 1 ; j < port_info->num_phys ; j++, - phy_info_cmp++) { - if (!phy_info_cmp->attached.sas_address) - continue; - if (sas_address != phy_info_cmp->attached.sas_address) - continue; - if (phy_info_cmp->port_details == port_details ) + out: + up(&ioc->sas_device_info_mutex); + return; +} + +/** + * mptsas_add_device_component_by_fw - + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: fw mapped id's + * @id: + * + **/ +static void +mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + struct mptsas_devinfo sas_device; + struct mptsas_enclosure enclosure_info; + int rc; + + rc = mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (channel << 8) + id); + if (rc) + return; + + memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); + mptsas_sas_enclosure_pg0(ioc, &enclosure_info, + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << + MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), + sas_device.handle_enclosure); + + mptsas_add_device_component(ioc, sas_device.channel, + sas_device.id, sas_device.sas_address, sas_device.device_info, + sas_device.slot, enclosure_info.enclosure_logical_id); +} + +/** + * mptsas_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) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidVolumePage0_t buffer = NULL; + int i; + RaidPhysDiskPage0_t phys_disk; + struct sas_device_info *sas_info, *next; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; + /* assumption that all volumes on channel = 0 */ + cfg.pageAddr = starget->id; + cfg.cfghdr.hdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (!hdr.PageLength) + goto out; + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) + goto out; + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (!buffer->NumPhysDisks) + goto out; + + /* + * Adding entry for hidden components + */ + for (i = 0; i < buffer->NumPhysDisks; i++) { + + 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); + + down(&ioc->sas_device_info_mutex); + list_for_each_entry(sas_info, &ioc->sas_device_info_list, + list) { + if (!sas_info->is_logical_volume && + (sas_info->fw.channel == phys_disk.PhysDiskBus && + sas_info->fw.id == phys_disk.PhysDiskID)) { + sas_info->is_hidden_raid_component = 1; + sas_info->volume_id = starget->id; + } + } + up(&ioc->sas_device_info_mutex); + } + + /* + * Delete all matching devices out of the list + */ + down(&ioc->sas_device_info_mutex); + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + if (sas_info->is_logical_volume && sas_info->fw.id == + starget->id) { + list_del(&sas_info->list); + kfree(sas_info); + } + } + + sas_info = kzalloc(sizeof(struct sas_device_info), GFP_KERNEL); + if (sas_info) { + sas_info->fw.id = starget->id; + sas_info->os.id = starget->id; + sas_info->os.channel = starget->channel; + sas_info->is_logical_volume = 1; + INIT_LIST_HEAD(&sas_info->list); + list_add_tail(&sas_info->list, &ioc->sas_device_info_list); + } + up(&ioc->sas_device_info_mutex); + + out: + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); +} + +/** + * mptsas_add_device_component_starget - + * @ioc: Pointer to MPT_ADAPTER structure + * @starget: + * + **/ +static void +mptsas_add_device_component_starget(MPT_ADAPTER *ioc, struct scsi_target *starget) +{ + VirtTarget *vtarget; + struct sas_rphy *rphy; + struct mptsas_phyinfo *phy_info = NULL; + struct mptsas_enclosure enclosure_info; + + rphy = dev_to_rphy(starget->dev.parent); + vtarget = starget->hostdata; + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + rphy->identify.sas_address); + if (!phy_info) + return; + + memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); + mptsas_sas_enclosure_pg0(ioc, &enclosure_info, + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << + MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), + phy_info->attached.handle_enclosure); + + mptsas_add_device_component(ioc, phy_info->attached.channel, + phy_info->attached.id, phy_info->attached.sas_address, + phy_info->attached.device_info, + phy_info->attached.slot, enclosure_info.enclosure_logical_id); +} + +/** + * mptsas_del_device_component_by_os - Once a device has been removed, we + * mark the entry in the list as being cached + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: os mapped id's + * @id: + * + **/ +static void +mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + struct sas_device_info *sas_info, *next; + + /* + * Set is_cached flag + */ + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + if (sas_info->os.channel == channel && sas_info->os.id == id) + sas_info->is_cached = 1; + } +} + +/** + * mptsas_del_device_components - Cleaning the list + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +static void +mptsas_del_device_components(MPT_ADAPTER *ioc) +{ + struct sas_device_info *sas_info, *next; + + 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); + } + up(&ioc->sas_device_info_mutex); +} + +/** + * mptsas_setup_wide_ports - Updates for new and existing narrow/wide port + * configuration + * in the sas_topology + * @ioc: Pointer to MPT_ADAPTER structure + * @port_info: + * + */ +static void +mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) +{ + struct mptsas_portinfo_details * port_details; + struct mptsas_phyinfo *phy_info, *phy_info_cmp; + u64 sas_address; +#if !defined(MPT_WIDE_PORT_API) + u8 found_wide_port; +#endif + int i, j; + + mutex_lock(&ioc->sas_topology_mutex); + + phy_info = port_info->phy_info; + for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { + if (phy_info->attached.handle) + continue; + port_details = phy_info->port_details; + if (!port_details) + continue; + if (port_details->num_phys < 2) + continue; + + /* + * Removing a phy from a port, letting the last + * phy be removed by firmware events. + */ +#if defined(MPT_WIDE_PORT_API) + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: [%p]: deleting phy = %d\n", + ioc->name, __FUNCTION__, port_details, i)); +#else + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: [%p]: port=%d deleting phy = %d\n", + ioc->name, __FUNCTION__, port_details, + port_details->port_id, i)); +#endif + port_details->num_phys--; + port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); + memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); +#if defined(MPT_WIDE_PORT_API) + devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev, + MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, + phy_info->phy_id, phy_info->phy)); + sas_port_delete_phy(port_details->port, phy_info->phy); +#endif + phy_info->port_details = NULL; + } + + /* + * Populate and refresh the tree + */ + phy_info = port_info->phy_info; + for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { + sas_address = phy_info->attached.sas_address; + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n", + ioc->name, i, (unsigned long long)sas_address)); + if (!sas_address) + continue; + port_details = phy_info->port_details; + /* + * Forming a port + */ + if (!port_details) { + port_details = kzalloc(sizeof(struct mptsas_portinfo_details), + GFP_KERNEL); + if (!port_details) + goto out; + port_details->num_phys = 1; + port_details->port_info = port_info; +#if !defined(MPT_WIDE_PORT_API) + port_details->port_id = phy_info->port_id; + port_details->rphy_id = i; + port_details->device_info = phy_info->attached.device_info; +#endif + if (phy_info->phy_id < 64 ) + port_details->phy_bitmask |= + (1 << phy_info->phy_id); +#if defined(MPT_WIDE_PORT_API) + phy_info->sas_port_add_phy=1; +#endif + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t" + "phy_id=%d sas_address=0x%018llX\n", ioc->name, i, + (unsigned long long) sas_address)); + phy_info->port_details = port_details; + } + + if (i == port_info->num_phys - 1) + continue; + phy_info_cmp = &port_info->phy_info[i + 1]; +#if !defined(MPT_WIDE_PORT_API) + found_wide_port = 0; +#endif + for (j = i + 1 ; j < port_info->num_phys ; j++, + phy_info_cmp++) { + if (!phy_info_cmp->attached.sas_address) + continue; + if (sas_address != phy_info_cmp->attached.sas_address) continue; - dsaswideprintk((KERN_DEBUG +#if !defined(MPT_WIDE_PORT_API) + found_wide_port = 1; +#endif + if (phy_info_cmp->port_details == port_details ) + continue; + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tphy_id=%d sas_address=0x%018llX\n", - j, (unsigned long long) + ioc->name, j, (unsigned long long) phy_info_cmp->attached.sas_address)); if (phy_info_cmp->port_details) { port_details->rphy = mptsas_get_rphy(phy_info_cmp); +#if defined(MPT_WIDE_PORT_API) port_details->port = mptsas_get_port(phy_info_cmp); +#endif port_details->starget = mptsas_get_starget(phy_info_cmp); +#if !defined(MPT_WIDE_PORT_API) + port_details->port_id = + phy_info_cmp->port_details->port_id; + port_details->rphy_id = + phy_info_cmp->port_details->rphy_id; +#endif port_details->num_phys = phy_info_cmp->port_details->num_phys; if (!phy_info_cmp->port_details->num_phys) kfree(phy_info_cmp->port_details); +#if defined(MPT_WIDE_PORT_API) } else phy_info_cmp->sas_port_add_phy=1; +#else + } +#endif /* * Adding a phy to a port */ @@ -554,65 +1112,124 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc port_details->phy_bitmask |= (1 << phy_info_cmp->phy_id); port_details->num_phys++; +#if !defined(MPT_WIDE_PORT_API) + phy_info_cmp->attached.wide_port_enable = 1; +#endif } +#if !defined(MPT_WIDE_PORT_API) + phy_info->attached.wide_port_enable = (found_wide_port) ? 1:0; +#endif } out: -#ifdef MPT_DEBUG_SAS_WIDE for (i = 0; i < port_info->num_phys; i++) { port_details = port_info->phy_info[i].port_details; if (!port_details) continue; - dsaswideprintk((KERN_DEBUG +#if defined(MPT_WIDE_PORT_API) + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: phy_id=%02d num_phys=%02d " - "bitmask=0x%016llX\n", __FUNCTION__, + "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details, i, port_details->num_phys, (unsigned long long)port_details->phy_bitmask)); - dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n", - port_details->port, port_details->rphy)); - } - dsaswideprintk((KERN_DEBUG"\n")); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n", + ioc->name, port_details->port, port_details->rphy)); +#else + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: [%p]: phy=%02d port=%02d num_phys=%02d " + "rphy=%02d bitmask=0x%016llX\n", + ioc->name, __FUNCTION__, + port_details, i, port_details->port_id, + port_details->num_phys, port_details->rphy_id, + (unsigned long long)port_details->phy_bitmask)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "\t\trphy=%p\n", ioc->name, port_details->rphy)); #endif + } + dsaswideprintk(ioc, printk("\n")); mutex_unlock(&ioc->sas_topology_mutex); } /** - * 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; - VirtDevice *vdev; + VirtDevice *vdevice; VirtTarget *vtarget = NULL; shost_for_each_device(sdev, ioc->sh) { - if ((vdev = sdev->hostdata) == NULL) + if ((vdevice = sdev->hostdata) == NULL || + (vdevice->vtarget == NULL)) + continue; + if ((vdevice->vtarget->tflags & + MPT_TARGET_FLAGS_RAID_COMPONENT || + vdevice->vtarget->raidVolume)) continue; - if (vdev->vtarget->id == id && - vdev->vtarget->channel == channel) - vtarget = vdev->vtarget; + if (vdevice->vtarget->id == id && + vdevice->vtarget->channel == channel) + vtarget = vdevice->vtarget; } return vtarget; } +static void +mptsas_queue_device_delete(MPT_ADAPTER *ioc, + MpiEventDataSasDeviceStatusChange_t *sas_event_data) +{ + struct fw_event_work *fw_event; + int sz; + + sz = offsetof(struct fw_event_work, event_data) + + sizeof(MpiEventDataSasDeviceStatusChange_t); + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", + ioc->name, __FUNCTION__, __LINE__); + return; + } + memcpy(fw_event->event_data, sas_event_data, + sizeof(MpiEventDataSasDeviceStatusChange_t)); + fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE; + fw_event->ioc = ioc; + mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); +} + +static void +mptsas_queue_rescan(MPT_ADAPTER *ioc) +{ + struct fw_event_work *fw_event; + int sz; + + sz = offsetof(struct fw_event_work, event_data); + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", + ioc->name, __FUNCTION__, __LINE__); + return; + } + fw_event->event = -1; + fw_event->ioc = ioc; + mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); +} + + /** - * mptsas_target_reset - * - * Issues TARGET_RESET to end device using handshaking method + * mptsas_target_reset - Issues TARGET_RESET to end device using + * handshaking method + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: + * @id: * - * @ioc - * @channel - * @id - * - * Returns (1) success - * (0) failure + * Returns (1) success + * (0) failure * **/ static int @@ -621,12 +1238,18 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; - if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { - dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n", - ioc->name,__FUNCTION__, __LINE__)); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) return 0; + + if ((mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n", + ioc->name,__FUNCTION__, __LINE__)); + goto out_fail; } + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", + ioc->name, mf)); + /* Format the Request */ pScsiTm = (SCSITaskMgmt_t *) mf; @@ -637,51 +1260,51 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; - DBG_DUMP_TM_REQUEST_FRAME(mf); + DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); - if (mpt_send_handshake_request(ioc->TaskCtx, ioc, - sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) { - mpt_free_msg_frame(ioc, mf); - dfailprintk((MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n", - ioc->name,__FUNCTION__, __LINE__)); - return 0; - } + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n", + ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id)); + + mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); return 1; -} + out_fail: + + mpt_clear_taskmgmt_in_progress_flag(ioc); + return 0; +} /** - * 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, EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + MPT_SCSI_HOST *hd = shost_private(ioc->sh); VirtTarget *vtarget = NULL; - struct mptsas_target_reset_event *target_reset_list; + struct mptsas_target_reset_event *target_reset_list; u8 id, channel; 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) + vtarget->deleted = 1; /* block IO */ + } - target_reset_list = kzalloc(sizeof(*target_reset_list), + target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), GFP_ATOMIC); if (!target_reset_list) { - dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", ioc->name,__FUNCTION__, __LINE__)); return; } @@ -690,84 +1313,98 @@ mptsas_target_reset_queue(MPT_ADAPTER *i sizeof(*sas_event_data)); list_add_tail(&target_reset_list->list, &hd->target_reset_list); - if (hd->resetPending) - return; + target_reset_list->time_count = jiffies; - if (mptsas_target_reset(ioc, channel, id)) { + if (mptsas_target_reset(ioc, channel, id)) target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; - } } /** - * mptsas_dev_reset_complete - * - * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, - * enable work queue to finish off removing device from upper layers. - * then send next TARGET_RESET in the queue. - * - * @ioc + * mptsas_taskmgmt_complete - Completion for TARGET_RESET after + * NOT_RESPONDING_EVENT, enable work queue to finish off removing device + * from upper layers. then send next TARGET_RESET in the queue. + * @ioc: Pointer to MPT_ADAPTER structure * **/ -static void -mptsas_dev_reset_complete(MPT_ADAPTER *ioc) +static int +mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + MPT_SCSI_HOST *hd = shost_private(ioc->sh); struct list_head *head = &hd->target_reset_list; - struct mptsas_target_reset_event *target_reset_list; - struct mptsas_hotplug_event *ev; - EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; + struct mptsas_target_reset_event *target_reset_list; u8 id, channel; - __le64 sas_address; + SCSITaskMgmtReply_t *pScsiTmReply; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: " + "(mf = %p, mr = %p)\n", ioc->name, mf, mr)); + + pScsiTmReply = (SCSITaskMgmtReply_t *)mr; + if (pScsiTmReply) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n" + "\ttask_type = 0x%02X, iocstatus = 0x%04X " + "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, " + "term_cmnds = %d\n", ioc->name, + pScsiTmReply->Bus, pScsiTmReply->TargetID, + pScsiTmReply->TaskType, + le16_to_cpu(pScsiTmReply->IOCStatus), + le32_to_cpu(pScsiTmReply->IOCLogInfo), + pScsiTmReply->ResponseCode, + le32_to_cpu(pScsiTmReply->TerminationCount))); + + if (pScsiTmReply->ResponseCode) + mptscsih_taskmgmt_response_code(ioc, + pScsiTmReply->ResponseCode); + } + + if (pScsiTmReply && (pScsiTmReply->TaskType == + MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType == + MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) { + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->taskmgmt_cmds.reply, mr, + min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->taskmgmt_cmds.done); + return 1; + } + return 0; + } + + mpt_clear_taskmgmt_in_progress_flag(ioc); if (list_empty(head)) - return; + return 1; - target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list); + target_reset_list = list_entry(head->next, + struct mptsas_target_reset_event, list); - sas_event_data = &target_reset_list->sas_event_data; - id = sas_event_data->TargetID; - channel = sas_event_data->Bus; - hd->resetPending = 0; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt: completed (%d seconds)\n", + ioc->name, jiffies_to_msecs(jiffies - + target_reset_list->time_count)/1000)); + + id = pScsiTmReply->TargetID; + channel = pScsiTmReply->Bus; + target_reset_list->time_count = jiffies; /* * retry target reset */ if (!target_reset_list->target_reset_issued) { - if (mptsas_target_reset(ioc, channel, id)) { + if (mptsas_target_reset(ioc, channel, id)) target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; - } - return; + return 1; } /* * enable work queue to remove device from upper layers */ list_del(&target_reset_list->list); + if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off) + mptsas_queue_device_delete(ioc, &target_reset_list->sas_event_data); - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", - ioc->name,__FUNCTION__, __LINE__)); - return; - } - - INIT_WORK(&ev->work, mptsas_hotplug_work, ev); - ev->ioc = ioc; - ev->handle = le16_to_cpu(sas_event_data->DevHandle); - ev->parent_handle = - le16_to_cpu(sas_event_data->ParentDevHandle); - ev->channel = channel; - ev->id =id; - ev->phy_id = sas_event_data->PhyNum; - memcpy(&sas_address, &sas_event_data->SASAddress, - sizeof(__le64)); - ev->sas_address = le64_to_cpu(sas_address); - ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo); - ev->event_type = MPTSAS_DEL_DEVICE; - schedule_work(&ev->work); - kfree(target_reset_list); /* * issue target reset to next device in the queue @@ -775,78 +1412,78 @@ mptsas_dev_reset_complete(MPT_ADAPTER *i head = &hd->target_reset_list; if (list_empty(head)) - return; + return 1; target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list); - sas_event_data = &target_reset_list->sas_event_data; - id = sas_event_data->TargetID; - channel = sas_event_data->Bus; + 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)) { + if (mptsas_target_reset(ioc, channel, id)) target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; - } -} -/** - * mptsas_taskmgmt_complete - * - * @ioc - * @mf - * @mr - * - **/ -static int -mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) -{ - mptsas_dev_reset_complete(ioc); - return mptscsih_taskmgmt_complete(ioc, mf, mr); + return 1; } /** - * mptscsih_ioc_reset - * - * @ioc - * @reset_phase + * mptsas_ioc_reset - + * @ioc: Pointer to MPT_ADAPTER structure + * @reset_phase: * **/ static int mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - MPT_SCSI_HOST *hd; - struct mptsas_target_reset_event *target_reset_list, *n; + MPT_SCSI_HOST *hd; int rc; rc = mptscsih_ioc_reset(ioc, reset_phase); + if ((ioc->bus_type != SAS) || (!rc)) + return rc; - if (ioc->bus_type != SAS) - goto out; - - if (reset_phase != MPT_IOC_POST_RESET) - goto out; - - if (!ioc->sh || !ioc->sh->hostdata) - goto out; - hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + hd = shost_private(ioc->sh); if (!hd->ioc) goto out; - if (list_empty(&hd->target_reset_list)) - goto out; - - /* flush the target_reset_list */ - list_for_each_entry_safe(target_reset_list, n, - &hd->target_reset_list, list) { - list_del(&target_reset_list->list); - kfree(target_reset_list); + switch(reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); + mptsas_fw_event_off(ioc); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->sas_mgmt.done); + } + mptsas_cleanup_fw_event_q(ioc); + mptsas_queue_rescan(ioc); + mptsas_fw_event_on(ioc); + break; + default: + break; } out: return rc; } +/** + * 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) @@ -869,7 +1506,7 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *io cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -912,36 +1549,363 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *io return error; } +/** + * 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_private(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 = mpt_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; +} + +/** + * enum device_state - + * @DEVICE_RETRY: need to retry the TUR + * @DEVICE_ERROR: TUR return error, don't add device + * @DEVICE_READY: device can be added + * + */ +enum device_state{ + DEVICE_RETRY, + DEVICE_ERROR, + DEVICE_READY, +}; + +/** + * mptsas_test_unit_ready - + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: + * @id: + * @count: retry count + * + */ +enum device_state +mptsas_test_unit_ready(MPT_ADAPTER *ioc, u8 channel, u8 id, u16 count) +{ + INTERNAL_CMD *iocmd; + MPT_SCSI_HOST *hd = shost_private(ioc->sh); + enum device_state state; + int rc; + u8 skey, asc, ascq; + u8 retry_ua; + + if (count >= mpt_cmd_retry_count) + return DEVICE_ERROR; + + retry_ua = 0; + iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL); + if (!iocmd) { + printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n", + __FUNCTION__, ioc->name, sizeof(INTERNAL_CMD)); + return DEVICE_ERROR; + } + + state = DEVICE_ERROR; + iocmd->cmd = TEST_UNIT_READY; + iocmd->data_dma = -1; + iocmd->data = NULL; + + if (mptscsih_is_phys_disk(ioc, channel, id)) { + iocmd->flags |= MPT_ICFLAG_PHYS_DISK; + iocmd->physDiskNum = mptscsih_raid_id_to_num(ioc, channel, id); + iocmd->id = id; + } + iocmd->channel = channel; + iocmd->id = id; + + retry: + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_channel=%d " + "fw_id=%d retry=%d\n", ioc->name, __FUNCTION__, channel, id, count)); + rc = mptscsih_do_cmd(hd, iocmd); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rc=0x%02x\n", + ioc->name, __FUNCTION__, rc)); + if (rc < 0) { + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "tur failed due to timeout\n", ioc->name, + __FUNCTION__, channel, id); + goto tur_done; + } + + switch(rc) { + case MPT_SCANDV_GOOD: + state = DEVICE_READY; + goto tur_done; + case MPT_SCANDV_BUSY: + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: " + "fw_channel=%d fw_id=%d : device busy\n", + ioc->name, __FUNCTION__, channel, id)); + state = DEVICE_RETRY; + break; + case MPT_SCANDV_DID_RESET: + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: " + "fw_channel=%d fw_id=%d : did reset\n", + ioc->name, __FUNCTION__, channel, id)); + state = DEVICE_RETRY; + break; + case MPT_SCANDV_SENSE: + skey = ioc->internal_cmds.sense[2] & 0x0F; + asc = ioc->internal_cmds.sense[12]; + ascq = ioc->internal_cmds.sense[13]; + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: " + "fw_channel=%d fw_id=%d : [sense_key,asc," + "ascq]: [0x%02x,0x%02x,0x%02x]\n", ioc->name, + __FUNCTION__, channel, id, skey, asc, ascq)); + + if (skey == UNIT_ATTENTION) { + if (!retry_ua) { + retry_ua++; + goto retry; + } + } else if (skey == NOT_READY) { + /* + * medium isn't present + */ + if (asc == 0x3a) { + state = DEVICE_READY; + goto tur_done; + } + /* + * LU becoming ready, or + * LU hasn't self-configured yet + */ + if ((asc == 0x04 && ascq == 0x01) || + (asc == 0x04 && ascq == 0x11) || + asc == 0x3e) { + state = DEVICE_RETRY; + break; + } + } else if (skey == ILLEGAL_REQUEST) { + /* try sending a tur to a non-zero lun number */ + if (!iocmd->lun && !mptsas_get_lun_number(ioc, + channel, id, &iocmd->lun) && iocmd->lun) + goto retry; + } + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d : " + "tur failed due to [sense_key,asc,ascq]: " + "[0x%02x,0x%02x,0x%02x]\n", ioc->name, + __FUNCTION__, channel, id, skey, asc, ascq); + goto tur_done; + case MPT_SCANDV_SELECTION_TIMEOUT: + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "tur failed due to no device\n", ioc->name, + __FUNCTION__, channel, + id); + goto tur_done; + case MPT_SCANDV_SOME_ERROR: + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "tur failed due to some error\n", ioc->name, + __FUNCTION__, + channel, id); + goto tur_done; + default: + printk(MYIOC_s_ERR_FMT + "%s: fw_channel=%d fw_id=%d: tur failed due to " + "unknown rc=0x%02x\n", ioc->name, __FUNCTION__, + channel, id, rc ); + goto tur_done; + } + tur_done: + kfree(iocmd); + return state; +} + +/** + * mptsas_issue_tlr - Enabling Transport Layer Retries + * @hd: + * @sdev: + * + **/ +static void +mptsas_issue_tlr(MPT_SCSI_HOST *hd, struct scsi_device *sdev) +{ + INTERNAL_CMD *iocmd; + VirtDevice *vdevice = sdev->hostdata; + u8 retries; + u8 rc; + MPT_ADAPTER *ioc = hd->ioc; + + if ( sdev->inquiry[8] == 'H' && + sdev->inquiry[9] == 'P' && + sdev->inquiry[10] == ' ' && + sdev->inquiry[11] == ' ' && + sdev->inquiry[12] == ' ' && + sdev->inquiry[13] == ' ' && + sdev->inquiry[14] == ' ' && + sdev->inquiry[15] == ' ' ) { + + iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL); + if (!iocmd) { + printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n", + __FUNCTION__, ioc->name, sizeof(INTERNAL_CMD)); + return; + } + iocmd->id = vdevice->vtarget->id; + iocmd->channel = vdevice->vtarget->channel; + iocmd->lun = vdevice->lun; + iocmd->physDiskNum = -1; + iocmd->cmd = TRANSPORT_LAYER_RETRIES; + iocmd->data_dma = -1; + for (retries = 0, rc = -1; retries < 3; retries++) { + rc = mptscsih_do_cmd(hd, iocmd); + if (!rc) + break; + } + if (rc != 0) + printk(MYIOC_s_DEBUG_FMT "unable to enable TLR on" + " fw_channel %d, fw_id %d, lun=%d\n", + ioc->name, vdevice->vtarget->channel, + vdevice->vtarget->id, sdev->lun); + kfree(iocmd); + } +} + +/** + * mptsas_slave_configure - + * @sdev: + * + **/ static int mptsas_slave_configure(struct scsi_device *sdev) { + struct Scsi_Host *host = sdev->host; + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + VirtDevice *vdevice = sdev->hostdata; + + + if (vdevice->vtarget->deleted) { + sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n"); + vdevice->vtarget->deleted = 0; + } - if (sdev->channel == MPTSAS_RAID_CHANNEL) + /* + * RAID volumes placed beyond the last expected port. + * Ignore sending sas mode pages in that case.. + */ + if (sdev->channel == MPTSAS_RAID_CHANNEL) { + mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev)); goto out; + } sas_read_port_mode_page(sdev); + mptsas_add_device_component_starget(ioc, scsi_target(sdev)); + + if (sdev->type == TYPE_TAPE && + (ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_TLR )) + mptsas_issue_tlr(hd, sdev); out: + return mptscsih_slave_configure(sdev); } +/** + * mptsas_target_alloc - + * @starget: + * + **/ static int mptsas_target_alloc(struct scsi_target *starget) { struct Scsi_Host *host = dev_to_shost(&starget->dev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_private(host); VirtTarget *vtarget; u8 id, channel; struct sas_rphy *rphy; struct mptsas_portinfo *p; int i; + MPT_ADAPTER *ioc = hd->ioc; vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); if (!vtarget) return -ENOMEM; vtarget->starget = starget; - vtarget->ioc_id = hd->ioc->id; + vtarget->ioc_id = ioc->id; vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; id = starget->id; channel = 0; @@ -950,38 +1914,49 @@ mptsas_target_alloc(struct scsi_target * * RAID volumes placed beyond the last expected port. */ if (starget->channel == MPTSAS_RAID_CHANNEL) { - for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) - if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) - channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; + if (!ioc->raid_data.pIocPg2) { + kfree(vtarget); + return -ENXIO; + } + for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) + if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) + channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; + vtarget->raidVolume = 1; goto out; } rphy = dev_to_rphy(starget->dev.parent); - mutex_lock(&hd->ioc->sas_topology_mutex); - list_for_each_entry(p, &hd->ioc->sas_topology, list) { + mutex_lock(&ioc->sas_topology_mutex); + list_for_each_entry(p, &ioc->sas_topology, list) { for (i = 0; i < p->num_phys; i++) { if (p->phy_info[i].attached.sas_address != - rphy->identify.sas_address) + rphy->identify.sas_address) continue; id = p->phy_info[i].attached.id; channel = p->phy_info[i].attached.channel; mptsas_set_starget(&p->phy_info[i], starget); + starget_printk(KERN_INFO, starget, MYIOC_s_FMT + "add device: fw_channel %d, fw_id %d, phy %d, sas_addr 0x%llx\n", + ioc->name, p->phy_info[i].attached.channel, + p->phy_info[i].attached.id, p->phy_info[i].attached.phy_id, + (unsigned long long)p->phy_info[i].attached.sas_address); + /* * Exposing hidden raid components */ - if (mptscsih_is_phys_disk(hd->ioc, channel, id)) { - id = mptscsih_raid_id_to_num(hd->ioc, - channel, id); + if (mptscsih_is_phys_disk(ioc, channel, id)) { + id = mptscsih_raid_id_to_num(ioc, + channel, id); vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; p->phy_info[i].attached.phys_disk_num = id; } - mutex_unlock(&hd->ioc->sas_topology_mutex); + mutex_unlock(&ioc->sas_topology_mutex); goto out; } } - mutex_unlock(&hd->ioc->sas_topology_mutex); + mutex_unlock(&ioc->sas_topology_mutex); kfree(vtarget); return -ENXIO; @@ -993,29 +1968,46 @@ mptsas_target_alloc(struct scsi_target * return 0; } +/** + * mptsas_target_destroy - + * @starget: + * + **/ static void mptsas_target_destroy(struct scsi_target *starget) { struct Scsi_Host *host = dev_to_shost(&starget->dev); - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_private(host); struct sas_rphy *rphy; struct mptsas_portinfo *p; int i; + MPT_ADAPTER *ioc = hd->ioc; if (!starget->hostdata) return; + mptsas_del_device_component_by_os(ioc, starget->channel, + starget->id); + if (starget->channel == MPTSAS_RAID_CHANNEL) goto out; rphy = dev_to_rphy(starget->dev.parent); - list_for_each_entry(p, &hd->ioc->sas_topology, list) { + list_for_each_entry(p, &ioc->sas_topology, list) { for (i = 0; i < p->num_phys; i++) { if (p->phy_info[i].attached.sas_address != rphy->identify.sas_address) continue; - mptsas_set_starget(&p->phy_info[i], NULL); - goto out; + + starget_printk(KERN_INFO, starget, MYIOC_s_FMT + "delete device: fw_channel %d, fw_id %d, phy %d, " + "sas_addr 0x%llx\n", ioc->name, + p->phy_info[i].attached.channel, + p->phy_info[i].attached.id, + p->phy_info[i].attached.phy_id, (unsigned long long) + p->phy_info[i].attached.sas_address); + + mptsas_port_delete(ioc, p->phy_info[i].port_details); } } @@ -1024,73 +2016,94 @@ mptsas_target_destroy(struct scsi_target starget->hostdata = NULL; } - +/** + * mptsas_slave_alloc - + * @sdev: + * + **/ static int mptsas_slave_alloc(struct scsi_device *sdev) { struct Scsi_Host *host = sdev->host; - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_private(host); struct sas_rphy *rphy; struct mptsas_portinfo *p; - VirtDevice *vdev; + VirtDevice *vdevice; struct scsi_target *starget; int i; + MPT_ADAPTER *ioc = hd->ioc; - vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); - if (!vdev) { + vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); + if (!vdevice) { printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n", - hd->ioc->name, sizeof(VirtDevice)); + ioc->name, sizeof(VirtDevice)); return -ENOMEM; } starget = scsi_target(sdev); - vdev->vtarget = starget->hostdata; + vdevice->vtarget = starget->hostdata; + /* + * RAID volumes placed beyond the last expected port. + */ if (sdev->channel == MPTSAS_RAID_CHANNEL) goto out; rphy = dev_to_rphy(sdev->sdev_target->dev.parent); - mutex_lock(&hd->ioc->sas_topology_mutex); - list_for_each_entry(p, &hd->ioc->sas_topology, list) { + mutex_lock(&ioc->sas_topology_mutex); + list_for_each_entry(p, &ioc->sas_topology, list) { for (i = 0; i < p->num_phys; i++) { if (p->phy_info[i].attached.sas_address != rphy->identify.sas_address) continue; - vdev->lun = sdev->lun; + vdevice->lun = sdev->lun; /* * Exposing hidden raid components */ - if (mptscsih_is_phys_disk(hd->ioc, + if (mptscsih_is_phys_disk(ioc, p->phy_info[i].attached.channel, p->phy_info[i].attached.id)) sdev->no_uld_attach = 1; - mutex_unlock(&hd->ioc->sas_topology_mutex); + mutex_unlock(&ioc->sas_topology_mutex); goto out; } } - mutex_unlock(&hd->ioc->sas_topology_mutex); + mutex_unlock(&ioc->sas_topology_mutex); - kfree(vdev); + kfree(vdevice); return -ENXIO; out: - vdev->vtarget->num_luns++; - sdev->hostdata = vdev; + vdevice->vtarget->num_luns++; + sdev->hostdata = vdevice; return 0; } +/** + * mptsas_qcmd - + * @SCpnt: + * @done: + * + **/ static int mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { - VirtDevice *vdev = SCpnt->device->hostdata; + MPT_SCSI_HOST *hd; + MPT_ADAPTER *ioc; + VirtDevice *vdevice = SCpnt->device->hostdata; - if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) { + if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } + + hd = shost_private(SCpnt->device->host); + ioc = hd->ioc; -// scsi_print_command(SCpnt); + if (ioc->sas_discovery_quiesce_io) + return SCSI_MLQUEUE_HOST_BUSY; +// scsi_print_command(SCpnt); return mptscsih_qcmd(SCpnt,done); } @@ -1119,8 +2132,14 @@ static struct scsi_host_template mptsas_ .max_sectors = 8192, .cmd_per_lun = 7, .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = mptscsih_host_attrs, }; +/** + * mptsas_get_linkerrors - + * @phy: + * + **/ static int mptsas_get_linkerrors(struct sas_phy *phy) { MPT_ADAPTER *ioc = phy_to_ioc(phy); @@ -1130,9 +2149,11 @@ static int mptsas_get_linkerrors(struct dma_addr_t dma_handle; int error; +#if defined(MPT_WIDE_PORT_API_PLUS) /* FIXME: only have link errors on local phys */ if (!scsi_is_sas_phy_local(phy)) return -EINVAL; +#endif hdr.PageVersion = MPI_SASPHY1_PAGEVERSION; hdr.ExtPageLength = 0; @@ -1147,7 +2168,7 @@ static int mptsas_get_linkerrors(struct cfg.pageAddr = phy->identify.phy_identifier; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -1167,7 +2188,7 @@ static int mptsas_get_linkerrors(struct if (error) goto out_free_consistent; - mptsas_print_phy_pg1(buffer); + mptsas_print_phy_pg1(ioc, buffer); phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount); phy->running_disparity_error_count = @@ -1183,19 +2204,37 @@ 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) { - ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD; + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD; if (reply != NULL) { - ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID; + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID; memcpy(ioc->sas_mgmt.reply, reply, min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); } - complete(&ioc->sas_mgmt.done); - return 1; + + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { + ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->sas_mgmt.done); + return 1; + } + return 0; } +/** + * mptsas_phy_reset - + * @phy: + * @hard_reset: + * + **/ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) { MPT_ADAPTER *ioc = phy_to_ioc(phy); @@ -1206,9 +2245,11 @@ static int mptsas_phy_reset(struct sas_p unsigned long timeleft; int error = -ERESTARTSYS; +#if defined(MPT_WIDE_PORT_API_PLUS) /* FIXME: fusion doesn't allow non-local phy reset */ if (!scsi_is_sas_phy_local(phy)) return -EINVAL; +#endif /* not implemented for expanders */ if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP) @@ -1232,21 +2273,24 @@ static int mptsas_phy_reset(struct sas_p MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; req->PhyNum = phy->identify.phy_identifier; + INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); - - timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, - 10 * HZ); - if (!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; + if (!timeleft) { + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + } goto out_unlock; } /* a reply frame is expected */ if ((ioc->sas_mgmt.status & - MPT_IOCTL_STATUS_RF_VALID) == 0) { + MPT_MGMT_STATUS_RF_VALID) == 0) { error = -ENXIO; goto out_unlock; } @@ -1254,10 +2298,8 @@ static int mptsas_phy_reset(struct sas_p /* process the completed Reply Message Frame */ reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { - printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", - __FUNCTION__, - reply->IOCStatus, - reply->IOCLogInfo); + printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", + ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo); error = -ENXIO; goto out_unlock; } @@ -1265,11 +2307,18 @@ static int mptsas_phy_reset(struct sas_p error = 0; out_unlock: + CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) mutex_unlock(&ioc->sas_mgmt.mutex); out: return error; } +/** + * mptsas_get_enclosure_identifier - + * @rphy: + * @identifier: + * + **/ static int mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) { @@ -1298,12 +2347,18 @@ mptsas_get_enclosure_identifier(struct s memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info, (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << - MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle); + MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), + enclosure_handle); if (!error) *identifier = enclosure_info.enclosure_logical_id; return error; } +/** + * mptsas_get_bay_identifier - + * @rphy: + * + **/ static int mptsas_get_bay_identifier(struct sas_rphy *rphy) { @@ -1336,6 +2391,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) { @@ -1358,7 +2419,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -1384,14 +2445,19 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, port_info->num_phys = buffer->NumPhys; port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(*port_info->phy_info),GFP_KERNEL); + sizeof(struct mptsas_phyinfo),GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; } + ioc->nvdata_version_persistent = + le16_to_cpu(buffer->NvdataVersionPersistent); + ioc->nvdata_version_default = + le16_to_cpu(buffer->NvdataVersionDefault); + for (i = 0; i < port_info->num_phys; i++) { - mptsas_print_phy_data(&buffer->PhyData[i]); + mptsas_print_phy_data(ioc, &buffer->PhyData[i]); port_info->phy_info[i].phy_id = i; port_info->phy_info[i].port_id = buffer->PhyData[i].Port; @@ -1400,8 +2466,72 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, port_info->phy_info[i].portinfo = port_info; port_info->phy_info[i].handle = le16_to_cpu(buffer->PhyData[i].ControllerDevHandle); + port_info->phy_info[i].port_flags = + buffer->PhyData[i].PortFlags; + } + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + buffer, dma_handle); + out: + return error; +} + +/** + * mptsas_sas_io_unit_pg1 - + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +static int +mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) +{ + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasIOUnitPage1_t *buffer; + dma_addr_t dma_handle; + int error; + u16 device_missing_delay; + + memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); + memset(&cfg, 0, sizeof(CONFIGPARMS)); + + cfg.cfghdr.ehdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + 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) + goto out; + if (!hdr.ExtPageLength) { + error = -ENXIO; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + &dma_handle); + if (!buffer) { + error = -ENOMEM; + goto out; } + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + error = mpt_config(ioc, &cfg); + if (error) + goto out_free_consistent; + + ioc->io_missing_delay = + le16_to_cpu(buffer->IODeviceMissingDelay); + device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay); + ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ? + (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 : + device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK; + out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, buffer, dma_handle); @@ -1409,6 +2539,14 @@ mptsas_sas_io_unit_pg0(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) @@ -1429,12 +2567,12 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, str cfg.cfghdr.ehdr = &hdr; cfg.dir = 0; /* read */ - cfg.timeout = 10; /* Get Phy Pg 0 for each Phy. */ cfg.physAddr = -1; cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -1459,12 +2597,14 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, str if (error) goto out_free_consistent; - mptsas_print_phy_pg0(buffer); + mptsas_print_phy_pg0(ioc, buffer); phy_info->hw_link_rate = buffer->HwLinkRate; phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); + phy_info->change_count = buffer->ChangeCount; + phy_info->phy_info = le32_to_cpu(buffer->PhyInfo); out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, @@ -1473,6 +2613,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) @@ -1484,10 +2632,6 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, __le64 sas_address; int error=0; - if (ioc->sas_discovery_runtime && - mptsas_is_end_device(device_info)) - goto out; - hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 0; @@ -1501,9 +2645,8 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, cfg.physAddr = -1; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - memset(device_info, 0, sizeof(struct mptsas_devinfo)); error = mpt_config(ioc, &cfg); if (error) goto out; @@ -1523,11 +2666,18 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; error = mpt_config(ioc, &cfg); + + if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { + error = -ENODEV; + goto out_free_consistent; + } + if (error) goto out_free_consistent; - mptsas_print_device_pg0(buffer); + mptsas_print_device_pg0(ioc, buffer); + memset(device_info, 0, sizeof(struct mptsas_devinfo)); device_info->handle = le16_to_cpu(buffer->DevHandle); device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); device_info->handle_enclosure = @@ -1550,6 +2700,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) @@ -1559,7 +2717,9 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc SasExpanderPage0_t *buffer; dma_addr_t dma_handle; int i, error; + __le64 sas_address; + memset(port_info, 0, sizeof(struct mptsas_portinfo)); hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 0; @@ -1573,9 +2733,8 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - memset(port_info, 0, sizeof(struct mptsas_portinfo)); error = mpt_config(ioc, &cfg); if (error) goto out; @@ -1596,22 +2755,32 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; error = mpt_config(ioc, &cfg); - if (error) + if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { + error = -ENODEV; + goto out_free_consistent; + } + + if (error) goto out_free_consistent; /* save config data */ - port_info->num_phys = buffer->NumPhys; + port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1; port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(*port_info->phy_info),GFP_KERNEL); + sizeof(struct mptsas_phyinfo),GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; } + memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); for (i = 0; i < port_info->num_phys; i++) { port_info->phy_info[i].portinfo = port_info; port_info->phy_info[i].handle = le16_to_cpu(buffer->DevHandle); + port_info->phy_info[i].identify.sas_address = + le64_to_cpu(sas_address); + port_info->phy_info[i].identify.handle_parent = + le16_to_cpu(buffer->ParentDevHandle); } out_free_consistent: @@ -1621,6 +2790,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) @@ -1631,11 +2808,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc dma_addr_t dma_handle; int error=0; - if (ioc->sas_discovery_runtime && - mptsas_is_end_device(&phy_info->attached)) - goto out; - - hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; + hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 1; hdr.Reserved1 = 0; @@ -1648,7 +2821,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -1670,11 +2843,16 @@ 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; + } + if (error) goto out_free_consistent; - mptsas_print_expander_pg1(buffer); + mptsas_print_expander_pg1(ioc, buffer); /* save config data */ phy_info->phy_id = buffer->PhyIdentifier; @@ -1684,6 +2862,8 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc phy_info->hw_link_rate = buffer->HwLinkRate; phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); + phy_info->change_count = buffer->ChangeCount; + phy_info->phy_info = le32_to_cpu(buffer->PhyInfo); out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, @@ -1692,6 +2872,12 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc return error; } +/** + * mptsas_parse_device_info - + * @identify: + * @device_info: + * + **/ static void mptsas_parse_device_info(struct sas_identify *identify, struct mptsas_devinfo *device_info) @@ -1751,12 +2937,21 @@ 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) { MPT_ADAPTER *ioc; struct sas_phy *phy; +#if defined(MPT_WIDE_PORT_API) struct sas_port *port; +#endif int error = 0; if (!dev) { @@ -1773,6 +2968,9 @@ static int mptsas_probe_one_phy(struct d } else phy = phy_info->phy; +#if !defined(MPT_WIDE_PORT_API) + phy->port_identifier = phy_info->port_id; +#endif mptsas_parse_device_info(&phy->identify, &phy_info->identify); /* @@ -1858,6 +3056,10 @@ static int mptsas_probe_one_phy(struct d if (!phy_info->phy) { +#if !defined(MPT_WIDE_PORT_API_PLUS) + if (local) + phy->local_attached = 1; +#endif error = sas_phy_add(phy); if (error) { sas_phy_free(phy); @@ -1870,11 +3072,13 @@ static int mptsas_probe_one_phy(struct d !phy_info->port_details) goto out; +#if defined(MPT_WIDE_PORT_API) port = mptsas_get_port(phy_info); +#endif ioc = phy_to_ioc(phy_info->phy); +#if defined(MPT_WIDE_PORT_API) if (phy_info->sas_port_add_phy) { - if (!port) { port = sas_port_alloc_num(dev); if (!port) { @@ -1883,78 +3087,99 @@ static int mptsas_probe_one_phy(struct d } error = sas_port_add(port); if (error) { - dfailprintk((MYIOC_s_ERR_FMT + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, __FUNCTION__, __LINE__)); goto out; } - mptsas_set_port(phy_info, port); - dsaswideprintk((KERN_DEBUG - "sas_port_alloc: port=%p dev=%p port_id=%d\n", - port, dev, port->port_identifier)); + mptsas_set_port(ioc, phy_info, port); + devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev, + MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n", + ioc->name, port->port_identifier, + (unsigned long long)phy_info->attached.sas_address)); } - dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n", - 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)); } +#else + /* + * wide port suport + * only report the expander or end device once + */ + if (phy_info->attached.wide_port_enable && + (phy_info->phy_id != mptsas_get_rphy_id(phy_info))) + goto out; + +#endif +#if defined(MPT_WIDE_PORT_API) if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { +#else + if (!mptsas_get_rphy(phy_info)) { +#endif struct sas_rphy *rphy; struct device *parent; struct sas_identify identify; parent = dev->parent->parent; - /* - * Let the hotplug_work thread handle processing - * the adding/removing of devices that occur - * after start of day. - */ - if (ioc->sas_discovery_runtime && - mptsas_is_end_device(&phy_info->attached)) - goto out; + + if (mptsas_is_end_device(&phy_info->attached) && + phy_info->attached.handle_parent) { + goto out; + } mptsas_parse_device_info(&identify, &phy_info->attached); if (scsi_is_host_device(parent)) { struct mptsas_portinfo *port_info; int i; - mutex_lock(&ioc->sas_topology_mutex); - port_info = mptsas_find_portinfo_by_handle(ioc, - ioc->handle); - mutex_unlock(&ioc->sas_topology_mutex); - + port_info = ioc->hba_port_info; for (i = 0; i < port_info->num_phys; i++) if (port_info->phy_info[i].identify.sas_address == identify.sas_address) { +#if defined(MPT_WIDE_PORT_API_PLUS) sas_port_mark_backlink(port); +#endif goto out; - } + } } else if (scsi_is_sas_rphy(parent)) { struct sas_rphy *parent_rphy = dev_to_rphy(parent); if (identify.sas_address == parent_rphy->identify.sas_address) { +#if defined(MPT_WIDE_PORT_API_PLUS) sas_port_mark_backlink(port); +#endif goto out; } } switch (identify.device_type) { case SAS_END_DEVICE: +#if defined(MPT_WIDE_PORT_API) rphy = sas_end_device_alloc(port); +#else + rphy = sas_end_device_alloc(phy); +#endif break; case SAS_EDGE_EXPANDER_DEVICE: case SAS_FANOUT_EXPANDER_DEVICE: +#if defined(MPT_WIDE_PORT_API) rphy = sas_expander_alloc(port, identify.device_type); +#else + rphy = sas_expander_alloc(phy, identify.device_type); +#endif break; default: rphy = NULL; break; } if (!rphy) { - dfailprintk((MYIOC_s_ERR_FMT + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, __FUNCTION__, __LINE__)); goto out; @@ -1963,26 +3188,32 @@ static int mptsas_probe_one_phy(struct d rphy->identify = identify; error = sas_rphy_add(rphy); if (error) { - dfailprintk((MYIOC_s_ERR_FMT + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, __FUNCTION__, __LINE__)); sas_rphy_free(rphy); goto out; } - mptsas_set_rphy(phy_info, rphy); + mptsas_set_rphy(ioc, phy_info, rphy); } out: return error; } +/** + * mptsas_probe_hba_phys - + * @ioc: Pointer to MPT_ADAPTER structure + * @handle: + * + **/ static int mptsas_probe_hba_phys(MPT_ADAPTER *ioc) { struct mptsas_portinfo *port_info, *hba; int error = -ENOMEM, i; - hba = kzalloc(sizeof(*port_info), GFP_KERNEL); + hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); if (! hba) goto out; @@ -1990,11 +3221,12 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) if (error) goto out_free_port_info; + mptsas_sas_io_unit_pg1(ioc); mutex_lock(&ioc->sas_topology_mutex); - ioc->handle = hba->phy_info[0].handle; - port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle); + port_info = ioc->hba_port_info; if (!port_info) { - port_info = hba; + ioc->hba_port_info = port_info = hba; + ioc->hba_port_num_phy = port_info->num_phys; list_add_tail(&port_info->list, &ioc->sas_topology); } else { for (i = 0; i < hba->num_phys; i++) { @@ -2004,21 +3236,30 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) hba->phy_info[i].handle; port_info->phy_info[i].port_id = hba->phy_info[i].port_id; + port_info->phy_info[i].port_flags = + hba->phy_info[i].port_flags; } kfree(hba->phy_info); kfree(hba); hba = NULL; } mutex_unlock(&ioc->sas_topology_mutex); +#if defined(CPQ_CIM) + ioc->num_ports = port_info->num_phys; +#endif for (i = 0; i < port_info->num_phys; i++) { mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << MPI_SAS_PHY_PGAD_FORM_SHIFT), i); - + port_info->phy_info[i].identify.handle = + port_info->phy_info[i].handle; mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].handle); + port_info->phy_info[i].identify.handle); + if (!ioc->hba_port_sas_addr) + ioc->hba_port_sas_addr = + port_info->phy_info[i].identify.sas_address; port_info->phy_info[i].identify.phy_id = port_info->phy_info[i].phy_id = i; if (port_info->phy_info[i].attached.handle) @@ -2043,248 +3284,12 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) return error; } -static int -mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) -{ - struct mptsas_portinfo *port_info, *p, *ex; - struct device *parent; - struct sas_rphy *rphy; - int error = -ENOMEM, i, j; - - ex = kzalloc(sizeof(*port_info), GFP_KERNEL); - if (!ex) - goto out; - - error = mptsas_sas_expander_pg0(ioc, ex, - (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); - if (error) - goto out_free_port_info; - - *handle = ex->phy_info[0].handle; - - mutex_lock(&ioc->sas_topology_mutex); - port_info = mptsas_find_portinfo_by_handle(ioc, *handle); - if (!port_info) { - port_info = ex; - list_add_tail(&port_info->list, &ioc->sas_topology); - } else { - for (i = 0; i < ex->num_phys; i++) { - port_info->phy_info[i].handle = - ex->phy_info[i].handle; - port_info->phy_info[i].port_id = - ex->phy_info[i].port_id; - } - kfree(ex->phy_info); - kfree(ex); - ex = NULL; - } - mutex_unlock(&ioc->sas_topology_mutex); - - for (i = 0; i < port_info->num_phys; i++) { - mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], - (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle); - - if (port_info->phy_info[i].identify.handle) { - mptsas_sas_device_pg0(ioc, - &port_info->phy_info[i].identify, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].identify.handle); - port_info->phy_info[i].identify.phy_id = - port_info->phy_info[i].phy_id; - } - - if (port_info->phy_info[i].attached.handle) { - mptsas_sas_device_pg0(ioc, - &port_info->phy_info[i].attached, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].attached.handle); - port_info->phy_info[i].attached.phy_id = - port_info->phy_info[i].phy_id; - } - } - - parent = &ioc->sh->shost_gendev; - for (i = 0; i < port_info->num_phys; i++) { - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(p, &ioc->sas_topology, list) { - for (j = 0; j < p->num_phys; j++) { - if (port_info->phy_info[i].identify.handle != - p->phy_info[j].attached.handle) - continue; - rphy = mptsas_get_rphy(&p->phy_info[j]); - parent = &rphy->dev; - } - } - mutex_unlock(&ioc->sas_topology_mutex); - } - - mptsas_setup_wide_ports(ioc, port_info); - - for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) - mptsas_probe_one_phy(parent, &port_info->phy_info[i], - ioc->sas_index, 0); - - return 0; - - out_free_port_info: - if (ex) { - kfree(ex->phy_info); - kfree(ex); - } - out: - return error; -} - -/* - * mptsas_delete_expander_phys - * +/** + * mptsas_find_phyinfo_by_sas_address - + * @ioc: Pointer to MPT_ADAPTER structure + * @sas_address: * - * This will traverse topology, and remove expanders - * that are no longer present - */ -static void -mptsas_delete_expander_phys(MPT_ADAPTER *ioc) -{ - struct mptsas_portinfo buffer; - struct mptsas_portinfo *port_info, *n, *parent; - struct mptsas_phyinfo *phy_info; - struct sas_port * port; - int i; - u64 expander_sas_address; - - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { - - if (port_info->phy_info && - (!(port_info->phy_info[0].identify.device_info & - MPI_SAS_DEVICE_INFO_SMP_TARGET))) - continue; - - if (mptsas_sas_expander_pg0(ioc, &buffer, - (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), - port_info->phy_info[0].handle)) { - - /* - * Obtain the port_info instance to the parent port - */ - parent = mptsas_find_portinfo_by_handle(ioc, - port_info->phy_info[0].identify.handle_parent); - - if (!parent) - goto next_port; - - expander_sas_address = - port_info->phy_info[0].identify.sas_address; - - /* - * Delete rphys in the parent that point - * to this expander. The transport layer will - * cleanup all the children. - */ - phy_info = parent->phy_info; - for (i = 0; i < parent->num_phys; i++, phy_info++) { - port = mptsas_get_port(phy_info); - if (!port) - continue; - if (phy_info->attached.sas_address != - expander_sas_address) - continue; -#ifdef MPT_DEBUG_SAS_WIDE - dev_printk(KERN_DEBUG, &port->dev, - "delete port (%d)\n", port->port_identifier); -#endif - sas_port_delete(port); - mptsas_port_delete(phy_info->port_details); - } - next_port: - - phy_info = port_info->phy_info; - for (i = 0; i < port_info->num_phys; i++, phy_info++) - mptsas_port_delete(phy_info->port_details); - - list_del(&port_info->list); - kfree(port_info->phy_info); - kfree(port_info); - } - /* - * Free this memory allocated from inside - * mptsas_sas_expander_pg0 - */ - kfree(buffer.phy_info); - } - mutex_unlock(&ioc->sas_topology_mutex); -} - -/* - * Start of day discovery - */ -static void -mptsas_scan_sas_topology(MPT_ADAPTER *ioc) -{ - u32 handle = 0xFFFF; - int i; - - mutex_lock(&ioc->sas_discovery_mutex); - mptsas_probe_hba_phys(ioc); - while (!mptsas_probe_expander_phys(ioc, &handle)) - ; - /* - Reporting RAID volumes. - */ - if (!ioc->ir_firmware) - goto out; - if (!ioc->raid_data.pIocPg2) - goto out; - if (!ioc->raid_data.pIocPg2->NumActiveVolumes) - goto out; - for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { - scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, - ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); - } - out: - mutex_unlock(&ioc->sas_discovery_mutex); -} - -/* - * Work queue thread to handle Runtime discovery - * Mere purpose is the hot add/delete of expanders - *(Mutex UNLOCKED) - */ -static void -__mptsas_discovery_work(MPT_ADAPTER *ioc) -{ - u32 handle = 0xFFFF; - - ioc->sas_discovery_runtime=1; - mptsas_delete_expander_phys(ioc); - mptsas_probe_hba_phys(ioc); - while (!mptsas_probe_expander_phys(ioc, &handle)) - ; - ioc->sas_discovery_runtime=0; -} - -/* - * Work queue thread to handle Runtime discovery - * Mere purpose is the hot add/delete of expanders - *(Mutex LOCKED) - */ -static void -mptsas_discovery_work(void * arg) -{ - struct mptsas_discovery_event *ev = arg; - MPT_ADAPTER *ioc = ev->ioc; - - mutex_lock(&ioc->sas_discovery_mutex); - __mptsas_discovery_work(ioc); - mutex_unlock(&ioc->sas_discovery_mutex); - kfree(ev); -} - + **/ static struct mptsas_phyinfo * mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) { @@ -2309,76 +3314,103 @@ mptsas_find_phyinfo_by_sas_address(MPT_A return phy_info; } +/** + * mptsas_find_phyinfo_by_phys_disk_num - + * @ioc: Pointer to MPT_ADAPTER structure + * @phys_disk_num: + * @channel: + * @id: + * + **/ static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id) +mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, + u8 channel, u8 id) { + struct mptsas_phyinfo *phy_info; struct mptsas_portinfo *port_info; - struct mptsas_phyinfo *phy_info = NULL; + RaidPhysDiskPage1_t *phys_disk = NULL; + int num_paths; + u64 sas_address = 0; int i; - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(port_info, &ioc->sas_topology, list) { - for (i = 0; i < port_info->num_phys; i++) { - if (!mptsas_is_end_device( - &port_info->phy_info[i].attached)) - continue; - if (port_info->phy_info[i].attached.id != id) - continue; - if (port_info->phy_info[i].attached.channel != channel) - continue; - phy_info = &port_info->phy_info[i]; - break; + phy_info = NULL; + if (!ioc->raid_data.pIocPg3) + return NULL; + /* dual port support */ + num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num); + if (!num_paths) + goto out; + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + goto out; + mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk); + for (i = 0; i < num_paths; i++) { + if ((phys_disk->Path[i].Flags & 1) != 0) + /* entry no longer valid */ + continue; + if ((id == phys_disk->Path[i].PhysDiskID) && + (channel == phys_disk->Path[i].PhysDiskBus)) { + memcpy(&sas_address, &phys_disk->Path[i].WWID, + sizeof(u64)); + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, sas_address); + goto out; } } - mutex_unlock(&ioc->sas_topology_mutex); - return phy_info; -} -static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id) -{ - struct mptsas_portinfo *port_info; - struct mptsas_phyinfo *phy_info = NULL; - int i; + out: + kfree(phys_disk); + if (phy_info) + return phy_info; + /* + * Extra code to handle RAID0 case, where the sas_address is not updated + * in phys_disk_page_1 when hotswapped + */ mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(port_info, &ioc->sas_topology, list) { - for (i = 0; i < port_info->num_phys; i++) { + for (i = 0; i < port_info->num_phys && !phy_info; i++) { if (!mptsas_is_end_device( &port_info->phy_info[i].attached)) continue; if (port_info->phy_info[i].attached.phys_disk_num == ~0) continue; - if (port_info->phy_info[i].attached.phys_disk_num != id) - continue; - if (port_info->phy_info[i].attached.channel != channel) - continue; - phy_info = &port_info->phy_info[i]; - break; + if (port_info->phy_info[i].attached.phys_disk_num == phys_disk_num && + port_info->phy_info[i].attached.id == id && + port_info->phy_info[i].attached.channel == channel) + phy_info = &port_info->phy_info[i]; } } mutex_unlock(&ioc->sas_topology_mutex); return phy_info; } -/* - * Work queue thread to clear the persitency table - */ -static void -mptsas_persist_clear_table(void * arg) -{ - MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; - - mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); -} - +/** + * mptsas_reprobe_lun - + * @sdev: + * @data: + * + **/ static void mptsas_reprobe_lun(struct scsi_device *sdev, void *data) { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) + int rc; +#endif sdev->no_uld_attach = data ? 1 : 0; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) + rc = scsi_device_reprobe(sdev); +#else scsi_device_reprobe(sdev); +#endif } +/** + * mptsas_reprobe_target - + * @starget: + * @uld_attach: + * + **/ static void mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) { @@ -2386,6 +3418,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) { @@ -2395,7 +3436,8 @@ mptsas_adding_inactive_raid_components(M pRaidVolumePage0_t buffer = NULL; RaidPhysDiskPage0_t phys_disk; int i; - struct mptsas_hotplug_event *ev; + struct mptsas_phyinfo *phy_info; + struct mptsas_devinfo sas_device; memset(&cfg, 0 , sizeof(CONFIGPARMS)); memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); @@ -2403,6 +3445,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; @@ -2435,20 +3478,16 @@ mptsas_adding_inactive_raid_components(M buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) continue; - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - printk(KERN_WARNING "mptsas: lost hotplug event\n"); - goto out; - } + if (mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (phys_disk.PhysDiskBus << 8) + + phys_disk.PhysDiskID)) + continue; - INIT_WORK(&ev->work, mptsas_hotplug_work, ev); - ev->ioc = ioc; - ev->id = phys_disk.PhysDiskID; - ev->channel = phys_disk.PhysDiskBus; - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = phys_disk.PhysDiskNum; - ev->event_type = MPTSAS_ADD_DEVICE; - schedule_work(&ev->work); + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_device.sas_address); + mptsas_add_end_device(ioc, phy_info); } out: @@ -2456,537 +3495,1754 @@ mptsas_adding_inactive_raid_components(M pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, dma_handle); } -/* - * Work queue thread to handle SAS hotplug events - */ -static void -mptsas_hotplug_work(void *arg) -{ - struct mptsas_hotplug_event *ev = arg; - MPT_ADAPTER *ioc = ev->ioc; - struct mptsas_phyinfo *phy_info; - struct sas_rphy *rphy; + +/** + * mptsas_add_end_device - report a new end device to sas transport layer + * @ioc: Pointer to MPT_ADAPTER structure + * @phy_info: decribes attached device + * + * return (0) success (1) failure + * + **/ +static int +mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) +{ + struct sas_rphy *rphy; +#if defined(MPT_WIDE_PORT_API) struct sas_port *port; - struct scsi_device *sdev; - struct scsi_target * starget; +#endif struct sas_identify identify; char *ds = NULL; + u8 fw_id; + + if (!phy_info){ + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + return 1; + } + + fw_id = phy_info->attached.id; + + if (mptsas_get_rphy(phy_info)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, fw_id, __LINE__)); + return 2; + } + +#if defined(MPT_WIDE_PORT_API) + port = mptsas_get_port(phy_info); + if (!port) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, fw_id, __LINE__)); + return 3; + } +#endif + + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET) + ds = "ssp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_STP_TARGET) + ds = "stp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE) + ds = "sata"; + + printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d," + " phy %d, sas_addr 0x%llx\n", ioc->name, ds, + phy_info->attached.channel, phy_info->attached.id, + phy_info->attached.phy_id, (unsigned long long) + phy_info->attached.sas_address); + + mptsas_parse_device_info(&identify, &phy_info->attached); +#if defined(MPT_WIDE_PORT_API) + rphy = sas_end_device_alloc(port); +#else + rphy = sas_end_device_alloc(phy_info->phy); +#endif + if (!rphy) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, fw_id, __LINE__)); + return 5; /* non-fatal: an rphy can be added later */ + } + + rphy->identify = identify; + if (sas_rphy_add(rphy)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, fw_id, __LINE__)); + sas_rphy_free(rphy); + return 6; + } + mptsas_set_rphy(ioc, phy_info, rphy); + return 0; +} + +/** + * mptsas_del_end_device - report a deleted end device to sas transport + * layer + * @ioc: Pointer to MPT_ADAPTER structure + * @phy_info: decribes attached device + * + **/ +static void +mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) +{ + struct sas_rphy *rphy; +#if defined(MPT_WIDE_PORT_API) + struct sas_port *port; + struct mptsas_portinfo *port_info; + struct mptsas_phyinfo *phy_info_parent; + int i; +#endif + struct scsi_target * starget; + char *ds = NULL; + u8 fw_id; + u64 sas_address; + + if (!phy_info) + return; + + fw_id = phy_info->attached.id; + sas_address = phy_info->attached.sas_address; + + if (!phy_info->port_details) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, fw_id, __LINE__)); + return; + } + rphy = mptsas_get_rphy(phy_info); + if (!rphy) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, fw_id, __LINE__)); + return; + } + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET) + ds = "ssp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_STP_TARGET) + ds = "stp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE) + ds = "sata"; + + starget = mptsas_get_starget(phy_info); + + printk(MYIOC_s_INFO_FMT "removing %s device: fw_channel %d," + " fw_id %d, phy %d, sas_addr 0x%llx\n", ioc->name, ds, + phy_info->attached.channel, phy_info->attached.id, + phy_info->attached.phy_id, (unsigned long long) + sas_address); + +#if defined(MPT_WIDE_PORT_API) + port = mptsas_get_port(phy_info); + if (!port) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, fw_id, __LINE__)); + return; + } + port_info = phy_info->portinfo; + phy_info_parent = port_info->phy_info; + for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) { + if(!phy_info_parent->phy) + continue; + if (phy_info_parent->attached.sas_address != + sas_address) + continue; + dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev, + MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", + ioc->name, phy_info_parent->phy_id, + phy_info_parent->phy); + sas_port_delete_phy(port, phy_info_parent->phy); + } + + dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT + "delete port %d, sas_addr (0x%llx)\n", ioc->name, + port->port_identifier, (unsigned long long)sas_address); + sas_port_delete(port); +#else + sas_rphy_delete(rphy); +#endif +// mptsas_port_delete(ioc, phy_info->port_details); +} + +struct mptsas_phyinfo * +mptsas_refreshing_device_handles(MPT_ADAPTER *ioc, struct mptsas_devinfo *sas_device) +{ + struct mptsas_phyinfo *phy_info; + struct mptsas_portinfo *port_info; + int i; + + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_device->sas_address); + if (!phy_info) + goto out; + port_info = phy_info->portinfo; + if (!port_info) + goto out; + mutex_lock(&ioc->sas_topology_mutex); + for (i = 0; i < port_info->num_phys; i++) { + if(port_info->phy_info[i].attached.sas_address != + sas_device->sas_address) + continue; + port_info->phy_info[i].attached.channel = sas_device->channel; + port_info->phy_info[i].attached.id = sas_device->id; + port_info->phy_info[i].attached.sas_address = + sas_device->sas_address; + port_info->phy_info[i].attached.handle = sas_device->handle; + port_info->phy_info[i].attached.handle_parent = + sas_device->handle_parent; + port_info->phy_info[i].attached.handle_enclosure = + sas_device->handle_enclosure; + } + mutex_unlock(&ioc->sas_topology_mutex); + out: + return phy_info; +} + + +/** + * mptsas_hotplug_work - Work queue thread to handle SAS hotplug events + * + * + **/ +static void +mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, + struct mptsas_hotplug_event *hot_plug_info) +{ + struct mptsas_phyinfo *phy_info; + struct scsi_target * starget; struct mptsas_devinfo sas_device; VirtTarget *vtarget; - VirtDevice *vdevice; + enum device_state state; + int i; - mutex_lock(&ioc->sas_discovery_mutex); - switch (ev->event_type) { - case MPTSAS_DEL_DEVICE: + switch (hot_plug_info->event_type) { - phy_info = NULL; - if (ev->phys_disk_num_valid) { - if (ev->hidden_raid_component){ - if (mptsas_sas_device_pg0(ioc, &sas_device, - (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (ev->channel << 8) + ev->id)) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - break; - } - phy_info = mptsas_find_phyinfo_by_sas_address( - ioc, sas_device.sas_address); - }else - phy_info = mptsas_find_phyinfo_by_phys_disk_num( - ioc, ev->channel, ev->phys_disk_num); + case MPTSAS_ADD_PHYSDISK: + + if (!ioc->raid_data.pIocPg2) + break; + + for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == + hot_plug_info->id) { + printk(MYIOC_s_WARN_FMT "firmware bug: unable " + "to add hidden disk - target_id matchs " + "volume_id\n", ioc->name); + mptsas_free_fw_event(ioc, fw_event); + return; + } } + case MPTSAS_ADD_DEVICE: + memset(&sas_device, 0, sizeof(struct mptsas_devinfo)); + mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (hot_plug_info->channel << 8) + + hot_plug_info->id); + + if (!sas_device.handle) + return; + + phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); if (!phy_info) - phy_info = mptsas_find_phyinfo_by_target(ioc, - ev->channel, ev->id); + break; - /* - * Sanity checks, for non-existing phys and remote rphys. - */ - if (!phy_info){ - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + if (mptsas_get_rphy(phy_info)) break; + + 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 (!phy_info->port_details) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - break; + + if (state == DEVICE_READY) + mptsas_add_end_device(ioc, phy_info); + break; + + case MPTSAS_DEL_DEVICE: + + 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); } - rphy = mptsas_get_rphy(phy_info); - if (!rphy) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + break; + + case MPTSAS_DEL_PHYSDISK: + + 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); + mptsas_del_end_device(ioc, phy_info); + break; + + case MPTSAS_ADD_PHYSDISK_REPROBE: + + if (mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (hot_plug_info->channel << 8) + hot_plug_info->id)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, hot_plug_info->id, __LINE__)); break; } - port = mptsas_get_port(phy_info); - if (!port) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + phy_info = mptsas_find_phyinfo_by_sas_address( + ioc, sas_device.sas_address); + + if (!phy_info){ + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, hot_plug_info->id, __LINE__)); break; } starget = mptsas_get_starget(phy_info); - if (starget) { - vtarget = starget->hostdata; - - if (!vtarget) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - break; - } + if (!starget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, hot_plug_info->id, __LINE__)); + break; + } - /* - * Handling RAID components - */ - if (ev->phys_disk_num_valid && - ev->hidden_raid_component) { - printk(MYIOC_s_INFO_FMT - "RAID Hidding: channel=%d, id=%d, " - "physdsk %d \n", ioc->name, ev->channel, - ev->id, ev->phys_disk_num); - vtarget->id = ev->phys_disk_num; - vtarget->tflags |= - MPT_TARGET_FLAGS_RAID_COMPONENT; - mptsas_reprobe_target(starget, 1); - phy_info->attached.phys_disk_num = - ev->phys_disk_num; + vtarget = starget->hostdata; + if (!vtarget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, hot_plug_info->id, __LINE__)); break; - } } - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SSP_TARGET) - ds = "ssp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_STP_TARGET) - ds = "stp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "sata"; - - printk(MYIOC_s_INFO_FMT - "removing %s device, channel %d, id %d, phy %d\n", - ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); -#ifdef MPT_DEBUG_SAS_WIDE - dev_printk(KERN_DEBUG, &port->dev, - "delete port (%d)\n", port->port_identifier); -#endif - sas_port_delete(port); - mptsas_port_delete(phy_info->port_details); + mpt_findImVolumes(ioc); + + starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: " + "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", + ioc->name, hot_plug_info->channel, hot_plug_info->id, + hot_plug_info->phys_disk_num, (unsigned long long) + sas_device.sas_address); + + vtarget->id = hot_plug_info->phys_disk_num; + vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; + phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num; + mptsas_reprobe_target(starget, 1); break; - case MPTSAS_ADD_DEVICE: - if (ev->phys_disk_num_valid) - mpt_findImVolumes(ioc); + case MPTSAS_DEL_PHYSDISK_REPROBE: - /* - * Refresh sas device pg0 data - */ if (mptsas_sas_device_pg0(ioc, &sas_device, (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (ev->channel << 8) + ev->id)) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + (hot_plug_info->channel << 8) + hot_plug_info->id)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", + ioc->name, __FUNCTION__, + hot_plug_info->id, __LINE__)); break; } - __mptsas_discovery_work(ioc); - phy_info = mptsas_find_phyinfo_by_sas_address(ioc, sas_device.sas_address); - - if (!phy_info || !phy_info->port_details) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + if (!phy_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, hot_plug_info->id, __LINE__)); break; } starget = mptsas_get_starget(phy_info); - if (starget && (!ev->hidden_raid_component)){ - - vtarget = starget->hostdata; - - if (!vtarget) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - break; - } - /* - * Handling RAID components - */ - if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - printk(MYIOC_s_INFO_FMT - "RAID Exposing: channel=%d, id=%d, " - "physdsk %d \n", ioc->name, ev->channel, - ev->id, ev->phys_disk_num); - vtarget->tflags &= - ~MPT_TARGET_FLAGS_RAID_COMPONENT; - vtarget->id = ev->id; - mptsas_reprobe_target(starget, 0); - phy_info->attached.phys_disk_num = ~0; - } + if (!starget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, hot_plug_info->id, __LINE__)); break; } - if (mptsas_get_rphy(phy_info)) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - if (ev->channel) printk("%d\n", __LINE__); + vtarget = starget->hostdata; + if (!vtarget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, hot_plug_info->id, __LINE__)); break; } - port = mptsas_get_port(phy_info); - if (!port) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __FUNCTION__, hot_plug_info->id, __LINE__)); break; } - memcpy(&phy_info->attached, &sas_device, - sizeof(struct mptsas_devinfo)); - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SSP_TARGET) - ds = "ssp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_STP_TARGET) - ds = "stp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "sata"; - - printk(MYIOC_s_INFO_FMT - "attaching %s device, channel %d, id %d, phy %d\n", - ioc->name, ds, ev->channel, ev->id, ev->phy_id); + mpt_findImVolumes(ioc); + + starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:" + " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", + ioc->name, hot_plug_info->channel, hot_plug_info->id, + hot_plug_info->phys_disk_num, (unsigned long long) + sas_device.sas_address); + + vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; + vtarget->id = hot_plug_info->id; + phy_info->attached.phys_disk_num = ~0; + mptsas_reprobe_target(starget, 0); + mptsas_add_device_component_by_fw(ioc, + hot_plug_info->channel, hot_plug_info->id); + break; + + case MPTSAS_ADD_RAID: + + mpt_findImVolumes(ioc); + printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, + hot_plug_info->id); + scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, + hot_plug_info->id, 0); + break; + + case MPTSAS_DEL_RAID: + + mpt_findImVolumes(ioc); + printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, + hot_plug_info->id); + scsi_remove_device(hot_plug_info->sdev); + scsi_device_put(hot_plug_info->sdev); + break; + + case MPTSAS_ADD_INACTIVE_VOLUME: + + mpt_findImVolumes(ioc); + mptsas_adding_inactive_raid_components(ioc, + hot_plug_info->channel, hot_plug_info->id); + break; + + default: + break; + } + + 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) +{ + MPT_ADAPTER *ioc; + struct mptsas_hotplug_event hot_plug_info; + EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; + u32 device_info; + u64 sas_address; + + ioc = fw_event->ioc; + sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) + fw_event->event_data; + device_info = le32_to_cpu(sas_event_data->DeviceInfo); + + if ((device_info & + (MPI_SAS_DEVICE_INFO_SSP_TARGET | + MPI_SAS_DEVICE_INFO_STP_TARGET | + MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) { + mptsas_free_fw_event(ioc, fw_event); + return; + } + + if (sas_event_data->ReasonCode == + MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) { + mptbase_sas_persist_operation(ioc, + MPI_SAS_OP_CLEAR_NOT_PRESENT); + mptsas_free_fw_event(ioc, fw_event); + return; + } + + switch (sas_event_data->ReasonCode) { + case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: + case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: + memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); + hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle); + hot_plug_info.channel = sas_event_data->Bus; + hot_plug_info.id = sas_event_data->TargetID; + hot_plug_info.phy_id = sas_event_data->PhyNum; + memcpy(&sas_address, &sas_event_data->SASAddress, + sizeof(u64)); + hot_plug_info.sas_address = le64_to_cpu(sas_address); + hot_plug_info.device_info = device_info; + if (sas_event_data->ReasonCode & + MPI_EVENT_SAS_DEV_STAT_RC_ADDED) + hot_plug_info.event_type = MPTSAS_ADD_DEVICE; + else + hot_plug_info.event_type = MPTSAS_DEL_DEVICE; + mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); + break; + + case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: + mptbase_sas_persist_operation(ioc, + MPI_SAS_OP_CLEAR_NOT_PRESENT); + mptsas_free_fw_event(ioc, fw_event); + break; + + case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: + /* TODO */ + case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: + /* TODO */ + default: + mptsas_free_fw_event(ioc, fw_event); + break; + } +} + + +/** + * mptsas_send_raid_event + * + * + * @ioc + * @raid_event_data + * + **/ +static void +mptsas_send_raid_event(struct fw_event_work *fw_event) +{ + MPT_ADAPTER *ioc; + EVENT_DATA_RAID *raid_event_data; + struct mptsas_hotplug_event hot_plug_info; + int status; + int state; + struct scsi_device *sdev = NULL; + VirtDevice *vdevice = NULL; + RaidPhysDiskPage0_t phys_disk; + + ioc = fw_event->ioc; + raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data; + status = le32_to_cpu(raid_event_data->SettingsStatus); + state = (status >> 8) & 0xff; + + memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); + hot_plug_info.id = raid_event_data->VolumeID; + hot_plug_info.channel = raid_event_data->VolumeBus; + hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum; + + if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED || + raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED || + raid_event_data->ReasonCode == + MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) { + sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, + hot_plug_info.id, 0); + hot_plug_info.sdev = sdev; + if (sdev) + vdevice = sdev->hostdata; + } + + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "Entering %s: " + "ReasonCode=%02x\n", ioc->name, __FUNCTION__, + raid_event_data->ReasonCode)); + + switch (raid_event_data->ReasonCode) { + case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: + hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE; + break; + case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: + hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE; + break; + case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: + switch (state) { + case MPI_PD_STATE_ONLINE: + case MPI_PD_STATE_NOT_COMPATIBLE: + mpt_raid_phys_disk_pg0(ioc, + raid_event_data->PhysDiskNum, &phys_disk); + hot_plug_info.id = phys_disk.PhysDiskID; + hot_plug_info.channel = phys_disk.PhysDiskBus; + hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; + break; + case MPI_PD_STATE_FAILED: + case MPI_PD_STATE_MISSING: + case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: + case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: + case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: + hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; + break; + default: + break; + } + break; + case MPI_EVENT_RAID_RC_VOLUME_DELETED: + if (!sdev) + break; + vdevice->vtarget->deleted = 1; /* block IO */ + hot_plug_info.event_type = MPTSAS_DEL_RAID; + break; + case MPI_EVENT_RAID_RC_VOLUME_CREATED: + if (sdev) { + scsi_device_put(sdev); + break; + } + hot_plug_info.event_type = MPTSAS_ADD_RAID; + break; + case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: + if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) { + if (!sdev) + break; + vdevice->vtarget->deleted = 1; /* block IO */ + hot_plug_info.event_type = MPTSAS_DEL_RAID; + break; + } + switch (state) { + case MPI_RAIDVOL0_STATUS_STATE_FAILED: + case MPI_RAIDVOL0_STATUS_STATE_MISSING: + if (!sdev) + break; + vdevice->vtarget->deleted = 1; /* block IO */ + hot_plug_info.event_type = MPTSAS_DEL_RAID; + break; + case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: + case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: + if (sdev) { + scsi_device_put(sdev); + break; + } + hot_plug_info.event_type = MPTSAS_ADD_RAID; + break; + default: + break; + } + break; + default: + break; + } + + if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT) + mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); + else + mptsas_free_fw_event(ioc, fw_event); +} + +/** + * mptsas_issue_tm - send mptsas internal tm request + * @ioc: Pointer to MPT_ADAPTER structure + * @type + * @channel + * @id + * @lun + * @task_context + * @timeout + * + * return: + * + **/ +static int +mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, int task_context, ulong timeout, + u8 *issue_reset) +{ + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + int retval; + unsigned long timeleft; + + *issue_reset = 0; + if ((mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc)) == NULL) { + retval = -1; /* return failure */ + dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no " + "msg frames!!\n", ioc->name)); + goto out; + } + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, " + "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, " + "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf, + type, timeout, channel, id, (unsigned long long)lun, + task_context)); + + pScsiTm = (SCSITaskMgmt_t *) mf; + memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + pScsiTm->TaskType = type; + pScsiTm->MsgFlags = 0; + pScsiTm->TargetID = id; + pScsiTm->Bus = channel; + pScsiTm->ChainOffset = 0; + pScsiTm->Reserved = 0; + pScsiTm->Reserved1 = 0; + pScsiTm->TaskMsgContext = task_context; + int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); + + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) + retval = 0; + mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); + + /* Now wait for the command to complete */ + timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, + timeout*HZ); + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + retval = -1; /* return failure */ + dtmprintk(ioc, printk(MYIOC_s_ERR_FMT + "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf)); + mpt_free_msg_frame(ioc, mf); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + *issue_reset = 1; + goto out; + } + + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + retval = -1; /* return failure */ + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt request: failed with no reply\n", ioc->name)); + goto out; + } + + out: + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + return retval; +} + +/** + * mptsas_broadcast_primative_work - Work queue thread to handle + * broadcast primitive events + * @work: work queue payload containing info describing the event + * + **/ +static void +mptsas_broadcast_primative_work(struct fw_event_work *fw_event) +{ + MPT_ADAPTER *ioc = fw_event->ioc; + MPT_FRAME_HDR *mf; + VirtDevice *vdevice; + int ii; + struct scsi_cmnd *sc; + SCSITaskMgmtReply_t * pScsiTmReply; + u8 issue_reset; + int task_context; + u8 channel, id; + int lun; + u32 termination_count; + u32 query_count; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s - enter\n", ioc->name, __FUNCTION__)); + + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + mptsas_requeue_fw_event(ioc, fw_event, 1000); + return; + } + + issue_reset = 0; + termination_count = 0; + query_count = 0; + mpt_findImVolumes(ioc); + pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; + + for (ii = 0; ii < ioc->req_depth; ii++) { + sc = mptscsih_get_scsi_lookup(ioc, ii); + if (!sc) + continue; + mf = MPT_INDEX_2_MFPTR(ioc, ii); + if (!mf) + continue; + task_context = mf->u.frame.hwhdr.msgctxu.MsgContext; + vdevice = sc->device->hostdata; + if (!vdevice || !vdevice->vtarget) + continue; + if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) + continue; /* skip hidden raid components */ + if (vdevice->vtarget->raidVolume) + continue; /* skip hidden raid components */ + channel = vdevice->vtarget->channel; + id = vdevice->vtarget->id; + lun = vdevice->lun; + if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK, + channel, id, (u64)lun, task_context, 30, &issue_reset)) + goto out; + query_count++; + termination_count += + le32_to_cpu(pScsiTmReply->TerminationCount); + if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) && + (pScsiTmReply->ResponseCode == + MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED || + pScsiTmReply->ResponseCode == + MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) + continue; + if (mptsas_issue_tm(ioc, + MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, + channel, id, (u64)lun, 0, 30, &issue_reset)) + goto out; + termination_count += + le32_to_cpu(pScsiTmReply->TerminationCount); + } + + out: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s - exit, query_count = %d termination_count = %d\n", + ioc->name, __FUNCTION__, query_count, termination_count)); + + ioc->broadcast_aen_busy = 0; + mpt_clear_taskmgmt_in_progress_flag(ioc); + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + + if (issue_reset) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", + ioc->name, __FUNCTION__); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP)) + mpt_HardResetHandler(ioc, CAN_SLEEP); + } + mptsas_free_fw_event(ioc, fw_event); +} + +/** + * 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) +{ + MPT_ADAPTER *ioc; + struct mptsas_hotplug_event hot_plug_info; + MPI_EVENT_DATA_IR2 * ir2_data; + u8 reasonCode; + RaidPhysDiskPage0_t phys_disk; + + ioc = fw_event->ioc; + ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data; + reasonCode = ir2_data->ReasonCode; + + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "Entering %s: " + "ReasonCode=%02x\n", ioc->name,__FUNCTION__, reasonCode)); + + memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); + hot_plug_info.id = ir2_data->TargetID; + hot_plug_info.channel = ir2_data->Bus; + switch (reasonCode) { + case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: + hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME; + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: + hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; + hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: + hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; + mpt_raid_phys_disk_pg0(ioc, + ir2_data->PhysDiskNum, &phys_disk); + hot_plug_info.id = phys_disk.PhysDiskID; + hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; + break; + default: + mptsas_free_fw_event(ioc, fw_event); + return; + } + mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); +} + +static void +mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) +{ + struct mptsas_portinfo *parent; + struct device *parent_dev; + struct sas_rphy *rphy; + int i; + u64 sas_address; /* expander sas address */ + u32 handle; + + handle = port_info->phy_info[0].handle; + sas_address = port_info->phy_info[0].identify.sas_address; + for (i = 0; i < port_info->num_phys; i++) { + mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], + (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle); + + mptsas_sas_device_pg0(ioc, + &port_info->phy_info[i].identify, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + port_info->phy_info[i].identify.handle); + port_info->phy_info[i].identify.phy_id = + port_info->phy_info[i].phy_id; + + if (port_info->phy_info[i].attached.handle) { + mptsas_sas_device_pg0(ioc, + &port_info->phy_info[i].attached, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + port_info->phy_info[i].attached.handle); + port_info->phy_info[i].attached.phy_id = + port_info->phy_info[i].phy_id; + } + } + + mutex_lock(&ioc->sas_topology_mutex); + parent = mptsas_find_portinfo_by_handle(ioc, + port_info->phy_info[0].identify.handle_parent); + if (!parent) { + mutex_unlock(&ioc->sas_topology_mutex); + return; + } + for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev; + i++) { + if (parent->phy_info[i].attached.sas_address == sas_address) { + rphy = mptsas_get_rphy(&parent->phy_info[i]); + parent_dev = &rphy->dev; + } + } + mutex_unlock(&ioc->sas_topology_mutex); + + mptsas_setup_wide_ports(ioc, port_info); + for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) + mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i], + ioc->sas_index, 0); +} + +static void +mptsas_expander_event_add(MPT_ADAPTER *ioc, + MpiEventDataSasExpanderStatusChange_t* expander_data) +{ + struct mptsas_portinfo *port_info; + int i; + __le64 sas_address; + + port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); + if (!port_info) + BUG(); + port_info->num_phys = (expander_data->NumPhys) ? + expander_data->NumPhys : 1; + port_info->phy_info = kcalloc(port_info->num_phys, + sizeof(struct mptsas_phyinfo),GFP_KERNEL); + if (!port_info->phy_info) + BUG(); + memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); + for (i = 0; i < port_info->num_phys; i++) { + port_info->phy_info[i].portinfo = port_info; + port_info->phy_info[i].handle = + le16_to_cpu(expander_data->DevHandle); + port_info->phy_info[i].identify.sas_address = + le64_to_cpu(sas_address); + port_info->phy_info[i].identify.handle_parent = + le16_to_cpu(expander_data->ParentDevHandle); + } + + mutex_lock(&ioc->sas_topology_mutex); + list_add_tail(&port_info->list, &ioc->sas_topology); + mutex_unlock(&ioc->sas_topology_mutex); + + printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)sas_address); + + mptsas_expander_refresh(ioc, port_info); +} + +/** + * mptsas_delete_expander_siblings - remove siblings attached to expander + * @ioc: Pointer to MPT_ADAPTER structure + * @parent: the parent port_info object + * @expander: the expander port_info object + **/ +static void +mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo + *parent, struct mptsas_portinfo *expander) +{ + struct mptsas_phyinfo *phy_info; + struct mptsas_portinfo *port_info; + struct sas_rphy *rphy; + int i; + + phy_info = expander->phy_info; + for (i = 0; i < expander->num_phys; i++, phy_info++) { + if (!(rphy = mptsas_get_rphy(phy_info))) + continue; + if (rphy->identify.device_type == SAS_END_DEVICE) + mptsas_del_end_device(ioc, phy_info); + } + + phy_info = expander->phy_info; + for (i = 0; i < expander->num_phys; i++, phy_info++) { + if (!(rphy = mptsas_get_rphy(phy_info))) + continue; + if (rphy->identify.device_type == + MPI_SAS_DEVICE_INFO_EDGE_EXPANDER || + rphy->identify.device_type == + MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) { + port_info = mptsas_find_portinfo_by_sas_address(ioc, + rphy->identify.sas_address); + if (!port_info) + continue; + if (port_info == parent) /* backlink rphy */ + continue; + mptsas_expander_delete(ioc, port_info); + } + } +} + + +/** + * mptsas_expander_delete - remove this expander + * @ioc: Pointer to MPT_ADAPTER structure + * @port_info: expander port_info struct + * + **/ + +static void +mptsas_expander_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) +{ + + struct mptsas_portinfo *parent; + int i; + u64 expander_sas_address; + struct mptsas_phyinfo *phy_info; + struct mptsas_portinfo buffer; + struct mptsas_portinfo_details * port_details; +#if defined(MPT_WIDE_PORT_API) + struct sas_port * port; +#else + struct sas_rphy * rphy; +#endif + + if (!port_info) + return; + + /* see if expander is still there before deleting */ + mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), + port_info->phy_info[0].identify.handle); + + if (buffer.num_phys) { + kfree(buffer.phy_info); + return; + } + + + /* + * Obtain the port_info instance to the parent port + */ + port_details = NULL; + expander_sas_address = + port_info->phy_info[0].identify.sas_address; + parent = mptsas_find_portinfo_by_handle(ioc, + port_info->phy_info[0].identify.handle_parent); + mptsas_delete_expander_siblings(ioc, parent, port_info); + if (!parent) + goto out; + + /* + * Delete rphys in the parent that point + * to this expander. + */ +#if defined(MPT_WIDE_PORT_API) + phy_info = parent->phy_info; + port = NULL; + for (i = 0; i < parent->num_phys; i++, phy_info++) { + if(!phy_info->phy) + continue; + if (phy_info->attached.sas_address != + expander_sas_address) + continue; + if (!port) { + port = mptsas_get_port(phy_info); + port_details = phy_info->port_details; + } + dev_printk(KERN_DEBUG, &phy_info->phy->dev, + MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, + phy_info->phy_id, phy_info->phy); + sas_port_delete_phy(port, phy_info->phy); + } + if (port) { + dev_printk(KERN_DEBUG, &port->dev, + MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n", + ioc->name, port->port_identifier, + (unsigned long long)expander_sas_address); + sas_port_delete(port); + mptsas_port_delete(ioc, port_details); + } +#else + phy_info = parent->phy_info; + for (i = 0; i < parent->num_phys; i++, phy_info++) { + rphy = mptsas_get_rphy(phy_info); + if (!rphy) + continue; + if (phy_info->attached.sas_address != + expander_sas_address) + continue; + dev_printk(KERN_DEBUG, &rphy->dev, + MYIOC_s_FMT "delete: sas_addr (0x%llx)\n", + ioc->name, (unsigned long long) expander_sas_address); + sas_rphy_delete(rphy); + mptsas_port_delete(ioc, port_details); + } +#endif + out: + + printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)expander_sas_address); + + /* + * free link + */ + list_del(&port_info->list); + kfree(port_info->phy_info); + kfree(port_info); +} + + +/** + * mptsas_send_expander_event - expanders events + * @ioc: Pointer to MPT_ADAPTER structure + * @expander_data: event data + * + * + * This function handles adding, removing, and refreshing + * device handles within the expander objects. + */ +static void +mptsas_send_expander_event(struct fw_event_work *fw_event) +{ + MPT_ADAPTER *ioc; + MpiEventDataSasExpanderStatusChange_t* expander_data; + struct mptsas_portinfo *port_info; + __le64 sas_address; + int i; + + ioc = fw_event->ioc; + expander_data = (MpiEventDataSasExpanderStatusChange_t *) + fw_event->event_data; + memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); + port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); + + if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { + if (port_info) { + for (i = 0; i < port_info->num_phys; i++) { + port_info->phy_info[i].portinfo = port_info; + port_info->phy_info[i].handle = + le16_to_cpu(expander_data->DevHandle); + port_info->phy_info[i].identify.sas_address = + le64_to_cpu(sas_address); + port_info->phy_info[i].identify.handle_parent = + le16_to_cpu(expander_data->ParentDevHandle); + } + mptsas_expander_refresh(ioc, port_info); + } else if (!port_info && expander_data->NumPhys) + mptsas_expander_event_add(ioc, expander_data); + } else if (expander_data->ReasonCode == + MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) + mptsas_expander_delete(ioc, port_info); + + mptsas_free_fw_event(ioc, fw_event); +} + + +/** + * mptsas_expander_add - + * @ioc: Pointer to MPT_ADAPTER structure + * @handle: + * + */ +struct mptsas_portinfo * +mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle) +{ + struct mptsas_portinfo buffer, *port_info; + int i; + + if ((mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle))) + return NULL; + + port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC); + if (!port_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + return NULL; + } + port_info->num_phys = buffer.num_phys; + port_info->phy_info = buffer.phy_info; + for (i = 0; i < port_info->num_phys; i++) + port_info->phy_info[i].portinfo = port_info; + mutex_lock(&ioc->sas_topology_mutex); + list_add_tail(&port_info->list, &ioc->sas_topology); + mutex_unlock(&ioc->sas_topology_mutex); + printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)buffer.phy_info[0].identify.sas_address); + mptsas_expander_refresh(ioc, port_info); + return port_info; +} + +static void +mptsas_send_link_status_event(struct fw_event_work *fw_event) +{ + MPT_ADAPTER *ioc; + MpiEventDataSasPhyLinkStatus_t *link_data; + struct mptsas_portinfo *port_info; + struct mptsas_phyinfo *phy_info = NULL; + __le64 sas_address; + u8 phy_num; + u8 link_rate; + + ioc = fw_event->ioc; + link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data; + + memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); + link_rate = link_data->LinkRates >> 4; + phy_num = link_data->PhyNum; + + port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); + if (port_info) { + phy_info = &port_info->phy_info[phy_num]; + if (phy_info) + phy_info->negotiated_link_rate = link_rate; + } + + if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 || + link_rate == MPI_SAS_IOUNIT0_RATE_3_0) { + + if (!port_info) { + if (ioc->old_sas_discovery_protocal) { + port_info = mptsas_expander_add(ioc, + le16_to_cpu(link_data->DevHandle)); + if (port_info) + goto out; + } + goto out; + } + if (port_info == ioc->hba_port_info) + mptsas_probe_hba_phys(ioc); + else + mptsas_expander_refresh(ioc, port_info); + } else if (phy_info && phy_info->phy) { + if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED) + phy_info->phy->negotiated_linkrate = + SAS_PHY_DISABLED; + else if (link_rate == + MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION) + phy_info->phy->negotiated_linkrate = + SAS_LINK_RATE_FAILED; + else + phy_info->phy->negotiated_linkrate = + SAS_LINK_RATE_UNKNOWN; + } + out: + mptsas_free_fw_event(ioc, fw_event); +} + + +static void +mptsas_handle_queue_full_event(struct fw_event_work *fw_event) +{ + MPT_ADAPTER *ioc; + EventDataQueueFull_t *qfull_data; + struct sas_device_info *sas_info; + struct scsi_device *sdev; + int depth; + int id = -1; + int channel = -1; + int fw_id, fw_channel; + u16 current_depth; + + + ioc = fw_event->ioc; + qfull_data = (EventDataQueueFull_t *)fw_event->event_data; + fw_id = qfull_data->TargetID; + fw_channel = qfull_data->Bus; + current_depth = le16_to_cpu(qfull_data->CurrentDepth); + + /* if hidden raid component, look for the volume id */ + down(&ioc->sas_device_info_mutex); + if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) { + list_for_each_entry(sas_info, &ioc->sas_device_info_list, + list) { + if (sas_info->is_cached || + sas_info->is_logical_volume) + continue; + if (sas_info->is_hidden_raid_component && + (sas_info->fw.channel == fw_channel && + sas_info->fw.id == fw_id)) { + id = sas_info->volume_id; + channel = MPTSAS_RAID_CHANNEL; + goto out; + } + } + } else { + list_for_each_entry(sas_info, &ioc->sas_device_info_list, + list) { + if (sas_info->is_cached || + sas_info->is_hidden_raid_component || + sas_info->is_logical_volume) + continue; + if (sas_info->fw.channel == fw_channel && + sas_info->fw.id == fw_id) { + id = sas_info->os.id; + channel = sas_info->os.channel; + goto out; + } + } + + } + + out: + up(&ioc->sas_device_info_mutex); + + if (id != -1) { + shost_for_each_device(sdev, ioc->sh) { + if (sdev->id == id && sdev->channel == channel) { + if (current_depth > sdev->queue_depth) { + sdev_printk(KERN_INFO, sdev, + "strange observation, the queue " + "depth is (%d) meanwhile fw queue " + "depth (%d)\n", sdev->queue_depth, + current_depth); + continue; + } + depth = scsi_track_queue_full(sdev, + current_depth - 1); + if (depth > 0) + sdev_printk(KERN_INFO, sdev, + "Queue depth reduced to (%d)\n", + depth); + else if (depth < 0) + sdev_printk(KERN_INFO, sdev, + "Tagged Command Queueing is being " + "disabled\n"); + else if (depth == 0) + sdev_printk(KERN_INFO, sdev, + "Queue depth not changed yet\n"); + } + } + } + + mptsas_free_fw_event(ioc, fw_event); +} + +/** + * mptsas_firmware_event_work - work thread for processing fw events + * @work: work queue payload containing info describing the event + * Context: user + * + */ +static void +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) +mptsas_firmware_event_work(struct work_struct *work) +{ + struct mptsas_hotplug_event *ev = + container_of(work, struct fw_event_work, fw_event.work); +#else +mptsas_firmware_event_work(void *arg) +{ + struct fw_event_work *fw_event = (struct fw_event_work *)arg; +#endif + MPT_ADAPTER *ioc = fw_event->ioc; + + /* special rescan topology handling */ + if (fw_event->event == -1) { + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: rescan after " + "reset\n", ioc->name,__FUNCTION__)); + mptsas_not_responding_devices(ioc); + mptsas_scan_sas_topology(ioc); + mptsas_free_fw_event(ioc, fw_event); + return; + } + + /* events handling turned off during host reset */ + if (ioc->fw_events_off) { + mptsas_free_fw_event(ioc, fw_event); + return; + } - mptsas_parse_device_info(&identify, &phy_info->attached); - rphy = sas_end_device_alloc(port); - if (!rphy) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - break; /* non-fatal: an rphy can be added later */ - } + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: fw_event=(0x%p), " + "event = (0x%02x)\n", ioc->name,__FUNCTION__, fw_event, + (fw_event->event & 0xFF))); - rphy->identify = identify; - if (sas_rphy_add(rphy)) { - dfailprintk((MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - sas_rphy_free(rphy); - break; - } - mptsas_set_rphy(phy_info, rphy); + switch (fw_event->event) { + case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: + mptsas_send_sas_event(fw_event); break; - case MPTSAS_ADD_RAID: - sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, - ev->id, 0); - if (sdev) { - scsi_device_put(sdev); - break; - } - printk(MYIOC_s_INFO_FMT - "attaching raid volume, channel %d, id %d\n", - ioc->name, MPTSAS_RAID_CHANNEL, ev->id); - scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0); - mpt_findImVolumes(ioc); + case MPI_EVENT_INTEGRATED_RAID: + mptsas_send_raid_event(fw_event); break; - case MPTSAS_DEL_RAID: - sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, - ev->id, 0); - if (!sdev) - break; - printk(MYIOC_s_INFO_FMT - "removing raid volume, channel %d, id %d\n", - ioc->name, MPTSAS_RAID_CHANNEL, ev->id); - vdevice = sdev->hostdata; - scsi_remove_device(sdev); - scsi_device_put(sdev); - mpt_findImVolumes(ioc); + case MPI_EVENT_IR2: + mptsas_send_ir2_event(fw_event); break; - case MPTSAS_ADD_INACTIVE_VOLUME: - mptsas_adding_inactive_raid_components(ioc, - ev->channel, ev->id); + case MPI_EVENT_PERSISTENT_TABLE_FULL: + mptbase_sas_persist_operation(ioc, + MPI_SAS_OP_CLEAR_NOT_PRESENT); + mptsas_free_fw_event(ioc, fw_event); break; - case MPTSAS_IGNORE_EVENT: - default: + case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: + mptsas_broadcast_primative_work(fw_event); + break; + case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: + mptsas_send_expander_event(fw_event); + break; + case MPI_EVENT_SAS_PHY_LINK_STATUS: + mptsas_send_link_status_event(fw_event); + break; + case MPI_EVENT_QUEUE_FULL: + mptsas_handle_queue_full_event(fw_event); break; } - - mutex_unlock(&ioc->sas_discovery_mutex); - kfree(ev); } -static void -mptsas_send_sas_event(MPT_ADAPTER *ioc, - EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) -{ - struct mptsas_hotplug_event *ev; - u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo); - __le64 sas_address; - if ((device_info & - (MPI_SAS_DEVICE_INFO_SSP_TARGET | - MPI_SAS_DEVICE_INFO_STP_TARGET | - MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) - return; +/** + * mptsas_event_process - + * @ioc: Pointer to MPT_ADAPTER structure + * @reply: + * + **/ +static int +mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) +{ + u32 event = le32_to_cpu(reply->Event); + int sz, event_data_sz; + struct fw_event_work *fw_event; + unsigned long delay; - switch (sas_event_data->ReasonCode) { - case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: + /* events turned off due to host reset or driver unloading */ + if (ioc->fw_events_off) + return 0; - mptsas_target_reset_queue(ioc, sas_event_data); + delay = msecs_to_jiffies(1); + switch (event) { + case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: + { + EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data = + (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data; + if (broadcast_event_data->Primitive != + MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) + return 0; + if (ioc->broadcast_aen_busy) + return 0; + ioc->broadcast_aen_busy = 1; break; + } + case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: + { + EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = + (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data; - case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - printk(KERN_WARNING "mptsas: lost hotplug event\n"); - break; + if (sas_event_data->ReasonCode == + MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) { + mptsas_target_reset_queue(ioc, sas_event_data); + return 0; } + break; + } + case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: + { + MpiEventDataSasExpanderStatusChange_t *expander_data = + (MpiEventDataSasExpanderStatusChange_t *)reply->Data; - INIT_WORK(&ev->work, mptsas_hotplug_work, ev); - ev->ioc = ioc; - ev->handle = le16_to_cpu(sas_event_data->DevHandle); - ev->parent_handle = - le16_to_cpu(sas_event_data->ParentDevHandle); - ev->channel = sas_event_data->Bus; - ev->id = sas_event_data->TargetID; - ev->phy_id = sas_event_data->PhyNum; - memcpy(&sas_address, &sas_event_data->SASAddress, - sizeof(__le64)); - ev->sas_address = le64_to_cpu(sas_address); - ev->device_info = device_info; + if (ioc->old_sas_discovery_protocal) + return 0; - if (sas_event_data->ReasonCode & - MPI_EVENT_SAS_DEV_STAT_RC_ADDED) - ev->event_type = MPTSAS_ADD_DEVICE; - else - ev->event_type = MPTSAS_DEL_DEVICE; - schedule_work(&ev->work); + if (expander_data->ReasonCode == + MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING && + ioc->device_missing_delay) + delay = HZ * ioc->device_missing_delay; break; - case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: - /* - * Persistent table is full. - */ - INIT_WORK(&ioc->sas_persist_task, - mptsas_persist_clear_table, (void *)ioc); - schedule_work(&ioc->sas_persist_task); + } + case MPI_EVENT_SAS_DISCOVERY: + { + u32 discovery_status; + EventDataSasDiscovery_t *discovery_data = + (EventDataSasDiscovery_t *)reply->Data; + + discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus); + ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0; + if (ioc->old_sas_discovery_protocal && !discovery_status) + mptsas_queue_rescan(ioc); + return 0; + } + case MPI_EVENT_INTEGRATED_RAID: + case MPI_EVENT_PERSISTENT_TABLE_FULL: + case MPI_EVENT_IR2: + case MPI_EVENT_SAS_PHY_LINK_STATUS: + case MPI_EVENT_QUEUE_FULL: break; - /* - * TODO, handle other events - */ - case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: - case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: - case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: - case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: - case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: - case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: - case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: default: - break; + return 0; + } + + event_data_sz = ((reply->MsgLength * 4) - + offsetof(EventNotificationReply_t, Data)); + sz = offsetof(struct fw_event_work, event_data) + event_data_sz; + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name, + __FUNCTION__, __LINE__); + return 0; } + memcpy(fw_event->event_data, reply->Data, event_data_sz); + fw_event->event = event; + fw_event->ioc = ioc; + mptsas_add_fw_event(ioc, fw_event, delay); + return 0; } -static void -mptsas_send_raid_event(MPT_ADAPTER *ioc, - EVENT_DATA_RAID *raid_event_data) + + +/* Delete a volume when no longer listed in ioc pg2 + */ +static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id) { - struct mptsas_hotplug_event *ev; - int status = le32_to_cpu(raid_event_data->SettingsStatus); - int state = (status >> 8) & 0xff; + struct scsi_device *sdev; + int i; - if (ioc->bus_type != SAS) + sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0); + if (!sdev) return; + if (!ioc->raid_data.pIocPg2) + goto out; + if (!ioc->raid_data.pIocPg2->NumActiveVolumes) + goto out; + for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) + if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) + goto release_sdev; + out: + printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,id); + scsi_remove_device(sdev); + release_sdev: + scsi_device_put(sdev); +} + +static void +mptsas_not_responding_devices(MPT_ADAPTER *ioc) +{ + struct mptsas_portinfo buffer, *port_info; + struct sas_device_info *sas_info; + struct mptsas_devinfo sas_device; + u32 handle; + VirtTarget *vtarget = NULL; + struct mptsas_phyinfo *phy_info; + u8 found_expander; - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - printk(KERN_WARNING "mptsas: lost hotplug event\n"); + if (ioc->disable_hotplug_remove) return; + + mpt_findImVolumes(ioc); + + /* devices, logical volumes */ + redo_device_scan: + list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) { + if (sas_info->is_cached) + continue; + if (!sas_info->is_logical_volume) { + sas_device.handle = 0; + mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (sas_info->fw.channel << 8) + + sas_info->fw.id); + if (sas_device.handle) + continue; + /* delete device */ + if ((vtarget = mptsas_find_vtarget(ioc, + sas_info->fw.channel, + sas_info->fw.id))) + vtarget->deleted = 1; + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_info->sas_address); + if (phy_info) { + mptsas_del_end_device(ioc, phy_info); + goto redo_device_scan; + } + } else + mptsas_volume_delete(ioc, sas_info->fw.id); } - INIT_WORK(&ev->work, mptsas_hotplug_work, ev); - ev->ioc = ioc; - ev->id = raid_event_data->VolumeID; - ev->channel = raid_event_data->VolumeBus; - ev->event_type = MPTSAS_IGNORE_EVENT; + /* expanders */ + redo_expander_scan: + list_for_each_entry(port_info, &ioc->sas_topology, list) { - switch (raid_event_data->ReasonCode) { - case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->event_type = MPTSAS_ADD_DEVICE; - break; - case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->hidden_raid_component = 1; - ev->event_type = MPTSAS_DEL_DEVICE; - break; - case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: - switch (state) { - case MPI_PD_STATE_ONLINE: - case MPI_PD_STATE_NOT_COMPATIBLE: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->hidden_raid_component = 1; - ev->event_type = MPTSAS_ADD_DEVICE; - break; - case MPI_PD_STATE_MISSING: - case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: - case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: - case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->event_type = MPTSAS_DEL_DEVICE; - break; - default: - break; + if (port_info->phy_info && + (!(port_info->phy_info[0].identify.device_info & + MPI_SAS_DEVICE_INFO_SMP_TARGET))) + continue; + found_expander = 0; + handle = 0xFFFF; + while (!mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) && + !found_expander) { + + handle = buffer.phy_info[0].handle; + if (buffer.phy_info[0].identify.sas_address == + port_info->phy_info[0].identify.sas_address) { + found_expander = 1; + } + kfree(buffer.phy_info); } - break; - case MPI_EVENT_RAID_RC_VOLUME_DELETED: - ev->event_type = MPTSAS_DEL_RAID; - break; - case MPI_EVENT_RAID_RC_VOLUME_CREATED: - ev->event_type = MPTSAS_ADD_RAID; - break; - case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: - switch (state) { - case MPI_RAIDVOL0_STATUS_STATE_FAILED: - case MPI_RAIDVOL0_STATUS_STATE_MISSING: - ev->event_type = MPTSAS_DEL_RAID; - break; - case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: - case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: - ev->event_type = MPTSAS_ADD_RAID; - break; - default: - break; + + if (!found_expander) { + mptsas_expander_delete(ioc, port_info); + goto redo_expander_scan; } - break; - default: - break; } - schedule_work(&ev->work); } +/** + * mptsas_probe_expanders - adding expanders + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ static void -mptsas_send_discovery_event(MPT_ADAPTER *ioc, - EVENT_DATA_SAS_DISCOVERY *discovery_data) +mptsas_probe_expanders(MPT_ADAPTER *ioc) { - struct mptsas_discovery_event *ev; + struct mptsas_portinfo buffer, *port_info; + u32 handle; + int i; - /* - * DiscoveryStatus - * - * This flag will be non-zero when firmware - * kicks off discovery, and return to zero - * once its completed. - */ - if (discovery_data->DiscoveryStatus) - return; + handle = 0xFFFF; + while (!mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) { - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) - return; - INIT_WORK(&ev->work, mptsas_discovery_work, ev); - ev->ioc = ioc; - schedule_work(&ev->work); -}; + handle = buffer.phy_info[0].handle; + port_info = mptsas_find_portinfo_by_sas_address(ioc, + buffer.phy_info[0].identify.sas_address); + + if (port_info) { + /* refreshing handles */ + for (i = 0; i < buffer.num_phys; i++) { + port_info->phy_info[i].handle = handle; + port_info->phy_info[i].identify.handle_parent = + buffer.phy_info[0].identify.handle_parent; + } + mptsas_expander_refresh(ioc, port_info); + kfree(buffer.phy_info); + continue; + } + + port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); + if (!port_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + return; + } + port_info->num_phys = buffer.num_phys; + port_info->phy_info = buffer.phy_info; + for (i = 0; i < port_info->num_phys; i++) + port_info->phy_info[i].portinfo = port_info; + mutex_lock(&ioc->sas_topology_mutex); + list_add_tail(&port_info->list, &ioc->sas_topology); + mutex_unlock(&ioc->sas_topology_mutex); + printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)buffer.phy_info[0].identify.sas_address); + mptsas_expander_refresh(ioc, port_info); + } +} -/* - * mptsas_send_ir2_event - handle exposing hidden disk when - * an inactive raid volume is added - * - * @ioc: Pointer to MPT_ADAPTER structure - * @ir2_data - * - */ static void -mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data) +mptsas_probe_devices(MPT_ADAPTER *ioc) { - struct mptsas_hotplug_event *ev; + u16 retry_count; + u16 handle; + struct mptsas_devinfo sas_device; + struct mptsas_phyinfo *phy_info; + enum device_state state; - if (ir2_data->ReasonCode != - MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED) - return; + handle = 0xFFFF; + while (!(mptsas_sas_device_pg0(ioc, &sas_device, + MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + + handle = sas_device.handle; + + if ((sas_device.device_info & + (MPI_SAS_DEVICE_INFO_SSP_TARGET | + MPI_SAS_DEVICE_INFO_STP_TARGET | + MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) + continue; - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) - return; + phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); + if (!phy_info) + continue; - INIT_WORK(&ev->work, mptsas_hotplug_work, ev); - ev->ioc = ioc; - ev->id = ir2_data->TargetID; - ev->channel = ir2_data->Bus; - ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME; + if (mptsas_get_rphy(phy_info)) + continue; - schedule_work(&ev->work); -}; + state = DEVICE_RETRY; + retry_count = 0; + while(state == DEVICE_RETRY) { + state = mptsas_test_unit_ready(ioc, sas_device.channel, + sas_device.id, retry_count++); + ssleep(1); + } + if (state == DEVICE_READY) + mptsas_add_end_device(ioc, phy_info); + } +} -static int -mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) +/** + * mptsas_scan_sas_topology - + * @ioc: Pointer to MPT_ADAPTER structure + * @sas_address: + * + **/ +static void +mptsas_scan_sas_topology(MPT_ADAPTER *ioc) { - int rc=1; - u8 event = le32_to_cpu(reply->Event) & 0xFF; + struct scsi_device *sdev; + int i; - if (!ioc->sh) - goto out; + mptsas_probe_hba_phys(ioc); + mptsas_probe_expanders(ioc); + mptsas_probe_devices(ioc); /* - * sas_discovery_ignore_events - * - * This flag is to prevent anymore processing of - * sas events once mptsas_remove function is called. - */ - if (ioc->sas_discovery_ignore_events) { - rc = mptscsih_event_process(ioc, reply); - goto out; - } - - switch (event) { - case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: - mptsas_send_sas_event(ioc, - (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); - break; - case MPI_EVENT_INTEGRATED_RAID: - mptsas_send_raid_event(ioc, - (EVENT_DATA_RAID *)reply->Data); - break; - case MPI_EVENT_PERSISTENT_TABLE_FULL: - INIT_WORK(&ioc->sas_persist_task, - mptsas_persist_clear_table, (void *)ioc); - schedule_work(&ioc->sas_persist_task); - break; - case MPI_EVENT_SAS_DISCOVERY: - mptsas_send_discovery_event(ioc, - (EVENT_DATA_SAS_DISCOVERY *)reply->Data); - break; - case MPI_EVENT_IR2: - mptsas_send_ir2_event(ioc, - (PTR_MPI_EVENT_DATA_IR2)reply->Data); - break; - default: - rc = mptscsih_event_process(ioc, reply); - break; + Reporting RAID volumes. + */ + if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 || + !ioc->raid_data.pIocPg2->NumActiveVolumes) + return; + for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + if ((sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0))) { + scsi_device_put(sdev); + continue; + } + printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID); + scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); } - out: - - return rc; } +/** + * mptsas_probe - + * @pdev: + * @id: + * + **/ static int mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -3006,6 +5262,7 @@ mptsas_probe(struct pci_dev *pdev, const return r; ioc = pci_get_drvdata(pdev); + mptsas_fw_event_off(ioc); ioc->DoneCtx = mptsasDoneCtx; ioc->TaskCtx = mptsasTaskCtx; ioc->InternalCtx = mptsasInternalCtx; @@ -3050,7 +5307,7 @@ mptsas_probe(struct pci_dev *pdev, const ioc->name); error = -1; goto out_mptsas_probe; - } + } spin_lock_irqsave(&ioc->FreeQlock, flags); @@ -3064,24 +5321,21 @@ mptsas_probe(struct pci_dev *pdev, const /* set 16 byte cdb's */ sh->max_cmd_len = 16; - + sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue); sh->max_id = ioc->pfacts[0].PortSCSIID; sh->max_lun = max_lun; - sh->transportt = mptsas_transport_template; - sh->this_id = ioc->pfacts[0].PortSCSIID; - /* Required entry. */ sh->unique_id = ioc->id; 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) @@ -3091,70 +5345,54 @@ mptsas_probe(struct pci_dev *pdev, const * A slightly different algorithm is required for * 64bit SGEs. */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) { + + scale = ioc->req_sz/ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 64) / ioc->SGE_size; } if (numSGE < sh->sg_tablesize) { /* Reset this value */ - dprintk((MYIOC_s_INFO_FMT + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Resetting sg_tablesize to %d from %d\n", ioc->name, numSGE, sh->sg_tablesize)); sh->sg_tablesize = numSGE; } - hd = (MPT_SCSI_HOST *) sh->hostdata; + hd = shost_private(sh); hd->ioc = ioc; /* SCSI needs scsi_cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ - hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); - if (!hd->ScsiLookup) { + ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); + if (!ioc->ScsiLookup) { error = -ENOMEM; + spin_unlock_irqrestore(&ioc->FreeQlock, flags); goto out_mptsas_probe; } + spin_lock_init(&ioc->scsi_lookup_lock); - dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", - ioc->name, hd->ScsiLookup)); - - /* Clear the TM flags - */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; - hd->abortSCpnt = NULL; - - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; - - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; + 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; - - init_waitqueue_head(&hd->scandv_waitq); - hd->scandv_wait_done = 0; hd->last_queue_full = 0; + ioc->disable_hotplug_remove = mpt_disable_hotplug_remove; + if (ioc->disable_hotplug_remove) + printk(MYIOC_s_INFO_FMT "disabling hotplug remove\n", ioc->name); + INIT_LIST_HEAD(&hd->target_reset_list); + INIT_LIST_HEAD(&ioc->sas_device_info_list); + init_MUTEX(&ioc->sas_device_info_mutex); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); if (ioc->sas_data.ptClear==1) { @@ -3164,13 +5402,16 @@ mptsas_probe(struct pci_dev *pdev, const error = scsi_add_host(sh, &ioc->pcidev->dev); if (error) { - dprintk((KERN_ERR MYNAM - "scsi_add_host failed\n")); + dprintk(ioc, printk(MYIOC_s_ERR_FMT + "scsi_add_host failed\n", ioc->name)); goto out_mptsas_probe; } + /* older firmware doesn't support expander events */ + if ((ioc->facts.HeaderVersion >> 8) < 0xE) + ioc->old_sas_discovery_protocal = 1; mptsas_scan_sas_topology(ioc); - + mptsas_fw_event_on(ioc); return 0; out_mptsas_probe: @@ -3179,25 +5420,36 @@ mptsas_probe(struct pci_dev *pdev, const return error; } -static void __devexit mptsas_remove(struct pci_dev *pdev) +/** + * mptsas_remove - + * @pdev: + * + **/ +static void __devexit +mptsas_remove(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct mptsas_portinfo *p, *n; int i; - ioc->sas_discovery_ignore_events = 1; + mptsas_fw_event_off(ioc); + mptsas_cleanup_fw_event_q(ioc); + + mptsas_del_device_components(ioc); + sas_remove_host(ioc->sh); mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { list_del(&p->list); for (i = 0 ; i < p->num_phys ; i++) - mptsas_port_delete(p->phy_info[i].port_details); + mptsas_port_delete(ioc, p->phy_info[i].port_details); + kfree(p->phy_info); kfree(p); } mutex_unlock(&ioc->sas_topology_mutex); - + ioc->hba_port_info = NULL; mptscsih_remove(pdev); } @@ -3229,9 +5481,15 @@ static struct pci_driver mptsas_driver = #endif }; +/** + * mptsas_init - + * + **/ static int __init mptsas_init(void) { + int error; + show_mptmod_ver(my_NAME, my_VERSION); mptsas_transport_template = @@ -3240,24 +5498,27 @@ mptsas_init(void) return -ENODEV; mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER); - mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER); + mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER); mptsasInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); + mptsasDeviceResetCtx = + mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER); - if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) { - devtverboseprintk((KERN_INFO MYNAM - ": Registered for IOC event notifications\n")); - } + mpt_event_register(mptsasDoneCtx, mptsas_event_process); + mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset); - if (mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset) == 0) { - dprintk((KERN_INFO MYNAM - ": Registered for IOC reset notifications\n")); - } + error = pci_register_driver(&mptsas_driver); + if (error) + sas_release_transport(mptsas_transport_template); - return pci_register_driver(&mptsas_driver); + return error; } +/** + * mptsas_exit - + * + **/ static void __exit mptsas_exit(void) { @@ -3271,6 +5532,7 @@ mptsas_exit(void) mpt_deregister(mptsasInternalCtx); mpt_deregister(mptsasTaskCtx); mpt_deregister(mptsasDoneCtx); + mpt_deregister(mptsasDeviceResetCtx); } module_init(mptsas_init); Index: linux-2.6.18.i386/drivers/message/fusion/mptsas.h =================================================================== --- /dev/null +++ linux-2.6.18.i386/drivers/message/fusion/mptsas.h @@ -0,0 +1,222 @@ +/* + * linux/drivers/message/fusion/mptsas.h + * High performance SCSI + LAN / Fibre Channel device drivers. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI 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 +*/ + +#ifndef MPTSAS_H_INCLUDED +#define MPTSAS_H_INCLUDED +/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +struct mptsas_target_reset_event { + struct list_head list; + MpiEventDataSasDeviceStatusChange_t sas_event_data; + u8 target_reset_issued; + unsigned long time_count; +}; + +enum mptsas_hotplug_action { + MPTSAS_ADD_DEVICE, + 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_REQUEUE_EVENT, + MPTSAS_IGNORE_EVENT, +}; + +struct sas_mapping{ + u8 id; + u8 channel; +}; + +struct sas_device_info { + struct list_head list; + struct sas_mapping os; /* operating system mapping*/ + struct sas_mapping fw; /* firmware mapping */ + u64 sas_address; + u32 device_info; /* specific bits for devices */ + u16 slot; /* enclosure slot id */ + u64 enclosure_logical_id; /*enclosure address */ + u8 is_logical_volume; /* is this logical volume */ + u8 is_hidden_raid_component; /* this belongs to volume */ + u8 volume_id; /* this valid when is_hidden_raid_component set */ + u8 is_cached; /* cached data for a removed device */ +}; + +struct mptsas_hotplug_event { + MPT_ADAPTER *ioc; + enum mptsas_hotplug_action event_type; + u64 sas_address; + u8 channel; + u8 id; + u32 device_info; + u16 handle; + u8 phy_id; + u8 phys_disk_num; /* hrc - unique index*/ + struct scsi_device *sdev; +}; + + +struct fw_event_work { + struct list_head list; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) + struct delayed_work work; +#else + struct work_struct work; +#endif + MPT_ADAPTER *ioc; + u32 event; + u8 retries; + u8 event_data[1]; +}; + +#if 0 +struct mptsas_link_status_event { + struct work_struct work; + MpiEventDataSasPhyLinkStatus_t link_data; + MPT_ADAPTER *ioc; +}; +#endif + +/* + * SAS topology structures + * + * The MPT Fusion firmware interface spreads information about the + * SAS topology over many manufacture pages, thus we need some data + * structure to collect it and process it for the SAS transport class. + */ + +struct mptsas_devinfo { + u16 handle; /* unique id to address this device */ + u16 handle_parent; /* unique id to address parent device */ + u16 handle_enclosure; /* enclosure identifier of the enclosure */ + u16 slot; /* physical slot in enclosure */ + u8 phy_id; /* phy number of parent device */ + u8 port_id; /* sas physical port this device + is assoc'd with */ + u8 id; /* logical target id of this device */ + u32 phys_disk_num; /* phys disk id, for csmi-ioctls */ + u8 channel; /* logical bus number of this device */ + u64 sas_address; /* WWN of this device, + SATA is assigned by HBA,expander */ + u32 device_info; /* bitfield detailed info about this device */ +#if !defined(MPT_WIDE_PORT_API) + u8 wide_port_enable; /* when set, this is part of wide port*/ +#endif +}; + +/* + * Specific details on ports, wide/narrow + */ +struct mptsas_portinfo_details{ +#if !defined(MPT_WIDE_PORT_API) + u8 port_id; /* port number provided to transport */ + u8 rphy_id; /* phy index used for reporting end device*/ + u32 device_info; /* bitfield detailed info about this device */ +#endif + 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 */ +#if defined(MPT_WIDE_PORT_API) + struct sas_port *port; /* transport layer port object */ +#endif + struct scsi_target *starget; + struct mptsas_portinfo *port_info; +}; + +struct mptsas_phyinfo { + 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 programmed_link_rate; /* programmed max/min phy link rate */ +#if defined(MPT_WIDE_PORT_API) + u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/ +#endif + u8 change_count; /* change count of the phy */ + u8 port_flags; /* info wrt host sas ports */ + u32 phy_info; /* various info wrt the phy */ + struct mptsas_devinfo identify; /* point to phy device info */ + struct mptsas_devinfo attached; /* point to attached device info */ + struct sas_phy *phy; + struct mptsas_portinfo *portinfo; + struct mptsas_portinfo_details * port_details; +}; + +struct mptsas_portinfo { + struct list_head list; + u16 num_phys; /* number of phys */ + struct mptsas_phyinfo *phy_info; +}; + +struct mptsas_enclosure { + u64 enclosure_logical_id; /* The WWN for the enclosure */ + u16 enclosure_handle; /* unique id to address this */ + u16 flags; /* details enclosure management */ + u16 num_slot; /* num slots */ + u16 start_slot; /* first slot */ + u8 start_id; /* starting logical target id */ + u8 start_channel; /* starting logical channel id */ + u8 sep_id; /* SEP device logical target id */ + u8 sep_channel; /* SEP channel logical channel id */ +}; +#if 0 +struct mptsas_broadcast_primative_event { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) + struct delayed_work aen_work; +#else + struct work_struct aen_work; +#endif + MPT_ADAPTER *ioc; +}; +#endif +/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif + Index: linux-2.6.18.i386/drivers/message/fusion/mptscsih.c =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/mptscsih.c +++ linux-2.6.18.i386/drivers/message/fusion/mptscsih.c @@ -1,10 +1,10 @@ /* * linux/drivers/message/fusion/mptscsih.c - * For use with LSI Logic PCI chip/adapter(s) - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI PCI chip/adapter(s) + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsi.com) + * Copyright (c) 1999-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -43,8 +43,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - -#include "linux_compat.h" /* linux-2.6 tweaks */ +#include #include #include #include @@ -54,7 +53,9 @@ #include /* for mdelay */ #include /* needed for in_interrupt() proto */ #include /* notifier code */ +#include #include +#include #include #include @@ -63,6 +64,7 @@ #include #include +#include "linux_compat.h" /* linux-2.6 tweaks */ #include "mptbase.h" #include "mptscsih.h" #include "lsi/mpi_log_sas.h" @@ -78,9 +80,18 @@ 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); +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); int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq); int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); @@ -89,18 +100,10 @@ static int mptscsih_AddSGE(MPT_ADAPTER * SCSIIORequest_t *pReq, int req_idx); static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx); static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); -static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd); -static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ); -static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc); - -static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); - -int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); -static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd); -static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice); +static void mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice); void mptscsih_remove(struct pci_dev *); void mptscsih_shutdown(struct pci_dev *); @@ -113,77 +116,13 @@ int mptscsih_resume(struct pci_dev *pd /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_add_sge - Place a simple SGE at address pAddr. - * @pAddr: virtual address for SGE - * @flagslength: SGE flags and data transfer length - * @dma_addr: Physical address - * - * This routine places a MPT request frame back on the MPT adapter's - * FreeQ. - */ -static inline void -mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) -{ - if (sizeof(dma_addr_t) == sizeof(u64)) { - SGESimple64_t *pSge = (SGESimple64_t *) pAddr; - u32 tmp = dma_addr & 0xFFFFFFFF; - - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address.Low = cpu_to_le32(tmp); - tmp = (u32) ((u64)dma_addr >> 32); - pSge->Address.High = cpu_to_le32(tmp); - - } else { - SGESimple32_t *pSge = (SGESimple32_t *) pAddr; - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address = cpu_to_le32(dma_addr); - } -} /* mptscsih_add_sge() */ - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_add_chain - Place a chain SGE at address pAddr. - * @pAddr: virtual address for SGE - * @next: nextChainOffset value (u32's) - * @length: length of next SGL segment - * @dma_addr: Physical address - * - * This routine places a MPT request frame back on the MPT adapter's - * FreeQ. - */ -static inline void -mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) -{ - if (sizeof(dma_addr_t) == sizeof(u64)) { - SGEChain64_t *pChain = (SGEChain64_t *) pAddr; - u32 tmp = dma_addr & 0xFFFFFFFF; - - pChain->Length = cpu_to_le16(length); - pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); - - pChain->NextChainOffset = next; - - pChain->Address.Low = cpu_to_le32(tmp); - tmp = (u32) ((u64)dma_addr >> 32); - pChain->Address.High = cpu_to_le32(tmp); - } else { - SGEChain32_t *pChain = (SGEChain32_t *) pAddr; - pChain->Length = cpu_to_le16(length); - pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); - pChain->NextChainOffset = next; - pChain->Address = cpu_to_le32(dma_addr); - } -} /* mptscsih_add_chain() */ - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* * mptscsih_getFreeChainBuffer - Function to get a free chain * from the MPT_SCSI_HOST FreeChainQ. * @ioc: Pointer to MPT_ADAPTER structure * @req_idx: Index of the SCSI IO request frame. (output) * * return SUCCESS or FAILED - */ + **/ static inline int mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex) { @@ -192,7 +131,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER int rc; int chain_idx; - dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n", + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n", ioc->name)); spin_lock_irqsave(&ioc->FreeQlock, flags); if (!list_empty(&ioc->FreeChainQ)) { @@ -204,12 +143,12 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer; chain_idx = offset / ioc->req_sz; rc = SUCCESS; - dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n", + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n", ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx)); } else { rc = FAILED; chain_idx = MPT_HOST_NO_CHAIN; - dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n", + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n", ioc->name)); } spin_unlock_irqrestore(&ioc->FreeQlock, flags); @@ -219,7 +158,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER } /* mptscsih_getFreeChainBuffer() */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the * SCSIIORequest_t Message Frame. * @ioc: Pointer to MPT_ADAPTER structure @@ -227,7 +166,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER * @pReq: Pointer to SCSIIORequest_t structure * * Returns ... - */ + **/ static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, SCSIIORequest_t *pReq, int req_idx) @@ -272,10 +211,10 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->sc_data_direction); - dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n", + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: non-SG for %p, len=%d\n", ioc->name, SCpnt, SCpnt->request_bufflen)); - mptscsih_add_sge((char *) &pReq->SGL, - 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen, + ioc->add_sge((char *) &pReq->SGL, + 0xD1000000|sgdir|SCpnt->request_bufflen, SCpnt->SCp.dma_handle); return SUCCESS; @@ -295,10 +234,10 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct */ nextSGEset: - numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) ); + numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size ); numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots; - sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir; + sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir; /* Get first (num - 1) SG elements * Skip any SG entries with a length of 0 @@ -313,11 +252,11 @@ nextSGEset: } v2 = sg_dma_address(sg); - mptscsih_add_sge(psge, sgflags | thisxfer, v2); + ioc->add_sge(psge, sgflags | thisxfer, v2); sg++; /* Get next SG element from the OS */ - psge += (sizeof(u32) + sizeof(dma_addr_t)); - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); + psge += ioc->SGE_size; + sgeOffset += ioc->SGE_size; sg_done++; } @@ -334,12 +273,8 @@ nextSGEset: thisxfer = sg_dma_len(sg); v2 = sg_dma_address(sg); - mptscsih_add_sge(psge, sgflags | thisxfer, v2); - /* - sg++; - psge += (sizeof(u32) + sizeof(dma_addr_t)); - */ - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); + ioc->add_sge(psge, sgflags | thisxfer, v2); + sgeOffset += ioc->SGE_size; sg_done++; if (chainSge) { @@ -348,14 +283,14 @@ nextSGEset: * Update the chain element * Offset and Length fields. */ - mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); + ioc->add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); } else { /* The current buffer is the original MF * and there is no Chain buffer. */ pReq->ChainOffset = 0; RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03; - dsgprintk((MYIOC_s_INFO_FMT + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset)); ioc->RequestNB[req_idx] = RequestNB; } @@ -371,7 +306,7 @@ nextSGEset: * Loop until done. */ - dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n", + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n", ioc->name, sg_done)); /* Set LAST_ELEMENT flag for last non-chain element @@ -381,7 +316,7 @@ nextSGEset: * set properly). */ if (sg_done) { - u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t))); + u32 *ptmp = (u32 *) (psge - ioc->SGE_size); sgflags = le32_to_cpu(*ptmp); sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT; *ptmp = cpu_to_le32(sgflags); @@ -395,8 +330,8 @@ nextSGEset: * Old chain element is now complete. */ u8 nextChain = (u8) (sgeOffset >> 2); - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); - mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); + sgeOffset += ioc->SGE_size; + ioc->add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); } else { /* The original MF buffer requires a chain buffer - * set the offset. @@ -404,7 +339,7 @@ nextSGEset: */ pReq->ChainOffset = (u8) (sgeOffset >> 2); RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03; - dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset)); + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset)); ioc->RequestNB[req_idx] = RequestNB; } @@ -415,7 +350,7 @@ nextSGEset: * in current buffer. Get a chain buffer. */ if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) { - dfailprintk((MYIOC_s_INFO_FMT + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n", ioc->name, pReq->CDB[0], SCpnt)); return FAILED; @@ -437,8 +372,8 @@ nextSGEset: * out the Address and Flags fields. */ chainSge = (char *) psge; - dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)", - psge, req_idx)); + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)", + ioc->name, psge, req_idx)); /* Start the SGE for the next buffer */ @@ -446,8 +381,8 @@ nextSGEset: sgeOffset = 0; sg_done = 0; - dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n", - psge, chain_idx)); + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n", + ioc->name, psge, chain_idx)); /* Start the SGE for the next buffer */ @@ -468,12 +403,13 @@ mptscsih_issue_sep_command(MPT_ADAPTER * if (ioc->bus_type != SAS) return; - /* not supported for hidden raid components */ + /* Not supported for hidden raid components + */ if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) return; if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { - dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n", + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n", ioc->name,__FUNCTION__)); return; } @@ -484,98 +420,161 @@ mptscsih_issue_sep_command(MPT_ADAPTER * SEPMsg->TargetID = vtarget->id; SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS; SEPMsg->SlotStatus = SlotStatus; - devtverboseprintk((MYIOC_s_WARN_FMT + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending SEP cmd=%x channel=%d id=%d\n", ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID)); mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); } -#ifdef MPT_DEBUG_REPLY +#ifdef CONFIG_FUSION_LOGGING /** - * mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO + * mptscsih_info_scsiio - debug print info on reply frame * @ioc: Pointer to MPT_ADAPTER structure - * @ioc_status: U32 IOCStatus word from IOC - * @scsi_status: U8 sam status from target - * @scsi_state: U8 scsi state * @sc: original scsi cmnd pointer - * @mf: Pointer to MPT request frame + * @pScsiReply: Pointer to MPT reply frame + * + * MPT_DEBUG_REPLY needs to be enabled to obtain this info * * Refer to lsi/mpi.h. **/ static void -mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status, - u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc) +mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply) { - char extend_desc[EVENT_DESCR_STR_SZ]; - char *desc = NULL; + char *desc = NULL; + char *desc1 = NULL; + u16 ioc_status; + u8 skey, asc, ascq; + + ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; switch (ioc_status) { - case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ - desc = "SCSI Invalid Bus"; + case MPI_IOCSTATUS_SUCCESS: + desc = "success"; break; - - case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ - desc = "SCSI Invalid TargetID"; + case MPI_IOCSTATUS_SCSI_INVALID_BUS: + desc = "invalid bus"; break; - - case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ - /* - * Inquiry is issued for device scanning - */ - if (sc->cmnd[0] != 0x12) - desc = "SCSI Device Not There"; + case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: + desc = "invalid target_id"; break; - - case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ - desc = "SCSI Data Overrun"; + case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: + desc = "device not there"; break; - - case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ - desc = "SCSI I/O Data Error"; + case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: + desc = "data overrun"; break; - - case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ - desc = "SCSI Protocol Error"; + case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: + desc = "data underrun"; break; - - case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ - desc = "SCSI Task Terminated"; + case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: + desc = "I/O data error"; break; - - case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ - desc = "SCSI Residual Mismatch"; + case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: + desc = "protocol error"; break; - - case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ - desc = "SCSI Task Management Failed"; + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: + desc = "task terminated"; break; - - case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ - desc = "SCSI IOC Terminated"; + case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: + desc = "residual mismatch"; break; + case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: + desc = "task management failed"; + break; + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: + desc = "IOC terminated"; + break; + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: + desc = "ext terminated"; + break; + default: + desc = ""; + break; + } - case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ - desc = "SCSI Ext Terminated"; + switch (pScsiReply->SCSIStatus) + { + + case MPI_SCSI_STATUS_SUCCESS: + desc1 = "success"; + break; + case MPI_SCSI_STATUS_CHECK_CONDITION: + desc1 = "check condition"; + break; + case MPI_SCSI_STATUS_CONDITION_MET: + desc1 = "condition met"; + break; + case MPI_SCSI_STATUS_BUSY: + desc1 = "busy"; + break; + case MPI_SCSI_STATUS_INTERMEDIATE: + desc1 = "intermediate"; + break; + case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET: + desc1 = "intermediate condmet"; + break; + case MPI_SCSI_STATUS_RESERVATION_CONFLICT: + desc1 = "reservation conflict"; + break; + case MPI_SCSI_STATUS_COMMAND_TERMINATED: + desc1 = "command terminated"; + break; + case MPI_SCSI_STATUS_TASK_SET_FULL: + desc1 = "task set full"; + break; + case MPI_SCSI_STATUS_ACA_ACTIVE: + desc1 = "aca active"; + break; + case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT: + desc1 = "fcpext device logged out"; + break; + case MPI_SCSI_STATUS_FCPEXT_NO_LINK: + desc1 = "fcpext no link"; + break; + case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED: + desc1 = "fcpext unassigned"; + break; + default: + desc1 = ""; break; } - if (!desc) - return; + scsi_print_command(sc); + printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n", + ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun); + printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, resid = %d\n", + ioc->name, sc->request_bufflen, sc->underflow, sc->resid); + printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, sc->result = %08X\n", + ioc->name, le16_to_cpu(pScsiReply->TaskTag), + le32_to_cpu(pScsiReply->TransferCount), sc->result); + + printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), " + "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n", + ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus, + pScsiReply->SCSIState); + + if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { + skey = sc->sense_buffer[2] & 0x0F; + asc = sc->sense_buffer[12]; + ascq = sc->sense_buffer[13]; - snprintf(extend_desc, EVENT_DESCR_STR_SZ, - "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh", - sc->device->host->host_no, - sc->device->channel, sc->device->id, sc->device->lun, - sc->cmnd[0], scsi_status, scsi_state); + printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: " + "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq); + } - printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n", - ioc->name, ioc_status, desc, extend_desc); + /* + * Look for + dump FCP ResponseInfo[]! + */ + if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID && + pScsiReply->ResponseInfo) + printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n", + ioc->name, le32_to_cpu(pScsiReply->ResponseInfo)); } #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mptscsih_io_done - Main SCSI IO callback routine registered to * Fusion MPT (base) driver * @ioc: Pointer to MPT_ADAPTER structure @@ -588,7 +587,7 @@ mptscsih_iocstatus_info_scsiio(MPT_ADAPT * load/init time via the mpt_register() API call. * * Returns 1 indicating alloc'd request frame ptr should be freed. - */ + **/ int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) { @@ -597,27 +596,26 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F SCSIIORequest_t *pScsiReq; SCSIIOReply_t *pScsiReply; u16 req_idx, req_idx_MR; - VirtDevice *vdev; + VirtDevice *vdevice; VirtTarget *vtarget; - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + hd = shost_private(ioc->sh); req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); req_idx_MR = (mr != NULL) ? le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx; if ((req_idx != req_idx_MR) || - (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) { - printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n", - ioc->name); - printk (MYIOC_s_ERR_FMT + (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf)) { + printk(MYIOC_s_WARN_FMT + "Received a mf that was already freed\n", ioc->name); + printk (MYIOC_s_WARN_FMT "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n", ioc->name, req_idx, req_idx_MR, mf, mr, - hd->ScsiLookup[req_idx_MR]); + mptscsih_get_scsi_lookup(ioc, req_idx_MR)); return 0; } - sc = hd->ScsiLookup[req_idx]; - hd->ScsiLookup[req_idx] = NULL; + sc = mptscsih_getclear_scsi_lookup(ioc, req_idx); if (sc == NULL) { MPIHeader_t *hdr = (MPIHeader_t *)mf; @@ -644,11 +642,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F pScsiReply = (SCSIIOReply_t *) mr; if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){ - dmfprintk((MYIOC_s_INFO_FMT - "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n", + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task_tag=%d)\n", ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag)); }else{ - dmfprintk((MYIOC_s_INFO_FMT + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n", ioc->name, mf, mr, sc, req_idx)); } @@ -658,6 +656,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 +667,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); sc->resid = sc->request_bufflen - 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,20 +685,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) mptscsih_copy_sense_data(sc, hd, mf, pScsiReply); - /* - * Look for + dump FCP ResponseInfo[]! - */ - if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID && - pScsiReply->ResponseInfo) { - printk(KERN_NOTICE "[%d:%d:%d:%d] " - "FCP_ResponseInfo=%08xh\n", - sc->device->host->host_no, sc->device->channel, - sc->device->id, sc->device->lun, - le32_to_cpu(pScsiReply->ResponseInfo)); - } - switch(status) { case MPI_IOCSTATUS_BUSY: /* 0x0002 */ + case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ /* CHECKME! * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry) * But not: DID_BUS_BUSY lest one risk @@ -723,10 +712,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF) hd->sel_timeout[pScsiReq->TargetID]++; - vdev = sc->device->hostdata; - if (!vdev) + if (!vdevice) break; - vtarget = vdev->vtarget; + vtarget = vdevice->vtarget; if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) { mptscsih_issue_sep_command(ioc, vtarget, MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED); @@ -745,14 +733,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F } } } else if (ioc->bus_type == FC) { - /* - * The FC IOC may kill a request for variety of - * reasons, some of which may be recovered by a - * retry, some which are unlikely to be - * recovered. Return DID_ERROR instead of - * DID_RESET to permit retry of the command, - * just not an infinite number of them - */ + /* The FC IOC may kill a request for variety of reasons, + some of which may be recovered by a retry, some which + are unlikely to be recovered. Return DID_ERROR instead + of DID_RESET to permit retry of the command, just not + an infinite number of them */ sc->result = DID_ERROR << 16; break; } @@ -762,12 +747,16 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F */ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ - case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ /* Linux handles an unsolicited DID_RESET better * than an unsolicited DID_ABORT. */ sc->result = DID_RESET << 16; + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + if ( ioc->bus_type == FC ) + sc->result = DID_ERROR << 16; + else + sc->result = DID_RESET << 16; break; case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ @@ -776,9 +765,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F sc->result=DID_SOFT_ERROR << 16; else /* Sufficient data transfer occurred */ sc->result = (DID_OK << 16) | scsi_status; - dreplyprintk((KERN_NOTICE - "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n", - sc->result, sc->device->channel, sc->device->id)); break; case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ @@ -787,11 +773,34 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F * precedence! */ sc->result = (DID_OK << 16) | scsi_status; - if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { - /* Have already saved the status and sense data + + if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) { + + /* + * For an Errata on LSI53C1030 + * When the length of request data + * and transfer data are different + * with result of command (READ or VERIFY), + * DID_SOFT_ERROR is set. */ - ; - } else { + if (ioc->bus_type == SPI && vdevice && + vdevice->vtarget->type == TYPE_DISK) { + if (pScsiReq->CDB[0] == READ_6 || + pScsiReq->CDB[0] == READ_10 || + pScsiReq->CDB[0] == READ_12 || + pScsiReq->CDB[0] == READ_16 || + pScsiReq->CDB[0] == VERIFY || + pScsiReq->CDB[0] == VERIFY_16) { + if (sc->request_bufflen != + xfer_cnt) { + sc->result = DID_SOFT_ERROR << 16; + printk(MYIOC_s_WARN_FMT "Errata" + "on LSI53C1030 occurred. sc->request_bufflen=0x%02x, " + "xfer_cnt=0x%02x\n", ioc->name, sc->request_bufflen, xfer_cnt); + } + } + } + if (xfer_cnt < sc->underflow) { if (scsi_status == SAM_STAT_BUSY) sc->result = SAM_STAT_BUSY; @@ -809,9 +818,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F } } - dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", - sc->underflow)); - dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt)); /* Report Queue Full */ if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL) @@ -827,6 +833,44 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F if (scsi_state == 0) { ; } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { + + /* + * For potential trouble on LSI53C1030. (date:2007.xx.) + * It is checked whether the length of request data is equal to + * the length of transfer and residual. + * MEDIUM_ERROR is set by incorrect data. + */ + if (ioc->bus_type == SPI && vdevice && + vdevice->vtarget->type == TYPE_DISK) { + if (sc->sense_buffer[2] & 0x20) { + difftransfer = + sc->sense_buffer[3] << 24 | + sc->sense_buffer[4] << 16 | + sc->sense_buffer[5] << 8 | + sc->sense_buffer[6]; + if ((sc->sense_buffer[3] & 0x80) == 0x80) { + if (sc->request_bufflen != xfer_cnt) { + sc->sense_buffer[2] = MEDIUM_ERROR; + sc->sense_buffer[12] = 0xff; + sc->sense_buffer[13] = 0xff; + printk(MYIOC_s_WARN_FMT "Errata on " + "LSI53C1030 occurred. sc->request_bufflen=0x%02x," + "xfer_cnt=0x%02x\n", ioc->name, sc->request_bufflen, xfer_cnt); + } + } else { + if (sc->request_bufflen != xfer_cnt + difftransfer) { + sc->sense_buffer[2] = MEDIUM_ERROR; + sc->sense_buffer[12] = 0xff; + sc->sense_buffer[13] = 0xff; + printk(MYIOC_s_WARN_FMT "Errata on " + "LSI53C1030 occurred. sc->request_bufflen=0x%02x," + " xfer_cnt=0x%02x, difftransfer=0x%02x\n", + ioc->name, sc->request_bufflen , xfer_cnt, difftransfer); + } + } + } + } + /* * If running against circa 200003dd 909 MPT f/w, * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL @@ -874,7 +918,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ - case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ @@ -888,26 +931,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F } /* switch(status) */ -#ifdef MPT_DEBUG_REPLY - if (sc->result) { - - mptscsih_iocstatus_info_scsiio(ioc, status, - scsi_status, scsi_state, sc); - - dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x " - "result=0x%08x\n\tiocstatus=0x%04X " - "scsi_state=0x%02X scsi_status=0x%02X " - "loginfo=0x%08X\n", __FUNCTION__, - sc->device->host->host_no, sc->device->channel, sc->device->id, - sc->device->lun, sc->cmnd[0], sc->result, status, - scsi_state, scsi_status, log_info)); - - dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d " - "bufflen=%d xfer_cnt=%d\n", __FUNCTION__, - sc->device->host->host_no, sc->device->channel, sc->device->id, - sc->device->lun, sc->resid, sc->request_bufflen, - xfer_cnt)); - } +#ifdef CONFIG_FUSION_LOGGING + if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY)) + mptscsih_info_scsiio(ioc, sc, pScsiReply); #endif } /* end of address reply case */ @@ -928,7 +954,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F return 1; } -/* +/** * mptscsih_flush_running_cmds - For each command found, search * Scsi_Host instance taskQ and reply to OS. * Called only if recovering from a FW reload. @@ -937,65 +963,48 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F * Returns: None. * * Must be called while new I/Os are being queued. - */ + **/ static void mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) { MPT_ADAPTER *ioc = hd->ioc; - struct scsi_cmnd *SCpnt; - MPT_FRAME_HDR *mf; + struct scsi_cmnd *sc; + SCSIIORequest_t *mf = NULL; int ii; - int max = ioc->req_depth; - - dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n")); - for (ii= 0; ii < max; ii++) { - if ((SCpnt = hd->ScsiLookup[ii]) != NULL) { - - /* Command found. - */ - - /* Null ScsiLookup index - */ - hd->ScsiLookup[ii] = NULL; - - mf = MPT_INDEX_2_MFPTR(ioc, ii); - dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n", - mf, SCpnt)); - - /* Free Chain buffers */ - mptscsih_freeChainBuffers(ioc, ii); - - /* Free Message frames */ - mpt_free_msg_frame(ioc, mf); - - if ((unsigned char *)mf != SCpnt->host_scribble) - continue; - - /* Set status, free OS resources (SG DMA buffers) - * Do OS callback - */ - if (SCpnt->use_sg) { - pci_unmap_sg(ioc->pcidev, - (struct scatterlist *) SCpnt->request_buffer, - SCpnt->use_sg, - SCpnt->sc_data_direction); - } else if (SCpnt->request_bufflen) { - pci_unmap_single(ioc->pcidev, - SCpnt->SCp.dma_handle, - SCpnt->request_bufflen, - SCpnt->sc_data_direction); - } - SCpnt->result = DID_RESET << 16; - SCpnt->host_scribble = NULL; + int channel, id; - SCpnt->scsi_done(SCpnt); /* Issue the command callback */ - } + for (ii= 0; ii < ioc->req_depth; ii++) { + sc = mptscsih_getclear_scsi_lookup(ioc, ii); + if (!sc) + continue; + mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii); + if (!mf) + continue; + channel = mf->Bus; + id = mf->TargetID; + mptscsih_freeChainBuffers(ioc, ii); + mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf); + if ((unsigned char *)mf != sc->host_scribble) + continue; + if (sc->use_sg) { + pci_unmap_sg(ioc->pcidev, + (struct scatterlist *) sc->request_buffer, + sc->use_sg, sc->sc_data_direction); + } else if (sc->request_bufflen) { + pci_unmap_single(ioc->pcidev, + sc->SCp.dma_handle, sc->request_bufflen, + sc->sc_data_direction); + } + sc->result = DID_RESET << 16; + sc->host_scribble = NULL; + dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT + "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, " + "idx=%x\n", ioc->name, channel, id, sc, mf, ii)); + sc->scsi_done(sc); } - - return; } -/* +/** * mptscsih_search_running_cmds - Delete any commands associated * with the specified target and lun. Function called only * when a lun is disable by mid-layer. @@ -1008,23 +1017,22 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOS * Returns: None. * * Called from slave_destroy. - */ + **/ static void mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice) { SCSIIORequest_t *mf = NULL; int ii; - int max = hd->ioc->req_depth; struct scsi_cmnd *sc; - struct scsi_lun lun; - - dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n", - vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max)); + struct scsi_lun lun; + MPT_ADAPTER *ioc = hd->ioc; + unsigned long flags; - for (ii=0; ii < max; ii++) { - if ((sc = hd->ScsiLookup[ii]) != NULL) { + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + for (ii = 0; ii < ioc->req_depth; ii++) { + if ((sc = ioc->ScsiLookup[ii]) != NULL) { - mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii); + mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii); if (mf == NULL) continue; @@ -1043,40 +1051,43 @@ mptscsih_search_running_cmds(MPT_SCSI_HO (mf->TargetID != vdevice->vtarget->id) || memcmp(lun.scsi_lun, mf->LUN, 8)) continue; - dsprintk(( "search_running: found (sc=%p, mf = %p) " - "channel %d id %d, lun %d \n", hd->ScsiLookup[ii], - mf, mf->Bus, mf->TargetID, vdevice->lun)); - /* Cleanup - */ - hd->ScsiLookup[ii] = NULL; - mptscsih_freeChainBuffers(hd->ioc, ii); - mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf); if ((unsigned char *)mf != sc->host_scribble) continue; + ioc->ScsiLookup[ii] = NULL; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + mptscsih_freeChainBuffers(ioc, ii); + mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf); if (sc->use_sg) { - pci_unmap_sg(hd->ioc->pcidev, + pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer, sc->use_sg, sc->sc_data_direction); } else if (sc->request_bufflen) { - pci_unmap_single(hd->ioc->pcidev, + pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle, sc->request_bufflen, sc->sc_data_direction); } sc->host_scribble = NULL; sc->result = DID_NO_CONNECT << 16; + dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, + MYIOC_s_FMT "completing cmds: fw_channel %d, " + "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, + vdevice->vtarget->channel, vdevice->vtarget->id, + sc, mf, ii)); sc->scsi_done(sc); + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); } } + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mptscsih_report_queue_full - Report QUEUE_FULL status returned * from a SCSI target device. * @sc: Pointer to scsi_cmnd structure @@ -1086,34 +1097,35 @@ mptscsih_search_running_cmds(MPT_SCSI_HO * This routine periodically reports QUEUE_FULL status returned from a * SCSI target device. It reports this to the console via kernel * printk() API call, not more than once every 10 seconds. - */ + **/ static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq) { long time = jiffies; - MPT_SCSI_HOST *hd; + MPT_SCSI_HOST *hd; + MPT_ADAPTER *ioc; if (sc->device == NULL) return; if (sc->device->host == NULL) return; - if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL) + if ((hd = shost_private(sc->device->host)) == NULL) return; - + ioc = hd->ioc; if (time - hd->last_queue_full > 10 * HZ) { - dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n", - hd->ioc->name, 0, sc->device->id, sc->device->lun)); + dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n", + ioc->name, 0, sc->device->id, sc->device->lun)); hd->last_queue_full = time; } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mptscsih_remove - Removed scsi devices * @pdev: Pointer to pci_dev structure * * - */ + **/ void mptscsih_remove(struct pci_dev *pdev) { @@ -1129,28 +1141,28 @@ mptscsih_remove(struct pci_dev *pdev) scsi_remove_host(host); - if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL) + if((hd = shost_private(host)) == NULL) return; mptscsih_shutdown(pdev); sz1=0; - if (hd->ScsiLookup != NULL) { - sz1 = hd->ioc->req_depth * sizeof(void *); - kfree(hd->ScsiLookup); - hd->ScsiLookup = NULL; + if (ioc->ScsiLookup != NULL) { + sz1 = ioc->req_depth * sizeof(void *); + kfree(ioc->ScsiLookup); + ioc->ScsiLookup = NULL; } - dprintk((MYIOC_s_INFO_FMT + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Free'd ScsiLookup (%d) memory\n", - hd->ioc->name, sz1)); + ioc->name, sz1)); kfree(hd->info_kbuf); /* NULL the Scsi_Host pointer */ - hd->ioc->sh = NULL; + ioc->sh = NULL; scsi_host_put(host); @@ -1159,61 +1171,48 @@ mptscsih_remove(struct pci_dev *pdev) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mptscsih_shutdown - reboot notifier * - */ + **/ void mptscsih_shutdown(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - struct Scsi_Host *host = ioc->sh; - MPT_SCSI_HOST *hd; - - if(!host) - return; - - hd = (MPT_SCSI_HOST *)host->hostdata; - } #ifdef CONFIG_PM /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mptscsih_suspend - Fusion MPT scsi driver suspend routine. * * - */ + **/ int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state) { + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + + scsi_block_requests(ioc->sh); + flush_scheduled_work(); mptscsih_shutdown(pdev); return mpt_suspend(pdev,state); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mptscsih_resume - Fusion MPT scsi driver resume routine. * * - */ + **/ int mptscsih_resume(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - struct Scsi_Host *host = ioc->sh; - MPT_SCSI_HOST *hd; - - mpt_resume(pdev); - - if(!host) - return 0; - - hd = (MPT_SCSI_HOST *)host->hostdata; - if(!hd) - return 0; + int rc; - return 0; + rc = mpt_resume(pdev); + scsi_unblock_requests(ioc->sh); + return rc; } #endif @@ -1226,14 +1225,14 @@ mptscsih_resume(struct pci_dev *pdev) * (linux scsi_host_template.info routine) * * Returns pointer to buffer where information was written. - */ + **/ const char * mptscsih_info(struct Scsi_Host *SChost) { MPT_SCSI_HOST *h; int size = 0; - h = (MPT_SCSI_HOST *)SChost->hostdata; + h = shost_private(SChost); if (h) { if (h->info_kbuf == NULL) @@ -1327,7 +1326,7 @@ int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_private(host); MPT_ADAPTER *ioc = hd->ioc; int size = 0; @@ -1359,41 +1358,38 @@ mptscsih_proc_info(struct Scsi_Host *hos * from a linux scsi_cmnd request and send it to the IOC. * * Returns 0. (rtn value discarded by linux scsi mid-layer) - */ + **/ int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; - VirtDevice *vdev = SCpnt->device->hostdata; - int lun; + VirtDevice *vdevice = SCpnt->device->hostdata; u32 datalen; u32 scsictl; u32 scsidir; u32 cmd_len; int my_idx; int ii; + MPT_ADAPTER *ioc; - hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; - lun = SCpnt->device->lun; + hd = shost_private(SCpnt->device->host); + ioc = hd->ioc; SCpnt->scsi_done = done; - dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n", - (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done)); + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n", + ioc->name, SCpnt, done)); - if (hd->resetPending) { - dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", - (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); + if (ioc->taskmgmt_quiesce_io) return SCSI_MLQUEUE_HOST_BUSY; - } /* * Put together a MPT SCSI request... */ - if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) { - dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n", - hd->ioc->name)); + if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { + dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n", + ioc->name)); return SCSI_MLQUEUE_HOST_BUSY; } @@ -1421,8 +1417,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v /* Default to untagged. Once a target structure has been allocated, * use the Inquiry data to determine if device supports tagged. */ - if (vdev - && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) + if (vdevice + && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) && (SCpnt->device->tagged_supported)) { scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ; } else { @@ -1431,17 +1427,17 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v /* Use the above information to set up the message frame */ - pScsiReq->TargetID = (u8) vdev->vtarget->id; - pScsiReq->Bus = vdev->vtarget->channel; + pScsiReq->TargetID = (u8) vdevice->vtarget->id; + pScsiReq->Bus = vdevice->vtarget->channel; pScsiReq->ChainOffset = 0; - if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) + if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; else pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; pScsiReq->CDBLength = SCpnt->cmd_len; pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; pScsiReq->Reserved = 0; - pScsiReq->MsgFlags = mpt_msg_flags(); + pScsiReq->MsgFlags = mpt_msg_flags(ioc); int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN); pScsiReq->Control = cpu_to_le32(scsictl); @@ -1459,7 +1455,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v pScsiReq->DataLength = cpu_to_le32(datalen); /* SenseBuffer low address */ - pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma + pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + (my_idx * MPT_SENSE_BUFFER_ALLOC)); /* Now add the SG list @@ -1467,32 +1463,31 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v */ if (datalen == 0) { /* Add a NULL SGE */ - mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, + ioc->add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); } else { /* Add a 32 or 64 bit SGE */ - if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS) + if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS) goto fail; } SCpnt->host_scribble = (unsigned char *)mf; - hd->ScsiLookup[my_idx] = SCpnt; + mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt); - mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf); - dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", - hd->ioc->name, SCpnt, mf, my_idx)); - DBG_DUMP_REQUEST_FRAME(mf) + mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", + ioc->name, SCpnt, mf, my_idx)); + DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf); return 0; fail: - hd->ScsiLookup[my_idx] = NULL; - mptscsih_freeChainBuffers(hd->ioc, my_idx); - mpt_free_msg_frame(hd->ioc, mf); + mptscsih_freeChainBuffers(ioc, my_idx); + mpt_free_msg_frame(ioc, mf); return SCSI_MLQUEUE_HOST_BUSY; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mptscsih_freeChainBuffers - Function to free chain buffers associated * with a SCSI IO request * @hd: Pointer to the MPT_SCSI_HOST instance @@ -1500,7 +1495,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v * * Called if SG chain buffer allocation fails and mptscsih callbacks. * No return. - */ + **/ static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx) { @@ -1532,7 +1527,7 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *i list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ); spin_unlock_irqrestore(&ioc->FreeQlock, flags); - dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n", + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n", ioc->name, chain_idx)); /* handle next */ @@ -1547,124 +1542,303 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *i */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_TMHandler - Generic handler for SCSI Task Management. - * Fall through to mpt_HardResetHandler if: not operational, too many - * failed TM requests or handshake failure. - * - * @ioc: Pointer to MPT_ADAPTER structure - * @type: Task Management type - * @id: Logical Target ID for reset (if appropriate) - * @lun: Logical Unit for reset (if appropriate) - * @ctx2abort: Context for the task to be aborted (if appropriate) - * - * Remark: Currently invoked from a non-interrupt thread (_bh). - * - * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC - * will be active. - * - * Returns 0 for SUCCESS, or FAILED. - **/ -int -mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +static int +mptscsih_scandv_bus_reset(MPT_ADAPTER *ioc) { - MPT_ADAPTER *ioc; - int rc = -1; - u32 ioc_raw_state; - unsigned long flags; + 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; + } - ioc = hd->ioc; - dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name)); + /* 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; + } - // SJR - CHECKME - Can we avoid this here? - // (mpt_HardResetHandler has this check...) - spin_lock_irqsave(&ioc->diagLock, flags); - if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) { - spin_unlock_irqrestore(&ioc->diagLock, flags); - return FAILED; + 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; } - spin_unlock_irqrestore(&ioc->diagLock, flags); - /* Wait a fixed amount of time for the TM pending flag to be cleared. - * If we time out and not bus reset, then we return a FAILED status - * to the caller. - * The call to mptscsih_tm_pending_wait() will set the pending flag - * if we are - * successful. Otherwise, reload the FW. - */ - if (mptscsih_tm_pending_wait(hd) == FAILED) { - if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { - dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: " - "Timed out waiting for last TM (%d) to complete! \n", - hd->ioc->name, hd->tmPending)); - return FAILED; - } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { - dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target " - "reset: Timed out waiting for last TM (%d) " - "to complete! \n", hd->ioc->name, - hd->tmPending)); - return FAILED; - } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { - dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: " - "Timed out waiting for last TM (%d) to complete! \n", - hd->ioc->name, hd->tmPending)); - return FAILED; + 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; } - } else { - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - hd->tmPending |= (1 << type); - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); } - ioc_raw_state = mpt_GetIocState(hd->ioc, 0); - - if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { - printk(MYIOC_s_WARN_FMT - "TM Handler for type=%x: IOC Not operational (0x%x)!\n", - ioc->name, type, ioc_raw_state); - printk(KERN_WARNING " Issuing HardReset!!\n"); - if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) - printk((KERN_WARNING "TMHandler: HardReset " - "FAILED!!\n")); - return FAILED; + /* 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_raw_state & MPI_DOORBELL_ACTIVE) { - printk(MYIOC_s_WARN_FMT - "TM Handler for type=%x: ioc_state: " - "DOORBELL_ACTIVE (0x%x)!\n", - ioc->name, type, ioc_raw_state); - return FAILED; + 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; } - /* Isse the Task Mgmt request. - */ - if (hd->hard_resets < -1) - hd->hard_resets++; + 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))); - rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun, - ctx2abort, timeout); - if (rc) - printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", - hd->ioc->name); - else - dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", - hd->ioc->name)); + iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; - dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc)); + if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || + iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED || + iocstatus == MPI_IOCSTATUS_SUCCESS) + retval = 0; + else { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt failed\n", ioc->name)); + retval = -1; /* return failure */ + } - return rc; + out: + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + return retval; +} + +int +mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) +{ + MPT_SCSI_HOST *hd; + + if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL)) + return 0; + + switch (reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); + hd = shost_private(ioc->sh); + mptscsih_flush_running_cmds(hd); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); + if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->internal_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->internal_cmds.done); + } + break; + default: + break; + } + return 1; /* currently means nothing really */ +} + +void +mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code) +{ + char *desc; + + switch (response_code) { + case MPI_SCSITASKMGMT_RSP_TM_COMPLETE: + desc = "The task completed."; + break; + case MPI_SCSITASKMGMT_RSP_INVALID_FRAME: + desc = "The IOC received an invalid frame status."; + break; + case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: + desc = "The task type is not supported."; + break; + case MPI_SCSITASKMGMT_RSP_TM_FAILED: + desc = "The requested task failed."; + break; + case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED: + desc = "The task completed successfully."; + break; + case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN: + desc = "The LUN request is invalid."; + break; + case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: + desc = "The task is in the IOC queue and has not been sent to target."; + break; + default: + desc = "unknown"; + break; + } + printk(MYIOC_s_DEBUG_FMT "Response Code(0x%08x): F/W: %s\n", + ioc->name, response_code, desc); } +static int +mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, SCSITaskMgmtReply_t *pScsiTmReply) +{ + u16 iocstatus; + u32 termination_count; + int retval; + + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + retval = FAILED; + goto out; + } + + DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply); + + iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; + termination_count = le32_to_cpu(pScsiTmReply->TerminationCount); + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n" + "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n" + "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus, + pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus), + le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode, + termination_count)); + + if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && + pScsiTmReply->ResponseCode) + mptscsih_taskmgmt_response_code(ioc, + pScsiTmReply->ResponseCode); + + if (iocstatus == MPI_IOCSTATUS_SUCCESS) { + retval = 0; + goto out; + } + + retval = FAILED; + if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { + if (termination_count == 1) + retval = 0; + goto out; + } + + if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || + iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED) + retval = 0; + + out: + return retval; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver + * @ioc: Pointer to MPT_ADAPTER structure + * @mf: Pointer to SCSI task mgmt request frame + * @mr: Pointer to SCSI task mgmt reply frame + * + * This routine is called from mptbase.c::mpt_interrupt() at the completion + * of any SCSI task management request. + * This routine is registered with the MPT (base) driver at driver + * load/init time via the mpt_register() API call. + * + * Returns 1 indicating alloc'd request frame ptr should be freed. + **/ +int +mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) +{ + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n", + ioc->name, mf, mr)); + + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + + if (!mr) + goto out; + + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->taskmgmt_cmds.reply, mr, + min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); + out: + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + mpt_clear_taskmgmt_in_progress_flag(ioc); + ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->taskmgmt_cmds.done); + return 1; + } + return 0; +} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_IssueTaskMgmt - Generic send Task Management function. * @hd: Pointer to MPT_SCSI_HOST structure * @type: Task Management type + * @channel: channel number for task management * @id: Logical Target ID for reset (if appropriate) * @lun: Logical Unit for reset (if appropriate) * @ctx2abort: Context for the task to be aborted (if appropriate) + * @timeout: timeout for task management control * * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) * or a non-interrupt thread. In the former, must not call schedule(). @@ -1674,23 +1848,60 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 * Returns 0 for SUCCESS, or FAILED. * **/ -static int +int 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; + unsigned long timeleft; + u8 issue_hard_reset; + u32 ioc_raw_state; + unsigned long time_count; + + issue_hard_reset = 0; + ioc_raw_state = mpt_GetIocState(ioc, 0); + + if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { + printk(MYIOC_s_WARN_FMT + "TaskMgmt type=%x: IOC Not operational (0x%x)!\n", + ioc->name, type, ioc_raw_state); + printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", + ioc->name, __FUNCTION__); + if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) + printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset " + "FAILED!!\n", ioc->name); + return 0; + } + + if (ioc_raw_state & MPI_DOORBELL_ACTIVE) { + printk(MYIOC_s_WARN_FMT + "TaskMgmt type=%x: ioc_state: " + "DOORBELL_ACTIVE (0x%x)!\n", + ioc->name, type, ioc_raw_state); + return FAILED; + } + + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + retval = FAILED; + goto out; + } /* Return Fail to calling function if no message frames available. */ - if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) { - dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", - hd->ioc->name)); - return FAILED; + if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt no msg frames!!\n", + ioc->name)); + retval = FAILED; + mpt_clear_taskmgmt_in_progress_flag(ioc); + goto out; } - dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n", - hd->ioc->name, mf)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", + ioc->name, mf)); /* Format the Request */ @@ -1713,52 +1924,62 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd pScsiTm->TaskMsgContext = ctx2abort; - dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) " - "type=%d\n", hd->ioc->name, ctx2abort, type)); - - DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm); - - if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc, - sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) { - dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!" - " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd, - hd->ioc, mf, retval)); - goto fail_out; - } - - if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) { - dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!" - " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, - hd->ioc, mf)); - dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n", - hd->ioc->name)); - retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP); - dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n", - hd->ioc->name, retval)); - goto fail_out; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) " + "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort, + type, timeout)); + + DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm); + + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + time_count = jiffies; + if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && + (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) + mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); + else { + retval = mpt_send_handshake_request(ioc->TaskCtx, ioc, + sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); + if (retval) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt handshake FAILED!" + " (mf=%p, rc=%d) \n", ioc->name, mf, retval)); + mpt_free_msg_frame(ioc, mf); + mpt_clear_taskmgmt_in_progress_flag(ioc); + goto out; + } } - /* - * Handle success case, see if theres a non-zero ioc_status. - */ - if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS || - hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || - hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED) - retval = 0; - else + timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { retval = FAILED; + dtmprintk(ioc, printk(MYIOC_s_ERR_FMT + "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf)); + mpt_clear_taskmgmt_in_progress_flag(ioc); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + issue_hard_reset = 1; + goto out; + } - return retval; + retval = mptscsih_taskmgmt_reply(ioc, type, + (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply); - fail_out: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt completed (%d seconds)\n", + ioc->name, jiffies_to_msecs(jiffies - time_count)/1000)); - /* - * Free task managment mf, and corresponding tm flags - */ - mpt_free_msg_frame(hd->ioc, mf); - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - return FAILED; + out: + + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + if(issue_hard_reset) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", + ioc->name, __FUNCTION__); + if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0) + retval = mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + } + + retval = (retval == 0) ? 0 : FAILED; + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + return retval; } static int @@ -1768,10 +1989,10 @@ mptscsih_get_tm_timeout(MPT_ADAPTER *ioc case FC: return 40; case SAS: - return 10; + return 30; case SPI: default: - return 2; + return 10; } } @@ -1792,49 +2013,79 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) u32 ctx2abort; int scpnt_idx; int retval; - VirtDevice *vdev; + VirtDevice *vdevice; ulong sn = SCpnt->serial_number; + MPT_ADAPTER *ioc; /* If we can't locate our host adapter structure, return FAILED status. */ - if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) { + if ((hd = shost_private(SCpnt->device->host)) == NULL) { SCpnt->result = DID_RESET << 16; SCpnt->scsi_done(SCpnt); - dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: " - "Can't locate host! (sc=%p)\n", - SCpnt)); + printk(KERN_ERR MYNAM ": task abort: " + "can't locate host! (sc=%p)\n", SCpnt); return FAILED; } + ioc = hd->ioc; + printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n", + ioc->name, SCpnt); + scsi_print_command(SCpnt); + + vdevice = SCpnt->device->hostdata; + if (!vdevice || !vdevice->vtarget) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "task abort: device has been deleted (sc=%p)\n", + ioc->name, SCpnt)); + SCpnt->result = DID_NO_CONNECT << 16; + SCpnt->scsi_done(SCpnt); + retval = SUCCESS; + goto out; + } + /* Find this command */ - if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { + if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) { /* Cmd not found in ScsiLookup. * Do OS callback. */ SCpnt->result = DID_RESET << 16; - dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: " - "Command not in the active list! (sc=%p)\n", - hd->ioc->name, SCpnt)); - return SUCCESS; + 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; } - if (hd->resetPending) - return FAILED; - - if (hd->timeouts < -1) - hd->timeouts++; - - printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n", - hd->ioc->name, SCpnt); - scsi_print_command(SCpnt); + /* Task aborts are not supported for hidden raid components. + */ + if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "task abort: hidden raid component (sc=%p)\n", + ioc->name, SCpnt)); + SCpnt->result = DID_RESET << 16; + retval = FAILED; + goto out; + } - vdev = SCpnt->device->hostdata; - if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { + /* Task aborts are not supported for volumes. + */ + 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; retval = FAILED; goto out; } + if(mpt_fwfault_debug) + mpt_halt_firmware(ioc); + + if (ioc->timeouts < -1) + ioc->timeouts++; + + /* Most important! Set TaskMsgContext to SCpnt's MsgContext! * (the IO to be ABORT'd) * @@ -1842,28 +2093,33 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) * swap it here either. It is an opaque cookie to * the controller, so it does not matter. -DaveM */ - mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); + mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx); ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; - - hd->abortSCpnt = SCpnt; - - retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, - vdev->vtarget->channel, vdev->vtarget->id, vdev->lun, - ctx2abort, mptscsih_get_tm_timeout(hd->ioc)); - - if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx && - SCpnt->serial_number == sn) + mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, + vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, + ctx2abort, mptscsih_get_tm_timeout(ioc)); + + /* check to see whether command actually completed and/or + * terminated + */ + if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx && + SCpnt->serial_number == sn) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "task abort: command still in active list! (sc=%p)\n", + ioc->name, SCpnt)); retval = FAILED; + } else { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "task abort: command cleared from active list! (sc=%p)\n", + ioc->name, SCpnt)); + retval = SUCCESS; + } out: - printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n", - hd->ioc->name, - ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); + printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n", + ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED" ), SCpnt); - if (retval == 0) - return SUCCESS; - else - return FAILED; + return retval; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1880,38 +2136,42 @@ mptscsih_dev_reset(struct scsi_cmnd * SC { MPT_SCSI_HOST *hd; int retval; - VirtDevice *vdev; + VirtDevice *vdevice; + MPT_ADAPTER *ioc; /* If we can't locate our host adapter structure, return FAILED status. */ - if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ - dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: " - "Can't locate host! (sc=%p)\n", - SCpnt)); + if ((hd = shost_private(SCpnt->device->host)) == NULL){ + printk(KERN_ERR MYNAM ": target reset: " + "Can't locate host! (sc=%p)\n", SCpnt); return FAILED; } - if (hd->resetPending) - return FAILED; - - printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n", - hd->ioc->name, SCpnt); + ioc = hd->ioc; + printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n", + ioc->name, SCpnt); scsi_print_command(SCpnt); - vdev = SCpnt->device->hostdata; - if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { + vdevice = SCpnt->device->hostdata; + if (!vdevice || !vdevice->vtarget) { + retval = SUCCESS; + goto out; + } + + /* Target reset to hidden raid component is not supported + */ + if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { retval = FAILED; goto out; } - retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - vdev->vtarget->channel, vdev->vtarget->id, - 0, 0, mptscsih_get_tm_timeout(hd->ioc)); + retval = mptscsih_IssueTaskMgmt(hd, + MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, vdevice->vtarget->channel, + vdevice->vtarget->id, 0, 0, mptscsih_get_tm_timeout(ioc)); out: - printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n", - hd->ioc->name, - ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); + printk(MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n", + ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); if (retval == 0) return SUCCESS; @@ -1934,31 +2194,33 @@ mptscsih_bus_reset(struct scsi_cmnd * SC { MPT_SCSI_HOST *hd; int retval; - VirtDevice *vdev; + VirtDevice *vdevice; + MPT_ADAPTER *ioc; /* If we can't locate our host adapter structure, return FAILED status. */ - if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ - dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: " - "Can't locate host! (sc=%p)\n", - SCpnt ) ); + if ((hd = shost_private(SCpnt->device->host)) == NULL){ + printk(KERN_ERR MYNAM ": bus_reset: " + "Can't locate host! (sc=%p)\n", SCpnt); return FAILED; } - printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n", - hd->ioc->name, SCpnt); + ioc = hd->ioc; + printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n", + ioc->name, SCpnt); scsi_print_command(SCpnt); - if (hd->timeouts < -1) - hd->timeouts++; + if (ioc->timeouts < -1) + ioc->timeouts++; + + vdevice = SCpnt->device->hostdata; + if (!vdevice || !vdevice->vtarget) + return SUCCESS; + retval = mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc)); - vdev = SCpnt->device->hostdata; - retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, - vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc)); - - printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n", - hd->ioc->name, - ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); + printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n", + ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); if (retval == 0) return SUCCESS; @@ -1980,242 +2242,41 @@ mptscsih_host_reset(struct scsi_cmnd *SC { MPT_SCSI_HOST * hd; int status = SUCCESS; + MPT_ADAPTER *ioc; + int retval; /* If we can't locate the host to reset, then we failed. */ - if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ - dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: " - "Can't locate host! (sc=%p)\n", - SCpnt ) ); + if ((hd = shost_private(SCpnt->device->host)) == NULL){ + printk(KERN_ERR MYNAM ": host reset: " + "Can't locate host! (sc=%p)\n", SCpnt); return FAILED; } - printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n", - hd->ioc->name, SCpnt); + ioc = hd->ioc; + printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n", + ioc->name, SCpnt); /* If our attempts to reset the host failed, then return a failed * status. The host will be taken off line by the SCSI mid-layer. */ - if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){ + if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0) + retval = mpt_HardResetHandler(ioc, CAN_SLEEP); + + if (retval < 0) status = FAILED; - } else { - /* Make sure TM pending is cleared and TM state is set to - * NONE. - */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - } + else + status = SUCCESS; - dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: " - "Status = %s\n", - (status == SUCCESS) ? "SUCCESS" : "FAILED" ) ); + printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n", + ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); return status; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_tm_pending_wait - wait for pending task management request to complete - * @hd: Pointer to MPT host structure. - * - * Returns {SUCCESS,FAILED}. - */ -static int -mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd) -{ - unsigned long flags; - int loop_count = 4 * 10; /* Wait 10 seconds */ - int status = FAILED; - - do { - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - if (hd->tmState == TM_STATE_NONE) { - hd->tmState = TM_STATE_IN_PROGRESS; - hd->tmPending = 1; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - status = SUCCESS; - break; - } - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - msleep(250); - } while (--loop_count); - - return status; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_tm_wait_for_completion - wait for completion of TM task - * @hd: Pointer to MPT host structure. - * - * Returns {SUCCESS,FAILED}. - */ -static int -mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ) -{ - unsigned long flags; - int loop_count = 4 * timeout; - int status = FAILED; - - do { - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - if(hd->tmPending == 0) { - status = SUCCESS; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - break; - } - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - msleep(250); - } while (--loop_count); - - return status; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static void -mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code) -{ - char *desc; - - switch (response_code) { - case MPI_SCSITASKMGMT_RSP_TM_COMPLETE: - desc = "The task completed."; - break; - case MPI_SCSITASKMGMT_RSP_INVALID_FRAME: - desc = "The IOC received an invalid frame status."; - break; - case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: - desc = "The task type is not supported."; - break; - case MPI_SCSITASKMGMT_RSP_TM_FAILED: - desc = "The requested task failed."; - break; - case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED: - desc = "The task completed successfully."; - break; - case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN: - desc = "The LUN request is invalid."; - break; - case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: - desc = "The task is in the IOC queue and has not been sent to target."; - break; - default: - desc = "unknown"; - break; - } - printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n", - ioc->name, response_code, desc); -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver - * @ioc: Pointer to MPT_ADAPTER structure - * @mf: Pointer to SCSI task mgmt request frame - * @mr: Pointer to SCSI task mgmt reply frame - * - * This routine is called from mptbase.c::mpt_interrupt() at the completion - * of any SCSI task management request. - * This routine is registered with the MPT (base) driver at driver - * load/init time via the mpt_register() API call. - * - * Returns 1 indicating alloc'd request frame ptr should be freed. - **/ -int -mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) -{ - SCSITaskMgmtReply_t *pScsiTmReply; - SCSITaskMgmt_t *pScsiTmReq; - MPT_SCSI_HOST *hd; - unsigned long flags; - u16 iocstatus; - u8 tmType; - u32 termination_count; - - dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n", - ioc->name, mf, mr)); - if (!ioc->sh) { - dtmprintk((MYIOC_s_WARN_FMT - "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name)); - return 1; - } - - if (mr == NULL) { - dtmprintk((MYIOC_s_WARN_FMT - "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf)); - return 1; - } - - hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; - pScsiTmReply = (SCSITaskMgmtReply_t*)mr; - pScsiTmReq = (SCSITaskMgmt_t*)mf; - tmType = pScsiTmReq->TaskType; - iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; - termination_count = le32_to_cpu(pScsiTmReply->TerminationCount); - - if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && - pScsiTmReply->ResponseCode) - mptscsih_taskmgmt_response_code(ioc, - pScsiTmReply->ResponseCode); - DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply); - -#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM) - printk("%s: ha=%d [%d:%d:0] task_type=0x%02X " - "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X " - "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus, - pScsiTmReply->TargetID, pScsiTmReq->TaskType, - le16_to_cpu(pScsiTmReply->IOCStatus), - le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode, - le32_to_cpu(pScsiTmReply->TerminationCount)); -#endif - if (!iocstatus) { - dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name)); - hd->abortSCpnt = NULL; - goto out; - } - - /* Error? (anything non-zero?) */ - - /* clear flags and continue. - */ - switch (tmType) { - - case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK: - if (termination_count == 1) - iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED; - hd->abortSCpnt = NULL; - break; - - case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS: - - /* If an internal command is present - * or the TM failed - reload the FW. - * FC FW may respond FAILED to an ABORT - */ - if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED || - hd->cmdPtr) - if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) - printk((KERN_WARNING " Firmware Reload FAILED!!\n")); - break; - - case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET: - default: - break; - } - - out: - spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->tm_iocstatus = iocstatus; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - return 1; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* * This is anyones guess quite frankly. - */ + **/ int mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, sector_t capacity, int geom[]) @@ -2249,33 +2310,71 @@ mptscsih_bios_param(struct scsi_device * geom[1] = sectors; geom[2] = cylinders; - dprintk((KERN_NOTICE - ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n", - sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors)); - return 0; } -/* Search IOC page 3 to determine if this is hidden physical disk +/** + * Search IOC page 3 to determine if this is hidden physical disk * - */ + **/ int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id) { struct inactive_raid_component_info *component_info; - int i; + u8 i, j; + RaidPhysDiskPage1_t *phys_disk; int rc = 0; + int num_paths; if (!ioc->raid_data.pIocPg3) goto out; for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && - (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { + (channel == + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { rc = 1; goto out; } } + if (ioc->bus_type != SAS) + goto out; + + /* + * Check if dual path + */ + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + num_paths = mpt_raid_phys_disk_get_num_paths(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); + if (num_paths < 2) + continue; + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + continue; + if ((mpt_raid_phys_disk_pg1(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum, + phys_disk))) { + kfree(phys_disk); + continue; + } + for (j = 0; j < num_paths; j++) { + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_INVALID)) + continue; + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_BROKEN)) + continue; + if ((id == phys_disk->Path[j].PhysDiskID) && + (channel == phys_disk->Path[j].PhysDiskBus)) { + rc = 1; + kfree(phys_disk); + goto out; + } + } + kfree(phys_disk); + } + /* * Check inactive list for matching phys disks */ @@ -2300,19 +2399,60 @@ u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) { struct inactive_raid_component_info *component_info; - int i; + int i,j; + RaidPhysDiskPage1_t *phys_disk; int rc = -ENXIO; + u8 num_paths; if (!ioc->raid_data.pIocPg3) goto out; for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && - (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { + (channel == + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum; goto out; } } + if (ioc->bus_type != SAS) + goto out; + + /* + * Check if dual path + */ + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + num_paths = mpt_raid_phys_disk_get_num_paths(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); + if (num_paths < 2) + continue; + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + continue; + if ((mpt_raid_phys_disk_pg1(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum, + phys_disk))) { + kfree(phys_disk); + continue; + } + for (j = 0; j < num_paths; j++) { + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_INVALID)) + continue; + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_BROKEN)) + continue; + if ((id == phys_disk->Path[j].PhysDiskID) && + (channel == phys_disk->Path[j].PhysDiskBus)) { + rc = phys_disk->PhysDiskNum; + kfree(phys_disk); + goto out; + } + } + kfree(phys_disk); + } + /* * Check inactive list for matching phys disks */ @@ -2333,60 +2473,64 @@ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc } EXPORT_SYMBOL(mptscsih_raid_id_to_num); -/* +/** * OS entry point to allow for host driver to free allocated memory * Called if no device present or device being unloaded - */ + **/ void mptscsih_slave_destroy(struct scsi_device *sdev) { struct Scsi_Host *host = sdev->host; - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + MPT_SCSI_HOST *hd = shost_private(host); VirtTarget *vtarget; VirtDevice *vdevice; 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; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mptscsih_change_queue_depth - This function will set a devices queue depth * @sdev: per scsi_device pointer * @qdepth: requested queue depth * * Adding support for new 'change_queue_depth' api. -*/ + **/ int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; + MPT_SCSI_HOST *hd = shost_private(sdev->host); VirtTarget *vtarget; struct scsi_target *starget; int max_depth; int tagged; + MPT_ADAPTER *ioc = hd->ioc; starget = scsi_target(sdev); vtarget = starget->hostdata; - if (hd->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 (ioc->bus_type == SPI) { + if (sdev->type == TYPE_DISK && + vtarget->minSyncFactor <= MPT_ULTRA160) max_depth = MPT_SCSI_CMD_PER_DEV_HIGH; else max_depth = MPT_SCSI_CMD_PER_DEV_LOW; } else - max_depth = MPT_SCSI_CMD_PER_DEV_HIGH; + max_depth = ioc->sh->can_queue; + + if (!sdev->tagged_supported) + max_depth = 1; if (qdepth > max_depth) qdepth = max_depth; @@ -2396,15 +2540,24 @@ mptscsih_change_queue_depth(struct scsi_ tagged = MSG_SIMPLE_TAG; scsi_adjust_queue_depth(sdev, tagged, qdepth); + + if (sdev->inquiry_len > 7) + sdev_printk(KERN_INFO, sdev, MYIOC_s_FMT "qdepth=%d, " + "tagged=%d, simple=%d, ordered=%d, scsi_level=%d, " + "cmd_que=%d\n", ioc->name, sdev->queue_depth, + sdev->tagged_supported, sdev->simple_tags, + sdev->ordered_tags, sdev->scsi_level, + (sdev->inquiry[7] & 2) >> 1); + return sdev->queue_depth; } -/* +/** * OS entry point to adjust the queue_depths on a per-device basis. * Called once per device the bus scan. Use it to force the queue_depth * member to 1 if a device does not support Q tags. * Return non-zero if fails. - */ + **/ int mptscsih_slave_configure(struct scsi_device *sdev) { @@ -2412,71 +2565,50 @@ mptscsih_slave_configure(struct scsi_dev VirtTarget *vtarget; VirtDevice *vdevice; struct scsi_target *starget; - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata; + MPT_SCSI_HOST *hd = shost_private(sh); + MPT_ADAPTER *ioc = hd->ioc; starget = scsi_target(sdev); vtarget = starget->hostdata; vdevice = sdev->hostdata; + vdevice->configured_lun = 1; - dsprintk((MYIOC_s_INFO_FMT - "device @ %p, channel=%d, id=%d, lun=%d\n", - hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun)); - if (hd->ioc->bus_type == SPI) - dsprintk((MYIOC_s_INFO_FMT - "sdtr %d wdtr %d ppr %d inq length=%d\n", - hd->ioc->name, sdev->sdtr, sdev->wdtr, - sdev->ppr, sdev->inquiry_len)); - - if (sdev->id > sh->max_id) { + if ((ioc->bus_type != SAS) && (sdev->id > sh->max_id)) { /* error case, should never happen */ scsi_adjust_queue_depth(sdev, 0, 1); goto slave_configure_exit; } - vdevice->configured_lun = 1; - mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH); - - dsprintk((MYIOC_s_INFO_FMT - "Queue depth=%d, tflags=%x\n", - hd->ioc->name, sdev->queue_depth, vtarget->tflags)); - - if (hd->ioc->bus_type == SPI) - dsprintk((MYIOC_s_INFO_FMT - "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n", - hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset, - vtarget->minSyncFactor)); + mptscsih_change_queue_depth(sdev, ioc->sdev_queue_depth); slave_configure_exit: - dsprintk((MYIOC_s_INFO_FMT - "tagged %d, simple %d, ordered %d\n", - hd->ioc->name,sdev->tagged_supported, sdev->simple_tags, - sdev->ordered_tags)); - return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * Private routines... */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* Utility function to copy sense data from the scsi_cmnd buffer +/** + * Utility function to copy sense data from the scsi_cmnd buffer * to the FC and SCSI target structures. * - */ + **/ static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply) { - VirtDevice *vdev; + VirtDevice *vdevice; SCSIIORequest_t *pReq; u32 sense_count = le32_to_cpu(pScsiReply->SenseCount); + MPT_ADAPTER *ioc = hd->ioc; /* Get target structure */ pReq = (SCSIIORequest_t *) mf; - vdev = sc->device->hostdata; + vdevice = sc->device->hostdata; if (sense_count) { u8 *sense_data; @@ -2484,444 +2616,357 @@ 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 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); + sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc)); /* Log SMART data (asc = 0x5D, non-IM case only) if required. */ - if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) { - if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) { + if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) { + if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) { int idx; - MPT_ADAPTER *ioc = hd->ioc; idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE; ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE; ioc->events[idx].eventContext = ioc->eventContext; - ioc->events[idx].data[0] = (pReq->LUN[1] << 24) || - (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) || - (sc->device->channel << 8) || sc->device->id; + ioc->events[idx].data[0] = (pReq->LUN[1] << 24) | + (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) | + (sc->device->channel << 8) | sc->device->id; - ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12]; + ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12]; ioc->eventContext++; - if (hd->ioc->pcidev->vendor == - PCI_VENDOR_ID_IBM) { - mptscsih_issue_sep_command(hd->ioc, - vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); - vdev->vtarget->tflags |= - MPT_TARGET_FLAGS_LED_ON; + if (ioc->pcidev->vendor == PCI_VENDOR_ID_IBM) { + mptscsih_issue_sep_command(ioc, vdevice->vtarget, + MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); + vdevice->vtarget->tflags |= MPT_TARGET_FLAGS_LED_ON; } } } } else { - dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n", - hd->ioc->name)); + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n", + ioc->name)); } } -static int -SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc) +/** + * 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) { - MPT_SCSI_HOST *hd; - int i; + unsigned long flags; + struct scsi_cmnd *scmd; - hd = (MPT_SCSI_HOST *) sc->device->host->hostdata; - - for (i = 0; i < hd->ioc->req_depth; i++) { - if (hd->ScsiLookup[i] == sc) { - return i; - } - } + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + scmd = ioc->ScsiLookup[i]; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return -1; + return scmd; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -int -mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) +/** + * mptscsih_getclear_scsi_lookup + * + * retrieves and clears scmd entry from ScsiLookup[] array list + * + * @ioc: Pointer to MPT_ADAPTER structure + * @i: index into the array + * + * Returns the scsi_cmd pointer + * + **/ +static struct scsi_cmnd * +mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i) { - MPT_SCSI_HOST *hd; - unsigned long flags; - int ii; - - dtmprintk((KERN_WARNING MYNAM - ": IOC %s_reset routed to SCSI host driver!\n", - reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - - /* If a FW reload request arrives after base installed but - * before all scsi hosts have been attached, then an alt_ioc - * may have a NULL sh pointer. - */ - if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL)) - return 0; - else - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; - - if (reset_phase == MPT_IOC_SETUP_RESET) { - dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name)); - - /* Clean Up: - * 1. Set Hard Reset Pending Flag - * All new commands go to doneQ - */ - hd->resetPending = 1; + unsigned long flags; + struct scsi_cmnd *scmd; - } else if (reset_phase == MPT_IOC_PRE_RESET) { - dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name)); + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + scmd = ioc->ScsiLookup[i]; + ioc->ScsiLookup[i] = NULL; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - /* 2. Flush running commands - * Clean ScsiLookup (and associated memory) - * AND clean mytaskQ - */ - - /* 2b. Reply to OS all known outstanding I/O commands. - */ - mptscsih_flush_running_cmds(hd); - - /* 2c. If there was an internal command that - * has not completed, configuration or io request, - * free these resources. - */ - if (hd->cmdPtr) { - del_timer(&hd->timer); - mpt_free_msg_frame(ioc, hd->cmdPtr); - } - - dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name)); - - } else { - dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name)); - - /* Once a FW reload begins, all new OS commands are - * redirected to the doneQ w/ a reset status. - * Init all control structures. - */ - - /* ScsiLookup initialization - */ - for (ii=0; ii < hd->ioc->req_depth; ii++) - hd->ScsiLookup[ii] = NULL; - - /* 2. Chain Buffer initialization - */ - - /* 4. Renegotiate to all devices, if SPI - */ - - /* 5. Enable new commands to be posted - */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmPending = 0; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - hd->resetPending = 0; - hd->tmState = TM_STATE_NONE; - - /* 6. If there was an internal command, - * wake this process up. - */ - if (hd->cmdPtr) { - /* - * Wake up the original calling thread - */ - hd->pLocal = &hd->localReply; - hd->pLocal->completion = MPT_SCANDV_DID_RESET; - hd->scandv_wait_done = 1; - wake_up(&hd->scandv_waitq); - hd->cmdPtr = NULL; - } - - dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name)); - - } - - return 1; /* currently means nothing really */ + return scmd; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -int -mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) -{ - MPT_SCSI_HOST *hd; - u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; - - devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", - ioc->name, event)); - - if (ioc->sh == NULL || - ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) - return 1; - - switch (event) { - case MPI_EVENT_UNIT_ATTENTION: /* 03 */ - /* FIXME! */ - break; - case MPI_EVENT_IOC_BUS_RESET: /* 04 */ - case MPI_EVENT_EXT_BUS_RESET: /* 05 */ - if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1)) - hd->soft_resets++; - break; - case MPI_EVENT_LOGOUT: /* 09 */ - /* FIXME! */ - break; - - case MPI_EVENT_RESCAN: /* 06 */ - break; - - /* - * CHECKME! Don't think we need to do - * anything for these, but... - */ - case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ - case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ - /* - * CHECKME! Falling thru... - */ - break; - - case MPI_EVENT_INTEGRATED_RAID: /* 0B */ - break; - - case MPI_EVENT_NONE: /* 00 */ - case MPI_EVENT_LOG_DATA: /* 01 */ - case MPI_EVENT_STATE_CHANGE: /* 02 */ - case MPI_EVENT_EVENT_CHANGE: /* 0A */ - default: - dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event)); - break; - } +/** + * mptscsih_set_scsi_lookup + * + * writes a scmd entry into the ScsiLookup[] array list + * + * @ioc: Pointer to MPT_ADAPTER structure + * @i: index into the array + * @scmd: scsi_cmnd pointer + * + **/ +static void +mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd) +{ + unsigned long flags; - return 1; /* currently means nothing really */ + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + ioc->ScsiLookup[i] = scmd; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Bus Scan and Domain Validation functionality ... - */ - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptscsih_scandv_complete - Scan and DV callback routine registered - * to Fustion MPT (base) driver. - * - * @ioc: Pointer to MPT_ADAPTER structure - * @mf: Pointer to original MPT request frame - * @mr: Pointer to MPT reply frame (NULL if TurboReply) +/** + * SCPNT_TO_LOOKUP_IDX * - * This routine is called from mpt.c::mpt_interrupt() at the completion - * of any SCSI IO request. - * This routine is registered with the Fusion MPT (base) driver at driver - * load/init time via the mpt_register() API call. + * search's for a given scmd in the ScsiLookup[] array list * - * Returns 1 indicating alloc'd request frame ptr should be freed. + * @ioc: Pointer to MPT_ADAPTER structure + * @scmd: scsi_cmnd pointer * - * Remark: Sets a completion code and (possibly) saves sense data - * in the IOC member localReply structure. - * Used ONLY for DV and other internal commands. - */ -int -mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) + **/ +static int +SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc) { - MPT_SCSI_HOST *hd; - SCSIIORequest_t *pReq; - int completionCode; - u16 req_idx; - - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + unsigned long flags; + int i, index=-1; - if ((mf == NULL) || - (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { - printk(MYIOC_s_ERR_FMT - "ScanDvComplete, %s req frame ptr! (=%p)\n", - ioc->name, mf?"BAD":"NULL", (void *) mf); - goto wakeup; + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + for (i = 0; i < ioc->req_depth; i++) { + if (ioc->ScsiLookup[i] == sc) { + index = i; + goto out; + } } - del_timer(&hd->timer); - req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); - hd->ScsiLookup[req_idx] = NULL; - pReq = (SCSIIORequest_t *) mf; + out: + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return index; +} - if (mf != hd->cmdPtr) { - printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n", - hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx); - } - hd->cmdPtr = NULL; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +int +mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) +{ + u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; + + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "MPT event (=%02Xh) routed to SCSI host driver!\n", + ioc->name, event)); + + if ((event == MPI_EVENT_IOC_BUS_RESET || + event == MPI_EVENT_EXT_BUS_RESET) && + (ioc->bus_type == SPI) && (ioc->soft_resets < -1)) + ioc->soft_resets++; + + return 1; /* currently means nothing really */ +} - ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n", - hd->ioc->name, mf, mr, req_idx)); +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; - hd->pLocal = &hd->localReply; - hd->pLocal->scsiStatus = 0; + mutex_lock(&ioc->internal_cmds.mutex); - /* If target struct exists, clear sense valid flag. + /* Get and Populate a free Frame */ - if (mr == NULL) { - completionCode = MPT_SCANDV_GOOD; - } else { - SCSIIOReply_t *pReply; - u16 status; - u8 scsi_status; - - pReply = (SCSIIOReply_t *) mr; - - status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; - scsi_status = pReply->SCSIStatus; - - ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n", - status, pReply->SCSIState, scsi_status, - le32_to_cpu(pReply->IOCLogInfo))); + 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; + } - switch(status) { + ret = ioc->internal_cmds.completion_code; - case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ - completionCode = MPT_SCANDV_SELECTION_TIMEOUT; - break; + out: + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) + mutex_unlock(&ioc->internal_cmds.mutex); + return ret; +} - case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ - case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ - case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ - case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ - completionCode = MPT_SCANDV_DID_RESET; - break; +/** + * mptscsih_get_completion_code - + * @ioc: Pointer to MPT_ADAPTER structure + * @reply: + * @cmd: + * + **/ +static int +mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) +{ + SCSIIOReply_t *pReply; + MpiRaidActionReply_t *pr; + u8 scsi_status; + u16 status; + int completion_code; - case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ - case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ - case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ - if (pReply->Function == MPI_FUNCTION_CONFIG) { - ConfigReply_t *pr = (ConfigReply_t *)mr; - completionCode = MPT_SCANDV_GOOD; - hd->pLocal->header.PageVersion = pr->Header.PageVersion; - hd->pLocal->header.PageLength = pr->Header.PageLength; - hd->pLocal->header.PageNumber = pr->Header.PageNumber; - hd->pLocal->header.PageType = pr->Header.PageType; - - } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) { - /* If the RAID Volume request is successful, - * return GOOD, else indicate that - * some type of error occurred. - */ - MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr; - if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS) - completionCode = MPT_SCANDV_GOOD; - else - completionCode = MPT_SCANDV_SOME_ERROR; - memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense)); - - } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { - u8 *sense_data; - int sz; + pReply = (SCSIIOReply_t *)reply; + status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; + scsi_status = pReply->SCSIStatus; - /* save sense data in global structure - */ - completionCode = MPT_SCANDV_SENSE; - hd->pLocal->scsiStatus = scsi_status; - sense_data = ((u8 *)hd->ioc->sense_buf_pool + - (req_idx * MPT_SENSE_BUFFER_ALLOC)); - - sz = min_t(int, pReq->SenseBufferLength, - SCSI_STD_SENSE_BYTES); - memcpy(hd->pLocal->sense, sense_data, sz); - - ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n", - sense_data)); - } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { - if (pReq->CDB[0] == INQUIRY) - completionCode = MPT_SCANDV_ISSUE_SENSE; - else - completionCode = MPT_SCANDV_DID_RESET; - } - else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) - completionCode = MPT_SCANDV_DID_RESET; - else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) - completionCode = MPT_SCANDV_DID_RESET; - else { - completionCode = MPT_SCANDV_GOOD; - hd->pLocal->scsiStatus = scsi_status; - } - break; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n", + ioc->name, status, pReply->SCSIState, scsi_status, le32_to_cpu(pReply->IOCLogInfo))); - case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ - if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) - completionCode = MPT_SCANDV_DID_RESET; - else - completionCode = MPT_SCANDV_SOME_ERROR; - break; + switch(status) { - default: - completionCode = MPT_SCANDV_SOME_ERROR; - break; + case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ + completion_code = MPT_SCANDV_SELECTION_TIMEOUT; + break; - } /* switch(status) */ + case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + completion_code = MPT_SCANDV_DID_RESET; + break; - ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n", - completionCode)); - } /* end of address reply case */ + case MPI_IOCSTATUS_BUSY: + case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: + completion_code = MPT_SCANDV_BUSY; + break; - hd->pLocal->completion = completionCode; + case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ + case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ + case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ + if (pReply->Function == MPI_FUNCTION_CONFIG) { + completion_code = MPT_SCANDV_GOOD; + } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) { + pr = (MpiRaidActionReply_t *)reply; + if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS) + completion_code = MPT_SCANDV_GOOD; + else + completion_code = MPT_SCANDV_SOME_ERROR; + } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) + completion_code = MPT_SCANDV_SENSE; + else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { + if (req->u.scsireq.CDB[0] == INQUIRY) + completion_code = MPT_SCANDV_ISSUE_SENSE; + else + completion_code = MPT_SCANDV_DID_RESET; + } + else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) + completion_code = MPT_SCANDV_DID_RESET; + else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) + completion_code = MPT_SCANDV_DID_RESET; + else if (scsi_status == MPI_SCSI_STATUS_BUSY) + completion_code = MPT_SCANDV_BUSY; + else + completion_code = MPT_SCANDV_GOOD; + break; - /* MF and RF are freed in mpt_interrupt - */ -wakeup: - /* Free Chain buffers (will never chain) in scan or dv */ - //mptscsih_freeChainBuffers(ioc, req_idx); + case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ + if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) + completion_code = MPT_SCANDV_DID_RESET; + else + completion_code = MPT_SCANDV_SOME_ERROR; + break; + default: + completion_code = MPT_SCANDV_SOME_ERROR; + break; - /* - * Wake up the original calling thread - */ - hd->scandv_wait_done = 1; - wake_up(&hd->scandv_waitq); + } /* switch(status) */ - return 1; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + " completionCode set to %08xh\n", ioc->name, completion_code)); + return completion_code; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptscsih_timer_expired - Call back for timer process. - * Used only for dv functionality. - * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long +/** + * mptscsih_scandv_complete - + * @ioc: Pointer to MPT_ADAPTER structure + * @req: + * @reply: * - */ -void -mptscsih_timer_expired(unsigned long data) + **/ +int +mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data; - - ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr)); + SCSIIORequest_t *pReq; + SCSIIOReply_t *pReply; + u8 cmd; + u16 req_idx; + u8 *sense_data; + int sz; - if (hd->cmdPtr) { - MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr; + ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD; + if (!reply) + goto out; - if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) { - /* Desire to issue a task management request here. - * TM requests MUST be single threaded. - * If old eh code and no TM current, issue request. - * If new eh code, do nothing. Wait for OS cmd timeout - * for bus reset. - */ - ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name)); - } else { - /* Perform a FW reload */ - if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) { - printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name); - } - } - } else { - /* This should NEVER happen */ - printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name); + pReply = (SCSIIOReply_t *) reply; + pReq = (SCSIIORequest_t *) req; + ioc->internal_cmds.completion_code = + mptscsih_get_completion_code(ioc, req, reply); + ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->internal_cmds.reply, reply, + min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength)); + cmd = reply->u.hdr.Function; + if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) || + (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) && + (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) { + req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx); + sense_data = ((u8 *)ioc->sense_buf_pool + + (req_idx * MPT_SENSE_BUFFER_ALLOC)); + sz = min_t(int, pReq->SenseBufferLength, + MPT_SENSE_BUFFER_ALLOC); + memcpy(ioc->internal_cmds.sense, sense_data, sz); } - - /* No more processing. - * TM call will generate an interrupt for SCSI TM Management. - * The FW will reply to all outstanding commands, callback will finish cleanup. - * Hard reset clean-up will free all resources. - */ - ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name)); - - return; + out: + if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING)) + return 0; + ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->internal_cmds.done); + return 1; } - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_do_cmd - Do internal command. @@ -2941,27 +2986,33 @@ mptscsih_timer_expired(unsigned long dat * 0 if good * * > 0 if command complete but some type of completion error. - */ -static int + **/ +int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) { MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; - SCSIIORequest_t ReqCopy; int my_idx, ii, dir; - int rc, cmdTimeout; - int in_isr; + int timeout; char cmdLen; char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - char cmd = io->cmd; + u8 cmd = io->cmd; + MPT_ADAPTER *ioc = hd->ioc; + int ret = 0; + unsigned long timeleft; + unsigned long flags; - in_isr = in_interrupt(); - if (in_isr) { - dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n", - hd->ioc->name)); - return -EPERM; + /* don't send internal command during diag reset */ + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: busy with host reset\n", ioc->name, __FUNCTION__)); + return MPT_SCANDV_BUSY; } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + mutex_lock(&ioc->internal_cmds.mutex); /* Set command specific information */ @@ -2971,13 +3022,13 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; CDB[4] = io->size; - cmdTimeout = 10; + timeout = 10; break; case TEST_UNIT_READY: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; - cmdTimeout = 10; + timeout = 10; break; case START_STOP: @@ -2985,7 +3036,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; CDB[4] = 1; /*Spin up the disk */ - cmdTimeout = 15; + timeout = 15; break; case REQUEST_SENSE: @@ -2993,7 +3044,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER CDB[0] = cmd; CDB[4] = io->size; dir = MPI_SCSIIO_CONTROL_READ; - cmdTimeout = 10; + timeout = 10; break; case READ_BUFFER: @@ -3012,7 +3063,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER CDB[6] = (io->size >> 16) & 0xFF; CDB[7] = (io->size >> 8) & 0xFF; CDB[8] = io->size & 0xFF; - cmdTimeout = 10; + timeout = 10; break; case WRITE_BUFFER: @@ -3027,21 +3078,21 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER CDB[6] = (io->size >> 16) & 0xFF; CDB[7] = (io->size >> 8) & 0xFF; CDB[8] = io->size & 0xFF; - cmdTimeout = 10; + timeout = 10; break; case RESERVE: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; - cmdTimeout = 10; + timeout = 10; break; case RELEASE: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; - cmdTimeout = 10; + timeout = 10; break; case SYNCHRONIZE_CACHE: @@ -3049,20 +3100,42 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; // CDB[1] = 0x02; /* set immediate bit */ - cmdTimeout = 10; + timeout = 10; + break; + + case REPORT_LUNS: + cmdLen = 12; + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; + CDB[6] = (io->size >> 24) & 0xFF; + CDB[7] = (io->size >> 16) & 0xFF; + CDB[8] = (io->size >> 8) & 0xFF; + CDB[9] = io->size & 0xFF; + timeout = 10; + break; + + case TRANSPORT_LAYER_RETRIES: + CDB[0] = cmd; + CDB[1] = 0x01; + cmdLen = 6; + dir = MPI_SCSIIO_CONTROL_READ; + timeout = 10; break; default: /* Error Case */ - return -EFAULT; + ret = -EFAULT; + goto out; } /* Get and Populate a free Frame + * MsgContext set in mpt_get_msg_frame call */ - if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) { - ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n", - hd->ioc->name)); - return -EBUSY; + if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n", + ioc->name, __FUNCTION__)); + ret = MPT_SCANDV_BUSY; + goto out; } pScsiReq = (SCSIIORequest_t *) mf; @@ -3085,14 +3158,10 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER pScsiReq->CDBLength = cmdLen; pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; - pScsiReq->Reserved = 0; - - pScsiReq->MsgFlags = mpt_msg_flags(); - /* MsgContext set in mpt_get_msg_fram call */ + pScsiReq->MsgFlags = mpt_msg_flags(ioc); int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN); - if (io->flags & MPT_ICFLAG_TAGGED_CMD) pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ); else @@ -3100,74 +3169,61 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER if (cmd == REQUEST_SENSE) { pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); - ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n", - hd->ioc->name, cmd)); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Untagged! 0x%02x\n", ioc->name, __FUNCTION__, cmd)); } - for (ii=0; ii < 16; ii++) - pScsiReq->CDB[ii] = CDB[ii]; + for (ii = 0; ii < 16; ii++) + pScsiReq->CDB[ii] = CDB[ii]; pScsiReq->DataLength = cpu_to_le32(io->size); - pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma + pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + (my_idx * MPT_SENSE_BUFFER_ALLOC)); - ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n", - hd->ioc->name, cmd, io->channel, io->id, io->lun)); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n", + ioc->name, __FUNCTION__, cmd, io->channel, io->id, io->lun)); + + if (dir == MPI_SCSIIO_CONTROL_READ) + ioc->add_sge((char *) &pScsiReq->SGL, + MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma); + else + ioc->add_sge((char *) &pScsiReq->SGL, + MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma); - if (dir == MPI_SCSIIO_CONTROL_READ) { - mpt_add_sge((char *) &pScsiReq->SGL, - MPT_SGE_FLAGS_SSIMPLE_READ | io->size, - io->data_dma); - } else { - mpt_add_sge((char *) &pScsiReq->SGL, - MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, - io->data_dma); + INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status) + mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); + timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, + timeout*HZ); + if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = MPT_SCANDV_DID_RESET; + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __FUNCTION__, + cmd)); + if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; + } + if (!timeleft) { + if (!mptscsih_scandv_bus_reset(ioc)) + goto out; + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", + ioc->name, __FUNCTION__); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + } + goto out; } - /* The ISR will free the request frame, but we need - * the information to initialize the target. Duplicate. - */ - memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t)); - - /* Issue this command after: - * finish init - * add timer - * Wait until the reply has been received - * ScsiScanDvCtx callback function will - * set hd->pLocal; - * set scandv_wait_done and call wake_up - */ - hd->pLocal = NULL; - hd->timer.expires = jiffies + HZ*cmdTimeout; - hd->scandv_wait_done = 0; - - /* Save cmd pointer, for resource free if timeout or - * FW reload occurs - */ - hd->cmdPtr = mf; - - add_timer(&hd->timer); - mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf); - wait_event(hd->scandv_waitq, hd->scandv_wait_done); - - if (hd->pLocal) { - rc = hd->pLocal->completion; - hd->pLocal->skip = 0; - - /* Always set fatal error codes in some cases. - */ - if (rc == MPT_SCANDV_SELECTION_TIMEOUT) - rc = -ENXIO; - else if (rc == MPT_SCANDV_SOME_ERROR) - rc = -rc; - } else { - rc = -EFAULT; - /* This should never happen. */ - ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n", - hd->ioc->name)); - } + ret = ioc->internal_cmds.completion_code; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n", + ioc->name, __FUNCTION__, ret)); - return rc; + out: + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) + mutex_unlock(&ioc->internal_cmds.mutex); + return ret; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -3181,13 +3237,13 @@ 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; - /* - * don't bother with hidden raid components, this is handled when - * sent to the volume + /* Ignore hidden raid components, this is handled when the command + * is sent to the volume */ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) return; @@ -3196,23 +3252,242 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST !vdevice->configured_lun) return; - /* Following parameters will not change - * in this routine. - */ + memset(&iocmd, 0, sizeof(INTERNAL_CMD)); iocmd.cmd = SYNCHRONIZE_CACHE; - iocmd.flags = 0; iocmd.physDiskNum = -1; iocmd.data = NULL; iocmd.data_dma = -1; - iocmd.size = 0; - iocmd.rsvd = iocmd.rsvd2 = 0; iocmd.channel = vdevice->vtarget->channel; iocmd.id = vdevice->vtarget->id; iocmd.lun = vdevice->lun; + sdev_printk(KERN_INFO, sdev, MYIOC_s_FMT "SYNCHRONIZE_CACHE: fw_channel %d," + " fw_id %d\n", ioc->name, vdevice->vtarget->channel, vdevice->vtarget->id); mptscsih_do_cmd(hd, &iocmd); } +/* + * shost attributes + */ +static ssize_t +mptscsih_version_fw_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", + (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, + (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, + (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, + ioc->facts.FWVersion.Word & 0x000000FF); +} +static CLASS_DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL); + +static ssize_t +mptscsih_version_bios_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + 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 CLASS_DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL); + +static ssize_t +mptscsih_version_mpi_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + 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 CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL); + +static ssize_t +mptscsih_version_product_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name); +} +static CLASS_DEVICE_ATTR(version_product, S_IRUGO, + mptscsih_version_product_show, NULL); + +static ssize_t +mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + return snprintf(buf, PAGE_SIZE, "%02xh\n", + ioc->nvdata_version_persistent); +} +static CLASS_DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, + mptscsih_version_nvdata_persistent_show, NULL); + +static ssize_t +mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default); +} +static CLASS_DEVICE_ATTR(version_nvdata_default, S_IRUGO, + mptscsih_version_nvdata_default_show, NULL); + +static ssize_t +mptscsih_board_name_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name); +} +static CLASS_DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL); + +static ssize_t +mptscsih_board_assembly_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly); +} +static CLASS_DEVICE_ATTR(board_assembly, S_IRUGO, + mptscsih_board_assembly_show, NULL); + +static ssize_t +mptscsih_board_tracer_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer); +} +static CLASS_DEVICE_ATTR(board_tracer, S_IRUGO, + mptscsih_board_tracer_show, NULL); + +static ssize_t +mptscsih_io_delay_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); +} +static CLASS_DEVICE_ATTR(io_delay, S_IRUGO, + mptscsih_io_delay_show, NULL); + +static ssize_t +mptscsih_device_delay_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); +} +static CLASS_DEVICE_ATTR(device_delay, S_IRUGO, + mptscsih_device_delay_show, NULL); + +static ssize_t +mptscsih_debug_level_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + + return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level); +} +static ssize_t +mptscsih_debug_level_store(struct class_device *cdev, const char *buf, size_t count) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(host); + MPT_ADAPTER *ioc = hd->ioc; + int val = 0; + + if (sscanf(buf, "%x", &val) != 1) + return -EINVAL; + + ioc->debug_level = val; + printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n", ioc->name, + ioc->debug_level); + return strlen(buf); +} +static CLASS_DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR, + mptscsih_debug_level_show, mptscsih_debug_level_store); + +static ssize_t +mptscsih_disable_hotplug_remove_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(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 class_device *cdev, const char *buf, size_t count) +{ + struct Scsi_Host *host = class_to_shost(cdev); + MPT_SCSI_HOST *hd = shost_private(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 CLASS_DEVICE_ATTR(disable_hotplug_remove, S_IRUGO | S_IWUSR, + mptscsih_disable_hotplug_remove_show, mptscsih_disable_hotplug_remove_store); + +struct class_device_attribute *mptscsih_host_attrs[] = { + &class_device_attr_version_fw, + &class_device_attr_version_bios, + &class_device_attr_version_mpi, + &class_device_attr_version_product, + &class_device_attr_version_nvdata_persistent, + &class_device_attr_version_nvdata_default, + &class_device_attr_board_name, + &class_device_attr_board_assembly, + &class_device_attr_board_tracer, + &class_device_attr_io_delay, + &class_device_attr_device_delay, + &class_device_attr_debug_level, + &class_device_attr_disable_hotplug_remove, + NULL, +}; +EXPORT_SYMBOL(mptscsih_host_attrs); + EXPORT_SYMBOL(mptscsih_remove); EXPORT_SYMBOL(mptscsih_shutdown); #ifdef CONFIG_PM @@ -3235,7 +3510,9 @@ EXPORT_SYMBOL(mptscsih_scandv_complete); EXPORT_SYMBOL(mptscsih_event_process); EXPORT_SYMBOL(mptscsih_ioc_reset); EXPORT_SYMBOL(mptscsih_change_queue_depth); -EXPORT_SYMBOL(mptscsih_timer_expired); -EXPORT_SYMBOL(mptscsih_TMHandler); - +EXPORT_SYMBOL(mptscsih_IssueTaskMgmt); +EXPORT_SYMBOL(mptscsih_do_cmd); +EXPORT_SYMBOL(mptscsih_quiesce_raid); +EXPORT_SYMBOL(mptscsih_get_scsi_lookup); +EXPORT_SYMBOL(mptscsih_taskmgmt_response_code); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ Index: linux-2.6.18.i386/drivers/message/fusion/mptscsih.h =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/mptscsih.h +++ linux-2.6.18.i386/drivers/message/fusion/mptscsih.h @@ -3,10 +3,10 @@ * High performance SCSI / Fibre Channel SCSI Host device driver. * For use with PCI chip/adapter(s): * LSIFC9xx/LSI409xx Fibre Channel - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsi.com) + * Copyright (c) 1999-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -60,6 +60,7 @@ #define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008) #define MPT_SCANDV_ISSUE_SENSE (0x00000010) #define MPT_SCANDV_FALLBACK (0x00000020) +#define MPT_SCANDV_BUSY (0x00000040) #define MPT_SCANDV_MAX_RETRIES (10) @@ -71,6 +72,7 @@ #define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */ #define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */ + #define MPT_SCSI_CMD_PER_DEV_HIGH 64 #define MPT_SCSI_CMD_PER_DEV_LOW 32 @@ -84,9 +86,11 @@ #define MPTSCSIH_DOMAIN_VALIDATION 1 #define MPTSCSIH_MAX_WIDTH 1 #define MPTSCSIH_MIN_SYNC 0x08 +#define MPTSCSIH_QAS 1 #define MPTSCSIH_SAF_TE 0 #define MPTSCSIH_PT_CLEAR 0 +#define TRANSPORT_LAYER_RETRIES 0xC2 #endif typedef struct _internal_cmd { @@ -112,7 +116,7 @@ extern int mptscsih_resume(struct pci_de extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func); extern const char * mptscsih_info(struct Scsi_Host *SChost); extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)); -extern void mptscsih_slave_destroy(struct scsi_device *device); +extern void mptscsih_slave_destroy(struct scsi_device *sdev); extern int mptscsih_slave_configure(struct scsi_device *device); extern int mptscsih_abort(struct scsi_cmnd * SCpnt); extern int mptscsih_dev_reset(struct scsi_cmnd * SCpnt); @@ -125,7 +129,11 @@ extern int mptscsih_scandv_complete(MPT_ extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth); -extern void mptscsih_timer_expired(unsigned long data); -extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); +extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id); extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); +extern int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd); +extern struct class_device_attribute *mptscsih_host_attrs[]; +extern int mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id); +extern struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); +extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code); Index: linux-2.6.18.i386/drivers/message/fusion/mptspi.c =================================================================== --- linux-2.6.18.i386.orig/drivers/message/fusion/mptspi.c +++ linux-2.6.18.i386/drivers/message/fusion/mptspi.c @@ -1,10 +1,10 @@ /* * linux/drivers/message/fusion/mptspi.c - * For use with LSI Logic PCI chip/adapter(s) - * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * For use with LSI PCI chip/adapter(s) + * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsi.com) + * Copyright (c) 1999-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -43,8 +43,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - -#include "linux_compat.h" /* linux-2.6 tweaks */ +#include #include #include #include @@ -54,8 +53,10 @@ #include /* for mdelay */ #include /* needed for in_interrupt() proto */ #include /* notifier code */ +#include #include #include +#include #include #include @@ -66,6 +67,7 @@ #include #include +#include "linux_compat.h" /* linux-2.6 tweaks */ #include "mptbase.h" #include "mptscsih.h" @@ -84,6 +86,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 *, @@ -91,25 +97,25 @@ static int mptspi_write_spi_device_pg1(s static struct scsi_transport_template *mptspi_transport_template = NULL; -static int mptspiDoneCtx = -1; -static int mptspiTaskCtx = -1; -static int mptspiInternalCtx = -1; /* Used only for internal commands */ +static u8 mptspiDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptspiTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ /** - * mptspi_setTargetNegoParms - Update the target negotiation - * parameters based on the the Inquiry data, adapter capabilities, - * and NVRAM settings - * + * mptspi_setTargetNegoParms - Update the target negotiation parameters * @hd: Pointer to a SCSI Host Structure - * @vtarget: per target private data + * @target: per target private data * @sdev: SCSI device * + * Update the target negotiation parameters based on the the Inquiry + * data, adapter capabilities, and NVRAM settings. **/ static void mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, struct scsi_device *sdev) { - SpiCfgData *pspi_data = &hd->ioc->spi_data; + MPT_ADAPTER *ioc = hd->ioc; + SpiCfgData *pspi_data = &ioc->spi_data; int id = (int) target->id; int nvram; u8 width = MPT_NARROW; @@ -132,7 +138,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)) @@ -140,7 +146,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST else { factor = MPT_ULTRA320; if (scsi_device_qas(sdev)) { - ddvprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id)); + ddvprintk(ioc, + printk(MYIOC_s_DEBUG_FMT "Enabling QAS due to " + "byte56=%02x on id=%d!\n", ioc->name, + scsi_device_qas(sdev), id)); noQas = 0; } if (sdev->type == TYPE_TAPE && @@ -207,6 +216,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. @@ -227,14 +240,15 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST /* Disable QAS in a mixed configuration case */ - ddvprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id)); + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id)); } } /** * mptspi_writeIOCPage4 - write IOC Page 4 * @hd: Pointer to a SCSI Host Structure - * @channel: + * @channel: channel number * @id: write IOC Page4 for this ID & Bus * * Return: -EAGAIN if unable to obtain a Message Frame @@ -258,8 +272,8 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, /* Get a MF for this command. */ if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { - dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n", - ioc->name)); + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT + "writeIOCPage4 : no msg frames!\n", ioc->name)); return -EAGAIN; } @@ -297,9 +311,9 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | (IOCPage4Ptr->Header.PageLength + ii) * 4; - mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); + ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); - ddvprintk((MYIOC_s_INFO_FMT + 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)); @@ -368,19 +382,20 @@ mptspi_initTarget(MPT_SCSI_HOST *hd, Vir * non-zero = true * zero = false * - */ + **/ static int mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id) { int i, rc = 0; + MPT_ADAPTER *ioc = hd->ioc; - if (!hd->ioc->raid_data.pIocPg2) + if (!ioc->raid_data.pIocPg2) goto out; - if (!hd->ioc->raid_data.pIocPg2->NumActiveVolumes) + if (!ioc->raid_data.pIocPg2->NumActiveVolumes) goto out; - for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { - if (hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) { + for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) { rc = 1; goto out; } @@ -393,8 +408,9 @@ mptspi_is_raid(struct _MPT_SCSI_HOST *hd static int mptspi_target_alloc(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; + struct _MPT_SCSI_HOST *hd = shost_private(shost); VirtTarget *vtarget; + MPT_ADAPTER *ioc = hd->ioc; if (hd == NULL) return -ENODEV; @@ -403,7 +419,7 @@ static int mptspi_target_alloc(struct sc if (!vtarget) return -ENOMEM; - vtarget->ioc_id = hd->ioc->id; + vtarget->ioc_id = ioc->id; vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; vtarget->id = (u8)starget->id; vtarget->channel = (u8)starget->channel; @@ -411,42 +427,43 @@ static int mptspi_target_alloc(struct sc starget->hostdata = vtarget; if (starget->channel == 1) { - if (mptscsih_is_phys_disk(hd->ioc, 0, starget->id) == 0) + if (mptscsih_is_phys_disk(ioc, 0, starget->id) == 0) return 0; vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; /* The real channel for this device is zero */ vtarget->channel = 0; /* The actual physdisknum (for RAID passthrough) */ - vtarget->id = mptscsih_raid_id_to_num(hd->ioc, 0, + vtarget->id = mptscsih_raid_id_to_num(ioc, 0, starget->id); } if (starget->channel == 0 && mptspi_is_raid(hd, starget->id)) { vtarget->raidVolume = 1; - ddvprintk((KERN_INFO - "RAID Volume @ channel=%d id=%d\n", starget->channel, + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "RAID Volume @ channel=%d id=%d\n", ioc->name, starget->channel, starget->id)); } - if (hd->ioc->spi_data.nvram && - hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { - u32 nvram = hd->ioc->spi_data.nvram[starget->id]; + if (ioc->spi_data.nvram && + ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { + u32 nvram = ioc->spi_data.nvram[starget->id]; spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT; spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; } else { - spi_min_period(starget) = hd->ioc->spi_data.minSyncFactor; - spi_max_width(starget) = hd->ioc->spi_data.maxBusWidth; + spi_min_period(starget) = ioc->spi_data.minSyncFactor; + spi_max_width(starget) = ioc->spi_data.maxBusWidth; } - spi_max_offset(starget) = hd->ioc->spi_data.maxSyncOffset; + spi_max_offset(starget) = ioc->spi_data.maxSyncOffset; spi_offset(starget) = 0; + spi_period(starget) = 0xFF; mptspi_write_width(starget, 0); return 0; } -void +static void mptspi_target_destroy(struct scsi_target *starget) { if (starget->hostdata) @@ -464,9 +481,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((MYIOC_s_INFO_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 ": "", @@ -476,7 +496,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 ": ""); } /** @@ -489,9 +509,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((MYIOC_s_INFO_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 ": "", @@ -501,17 +524,17 @@ 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, struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; + struct _MPT_SCSI_HOST *hd = shost_private(shost); struct _MPT_ADAPTER *ioc = hd->ioc; - struct _CONFIG_PAGE_SCSI_DEVICE_0 *pg0; - dma_addr_t pg0_dma; + struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0; + dma_addr_t spi_dev_pg0_dma; int size; struct _x_config_parms cfg; struct _CONFIG_PAGE_HEADER hdr; @@ -529,9 +552,10 @@ static int mptspi_read_spi_device_pg0(st size += 2048; */ - pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg0_dma, GFP_KERNEL); - if (pg0 == NULL) { - starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n"); + spi_dev_pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &spi_dev_pg0_dma, GFP_KERNEL); + if (spi_dev_pg0 == NULL) { + starget_printk(KERN_ERR, starget, MYIOC_s_FMT + "dma_alloc_coherent for parameters failed\n", ioc->name); return -EINVAL; } @@ -545,22 +569,24 @@ static int mptspi_read_spi_device_pg0(st memset(&cfg, 0, sizeof(cfg)); cfg.cfghdr.hdr = &hdr; - cfg.physAddr = pg0_dma; + cfg.physAddr = spi_dev_pg0_dma; 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, "mpt_config failed\n"); + starget_printk(KERN_ERR, starget, + MYIOC_s_FMT "mpt_config failed\n", ioc->name); goto out_free; } err = 0; - memcpy(pass_pg0, pg0, size); + memcpy(pass_pg0, spi_dev_pg0, size); - mptspi_print_read_nego(hd, starget, le32_to_cpu(pg0->NegotiatedParameters)); + mptspi_print_read_nego(hd, starget, le32_to_cpu(spi_dev_pg0->NegotiatedParameters)); out_free: - dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma); + dma_free_coherent(&ioc->pcidev->dev, size, spi_dev_pg0, spi_dev_pg0_dma); return err; } @@ -587,11 +613,11 @@ static u32 mptspi_getRP(struct scsi_targ static void mptspi_read_parameters(struct scsi_target *starget) { int nego; - struct _CONFIG_PAGE_SCSI_DEVICE_0 pg0; + struct _CONFIG_PAGE_SCSI_DEVICE_0 spi_dev_pg0; - mptspi_read_spi_device_pg0(starget, &pg0); + mptspi_read_spi_device_pg0(starget, &spi_dev_pg0); - nego = le32_to_cpu(pg0.NegotiatedParameters); + nego = le32_to_cpu(spi_dev_pg0.NegotiatedParameters); spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0; spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0; @@ -606,83 +632,43 @@ static void mptspi_read_parameters(struc spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0; } -static int -mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) -{ - MpiRaidActionRequest_t *pReq; - MPT_FRAME_HDR *mf; - - /* Get and Populate a free Frame - */ - if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) { - ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n", - hd->ioc->name)); - return -EAGAIN; - } - pReq = (MpiRaidActionRequest_t *)mf; - if (quiesce) - pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO; - else - pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO; - pReq->Reserved1 = 0; - pReq->ChainOffset = 0; - pReq->Function = MPI_FUNCTION_RAID_ACTION; - pReq->VolumeID = id; - pReq->VolumeBus = channel; - pReq->PhysDiskNum = 0; - pReq->MsgFlags = 0; - pReq->Reserved2 = 0; - pReq->ActionDataWord = 0; /* Reserved for this action */ - - mpt_add_sge((char *)&pReq->ActionDataSGE, - MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); - - ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action=%x channel=%d id=%d\n", - hd->ioc->name, pReq->Action, channel, id)); - - hd->pLocal = NULL; - hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ - hd->scandv_wait_done = 0; - - /* Save cmd pointer, for resource free if timeout or - * FW reload occurs - */ - hd->cmdPtr = mf; - - add_timer(&hd->timer); - mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf); - wait_event(hd->scandv_waitq, hd->scandv_wait_done); - - if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0)) - return -1; - - return 0; -} - static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, struct scsi_device *sdev) { VirtTarget *vtarget = scsi_target(sdev)->hostdata; + struct scsi_target *starget = scsi_target(sdev); + MPT_ADAPTER *ioc = hd->ioc; /* no DV on RAID devices */ if (sdev->channel == 0 && 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), - "Integrated RAID quiesce failed\n"); + MYIOC_s_FMT "Integrated RAID quiesce failed\n", ioc->name); return; } + hd->spi_pending |= (1 << sdev->id); spi_dv_device(sdev); + hd->spi_pending &= ~(1 << sdev->id); if (sdev->channel == 1 && mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0) starget_printk(KERN_ERR, scsi_target(sdev), - "Integrated RAID resume failed\n"); + MYIOC_s_FMT "Integrated RAID resume failed\n", ioc->name); mptspi_read_parameters(sdev->sdev_target); spi_display_xfer_agreement(sdev->sdev_target); @@ -691,28 +677,29 @@ static void mptspi_dv_device(struct _MPT static int mptspi_slave_alloc(struct scsi_device *sdev) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; + MPT_SCSI_HOST *hd = shost_private(sdev->host); VirtTarget *vtarget; - VirtDevice *vdev; + VirtDevice *vdevice; struct scsi_target *starget; + MPT_ADAPTER *ioc = hd->ioc; if (sdev->channel == 1 && - mptscsih_is_phys_disk(hd->ioc, 0, sdev->id) == 0) + mptscsih_is_phys_disk(ioc, 0, sdev->id) == 0) return -ENXIO; - vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); - if (!vdev) { + vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); + if (!vdevice) { printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", - hd->ioc->name, sizeof(VirtDevice)); + ioc->name, sizeof(VirtDevice)); return -ENOMEM; } - vdev->lun = sdev->lun; - sdev->hostdata = vdev; + vdevice->lun = sdev->lun; + sdev->hostdata = vdevice; starget = scsi_target(sdev); vtarget = starget->hostdata; - vdev->vtarget = vtarget; + vdevice->vtarget = vtarget; vtarget->num_luns++; if (sdev->channel == 1) @@ -723,24 +710,15 @@ static int mptspi_slave_alloc(struct scs static int mptspi_slave_configure(struct scsi_device *sdev) { - struct _MPT_SCSI_HOST *hd = - (struct _MPT_SCSI_HOST *)sdev->host->hostdata; + struct _MPT_SCSI_HOST *hd = shost_private(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((MYIOC_s_INFO_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)) @@ -752,26 +730,25 @@ static int mptspi_slave_configure(struct static int mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { - struct _MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; - VirtDevice *vdev = SCpnt->device->hostdata; + struct _MPT_SCSI_HOST *hd = shost_private(SCpnt->device->host); + VirtDevice *vdevice = SCpnt->device->hostdata; + MPT_ADAPTER *ioc = hd->ioc; - if (!vdev || !vdev->vtarget) { + if (!vdevice || !vdevice->vtarget) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } if (SCpnt->device->channel == 1 && - mptscsih_is_phys_disk(hd->ioc, 0, SCpnt->device->id) == 0) { + mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } -#ifdef MPT_DEBUG_DV if (spi_dv_pending(scsi_target(SCpnt->device))) - scsi_print_command(SCpnt); -#endif + ddvprintk(ioc, scsi_print_command(SCpnt)); return mptscsih_qcmd(SCpnt,done); } @@ -821,13 +798,14 @@ static struct scsi_host_template mptspi_ .max_sectors = 8192, .cmd_per_lun = 7, .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = mptscsih_host_attrs, }; static int mptspi_write_spi_device_pg1(struct scsi_target *starget, struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; + struct _MPT_SCSI_HOST *hd = shost_private(shost); struct _MPT_ADAPTER *ioc = hd->ioc; struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1; dma_addr_t pg1_dma; @@ -845,7 +823,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, "dma_alloc_coherent for parameters failed\n"); + starget_printk(KERN_ERR, starget, + MYIOC_s_FMT "dma_alloc_coherent for parameters failed\n", ioc->name); return -EINVAL; } @@ -874,7 +853,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, "mpt_config failed\n"); + starget_printk(KERN_ERR, starget, + MYIOC_s_FMT "mpt_config failed\n", ioc->name); goto out_free; } err = 0; @@ -949,14 +929,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; @@ -972,9 +953,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); @@ -1013,12 +991,14 @@ static void mptspi_write_qas(struct scsi { struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; + struct _MPT_SCSI_HOST *hd = shost_private(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; @@ -1039,8 +1019,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; @@ -1060,19 +1040,28 @@ struct work_queue_wrapper { int disk; }; -static void mpt_work_wrapper(void *data) +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; - struct Scsi_Host *shost = hd->ioc->sh; + MPT_ADAPTER *ioc = hd->ioc; + struct Scsi_Host *shost = ioc->sh; struct scsi_device *sdev; int disk = wqw->disk; struct _CONFIG_PAGE_IOC_3 *pg3; kfree(wqw); - mpt_findImVolumes(hd->ioc); - pg3 = hd->ioc->raid_data.pIocPg3; + mpt_findImVolumes(ioc); + pg3 = ioc->raid_data.pIocPg3; if (!pg3) return; @@ -1090,26 +1079,31 @@ static void mpt_work_wrapper(void *data) continue; starget_printk(KERN_INFO, vtarget->starget, - "Integrated RAID requests DV of new device\n"); + MYIOC_s_FMT "Integrated RAID requests DV of new device\n", ioc->name); mptspi_dv_device(hd, sdev); } shost_printk(KERN_INFO, shost, - "Integrated RAID detects new device %d\n", disk); - scsi_scan_target(&hd->ioc->sh->shost_gendev, 1, disk, 0, 1); + MYIOC_s_FMT "Integrated RAID detects new device %d\n", ioc->name, disk); + scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, 1); } static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk) { struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC); + MPT_ADAPTER *ioc = hd->ioc; if (!wqw) { - shost_printk(KERN_ERR, hd->ioc->sh, - "Failed to act on RAID event for physical disk %d\n", - disk); + 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; @@ -1120,7 +1114,7 @@ static int mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) { u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata; + struct _MPT_SCSI_HOST *hd = shost_private(ioc->sh); if (hd && event == MPI_EVENT_INTEGRATED_RAID) { int reason @@ -1187,6 +1181,8 @@ static struct spi_function_template mpts static struct pci_device_id mptspi_pci_table[] = { { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030, PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_ATTO, MPI_MANUFACTPAGE_DEVID_53C1030, + PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035, PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ @@ -1194,20 +1190,44 @@ 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; + struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; + u32 nego; + MPT_ADAPTER *ioc = hd->ioc; kfree(wqw); - shost_for_each_device(sdev, hd->ioc->sh) - mptspi_dv_device(hd, sdev); + if (hd->spi_pending) { + shost_for_each_device(sdev, ioc->sh) { + if (hd->spi_pending & (1 << sdev->id)) + continue; + starget = scsi_target(sdev); + nego = mptspi_getRP(starget); + pg1.RequestedParameters = cpu_to_le32(nego); + pg1.Reserved = 0; + pg1.Configuration = 0; + mptspi_write_spi_device_pg1(starget, &pg1); + } + } else { + shost_for_each_device(sdev, ioc->sh) + mptspi_dv_device(hd, sdev); + } } static void @@ -1218,38 +1238,48 @@ 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 = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata; + struct _MPT_SCSI_HOST *hd = NULL; int rc; rc = mptscsih_ioc_reset(ioc, reset_phase); + if ((ioc->bus_type != SPI) || (!rc)) + goto out; - if (reset_phase == MPT_IOC_POST_RESET) - mptspi_dv_renegotiate(hd); + hd = shost_private(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) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata; + struct _MPT_SCSI_HOST *hd = shost_private(ioc->sh); int rc; rc = mptscsih_resume(pdev); @@ -1261,13 +1291,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) { @@ -1381,88 +1411,62 @@ mptspi_probe(struct pci_dev *pdev, const * A slightly different algorithm is required for * 64bit SGEs. */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) { + scale = ioc->req_sz/ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 64) / ioc->SGE_size; } + if (numSGE < sh->sg_tablesize) { /* Reset this value */ - dprintk((MYIOC_s_INFO_FMT + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Resetting sg_tablesize to %d from %d\n", ioc->name, numSGE, sh->sg_tablesize)); sh->sg_tablesize = numSGE; } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - hd = (MPT_SCSI_HOST *) sh->hostdata; + hd = shost_private(sh); hd->ioc = ioc; + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + /* SCSI needs scsi_cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ - hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); - if (!hd->ScsiLookup) { + ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); + if (!ioc->ScsiLookup) { error = -ENOMEM; goto out_mptspi_probe; } + spin_lock_init(&ioc->scsi_lookup_lock); - dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", - ioc->name, hd->ScsiLookup)); - - /* Clear the TM flags - */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; - hd->abortSCpnt = NULL; - - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; - - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; + 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 = mpt_qas ? 0 : MPT_TARGET_NO_NEGO_QAS; - hd->negoNvram = MPT_SCSICFG_USE_NVRAM; - ddvprintk((MYIOC_s_INFO_FMT - "saf_te %x\n", - ioc->name, - mpt_saf_te)); - ioc->spi_data.noQas = 0; - - init_waitqueue_head(&hd->scandv_waitq); - hd->scandv_wait_done = 0; hd->last_queue_full = 0; + hd->spi_pending = 0; /* Some versions of the firmware don't support page 0; without * that we can't get the parameters */ - if (hd->ioc->spi_data.sdp0length != 0) + if (ioc->spi_data.sdp0length != 0) sh->transportt = mptspi_transport_template; error = scsi_add_host (sh, &ioc->pcidev->dev); if(error) { - dprintk((KERN_ERR MYNAM - "scsi_add_host failed\n")); + dprintk(ioc, printk(MYIOC_s_ERR_FMT + "scsi_add_host failed\n", ioc->name)); goto out_mptspi_probe; } @@ -1470,7 +1474,7 @@ mptspi_probe(struct pci_dev *pdev, const * issue internal bus reset */ if (ioc->spi_data.bus_reset) - mptscsih_TMHandler(hd, + mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, 0, 0, 0, 0, 5); @@ -1500,10 +1504,12 @@ 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) { + int error; + show_mptmod_ver(my_NAME, my_VERSION); mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions); @@ -1514,37 +1520,29 @@ mptspi_init(void) mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER); mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER); - if (mpt_event_register(mptspiDoneCtx, mptspi_event_process) == 0) { - devtverboseprintk((KERN_INFO MYNAM - ": Registered for IOC event notifications\n")); - } + mpt_event_register(mptspiDoneCtx, mptspi_event_process); + mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset); - if (mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset) == 0) { - dprintk((KERN_INFO MYNAM - ": Registered for IOC reset notifications\n")); - } + error = pci_register_driver(&mptspi_driver); + if (error) + spi_release_transport(mptspi_transport_template); - return pci_register_driver(&mptspi_driver); + return error; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptspi_exit - Unregisters MPT adapter(s) - */ + * + **/ static void __exit mptspi_exit(void) { pci_unregister_driver(&mptspi_driver); mpt_reset_deregister(mptspiDoneCtx); - dprintk((KERN_INFO MYNAM - ": Deregistered for IOC reset notifications\n")); - mpt_event_deregister(mptspiDoneCtx); - dprintk((KERN_INFO MYNAM - ": Deregistered for IOC event notifications\n")); - mpt_deregister(mptspiInternalCtx); mpt_deregister(mptspiTaskCtx); mpt_deregister(mptspiDoneCtx); Index: linux-2.6.18.i386/drivers/message/fusion/rejected_ioctls/diag_buffer.c =================================================================== --- /dev/null +++ linux-2.6.18.i386/drivers/message/fusion/rejected_ioctls/diag_buffer.c @@ -0,0 +1,667 @@ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* REGISTER DIAG BUFFER Routine. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -EBUSY if previous command timout and IOC reset is not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ +static int +mptctl_register_diag_buffer (unsigned long arg) +{ + mpt_diag_register_t __user *uarg = (void __user *) arg; + mpt_diag_register_t karg; + MPT_ADAPTER *ioc; + int iocnum, rc, ii; + void * request_data; + dma_addr_t request_data_dma; + u32 request_data_sz; + MPT_FRAME_HDR *mf; + DiagBufferPostRequest_t *diag_buffer_post_request; + DiagBufferPostReply_t *diag_buffer_post_reply; + u32 tmp; + u8 buffer_type; + unsigned long timeleft; + + rc = 0; + if (copy_from_user(&karg, uarg, sizeof(mpt_diag_register_t))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in mpt_diag_register_t struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, + __FUNCTION__)); + buffer_type = karg.data.BufferType; + if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " + "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); + return -ENODEV; + } + + if (ioc->DiagBuffer_Status[buffer_type] & + MPT_DIAG_BUFFER_IS_REGISTERED) { + printk(MYIOC_s_DEBUG_FMT "%s: already has a Registered " + "buffer for buffer_type=%x\n", ioc->name, __FUNCTION__, + buffer_type); + return -EFAULT; + } + + /* Get a free request frame and save the message context. + */ + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) + return -EAGAIN; + + request_data = ioc->DiagBuffer[buffer_type]; + request_data_sz = karg.data.RequestedBufferSize; + + if (request_data) { + request_data_dma = ioc->DiagBuffer_dma[buffer_type]; + if (request_data_sz != ioc->DiagBuffer_sz[buffer_type]) { + pci_free_consistent(ioc->pcidev, + ioc->DiagBuffer_sz[buffer_type], + request_data, request_data_dma); + request_data = NULL; + } + } + + if (request_data == NULL) { + ioc->DiagBuffer_sz[buffer_type] = 0; + ioc->DiagBuffer_dma[buffer_type] = 0; + ioc->DataSize[buffer_type] = 0; + request_data = pci_alloc_consistent( + ioc->pcidev, request_data_sz, &request_data_dma); + if (request_data == NULL) { + printk(MYIOC_s_DEBUG_FMT "%s: pci_alloc_consistent" + " FAILED, (request_sz=%d)\n", ioc->name, + __FUNCTION__, request_data_sz); + mpt_free_msg_frame(ioc, mf); + return -EAGAIN; + } + ioc->DiagBuffer[buffer_type] = request_data; + ioc->DiagBuffer_sz[buffer_type] = request_data_sz; + ioc->DiagBuffer_dma[buffer_type] = request_data_dma; + } + + ioc->DiagBuffer_Status[buffer_type] = 0; + diag_buffer_post_request = (DiagBufferPostRequest_t *)mf; + diag_buffer_post_request->Function = MPI_FUNCTION_DIAG_BUFFER_POST; + diag_buffer_post_request->ChainOffset = 0; + diag_buffer_post_request->BufferType = karg.data.BufferType; + diag_buffer_post_request->TraceLevel = ioc->TraceLevel[buffer_type] = + karg.data.TraceLevel; + diag_buffer_post_request->MsgFlags = 0; + diag_buffer_post_request->Reserved1 = 0; + diag_buffer_post_request->Reserved2 = 0; + diag_buffer_post_request->Reserved3 = 0; + diag_buffer_post_request->BufferAddress.High = 0; + if (buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED) + ioc->ExtendedType[buffer_type] = karg.data.ExtendedType; + else + ioc->ExtendedType[buffer_type] = 0; + diag_buffer_post_request->ExtendedType = + cpu_to_le32(ioc->ExtendedType[buffer_type]); + ioc->UniqueId[buffer_type] = karg.data.UniqueId; + diag_buffer_post_request->BufferLength = cpu_to_le32(request_data_sz); + for (ii = 0; ii < 4; ii++) { + ioc->ProductSpecific[buffer_type][ii] = + karg.data.ProductSpecific[ii]; + diag_buffer_post_request->ProductSpecific[ii] = + cpu_to_le32(ioc->ProductSpecific[buffer_type][ii]); + } + + tmp = request_data_dma & 0xFFFFFFFF; + diag_buffer_post_request->BufferAddress.Low = cpu_to_le32(tmp); + if (ioc->sg_addr_size == sizeof(u64)) { + tmp = (u32)((u64)request_data_dma >> 32); + diag_buffer_post_request->BufferAddress.High = cpu_to_le32(tmp); + } + + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, + diag_buffer_post_request->MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) + mpt_put_msg_frame(mptctl_id, ioc, mf); + timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, + MPT_IOCTL_DEFAULT_TIMEOUT*HZ); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, + __FUNCTION__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; + } + if (!timeleft) + mptctl_timeout_expired(ioc, mf); + goto out; + } + + /* process the completed Reply Message Frame */ + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n", + ioc->name, __FUNCTION__, ioc->ioctl_cmds.status)); + rc = -EFAULT; + goto out; + } + + diag_buffer_post_reply = (DiagBufferPostReply_t *)ioc->ioctl_cmds.reply; + if (le16_to_cpu(diag_buffer_post_reply->IOCStatus) == + MPI_IOCSTATUS_SUCCESS) { + if (diag_buffer_post_reply->MsgLength > 5) + ioc->DataSize[buffer_type] = + le32_to_cpu(diag_buffer_post_reply->TransferLength); + ioc->DiagBuffer_Status[buffer_type] |= + MPT_DIAG_BUFFER_IS_REGISTERED; + } else { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x " + "IOCLogInfo=%x\n", ioc->name, __FUNCTION__, + diag_buffer_post_reply->IOCStatus, + diag_buffer_post_reply->IOCLogInfo)); + rc = -EFAULT; + } + + out: + + CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); + if (rc) + pci_free_consistent(ioc->pcidev, request_data_sz, + request_data, request_data_dma); + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* RELEASE DIAG BUFFER Routine. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -EBUSY if previous command timout and IOC reset is not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ +static int +mptctl_release_diag_buffer (unsigned long arg) +{ + mpt_diag_release_t __user *uarg = (void __user *) arg; + mpt_diag_release_t karg; + MPT_ADAPTER *ioc; + void * request_data; + int iocnum, rc; + MPT_FRAME_HDR *mf; + DiagReleaseRequest_t *diag_release; + DiagReleaseReply_t *diag_release_reply; + u8 buffer_type; + unsigned long timeleft; + + rc = 0; + if (copy_from_user(&karg, uarg, sizeof(mpt_diag_release_t))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in mpt_diag_release_t struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, + __FUNCTION__)); + buffer_type = karg.data.UniqueId & 0x000000ff; + if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " + "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); + return -ENODEV; + } + + if ((ioc->DiagBuffer_Status[buffer_type] & + MPT_DIAG_BUFFER_IS_REGISTERED) == 0 ) { + printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not " + "registered\n", ioc->name, __FUNCTION__, buffer_type); + return -EFAULT; + } + + if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { + printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n", + ioc->name, __FUNCTION__, karg.data.UniqueId); + return -EFAULT; + } + + if (ioc->DiagBuffer_Status[buffer_type] & MPT_DIAG_BUFFER_IS_RELEASED) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x " + "is already released\n", ioc->name, __FUNCTION__, + buffer_type)); + return rc; + } + + request_data = ioc->DiagBuffer[buffer_type]; + + if (request_data == NULL) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " + "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); + return -ENODEV; + } + + /* Get a free request frame and save the message context. + */ + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) + return -EAGAIN; + + diag_release = (DiagReleaseRequest_t *)mf; + diag_release->Function = MPI_FUNCTION_DIAG_RELEASE; + diag_release->BufferType = buffer_type; + diag_release->ChainOffset = 0; + diag_release->Reserved1 = 0; + diag_release->Reserved2 = 0; + diag_release->Reserved3 = 0; + diag_release->MsgFlags = 0; + + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, + diag_release->MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) + mpt_put_msg_frame(mptctl_id, ioc, mf); + timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, + MPT_IOCTL_DEFAULT_TIMEOUT*HZ); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, + __FUNCTION__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; + } + if (!timeleft) + mptctl_timeout_expired(ioc, mf); + goto out; + } + + /* process the completed Reply Message Frame */ + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n", + ioc->name, __FUNCTION__, ioc->ioctl_cmds.status)); + rc = -EFAULT; + goto out; + } + + diag_release_reply = (DiagReleaseReply_t *)ioc->ioctl_cmds.reply; + if (le16_to_cpu(diag_release_reply->IOCStatus) != + MPI_IOCSTATUS_SUCCESS) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x " + "IOCLogInfo=%x\n", + ioc->name, __FUNCTION__, diag_release_reply->IOCStatus, + diag_release_reply->IOCLogInfo)); + rc = -EFAULT; + } else + ioc->DiagBuffer_Status[buffer_type] |= + MPT_DIAG_BUFFER_IS_RELEASED; + + out: + + CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* UNREGISTER DIAG BUFFER Routine. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -EBUSY if previous command timout and IOC reset is not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ +static int +mptctl_unregister_diag_buffer (unsigned long arg) +{ + mpt_diag_unregister_t __user *uarg = (void __user *) arg; + mpt_diag_unregister_t karg; + MPT_ADAPTER *ioc; + int iocnum; + void * request_data; + dma_addr_t request_data_dma; + u32 request_data_sz; + u8 buffer_type; + + if (copy_from_user(&karg, uarg, sizeof(mpt_diag_unregister_t))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in mpt_diag_unregister_t struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, + __FUNCTION__)); + buffer_type = karg.data.UniqueId & 0x000000ff; + if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " + "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); + return -ENODEV; + } + + if ((ioc->DiagBuffer_Status[buffer_type] & + MPT_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not " + "registered\n", ioc->name, __FUNCTION__, buffer_type); + return -EFAULT; + } + if ((ioc->DiagBuffer_Status[buffer_type] & + MPT_DIAG_BUFFER_IS_RELEASED) == 0) { + printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x has not been " + "released\n", ioc->name, __FUNCTION__, buffer_type); + return -EFAULT; + } + + if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { + printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n", + ioc->name, __FUNCTION__, karg.data.UniqueId); + return -EFAULT; + } + + request_data = ioc->DiagBuffer[buffer_type]; + if (!request_data) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " + "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); + return -ENODEV; + } + + request_data_sz = ioc->DiagBuffer_sz[buffer_type]; + request_data_dma = ioc->DiagBuffer_dma[buffer_type]; + pci_free_consistent(ioc->pcidev, request_data_sz, + request_data, request_data_dma); + ioc->DiagBuffer[buffer_type] = NULL; + ioc->DiagBuffer_Status[buffer_type] = 0; + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* QUERY DIAG BUFFER Routine. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -EBUSY if previous command timout and IOC reset is not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ +static int +mptctl_query_diag_buffer (unsigned long arg) +{ + mpt_diag_query_t __user *uarg = (void __user *)arg; + mpt_diag_query_t karg; + MPT_ADAPTER *ioc; + void * request_data; + int iocnum, ii, rc; + u8 buffer_type; + + rc = -EFAULT; + if (copy_from_user(&karg, uarg, sizeof(mpt_diag_query_t))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in mpt_diag_query_t struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + karg.data.Flags = 0; + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + goto out; + } + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, + __FUNCTION__)); + buffer_type = karg.data.BufferType; + if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " + "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); + goto out; + } + + if ((ioc->DiagBuffer_Status[buffer_type] & + MPT_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not " + "registered\n", ioc->name, __FUNCTION__, buffer_type); + goto out; + } + + if (karg.data.UniqueId & 0xffffff00) { + if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { + printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not " + "registered\n", ioc->name, __FUNCTION__, + karg.data.UniqueId); + goto out; + } + } + + request_data = ioc->DiagBuffer[buffer_type]; + if (!request_data) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " + "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); + goto out; + } + + rc = 0; + if (buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED) { + if (karg.data.ExtendedType != ioc->ExtendedType[buffer_type]) + goto out; + } else + karg.data.ExtendedType = 0; + + if (ioc->DiagBuffer_Status[buffer_type] & MPT_DIAG_BUFFER_IS_RELEASED) + karg.data.Flags = 3; + else + karg.data.Flags = 7; + karg.data.TraceLevel = ioc->TraceLevel[buffer_type]; + for (ii = 0; ii < 4; ii++) + karg.data.ProductSpecific[ii] = + ioc->ProductSpecific[buffer_type][ii]; + karg.data.DataSize = ioc->DiagBuffer_sz[buffer_type]; + karg.data.DriverAddedBufferSize = 0; + karg.data.UniqueId = ioc->UniqueId[buffer_type]; + + out: + if (copy_to_user(uarg, &karg, sizeof(mpt_diag_query_t))) { + printk(MYIOC_s_ERR_FMT "%s Unable to write mpt_diag_query_t " + "data @ %p\n", ioc->name, __FUNCTION__, uarg); + return -EFAULT; + } + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* READ DIAG BUFFER Routine. + * + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable + * -EBUSY if previous command timout and IOC reset is not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ +static int +mptctl_read_diag_buffer (unsigned long arg) +{ + mpt_diag_read_buffer_t __user *uarg = (void __user *) arg; + mpt_diag_read_buffer_t karg; + MPT_ADAPTER *ioc; + void *request_data, *diagData; + dma_addr_t request_data_dma; + DiagBufferPostRequest_t *diag_buffer_post_request; + DiagBufferPostReply_t *diag_buffer_post_reply; + MPT_FRAME_HDR *mf; + int iocnum, rc, ii; + u8 buffer_type; + u32 tmp; + unsigned long timeleft; + + rc = 0; + if (copy_from_user(&karg, uarg, sizeof(mpt_diag_read_buffer_t))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in mpt_diag_read_buffer_t struct @ %p\n", + __FILE__, __LINE__, __FUNCTION__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", + __FILE__, __FUNCTION__, __LINE__, iocnum); + return -ENODEV; + } + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, + __FUNCTION__)); + buffer_type = karg.data.UniqueId & 0x000000ff; + if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability " + "for buffer_type=%x\n", ioc->name, __FUNCTION__, + buffer_type); + return -EFAULT; + } + + if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { + printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n", + ioc->name, __FUNCTION__, karg.data.UniqueId); + return -EFAULT; + } + + request_data = ioc->DiagBuffer[buffer_type]; + if (!request_data) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " + "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); + return -EFAULT; + } + + diagData = (void *)(request_data + karg.data.StartingOffset); + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: diagData=%p " + "request_data=%p StartingOffset=%x\n", ioc->name, __FUNCTION__, + diagData, request_data, karg.data.StartingOffset)); + + if (copy_to_user((void __user *)&uarg->data.DiagnosticData[0], + diagData, karg.data.BytesToRead)) { + printk(MYIOC_s_ERR_FMT "%s: Unable to write " + "mpt_diag_read_buffer_t data @ %p\n", ioc->name, + __FUNCTION__, diagData); + return -EFAULT; + } + + if ((karg.data.Flags & MPI_FW_DIAG_FLAG_REREGISTER) == 0) + goto out; + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Reregister " + "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type)); + if ((ioc->DiagBuffer_Status[buffer_type] & + MPT_DIAG_BUFFER_IS_RELEASED) == 0) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x " + "is still registered\n", ioc->name, __FUNCTION__, + buffer_type)); + return rc; + } + /* Get a free request frame and save the message context. + */ + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) + return -EAGAIN; + + diag_buffer_post_request = (DiagBufferPostRequest_t *)mf; + diag_buffer_post_request->Function = MPI_FUNCTION_DIAG_BUFFER_POST; + diag_buffer_post_request->ChainOffset = 0; + diag_buffer_post_request->BufferType = buffer_type; + diag_buffer_post_request->TraceLevel = + ioc->TraceLevel[buffer_type]; + diag_buffer_post_request->MsgFlags = 0; + diag_buffer_post_request->Reserved1 = 0; + diag_buffer_post_request->Reserved2 = 0; + diag_buffer_post_request->Reserved3 = 0; + diag_buffer_post_request->BufferAddress.High = 0; + if ( buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED ) + diag_buffer_post_request->ExtendedType = + cpu_to_le32(ioc->ExtendedType[buffer_type]); + diag_buffer_post_request->BufferLength = + cpu_to_le32(ioc->DiagBuffer_sz[buffer_type]); + for (ii = 0; ii < 4; ii++) + diag_buffer_post_request->ProductSpecific[ii] = + cpu_to_le32(ioc->ProductSpecific[buffer_type][ii]); + request_data_dma = ioc->DiagBuffer_dma[buffer_type]; + tmp = request_data_dma & 0xFFFFFFFF; + diag_buffer_post_request->BufferAddress.Low = cpu_to_le32(tmp); + if (ioc->sg_addr_size == sizeof(u64)) { + tmp = (u32)((u64)request_data_dma >> 32); + diag_buffer_post_request->BufferAddress.High = cpu_to_le32(tmp); + } + + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, + diag_buffer_post_request->MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) + mpt_put_msg_frame(mptctl_id, ioc, mf); + timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, + MPT_IOCTL_DEFAULT_TIMEOUT*HZ); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, + __FUNCTION__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; + } + if (!timeleft) + mptctl_timeout_expired(ioc, mf); + goto out; + } + + /* process the completed Reply Message Frame */ + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n", + ioc->name, __FUNCTION__, ioc->ioctl_cmds.status)); + rc = -EFAULT; + } + + diag_buffer_post_reply = (DiagBufferPostReply_t *)ioc->ioctl_cmds.reply; + if (le16_to_cpu(diag_buffer_post_reply->IOCStatus) == + MPI_IOCSTATUS_SUCCESS) { + if (diag_buffer_post_reply->MsgLength > 5) + ioc->DataSize[buffer_type] = + le32_to_cpu(diag_buffer_post_reply->TransferLength); + ioc->DiagBuffer_Status[buffer_type] |= + MPT_DIAG_BUFFER_IS_REGISTERED; + } else { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x " + "IOCLogInfo=%x\n", ioc->name, __FUNCTION__, + diag_buffer_post_reply->IOCStatus, + diag_buffer_post_reply->IOCLogInfo)); + rc = -EFAULT; + } + + out: + CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); + return rc; +} Index: linux-2.6.18.i386/drivers/message/fusion/rejected_ioctls/diag_buffer.h =================================================================== --- /dev/null +++ linux-2.6.18.i386/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;