--- /dev/null
+CONFIG_FUSION_MAX_FC_SGE=256
+# CONFIG_FUSION_LOGGING is not set
-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.
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.
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.
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_LOGGING
bool "Fusion MPT logging facility"
- depends on FUSION
---help---
This turns on a logging facility that can be used to debug a number
of Fusion MPT related problems.
echo [level] > /sys/class/scsi_host/host#/debug_level
- There are various debug levels that an be found in the source:
+ There are various debug levels that can be found in the source:
file:drivers/message/fusion/mptdebug.h
-endmenu
+endif # FUSION
-# Fusion MPT drivers; recognized debug defines...
+#
+# LSI Logic mpt fusion
+#
+
+# csmi ioctls enable
+EXTRA_CFLAGS += -DCPQ_CIM
+EXTRA_CFLAGS += -DDIAG_BUFFER_SUPPORT
+
+EXTRA_CFLAGS += -DCONFIG_FUSION_LOGGING
# enable verbose logging
# CONFIG_FUSION_LOGGING needs to be enabled in Kconfig
#EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE
-
-#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
-
obj-$(CONFIG_FUSION_SPI) += mptbase.o mptscsih.o mptspi.o
obj-$(CONFIG_FUSION_FC) += mptbase.o mptscsih.o mptfc.o
obj-$(CONFIG_FUSION_SAS) += mptbase.o mptscsih.o mptsas.o
--- /dev/null
+/*
+ * linux/drivers/message/fusion/csmi/csmisas.c
+ * For use with LSI Logic PCI chip/adapter(s)
+ * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ * Copyright (c) 1999-2007 LSI Logic 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 Logic Corporation: Fusion MPT Driver "MPT_LINUX_VERSION_COMMON
+#define csmisas_is_this_sas_cntr(ioc) (ioc->bus_type == SAS) ? 1 : 0
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+#define __user
+#include <asm/div64.h>
+#endif
+
+static int csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus,
+ u8 VolumeId, pMpiRaidActionReply_t reply);
+static u8 map_sas_status_to_csmi(u8 mpi_sas_status);
+
+/**
+ * reverse_byte_order64
+ *
+ * @data64
+ *
+ **/
+static u64
+reverse_byte_order64(u64 data64)
+{
+ int i;
+ u64 rc;
+ u8 *inWord = (u8*)&data64, *outWord = (u8*)&rc;
+
+ for (i = 0 ; i < 8 ; i++)
+ outWord[i] = inWord[7-i];
+
+ return rc;
+}
+
+/**
+ * csmisas_is_sata
+ *
+ * @phys_disk
+ *
+ **/
+static int
+csmisas_is_sata(RaidPhysDiskPage0_t *phys_disk)
+{
+ if ((phys_disk->ExtDiskIdentifier[0] == 'A') &&
+ (phys_disk->ExtDiskIdentifier[1] == 'T') &&
+ (phys_disk->ExtDiskIdentifier[2] == 'A'))
+ return 1;
+ else
+ return 0;
+}
+
+/**
+ * csmisas_is_end_device
+ *
+ * @attached
+ *
+ **/
+static inline int
+csmisas_is_end_device(struct mptsas_devinfo * attached)
+{
+ if ((attached->sas_address) &&
+ (attached->device_info &
+ MPI_SAS_DEVICE_INFO_END_DEVICE) &&
+ ((attached->device_info &
+ MPI_SAS_DEVICE_INFO_SSP_TARGET) |
+ (attached->device_info &
+ MPI_SAS_DEVICE_INFO_STP_TARGET) |
+ (attached->device_info &
+ MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
+ return 1;
+ else
+ return 0;
+}
+
+/**
+ * csmisas_is_phys_disk
+ *
+ * returns (1) success (0) fail - not a phys disk
+ **/
+static int
+csmisas_is_phys_disk(MPT_ADAPTER *ioc, int channel, int id)
+{
+ struct inactive_raid_component_info *component_info;
+ int i;
+ int rc = 0;
+
+ if (!ioc->raid_data.pIocPg3)
+ goto out;
+ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+ if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
+ (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
+ rc = 1;
+ goto out;
+ }
+ }
+
+ /*
+ * Check inactive list for matching phys disks
+ */
+ if (list_empty(&ioc->raid_data.inactive_list))
+ goto out;
+
+ down(&ioc->raid_data.inactive_list_mutex);
+ list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
+ list) {
+ if ((component_info->d.PhysDiskID == id) &&
+ (component_info->d.PhysDiskBus == channel))
+ rc = 1;
+ }
+ up(&ioc->raid_data.inactive_list_mutex);
+
+ out:
+ return rc;
+}
+
+/**
+ * csmisas_raid_id_to_num
+ *
+ * Obtains the phys disk num for given H:C:T nexus
+ *
+ * input (channel/id)
+ * output (phys disk number - used by SCSI_IO_PASSTHRU to access hidden component)
+ *
+ * returns - signed return means failure
+ **/
+static s8
+csmisas_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+ struct inactive_raid_component_info *component_info;
+ int i;
+ s8 rc = -ENXIO;
+
+ if (!ioc->raid_data.pIocPg3)
+ goto out;
+ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+ if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
+ (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
+ rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
+ goto out;
+ }
+ }
+
+ /*
+ * Check inactive list for matching phys disks
+ */
+ if (list_empty(&ioc->raid_data.inactive_list))
+ goto out;
+
+ down(&ioc->raid_data.inactive_list_mutex);
+ list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
+ list) {
+ if ((component_info->d.PhysDiskID == id) &&
+ (component_info->d.PhysDiskBus == channel))
+ rc = component_info->d.PhysDiskNum;
+ }
+ up(&ioc->raid_data.inactive_list_mutex);
+
+ out:
+ return rc;
+}
+
+/**
+ * csmisas_get_device_component_by_os
+ *
+ * Obtain device component object by operating system mapping
+ *
+ * @ioc
+ * @channel
+ * @id
+ *
+ **/
+static struct sas_device_info *
+csmisas_get_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+ struct sas_device_info *sas_info, *p;
+
+ sas_info = NULL;
+
+ down(&ioc->sas_device_info_mutex);
+ list_for_each_entry(p, &ioc->sas_device_info_list, list) {
+ if (p->os.channel == channel && p->os.id == id) {
+ sas_info = p;
+ goto out;
+ }
+ }
+
+ out:
+ up(&ioc->sas_device_info_mutex);
+ return sas_info;
+}
+
+/**
+ * csmisas_get_device_component
+ *
+ * Obtain device component object by firmware system mapping
+ *
+ * @ioc
+ * @channel
+ * @id
+ *
+ **/
+static struct sas_device_info *
+csmisas_get_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+ struct sas_device_info *sas_info, *p;
+
+ sas_info = NULL;
+
+ down(&ioc->sas_device_info_mutex);
+ list_for_each_entry(p, &ioc->sas_device_info_list, list) {
+ if (p->fw.channel == channel && p->fw.id == id) {
+ sas_info = p;
+ goto out;
+ }
+ }
+
+ out:
+ up(&ioc->sas_device_info_mutex);
+ return sas_info;
+}
+
+
+/**
+ * csmisas_get_device_component_by_sas_addr
+ *
+ * Obtain device component object by sas address
+ *
+ * @ioc
+ * @channel
+ * @id
+ *
+ **/
+static struct sas_device_info *
+csmisas_get_device_component_by_sas_addr(MPT_ADAPTER *ioc, u64 sas_address)
+{
+ struct sas_device_info *sas_info, *p;
+
+ sas_info = NULL;
+
+ down(&ioc->sas_device_info_mutex);
+ list_for_each_entry(p, &ioc->sas_device_info_list, list) {
+ if (p->sas_address == sas_address) {
+ sas_info = p;
+ goto out;
+ }
+ }
+
+ out:
+ up(&ioc->sas_device_info_mutex);
+ return sas_info;
+}
+
+/**
+ * csmisas_send_command_wait
+ *
+ * Send mf to firmware
+ *
+ * @ioc
+ * @mf
+ * @timeout - timeout
+ *
+ * Return: 0 for success
+ * non-zero, failure
+ **/
+static int
+csmisas_send_command_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout)
+{
+ int rc;
+ unsigned long timeleft;
+
+ timeout = max_t(unsigned long, MPT_IOCTL_DEFAULT_TIMEOUT, timeout);
+ rc = 0;
+ timeleft = 0;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+
+ INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status)
+ ioc->ioctl_cmds.wait_done = 0;
+ ioc->ioctl_cmds.timer.expires = jiffies + (MPT_JIFFY * timeout);
+ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE;
+ ADD_TIMER(&ioc->ioctl_cmds.timer);
+ mpt_put_msg_frame(mptctl_id, ioc, mf);
+ WAIT_EVENT(mptctl_wait, ioc->ioctl_cmds.wait_done);
+
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+
+ INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status)
+ ioc->ioctl_cmds.wait_done = 0;
+ mpt_put_msg_frame(mptctl_id, ioc, mf);
+
+ if ((wait_event_timeout(mptctl_wait,
+ ioc->ioctl_cmds.wait_done == 1, HZ * timeout) <=0) &&
+ ioc->ioctl_cmds.wait_done != 1 ) {
+ mptctl_timeout_expired(ioc,mf);
+ mpt_free_msg_frame(ioc, mf);
+ rc = -1;
+ }
+
+#else
+
+ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
+ mf->u.hdr.MsgContext);
+ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
+ mpt_put_msg_frame(mptctl_id, ioc, mf);
+ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, timeout*HZ);
+ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ rc = -1;
+ printk("%s: failed\n", __FUNCTION__);
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+ mpt_free_msg_frame(ioc, mf);
+ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+ return rc;
+ }
+ if (!timeleft)
+ mptctl_timeout_expired(ioc, mf);
+ }
+ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
+#endif
+ return rc;
+}
+
+/**
+ * csmisas_send_handshake_wait
+ *
+ * Handshake a mf to firmware
+ *
+ * @ioc
+ * @mf
+ * @mf_size
+ * @timeout - timeout
+ *
+ * Return: 0 for success
+ * non-zero, failure
+ **/
+static int
+csmisas_send_handshake_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout)
+{
+ int rc;
+ unsigned long timeleft;
+
+ timeout = max_t(unsigned long, MPT_IOCTL_DEFAULT_TIMEOUT, timeout);
+ rc = 0;
+ timeleft = 0;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+
+ INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status)
+ ioc->taskmgmt_cmds.timer.expires = jiffies + (MPT_JIFFY*timeout);
+ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE;
+ ioc->taskmgmt_cmds.wait_done = 0;
+ ADD_TIMER(&ioc->taskmgmt_cmds.timer);
+ rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc,
+ sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP);
+ if (rc != 0)
+ return rc;
+ WAIT_EVENT(mptctl_taskmgmt_wait, ioc->taskmgmt_cmds.wait_done);
+
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+
+ INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status)
+ ioc->taskmgmt_cmds.wait_done = 0;
+ rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc,
+ sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP);
+ if (rc != 0)
+ return rc;
+ if ((wait_event_timeout(mptctl_taskmgmt_wait,
+ ioc->taskmgmt_cmds.wait_done == 1, HZ * timeout) <=0) &&
+ ioc->taskmgmt_cmds.wait_done != 1 ) {
+ mptctl_timeout_expired(ioc, mf);
+ mpt_free_msg_frame(ioc, mf);
+ rc = -1;
+ }
+
+#else
+ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+ mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf);
+ timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ rc = -1;
+ printk("%s: failed\n", __FUNCTION__);
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+ mpt_free_msg_frame(ioc, mf);
+ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+ return rc;
+ }
+ if (!timeleft)
+ mptctl_timeout_expired(ioc, mf);
+ }
+#endif
+ return rc;
+}
+
+/**
+ * csmisas_get_number_hotspares - returns num hot spares in this ioc
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * Return: number of hotspares
+ *
+ **/
+static int
+csmisas_get_number_hotspares(MPT_ADAPTER *ioc)
+{
+ ConfigPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ IOCPage5_t *buffer = NULL;
+ dma_addr_t dma_handle;
+ int data_sz;
+ int rc;
+
+ memset(&hdr, 0, sizeof(ConfigPageHeader_t));
+ memset(&cfg, 0, sizeof(CONFIGPARMS));
+
+ rc = 0;
+ data_sz = 0;
+ hdr.PageNumber = 5;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_IOC;
+ cfg.cfghdr.hdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+ if (mpt_config(ioc, &cfg) != 0)
+ goto get_ioc_pg5;
+
+ if (hdr.PageLength == 0)
+ goto get_ioc_pg5;
+
+ data_sz = hdr.PageLength * 4;
+ buffer = (IOCPage5_t *) pci_alloc_consistent(ioc->pcidev,
+ data_sz, &dma_handle);
+ if (!buffer)
+ goto get_ioc_pg5;
+
+ memset((u8 *)buffer, 0, data_sz);
+ cfg.physAddr = dma_handle;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if (mpt_config(ioc, &cfg) != 0)
+ goto get_ioc_pg5;
+
+ rc = buffer->NumHotSpares;
+
+ get_ioc_pg5:
+
+ if (buffer)
+ pci_free_consistent(ioc->pcidev, data_sz,
+ (u8 *) buffer, dma_handle);
+
+ return rc;
+}
+
+
+/**
+ * csmisas_get_ioc_pg5 - ioc Page 5 hot spares
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @pIocPage5: ioc page 5
+ * @data_size: expected data size(units=bytes)
+ *
+ * Return: 0 for success
+ * -ENOMEM if no memory available
+ * -EPERM if not allowed due to ISR context
+ * -EAGAIN if no msg frames currently available
+ * -EFAULT for non-successful reply or no reply (timeout)
+ **/
+static int
+csmisas_get_ioc_pg5(MPT_ADAPTER *ioc, IOCPage5_t *iocPage5, int data_size)
+{
+ ConfigPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ IOCPage5_t *buffer = NULL;
+ dma_addr_t dma_handle;
+ int data_sz;
+ int rc;
+
+ memset(&hdr, 0, sizeof(ConfigPageHeader_t));
+ memset(&cfg, 0, sizeof(CONFIGPARMS));
+
+ rc = 0;
+ data_sz = 0;
+ hdr.PageNumber = 5;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_IOC;
+ cfg.cfghdr.hdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0)
+ goto get_ioc_pg5;
+
+ if (hdr.PageLength == 0) {
+ rc = -EFAULT;
+ goto get_ioc_pg5;
+ }
+
+ data_sz = hdr.PageLength * 4;
+ buffer = (IOCPage5_t *) pci_alloc_consistent(ioc->pcidev,
+ data_sz, &dma_handle);
+ if (!buffer) {
+ rc = -ENOMEM;
+ goto get_ioc_pg5;
+ }
+
+ memset((u8 *)buffer, 0, data_sz);
+ cfg.physAddr = dma_handle;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0)
+ goto get_ioc_pg5;
+
+ memcpy(iocPage5, buffer, data_size);
+
+ get_ioc_pg5:
+
+ if (buffer)
+ pci_free_consistent(ioc->pcidev, data_sz,
+ (u8 *) buffer, dma_handle);
+
+ return rc;
+}
+
+/**
+ * csmisas_sas_device_pg0 - sas device page 0
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @mptsas_devinfo: structure found in mptsas.h
+ * @form, @form_specific - defines the Page Address field in the config page
+ * (pls refer to chapter 5.1 in the mpi spec)
+ *
+ * Return: 0 for success
+ * -ENOMEM if no memory available
+ * -EPERM if not allowed due to ISR context
+ * -EAGAIN if no msg frames currently available
+ * -EFAULT for non-successful reply or no reply (timeout)
+ **/
+static int
+csmisas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
+ u32 form, u32 form_specific)
+{
+ ConfigExtendedPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ SasDevicePage0_t *buffer;
+ dma_addr_t dma_handle;
+ u64 sas_address;
+ int rc;
+
+ rc = 0;
+ hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 0;
+ hdr.Reserved1 = 0;
+ hdr.Reserved2 = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.pageAddr = form + form_specific;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+ cfg.timeout = 10;
+
+ memset(device_info, 0, sizeof(struct mptsas_devinfo));
+ if ((rc = mpt_config(ioc, &cfg)) != 0)
+ goto out;
+
+ if (!hdr.ExtPageLength) {
+ rc = -ENXIO;
+ goto out;
+ }
+
+ buffer = pci_alloc_consistent(ioc->pcidev,
+ hdr.ExtPageLength * 4, &dma_handle);
+ if (!buffer) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ cfg.physAddr = dma_handle;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0)
+ goto out_free_consistent;
+
+ device_info->handle = le16_to_cpu(buffer->DevHandle);
+ device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
+ device_info->handle_enclosure =
+ le16_to_cpu(buffer->EnclosureHandle);
+ device_info->slot = le16_to_cpu(buffer->Slot);
+ device_info->phy_id = buffer->PhyNum;
+ device_info->port_id = buffer->PhysicalPort;
+ device_info->id = buffer->TargetID;
+ device_info->channel = buffer->Bus;
+ memcpy(&sas_address, &buffer->SASAddress, sizeof(u64));
+ device_info->sas_address = le64_to_cpu(sas_address);
+ device_info->device_info =
+ le32_to_cpu(buffer->DeviceInfo);
+
+ out_free_consistent:
+ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+ buffer, dma_handle);
+ out:
+ return rc;
+}
+
+/**
+ * Routine for the CSMI Sas Get Driver Info command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_driver_info(unsigned long arg)
+{
+
+ CSMI_SAS_DRIVER_INFO_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_DRIVER_INFO_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+
+ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s - "
+ "Unable to read in csmi_sas_get_driver_info_buffer struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ /* Fill in the data and return the structure to the calling
+ * program
+ */
+ memcpy( karg.Information.szName, MPT_MISCDEV_BASENAME,
+ sizeof(MPT_MISCDEV_BASENAME));
+ memcpy( karg.Information.szDescription, MPT_CSMI_DESCRIPTION,
+ sizeof(MPT_CSMI_DESCRIPTION));
+
+ karg.Information.usMajorRevision = MPT_LINUX_MAJOR_VERSION;
+ karg.Information.usMinorRevision = MPT_LINUX_MINOR_VERSION;
+ karg.Information.usBuildRevision = MPT_LINUX_BUILD_VERSION;
+ karg.Information.usReleaseRevision = MPT_LINUX_RELEASE_VERSION;
+
+ karg.Information.usCSMIMajorRevision = CSMI_MAJOR_REVISION;
+ karg.Information.usCSMIMinorRevision = CSMI_MINOR_REVISION;
+
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s - "
+ "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI_SAS_GET_CNTLR_CONFIG command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_cntlr_config(unsigned long arg)
+{
+
+ CSMI_SAS_CNTLR_CONFIG_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_CNTLR_CONFIG_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+ u64 mem_phys;
+
+ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_CONFIG_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s - "
+ "Unable to read in csmi_sas_get_cntlr_config_buffer struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ /* Clear the struct before filling in data. */
+ memset( &karg.Configuration, 0, sizeof(CSMI_SAS_CNTLR_CONFIG));
+
+ /* Fill in the data and return the structure to the calling
+ * program
+ */
+
+ karg.Configuration.uBaseIoAddress = ioc->pio_mem_phys;
+ karg.Configuration.BaseMemoryAddress.uLowPart = ioc->mem_phys;
+ if (sizeof(ioc->mem_phys) == sizeof(u64)) {
+ mem_phys = ioc->mem_phys;
+ karg.Configuration.BaseMemoryAddress.uHighPart =
+ (u32)(mem_phys >> 32);
+ }
+
+ karg.Configuration.uBoardID = (ioc->pcidev->subsystem_device << 16) |
+ (ioc->pcidev->subsystem_vendor);
+
+ karg.Configuration.usSlotNumber =
+ (ioc->pci_slot_number = 0xff) ?
+ SLOT_NUMBER_UNKNOWN : ioc->pci_slot_number;
+ karg.Configuration.bControllerClass = CSMI_SAS_CNTLR_CLASS_HBA;
+ karg.Configuration.bIoBusType = CSMI_SAS_BUS_TYPE_PCI;
+ karg.Configuration.BusAddress.PciAddress.bBusNumber =
+ ioc->pcidev->bus->number;
+ karg.Configuration.BusAddress.PciAddress.bDeviceNumber =
+ PCI_SLOT(ioc->pcidev->devfn);
+ karg.Configuration.BusAddress.PciAddress.bFunctionNumber =
+ PCI_FUNC(ioc->pcidev->devfn);
+ karg.Configuration.BusAddress.PciAddress.bReserved = 0;
+ memcpy( &karg.Configuration.szSerialNumber, ioc->board_tracer, 16 );
+ karg.Configuration.usMajorRevision = ioc->facts.FWVersion.Struct.Major;
+ karg.Configuration.usMinorRevision = ioc->facts.FWVersion.Struct.Minor;
+ karg.Configuration.usBuildRevision = ioc->facts.FWVersion.Struct.Unit;
+ karg.Configuration.usReleaseRevision = ioc->facts.FWVersion.Struct.Dev;
+ karg.Configuration.usBIOSMajorRevision =
+ (ioc->biosVersion & 0xFF000000) >> 24;
+ karg.Configuration.usBIOSMinorRevision =
+ (ioc->biosVersion & 0x00FF0000) >> 16;
+ karg.Configuration.usBIOSBuildRevision =
+ (ioc->biosVersion & 0x0000FF00) >> 8;
+ karg.Configuration.usBIOSReleaseRevision =
+ (ioc->biosVersion & 0x000000FF);
+ karg.Configuration.uControllerFlags = CSMI_SAS_CNTLR_SAS_HBA |
+ CSMI_SAS_CNTLR_FWD_SUPPORT | CSMI_SAS_CNTLR_FWD_ONLINE |
+ CSMI_SAS_CNTLR_FWD_SRESET ;
+
+ /*
+ * Enabling CSMI_SAS_CNTLR_SAS_RAID bit when IR fw detected
+ */
+ if (ioc->ir_firmware)
+ karg.Configuration.uControllerFlags |= CSMI_SAS_CNTLR_SAS_RAID;
+
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ /* All Rrom entries will be zero. Skip them. */
+ /* bReserved will also be zeros. */
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s - "
+ "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get Controller Status command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_cntlr_status(unsigned long arg)
+{
+
+ CSMI_SAS_CNTLR_STATUS_BUFFER __user *uarg = (void __user *) arg;
+ MPT_ADAPTER *ioc = NULL;
+ CSMI_SAS_CNTLR_STATUS_BUFFER karg;
+ int iocnum;
+ int rc;
+
+ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s - "
+ "Unable to read in csmi_sas_get_cntlr_status_buffer struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ /* Fill in the data and return the structure to the calling
+ * program
+ */
+
+ rc = mpt_GetIocState(ioc, 1);
+ switch (rc) {
+ case MPI_IOC_STATE_OPERATIONAL:
+ karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_GOOD;
+ karg.Status.uOfflineReason = 0;
+ break;
+
+ case MPI_IOC_STATE_FAULT:
+ karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_FAILED;
+ karg.Status.uOfflineReason = 0;
+ break;
+
+ case MPI_IOC_STATE_RESET:
+ case MPI_IOC_STATE_READY:
+ default:
+ karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_OFFLINE;
+ karg.Status.uOfflineReason =
+ CSMI_SAS_OFFLINE_REASON_INITIALIZING;
+ break;
+ }
+
+ memset(&karg.Status.bReserved, 0, 28);
+
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s - "
+ "Unable to write out csmi_sas_get_cntlr_status @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get Phy Info command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_phy_info(unsigned long arg)
+{
+ CSMI_SAS_PHY_INFO_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_PHY_INFO_BUFFER *karg;
+ MPT_ADAPTER *ioc = NULL;
+ ConfigExtendedPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ SasIOUnitPage0_t *sasIoUnitPg0;
+ dma_addr_t sasIoUnitPg0_dma;
+ int sasIoUnitPg0_data_sz;
+ SasPhyPage0_t *sasPhyPg0;
+ dma_addr_t sasPhyPg0_dma;
+ int sasPhyPg0_data_sz;
+ u16 protocol;
+ int iocnum;
+ int rc;
+ int ii;
+ u64 sas_address;
+ struct mptsas_devinfo device_info;
+ int memory_pages;
+
+ sasIoUnitPg0=NULL;
+ sasPhyPg0=NULL;
+ sasIoUnitPg0_data_sz=0;
+ sasPhyPg0_data_sz=0;
+
+ memory_pages = get_order(sizeof(CSMI_SAS_PHY_INFO_BUFFER));
+ karg = (CSMI_SAS_PHY_INFO_BUFFER *)__get_free_pages(
+ GFP_KERNEL, memory_pages);
+ if (!karg){
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to malloc CSMI_SAS_PHY_INFO_BUFFER "
+ "malloc_data_sz=%d memory_pages=%d\n",
+ __FILE__, __LINE__, __FUNCTION__,
+ (int)sizeof(CSMI_SAS_PHY_INFO_BUFFER), memory_pages);
+ return -ENOMEM;
+ }
+
+ memset(karg, 0, sizeof(*karg));
+
+ if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_PHY_INFO_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s - "
+ "Unable to read in csmisas_get_phy_info_buffer struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)karg, memory_pages);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)karg, memory_pages);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ /* Fill in the data and return the structure to the calling
+ * program
+ */
+
+ /* Issue a config request to get the number of phys
+ */
+ hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 0;
+ hdr.Reserved1 = 0;
+ hdr.Reserved2 = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.pageAddr = 0;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ /* Don't check if this failed. Already in a
+ * failure case.
+ */
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: HEADER\n"));
+ dcsmisasprintk(ioc, printk(": rc=%x\n",rc));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto sas_get_phy_info_exit;
+ }
+
+ if (hdr.ExtPageLength == 0) {
+ /* Don't check if this failed. Already in a
+ * failure case.
+ */
+ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto sas_get_phy_info_exit;
+ }
+
+ sasIoUnitPg0_data_sz = hdr.ExtPageLength * 4;
+ rc = -ENOMEM;
+
+ sasIoUnitPg0 = (SasIOUnitPage0_t *) pci_alloc_consistent(ioc->pcidev,
+ sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma);
+
+ if (!sasIoUnitPg0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto sas_get_phy_info_exit;
+ }
+
+ memset((u8 *)sasIoUnitPg0, 0, sasIoUnitPg0_data_sz);
+ cfg.physAddr = sasIoUnitPg0_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+
+ /* Don't check if this failed. Already in a
+ * failure case.
+ */
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: PAGE\n"));
+ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto sas_get_phy_info_exit;
+ }
+
+ /* Number of Phys. */
+ karg->Information.bNumberOfPhys = sasIoUnitPg0->NumPhys;
+
+ /* Fill in information for each phy. */
+ for (ii = 0; ii < karg->Information.bNumberOfPhys; ii++) {
+
+/* EDM : dump IO Unit Page 0 data*/
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n"));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
+ le16_to_cpu(sasIoUnitPg0->PhyData[ii].AttachedDeviceHandle)));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n",
+ le16_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerDevHandle)));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n",
+ sasIoUnitPg0->PhyData[ii].Port));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n",
+ sasIoUnitPg0->PhyData[ii].PortFlags));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n",
+ sasIoUnitPg0->PhyData[ii].PhyFlags));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n",
+ sasIoUnitPg0->PhyData[ii].NegotiatedLinkRate));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n",
+ le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo)));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n",
+ le32_to_cpu(sasIoUnitPg0->PhyData[ii].DiscoveryStatus)));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
+/* EDM : debug data */
+
+ /* PHY stuff. */
+ karg->Information.Phy[ii].bPortIdentifier =
+ sasIoUnitPg0->PhyData[ii].Port;
+
+ /* Get the negotiated link rate for the phy. */
+ switch (sasIoUnitPg0->PhyData[ii].NegotiatedLinkRate) {
+
+ case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
+ karg->Information.Phy[ii].bNegotiatedLinkRate =
+ CSMI_SAS_PHY_DISABLED;
+ break;
+
+ case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
+ karg->Information.Phy[ii].bNegotiatedLinkRate =
+ CSMI_SAS_LINK_RATE_FAILED;
+ break;
+
+ case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
+ break;
+
+ case MPI_SAS_IOUNIT0_RATE_1_5:
+ karg->Information.Phy[ii].bNegotiatedLinkRate =
+ CSMI_SAS_LINK_RATE_1_5_GBPS;
+ break;
+
+ case MPI_SAS_IOUNIT0_RATE_3_0:
+ karg->Information.Phy[ii].bNegotiatedLinkRate =
+ CSMI_SAS_LINK_RATE_3_0_GBPS;
+ break;
+
+ case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
+ default:
+ karg->Information.Phy[ii].bNegotiatedLinkRate =
+ CSMI_SAS_LINK_RATE_UNKNOWN;
+ break;
+ }
+
+ if (sasIoUnitPg0->PhyData[ii].PortFlags &
+ MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS) {
+ karg->Information.Phy[ii].bAutoDiscover =
+ CSMI_SAS_DISCOVER_IN_PROGRESS;
+ } else {
+ karg->Information.Phy[ii].bAutoDiscover =
+ CSMI_SAS_DISCOVER_COMPLETE;
+ }
+
+ /* Issue a config request to get
+ * phy information.
+ */
+ hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 0;
+ hdr.Reserved1 = 0;
+ hdr.Reserved2 = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.pageAddr = ii;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n"));
+ dcsmisasprintk(ioc, printk(": rc=%x\n",rc));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto sas_get_phy_info_exit;
+ }
+
+ if (hdr.ExtPageLength == 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto sas_get_phy_info_exit;
+ }
+
+ sasPhyPg0_data_sz = hdr.ExtPageLength * 4;
+ rc = -ENOMEM;
+
+ sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent(
+ ioc->pcidev, sasPhyPg0_data_sz, &sasPhyPg0_dma);
+
+ if (! sasPhyPg0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto sas_get_phy_info_exit;
+ }
+
+ memset((u8 *)sasPhyPg0, 0, sasPhyPg0_data_sz);
+ cfg.physAddr = sasPhyPg0_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n"));
+ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz,
+ (u8 *) sasPhyPg0, sasPhyPg0_dma);
+ goto sas_get_phy_info_exit;
+ }
+
+/* EDM : dump PHY Page 0 data*/
+ memcpy(&sas_address, &sasPhyPg0->SASAddress, sizeof(u64));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n"));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
+ le16_to_cpu(sasPhyPg0->AttachedDevHandle)));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
+ (unsigned long long)sas_address));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n",
+ sasPhyPg0->AttachedPhyIdentifier));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n",
+ le32_to_cpu(sasPhyPg0->AttachedDeviceInfo)));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n",
+ sasPhyPg0->ProgrammedLinkRate));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n",
+ sasPhyPg0->HwLinkRate));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n",
+ sasPhyPg0->ChangeCount));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n",
+ le32_to_cpu(sasPhyPg0->PhyInfo)));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
+/* EDM : debug data */
+
+ /* save the data */
+
+ /* Set Max hardware link rate.
+ * This value is hard coded
+ * because the HW link rate
+ * is currently being
+ * overwritten in FW.
+ */
+
+ /* Set Max hardware link rate. */
+ switch (sasPhyPg0->HwLinkRate &
+ MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
+
+ case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
+ karg->Information.Phy[ii].bMaximumLinkRate =
+ CSMI_SAS_LINK_RATE_1_5_GBPS;
+ break;
+
+ case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
+ karg->Information.Phy[ii].bMaximumLinkRate =
+ CSMI_SAS_LINK_RATE_3_0_GBPS;
+ break;
+ default:
+ break;
+ }
+
+ /* Set Max programmed link rate. */
+ switch (sasPhyPg0->ProgrammedLinkRate &
+ MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
+
+ case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
+ karg->Information.Phy[ii].bMaximumLinkRate |=
+ (CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS << 4);
+ break;
+
+ case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
+ karg->Information.Phy[ii].bMaximumLinkRate |=
+ (CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS << 4);
+ break;
+ default:
+ break;
+ }
+
+ /* Set Min hardware link rate. */
+ switch (sasPhyPg0->HwLinkRate &
+ MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
+
+ case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
+ karg->Information.Phy[ii].bMinimumLinkRate =
+ CSMI_SAS_LINK_RATE_1_5_GBPS;
+ break;
+
+ case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
+ karg->Information.Phy[ii].bMinimumLinkRate =
+ CSMI_SAS_LINK_RATE_3_0_GBPS;
+ break;
+ default:
+ break;
+ }
+
+ /* Set Min programmed link rate. */
+ switch (sasPhyPg0->ProgrammedLinkRate &
+ MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
+
+ case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
+ karg->Information.Phy[ii].bMinimumLinkRate |=
+ (CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS << 4);
+ break;
+
+ case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
+ karg->Information.Phy[ii].bMinimumLinkRate |=
+ (CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS << 4);
+ break;
+ default:
+ break;
+ }
+
+ karg->Information.Phy[ii].bPhyChangeCount = sasPhyPg0->ChangeCount;
+ if( sasPhyPg0->PhyInfo & MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY )
+ karg->Information.Phy[ii].bPhyFeatures = CSMI_SAS_PHY_VIRTUAL_SMP;
+
+ /* Fill in Attached Device
+ * Initiator Port Protocol.
+ * Bits 6:3
+ * More than one bit can be set.
+ */
+ protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x78;
+ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol = 0;
+ if (protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
+ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol =
+ CSMI_SAS_PROTOCOL_SSP;
+ if (protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
+ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |=
+ CSMI_SAS_PROTOCOL_STP;
+ if (protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
+ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |=
+ CSMI_SAS_PROTOCOL_SMP;
+ if (protocol & MPI_SAS_DEVICE_INFO_SATA_HOST)
+ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |=
+ CSMI_SAS_PROTOCOL_SATA;
+
+ /* Fill in Phy Target Port
+ * Protocol. Bits 10:7
+ * More than one bit can be set.
+ */
+ protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x780;
+ karg->Information.Phy[ii].Attached.bTargetPortProtocol = 0;
+ if (protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET)
+ karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
+ CSMI_SAS_PROTOCOL_SSP;
+ if (protocol & MPI_SAS_DEVICE_INFO_STP_TARGET)
+ karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
+ CSMI_SAS_PROTOCOL_STP;
+ if (protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET)
+ karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
+ CSMI_SAS_PROTOCOL_SMP;
+ if (protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+ karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
+ CSMI_SAS_PROTOCOL_SATA;
+
+
+ /* Fill in Attached device type */
+ switch (le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) &
+ MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
+
+ case MPI_SAS_DEVICE_INFO_NO_DEVICE:
+ karg->Information.Phy[ii].Attached.bDeviceType =
+ CSMI_SAS_NO_DEVICE_ATTACHED;
+ break;
+
+ case MPI_SAS_DEVICE_INFO_END_DEVICE:
+ karg->Information.Phy[ii].Attached.bDeviceType =
+ CSMI_SAS_END_DEVICE;
+ break;
+
+ case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
+ karg->Information.Phy[ii].Attached.bDeviceType =
+ CSMI_SAS_EDGE_EXPANDER_DEVICE;
+ break;
+
+ case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
+ karg->Information.Phy[ii].Attached.bDeviceType =
+ CSMI_SAS_FANOUT_EXPANDER_DEVICE;
+ break;
+ }
+
+ /* Identify Info. */
+ switch (le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) &
+ MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
+
+ case MPI_SAS_DEVICE_INFO_NO_DEVICE:
+ karg->Information.Phy[ii].Identify.bDeviceType =
+ CSMI_SAS_NO_DEVICE_ATTACHED;
+ break;
+
+ case MPI_SAS_DEVICE_INFO_END_DEVICE:
+ karg->Information.Phy[ii].Identify.bDeviceType =
+ CSMI_SAS_END_DEVICE;
+ break;
+
+ case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
+ karg->Information.Phy[ii].Identify.bDeviceType =
+ CSMI_SAS_EDGE_EXPANDER_DEVICE;
+ break;
+
+ case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
+ karg->Information.Phy[ii].Identify.bDeviceType =
+ CSMI_SAS_FANOUT_EXPANDER_DEVICE;
+ break;
+ }
+
+ /* Fill in Phy Initiator Port Protocol. Bits 6:3
+ * More than one bit can be set, fall through cases.
+ */
+ protocol = le32_to_cpu(
+ sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x78;
+ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol = 0;
+ if( protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR )
+ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
+ CSMI_SAS_PROTOCOL_SSP;
+ if( protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR )
+ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
+ CSMI_SAS_PROTOCOL_STP;
+ if( protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR )
+ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
+ CSMI_SAS_PROTOCOL_SMP;
+ if( protocol & MPI_SAS_DEVICE_INFO_SATA_HOST )
+ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
+ CSMI_SAS_PROTOCOL_SATA;
+
+ /* Fill in Phy Target Port Protocol. Bits 10:7
+ * More than one bit can be set, fall through cases.
+ */
+ protocol = le32_to_cpu(
+ sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x780;
+ karg->Information.Phy[ii].Identify.bTargetPortProtocol = 0;
+ if( protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET )
+ karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
+ CSMI_SAS_PROTOCOL_SSP;
+ if( protocol & MPI_SAS_DEVICE_INFO_STP_TARGET )
+ karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
+ CSMI_SAS_PROTOCOL_STP;
+ if( protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET )
+ karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
+ CSMI_SAS_PROTOCOL_SMP;
+ if( protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE )
+ karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
+ CSMI_SAS_PROTOCOL_SATA;
+
+ /* Setup SAS Address for the attached device */
+ if (sasPhyPg0->AttachedDevHandle) {
+ sas_address = reverse_byte_order64(sas_address);
+ memcpy(karg->Information.Phy[ii].Attached.bSASAddress,
+ &sas_address, sizeof(u64));
+ karg->Information.Phy[ii].Attached.bPhyIdentifier =
+ sasPhyPg0->AttachedPhyIdentifier;
+ }
+
+ /* Setup SAS Address for the parent device */
+ csmisas_sas_device_pg0(ioc, &device_info,
+ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+ sasIoUnitPg0->PhyData[ii].ControllerDevHandle);
+ sas_address = reverse_byte_order64(device_info.sas_address);
+ memcpy(karg->Information.Phy[ii].Identify.bSASAddress,
+ &sas_address, sizeof(u64));
+ karg->Information.Phy[ii].Identify.bPhyIdentifier = ii;
+
+ pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz,
+ (u8 *) sasPhyPg0, sasPhyPg0_dma);
+ }
+
+sas_get_phy_info_exit:
+
+ if (sasIoUnitPg0)
+ pci_free_consistent(ioc->pcidev, sasIoUnitPg0_data_sz,
+ (u8 *) sasIoUnitPg0, sasIoUnitPg0_dma);
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, karg,
+ sizeof(CSMI_SAS_PHY_INFO_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s - "
+ "Unable to write out csmisas_get_phy_info_buffer @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EFAULT;
+ }
+
+ free_pages((unsigned long)karg, memory_pages);
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Set PHY Info command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_set_phy_info(unsigned long arg)
+{
+ CSMI_SAS_SET_PHY_INFO_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_SET_PHY_INFO_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+
+ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_set_phy_info struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+/* TODO - implement IOCTL here */
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE;
+ dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n"));
+
+// cim_set_phy_info_exit:
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_set_phy_info @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get SCSI Address command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_scsi_address(unsigned long arg)
+{
+ CSMI_SAS_GET_SCSI_ADDRESS_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_GET_SCSI_ADDRESS_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+ u64 sas_address;
+ struct sas_device_info *sas_info;
+
+ if (copy_from_user(&karg, uarg,
+ sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_get_scsi_address struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ /* reverse byte order the sas address */
+ memcpy(&sas_address, karg.bSASAddress, sizeof(u64));
+ sas_address = reverse_byte_order64(sas_address);
+
+ /* Search the list for the matching SAS address. */
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_SCSI_ADDRESS;
+ karg.bPathId = 0;
+ karg.bTargetId = 0;
+ karg.bLun = 0;
+
+ sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address);
+ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume)
+ goto csmisas_get_scsi_address_exit;
+
+ karg.bPathId = sas_info->os.channel;
+ karg.bTargetId = sas_info->os.id;
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ csmisas_get_scsi_address_exit:
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_get_scsi_address @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get SCSI Address command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_sata_signature(unsigned long arg)
+{
+ CSMI_SAS_SATA_SIGNATURE_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_SATA_SIGNATURE_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+ int rc, jj;
+ ConfigExtendedPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ SasPhyPage0_t *sasPhyPg0;
+ dma_addr_t sasPhyPg0_dma;
+ int sasPhyPg0_data_sz;
+ SasDevicePage1_t *sasDevicePg1;
+ dma_addr_t sasDevicePg1_dma;
+ int sasDevicePg1_data_sz;
+ u8 phyId;
+ u64 sas_address;
+
+ sasPhyPg0=NULL;
+ sasPhyPg0_data_sz=0;
+ sasDevicePg1=NULL;
+ sasDevicePg1_data_sz=0;
+
+ if (copy_from_user(&karg, uarg,
+ sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_sata_signature struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+ phyId = karg.Signature.bPhyIdentifier;
+ if (phyId >= ioc->num_ports) {
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST;
+ dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n"));
+ goto cim_sata_signature_exit;
+ }
+
+ /* Default to success.*/
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ /* Issue a config request to get the devHandle of the attached device
+ */
+
+ /* Issue a config request to get phy information. */
+ hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 0;
+ hdr.Reserved1 = 0;
+ hdr.Reserved2 = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.pageAddr = phyId;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ /* Don't check if this failed. Already in a
+ * failure case.
+ */
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n"));
+ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sata_signature_exit;
+ }
+
+ if (hdr.ExtPageLength == 0) {
+ /* Don't check if this failed. Already in a
+ * failure case.
+ */
+ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sata_signature_exit;
+ }
+
+
+ sasPhyPg0_data_sz = hdr.ExtPageLength * 4;
+ rc = -ENOMEM;
+
+ sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent(ioc->pcidev,
+ sasPhyPg0_data_sz, &sasPhyPg0_dma);
+
+ if (! sasPhyPg0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sata_signature_exit;
+ }
+
+ memset((u8 *)sasPhyPg0, 0, sasPhyPg0_data_sz);
+ cfg.physAddr = sasPhyPg0_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ /* Don't check if this failed. Already in a
+ * failure case.
+ */
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n"));
+ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sata_signature_exit;
+ }
+
+ /* Make sure a SATA device is attached. */
+ if ((le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) &
+ MPI_SAS_DEVICE_INFO_SATA_DEVICE) == 0) {
+ dcsmisasprintk(ioc, printk(KERN_WARNING ": NOT A SATA DEVICE\n"));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_SATA_DEVICE;
+ goto cim_sata_signature_exit;
+ }
+
+ /* Get device page 1 for FIS signature. */
+ hdr.PageVersion = MPI_SASDEVICE1_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 1 /* page number 1 */;
+ hdr.Reserved1 = 0;
+ hdr.Reserved2 = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.physAddr = -1;
+
+ cfg.pageAddr = ((MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+ MPI_SAS_DEVICE_PGAD_FORM_SHIFT) |
+ le16_to_cpu(sasPhyPg0->AttachedDevHandle));
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: MPI_SASDEVICE1_PAGEVERSION: HEADER\n"));
+ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sata_signature_exit;
+ }
+
+ if (hdr.ExtPageLength == 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sata_signature_exit;
+ }
+
+ sasDevicePg1_data_sz = hdr.ExtPageLength * 4;
+ rc = -ENOMEM;
+
+ sasDevicePg1 = (SasDevicePage1_t *) pci_alloc_consistent
+ (ioc->pcidev, sasDevicePg1_data_sz, &sasDevicePg1_dma);
+
+ if (! sasDevicePg1) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sata_signature_exit;
+ }
+
+ memset((u8 *)sasDevicePg1, 0, sasDevicePg1_data_sz);
+ cfg.physAddr = sasDevicePg1_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: MPI_SASDEVICE1_PAGEVERSION: PAGE\n"));
+ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sata_signature_exit;
+ }
+
+/* EDM : dump Device Page 1 data*/
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 1 ---------\n"));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%x\n",sasDevicePg1->DevHandle));
+ memcpy(&sas_address, &sasDevicePg1->SASAddress, sizeof(u64));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
+ (unsigned long long)sas_address));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%x\n",sasDevicePg1->TargetID));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Bus=0x%x\n",sasDevicePg1->Bus));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Initial Reg Device FIS="));
+ for(jj=0;jj<20;jj++)
+ dcsmisasprintk(ioc, printk("%02x ",
+ ((u8 *)&sasDevicePg1->InitialRegDeviceFIS)[jj]));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n"));
+/* EDM : debug data */
+
+ memcpy(karg.Signature.bSignatureFIS,
+ sasDevicePg1->InitialRegDeviceFIS,20);
+
+ cim_sata_signature_exit:
+
+ if (sasPhyPg0)
+ pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz,
+ (u8 *) sasPhyPg0, sasPhyPg0_dma);
+
+ if (sasDevicePg1)
+ pci_free_consistent(ioc->pcidev, sasDevicePg1_data_sz,
+ (u8 *) sasDevicePg1, sasDevicePg1_dma);
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_sata_signature @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get SCSI Address command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_device_address(unsigned long arg)
+{
+ CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+ struct sas_device_info *sas_info;
+ u64 sas_address;
+
+ if (copy_from_user(&karg, uarg,
+ sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_get_device_address_buffer struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_DEVICE_ADDRESS;
+ memset(karg.bSASAddress, 0, sizeof(u64));
+ memset(karg.bSASLun, 0, sizeof(karg.bSASLun));
+
+ /* Search the list for the matching SAS address. */
+ sas_info = csmisas_get_device_component_by_os(ioc, karg.bPathId,
+ karg.bTargetId);
+ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume)
+ goto csmisas_get_device_address_exit;
+
+ sas_address = reverse_byte_order64(sas_info->sas_address);
+ memcpy(karg.bSASAddress, &sas_address, sizeof(u64));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ csmisas_get_device_address_exit:
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_get_device_address_buffer @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get Link Errors command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_link_errors(unsigned long arg)
+{
+ CSMI_SAS_LINK_ERRORS_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_LINK_ERRORS_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ MPT_FRAME_HDR *mf = NULL;
+ MPIHeader_t *mpi_hdr;
+ int iocnum;
+ int rc;
+ ConfigExtendedPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ SasPhyPage1_t *sasPhyPage1;
+ dma_addr_t sasPhyPage1_dma;
+ int sasPhyPage1_data_sz;
+ SasIoUnitControlRequest_t *sasIoUnitCntrReq;
+ SasIoUnitControlReply_t *sasIoUnitCntrReply;
+ u8 phyId;
+ u16 ioc_status;
+ u32 MsgContext;
+
+ sasPhyPage1=NULL;
+ sasPhyPage1_data_sz=0;
+
+ if (copy_from_user(&karg, uarg,
+ sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmisas_get_link_errors struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+ phyId = karg.Information.bPhyIdentifier;
+ if (phyId >= ioc->num_ports) {
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST;
+ dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n"));
+ goto cim_get_link_errors_exit;
+ }
+
+ /* Default to success.*/
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ /* Issue a config request to get the devHandle of the attached device
+ */
+
+ /* Issue a config request to get phy information. */
+ hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 1 /* page number 1*/;
+ hdr.Reserved1 = 0;
+ hdr.Reserved2 = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.pageAddr = phyId;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ /* Don't check if this failed. Already in a
+ * failure case.
+ */
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: MPI_SASPHY1_PAGEVERSION: HEADER\n"));
+ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_link_errors_exit;
+ }
+
+ if (hdr.ExtPageLength == 0) {
+ /* Don't check if this failed. Already in a
+ * failure case.
+ */
+ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_link_errors_exit;
+ }
+
+
+ sasPhyPage1_data_sz = hdr.ExtPageLength * 4;
+ rc = -ENOMEM;
+
+ sasPhyPage1 = (SasPhyPage1_t *) pci_alloc_consistent(ioc->pcidev,
+ sasPhyPage1_data_sz, &sasPhyPage1_dma);
+
+ if (! sasPhyPage1) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_link_errors_exit;
+ }
+
+ memset((u8 *)sasPhyPage1, 0, sasPhyPage1_data_sz);
+ cfg.physAddr = sasPhyPage1_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ /* Don't check if this failed. Already in a
+ * failure case.
+ */
+ dcsmisasprintk(ioc, printk(KERN_ERR ": FAILED: MPI_SASPHY1_PAGEVERSION: PAGE\n"));
+ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_link_errors_exit;
+ }
+
+/* EDM : dump PHY Page 1 data*/
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n"));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n",
+ sasPhyPage1->InvalidDwordCount));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n",
+ sasPhyPage1->RunningDisparityErrorCount));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n",
+ sasPhyPage1->LossDwordSynchCount));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n",
+ sasPhyPage1->PhyResetProblemCount));
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n"));
+/* EDM : debug data */
+
+ karg.Information.uInvalidDwordCount =
+ le32_to_cpu(sasPhyPage1->InvalidDwordCount);
+ karg.Information.uRunningDisparityErrorCount =
+ le32_to_cpu(sasPhyPage1->RunningDisparityErrorCount);
+ karg.Information.uLossOfDwordSyncCount =
+ le32_to_cpu(sasPhyPage1->LossDwordSynchCount);
+ karg.Information.uPhyResetProblemCount =
+ le32_to_cpu(sasPhyPage1->PhyResetProblemCount);
+
+ if (karg.Information.bResetCounts ==
+ CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS ) {
+ goto cim_get_link_errors_exit;
+ }
+
+ /* Clear Error log
+ *
+ * Issue IOUNIT Control Reqeust Message
+ */
+
+ /* Get a MF for this command.
+ */
+ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_link_errors_exit;
+ }
+
+ mpi_hdr = (MPIHeader_t *) mf;
+ MsgContext = mpi_hdr->MsgContext;
+ sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
+ memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
+ sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
+ sasIoUnitCntrReq->MsgContext = MsgContext;
+ sasIoUnitCntrReq->PhyNum = phyId;
+ sasIoUnitCntrReq->Operation = MPI_SAS_OP_PHY_CLEAR_ERROR_LOG;
+
+ if (csmisas_send_command_wait(ioc, mf, karg.IoctlHeader.Timeout) != 0) {
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_link_errors_exit;
+ }
+
+ /* process the completed Reply Message Frame */
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
+
+ sasIoUnitCntrReply =
+ (SasIoUnitControlReply_t *)ioc->ioctl_cmds.reply;
+ ioc_status = le16_to_cpu(sasIoUnitCntrReply->IOCStatus)
+ & MPI_IOCSTATUS_MASK;
+
+ if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+ dcsmisasprintk(ioc, printk(KERN_DEBUG ": SAS IO Unit Control: "));
+ dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X\n",
+ sasIoUnitCntrReply->IOCStatus,
+ sasIoUnitCntrReply->IOCLogInfo));
+ }
+ }
+
+ cim_get_link_errors_exit:
+
+ if (sasPhyPage1)
+ pci_free_consistent(ioc->pcidev, sasPhyPage1_data_sz,
+ (u8 *) sasPhyPage1, sasPhyPage1_dma);
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmisas_get_link_errors @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+
+}
+
+/**
+ * Prototype Routine for the CSMI SAS SMP Passthru command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_smp_passthru(unsigned long arg)
+{
+ CSMI_SAS_SMP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg;
+ MPT_ADAPTER *ioc;
+ CSMI_SAS_SMP_PASSTHRU_BUFFER *karg;
+ pSmpPassthroughRequest_t smpReq;
+ pSmpPassthroughReply_t smpReply;
+ MPT_FRAME_HDR *mf = NULL;
+ MPIHeader_t *mpi_hdr;
+ char *psge;
+ int iocnum, flagsLength;
+ void * request_data;
+ dma_addr_t request_data_dma;
+ u32 request_data_sz;
+ void * response_data;
+ dma_addr_t response_data_dma;
+ u32 response_data_sz;
+ u16 ioc_status;
+ u64 sas_address;
+ u32 MsgContext;
+ int malloc_data_sz;
+ int memory_pages;
+
+ malloc_data_sz = sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER);
+ memory_pages = get_order(malloc_data_sz);
+ karg = (CSMI_SAS_SMP_PASSTHRU_BUFFER *)__get_free_pages(
+ GFP_KERNEL, memory_pages);
+ if (!karg){
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to malloc CSMI_SAS_SMP_PASSTHRU_BUFFER "
+ "malloc_data_sz=%d memory_pages=%d\n",
+ __FILE__, __LINE__, __FUNCTION__,
+ malloc_data_sz, memory_pages);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_smp_passthru struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EFAULT;
+ }
+
+ request_data = NULL;
+ response_data = NULL;
+ response_data_sz = sizeof(CSMI_SAS_SMP_RESPONSE);
+ request_data_sz = karg->Parameters.uRequestLength;
+
+ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)karg, memory_pages);
+ return -ENODEV;
+ }
+
+ if (ioc->ioc_reset_in_progress) {
+ printk(KERN_ERR "%s@%d::%s - "
+ "Busy with IOC Reset \n",
+ __FILE__, __LINE__,__FUNCTION__);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EBUSY;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)karg, memory_pages);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ /* Default to success.*/
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ /* Do some error checking on the request. */
+ if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) {
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT;
+ goto cim_smp_passthru_exit;
+ }
+
+ if ((request_data_sz > 0xFFFF) || (!request_data_sz)) {
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_smp_passthru_exit;
+ }
+
+ /* Get a free request frame and save the message context.
+ */
+ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_smp_passthru_exit;
+ }
+
+ mpi_hdr = (MPIHeader_t *) mf;
+ MsgContext = mpi_hdr->MsgContext;
+ smpReq = (pSmpPassthroughRequest_t ) mf;
+
+ memset(smpReq,0,ioc->req_sz);
+
+ memcpy(&sas_address, karg->Parameters.bDestinationSASAddress,
+ sizeof(u64));
+ sas_address = cpu_to_le64(reverse_byte_order64(sas_address));
+ memcpy(&smpReq->SASAddress, &sas_address, sizeof(u64));
+
+ /* Fill in smp request. */
+ smpReq->PhysicalPort = karg->Parameters.bPortIdentifier;
+ smpReq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
+ smpReq->RequestDataLength = cpu_to_le16(request_data_sz);
+ smpReq->ConnectionRate = karg->Parameters.bConnectionRate;
+ smpReq->MsgContext = MsgContext;
+ smpReq->Reserved2 = 0;
+ smpReq->Reserved3 = 0;
+
+ /*
+ * Prepare the necessary pointers to run
+ * through the SGL generation
+ */
+
+ psge = (char *)&smpReq->SGL;
+
+ /* setup the *Request* payload SGE */
+ flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+ MPI_SGE_FLAGS_32_BIT_ADDRESSING |
+ MPI_SGE_FLAGS_HOST_TO_IOC |
+ MPI_SGE_FLAGS_END_OF_BUFFER;
+
+ if (sizeof(dma_addr_t) == sizeof(u64)) {
+ flagsLength |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
+ }
+ 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 += (sizeof(u32) + sizeof(dma_addr_t));
+
+ 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_32_BIT_ADDRESSING |
+ MPI_SGE_FLAGS_IOC_TO_HOST |
+ MPI_SGE_FLAGS_END_OF_BUFFER;
+
+ if (sizeof(dma_addr_t) == sizeof(u64)) {
+ flagsLength |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
+ }
+
+ 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 |= mpt_msg_flags();
+ /* task attributes
+ */
+ if((karg->Parameters.uFlags && 0xFF) == 0) {
+ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ);
+ } else if (karg->Parameters.uFlags &
+ CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE) {
+ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_HEADOFQ);
+ } else if (karg->Parameters.uFlags &
+ CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED) {
+ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ORDEREDQ);
+ } else if (karg->Parameters.uFlags &
+ CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA) {
+ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ACAQ);
+ } else {
+ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_UNTAGGED);
+ }
+
+ /* setup sense
+ */
+ pScsiRequest->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+ pScsiRequest->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma +
+ (req_idx * MPT_SENSE_BUFFER_ALLOC));
+
+ /* setup databuffer sg, assuming we fit everything one contiguous buffer
+ */
+ psge = (char *)&pScsiRequest->SGL;
+
+ if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) {
+ flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
+ } else if (karg->Parameters.uFlags & CSMI_SAS_SSP_READ) {
+ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+ }else {
+ flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_DIRECTION )
+ << MPI_SGE_FLAGS_SHIFT;
+ }
+ flagsLength |= request_data_sz;
+
+ if ( request_data_sz > 0) {
+ request_data = pci_alloc_consistent(
+ ioc->pcidev, request_data_sz, &request_data_dma);
+
+ if (request_data == NULL) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED "
+ "request_data_sz=%d\n", request_data_sz));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ mpt_free_msg_frame(ioc, mf);
+ goto cim_ssp_passthru_exit;
+ }
+
+ ioc->add_sge(psge, flagsLength, request_data_dma);
+ if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE)
+ memcpy(request_data, karg->bDataBuffer, request_data_sz);
+ } else {
+ ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
+ }
+
+ if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) {
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_ssp_passthru_exit;
+ }
+
+ memset(&karg->Status,0,sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS));
+ karg->Status.bConnectionStatus = CSMI_SAS_OPEN_ACCEPT;
+ karg->Status.bDataPresent = CSMI_SAS_SSP_NO_DATA_PRESENT;
+ karg->Status.bStatus = GOOD;
+ karg->Status.bResponseLength[0] = 0;
+ karg->Status.bResponseLength[1] = 0;
+ karg->Status.uDataBytes = request_data_sz;
+
+ /* process the completed Reply Message Frame */
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
+
+ pScsiReply = (pSCSIIOReply_t ) ioc->ioctl_cmds.reply;
+ karg->Status.bStatus = pScsiReply->SCSIStatus;
+ karg->Status.uDataBytes = min(le32_to_cpu(pScsiReply->TransferCount),
+ request_data_sz);
+ ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+ if (pScsiReply->SCSIState ==
+ MPI_SCSI_STATE_AUTOSENSE_VALID) {
+ karg->Status.bConnectionStatus =
+ CSMI_SAS_SSP_SENSE_DATA_PRESENT;
+ karg->Status.bResponseLength[0] =
+ (u8)le32_to_cpu(pScsiReply->SenseCount) & 0xFF;
+ memcpy(karg->Status.bResponse,
+ ioc->ioctl_cmds.sense, le32_to_cpu(pScsiReply->SenseCount));
+
+ skey = ioc->ioctl_cmds.sense[2] & 0x0F;
+ asc = ioc->ioctl_cmds.sense[12];
+ ascq = ioc->ioctl_cmds.sense[13];
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "\t [sense_key,asc,ascq]: "
+ "[0x%02x,0x%02x,0x%02x]\n",
+ skey, asc, ascq));
+
+ } else if(pScsiReply->SCSIState ==
+ MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
+ karg->Status.bDataPresent =
+ CSMI_SAS_SSP_RESPONSE_DATA_PRESENT;
+ karg->Status.bResponseLength[0] =
+ sizeof(pScsiReply->ResponseInfo);
+ for (ii=0;ii<sizeof(pScsiReply->ResponseInfo);ii++) {
+ karg->Status.bResponse[ii] =
+ ((u8*)&pScsiReply->ResponseInfo)[
+ (sizeof(pScsiReply->ResponseInfo)-1)-ii];
+ }
+ } else if ((ioc_status != MPI_IOCSTATUS_SUCCESS) &&
+ (ioc_status != MPI_IOCSTATUS_SCSI_RECOVERED_ERROR) &&
+ (ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN)) {
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ dcsmisasprintk(ioc, printk(KERN_DEBUG ": SCSI IO : "));
+ dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X\n",
+ pScsiReply->IOCStatus,
+ pScsiReply->IOCLogInfo));
+ }
+ }
+
+ if ((karg->Status.uDataBytes) && (request_data) &&
+ (karg->Parameters.uFlags & CSMI_SAS_SSP_READ)) {
+ if (copy_to_user((void __user *)uarg->bDataBuffer,
+ request_data, karg->Status.uDataBytes)) {
+ printk(KERN_ERR "%s@%d::%s - "
+ "Unable to write data to user %p\n",
+ __FILE__, __LINE__,__FUNCTION__,
+ (void*)karg->bDataBuffer);
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ }
+ }
+
+ cim_ssp_passthru_exit:
+
+
+ if (request_data)
+ pci_free_consistent(ioc->pcidev, request_data_sz,
+ (u8 *)request_data, request_data_dma);
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, karg,
+ offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER, bDataBuffer))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_ssp_passthru @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ free_pages((unsigned long)karg, memory_pages);
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS STP Passthru command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_stp_passthru(unsigned long arg)
+{
+ CSMI_SAS_STP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_STP_PASSTHRU_BUFFER karg_hdr, *karg;
+ MPT_ADAPTER *ioc = NULL;
+ pSataPassthroughRequest_t pSataRequest;
+ pSataPassthroughReply_t pSataReply;
+ MPT_FRAME_HDR *mf = NULL;
+ MPIHeader_t *mpi_hdr;
+ int iocnum;
+ u32 data_sz;
+ u64 sas_address;
+ u16 req_idx;
+ char *psge;
+ int flagsLength;
+ void * request_data;
+ dma_addr_t request_data_dma;
+ u32 request_data_sz;
+ int malloc_data_sz;
+ int memory_pages;
+ u8 channel;
+ u8 id;
+ u8 volume_id;
+ u8 volume_bus;
+ struct sas_device_info *sas_info;
+ u16 ioc_status;
+ u32 MsgContext;
+
+ if (copy_from_user(&karg_hdr, uarg, sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ request_data=NULL;
+ request_data_sz = karg_hdr.Parameters.uDataLength;
+ volume_id = 0;
+ volume_bus = 0;
+ channel = 0;
+ id = 0;
+
+ malloc_data_sz = (request_data_sz +
+ offsetof(CSMI_SAS_STP_PASSTHRU_BUFFER, bDataBuffer));
+ memory_pages = get_order(malloc_data_sz);
+ karg = (CSMI_SAS_STP_PASSTHRU_BUFFER *)__get_free_pages(
+ GFP_KERNEL, memory_pages);
+ if (!karg){
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to malloc CSMI_SAS_STP_PASSTHRU_BUFFER "
+ "malloc_data_sz=%d memory_pages=%d\n",
+ __FILE__, __LINE__, __FUNCTION__,
+ malloc_data_sz, memory_pages);
+ return -ENOMEM;
+ }
+
+ memset(karg, 0, sizeof(*karg));
+
+ if (copy_from_user(karg, uarg, malloc_data_sz)) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_ssp_passthru struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)karg, memory_pages);
+ return -ENODEV;
+ }
+
+ if (ioc->ioc_reset_in_progress) {
+ printk(KERN_ERR "%s@%d::%s - "
+ "Busy with IOC Reset \n",
+ __FILE__, __LINE__,__FUNCTION__);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EBUSY;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)karg, memory_pages);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ /* Default to success.
+ */
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ /* Neither a phy nor a port has been selected.
+ */
+ if ((karg->Parameters.bPhyIdentifier == CSMI_SAS_USE_PORT_IDENTIFIER) &&
+ (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT)) {
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT;
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ "%s::%s() @%d - incorrect bPhyIdentifier and bPortIdentifier!\n",
+ __FILE__,__FUNCTION__, __LINE__));
+ goto cim_stp_passthru_exit;
+ }
+
+ /* A phy has been selected. Verify that it's valid.
+ */
+ if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) {
+
+ /* Is the phy in range? */
+ if (karg->Parameters.bPhyIdentifier >= ioc->num_ports) {
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_PHY_DOES_NOT_EXIST;
+ goto cim_stp_passthru_exit;
+ }
+ }
+
+ data_sz = sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) -
+ sizeof(IOCTL_HEADER) - sizeof(u8*) +
+ request_data_sz;
+
+ if ( data_sz > karg->IoctlHeader.Length ) {
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ "%s::%s() @%d - expected datalen incorrect!\n",
+ __FILE__, __FUNCTION__,__LINE__));
+ goto cim_stp_passthru_exit;
+ }
+
+
+ /* we will use SAS address to resolve the scsi adddressing
+ */
+ memcpy(&sas_address, karg->Parameters.bDestinationSASAddress,
+ sizeof(u64));
+ sas_address = reverse_byte_order64(sas_address);
+
+ /* Search the list for the matching SAS address.
+ */
+ sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address);
+ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume) {
+ /*
+ *Invalid SAS address
+ */
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ "%s::%s() @%d - couldn't find associated "
+ "SASAddress=%llX!\n", __FILE__, __FUNCTION__, __LINE__,
+ (unsigned long long)sas_address));
+ goto cim_stp_passthru_exit;
+ }
+
+ id = sas_info->fw.id;
+ channel = sas_info->fw.channel;
+
+ /* check that this is an STP or SATA target device
+ */
+ if ( !(sas_info->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET ) &&
+ !(sas_info->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE )) {
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ goto cim_stp_passthru_exit;
+ }
+
+ /* Get a free request frame and save the message context.
+ */
+ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_stp_passthru_exit;
+ }
+
+ mpi_hdr = (MPIHeader_t *) mf;
+ MsgContext = mpi_hdr->MsgContext;
+ pSataRequest = (pSataPassthroughRequest_t) mf;
+ req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+
+ memset(pSataRequest,0,sizeof(pSataPassthroughRequest_t));
+
+ pSataRequest->TargetID = id;
+ pSataRequest->Bus = channel;
+ pSataRequest->Function = MPI_FUNCTION_SATA_PASSTHROUGH;
+ pSataRequest->PassthroughFlags = cpu_to_le16(karg->Parameters.uFlags);
+ pSataRequest->ConnectionRate = karg->Parameters.bConnectionRate;
+ pSataRequest->MsgContext = MsgContext;
+ pSataRequest->DataLength = cpu_to_le32(request_data_sz);
+ pSataRequest->MsgFlags = 0;
+ memcpy( pSataRequest->CommandFIS,karg->Parameters.bCommandFIS, 20);
+
+ psge = (char *)&pSataRequest->SGL;
+ if (karg->Parameters.uFlags & CSMI_SAS_STP_WRITE) {
+ flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
+ } else if (karg->Parameters.uFlags & CSMI_SAS_STP_READ) {
+ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+ }else {
+ flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_DIRECTION )
+ << MPI_SGE_FLAGS_SHIFT;
+ }
+
+ flagsLength |= request_data_sz;
+ if (request_data_sz > 0) {
+ request_data = pci_alloc_consistent(
+ ioc->pcidev, request_data_sz, &request_data_dma);
+
+ if (request_data == NULL) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ mpt_free_msg_frame(ioc, mf);
+ goto cim_stp_passthru_exit;
+ }
+
+ ioc->add_sge(psge, flagsLength, request_data_dma);
+ if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE)
+ memcpy(request_data, karg->bDataBuffer, request_data_sz);
+ } else {
+ ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
+ }
+
+ if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) {
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_stp_passthru_exit;
+ }
+
+ memset(&karg->Status,0,sizeof(CSMI_SAS_STP_PASSTHRU_STATUS));
+
+ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
+ dcsmisasprintk(ioc, printk(KERN_DEBUG ": STP Passthru: oh no, there is no reply!!"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_stp_passthru_exit;
+ }
+
+ /* process the completed Reply Message Frame */
+ pSataReply = (pSataPassthroughReply_t ) ioc->ioctl_cmds.reply;
+ ioc_status = le16_to_cpu(pSataReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+ if (ioc_status != MPI_IOCSTATUS_SUCCESS &&
+ ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) {
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ dcsmisasprintk(ioc, printk(KERN_DEBUG ": STP Passthru: "));
+ dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n",
+ le16_to_cpu(pSataReply->IOCStatus),
+ le32_to_cpu(pSataReply->IOCLogInfo),
+ pSataReply->SASStatus));
+ }
+
+ karg->Status.bConnectionStatus =
+ map_sas_status_to_csmi(pSataReply->SASStatus);
+
+ memcpy(karg->Status.bStatusFIS,pSataReply->StatusFIS, 20);
+
+ /*
+ * for now, just zero out uSCR array,
+ * then copy the one dword returned
+ * in the reply frame into uSCR[0]
+ */
+ memset( karg->Status.uSCR, 0, 64);
+ karg->Status.uSCR[0] = le32_to_cpu(pSataReply->StatusControlRegisters);
+
+ if((le32_to_cpu(pSataReply->TransferCount)) && (request_data) &&
+ (karg->Parameters.uFlags & CSMI_SAS_STP_READ)) {
+ karg->Status.uDataBytes =
+ min(le32_to_cpu(pSataReply->TransferCount),request_data_sz);
+ if (copy_to_user((void __user *)uarg->bDataBuffer,
+ request_data, karg->Status.uDataBytes)) {
+ printk(KERN_ERR "%s::%s() @%d - "
+ "Unable to write data to user %p\n",
+ __FILE__, __FUNCTION__, __LINE__,
+ (void*)karg->bDataBuffer);
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ }
+ }
+
+ cim_stp_passthru_exit:
+
+ if (request_data)
+ pci_free_consistent(ioc->pcidev, request_data_sz,
+ (u8 *)request_data, request_data_dma);
+
+ /* Copy th data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, karg,
+ offsetof(CSMI_SAS_STP_PASSTHRU_BUFFER, bDataBuffer))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_ssp_passthru @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EFAULT;
+ }
+
+ free_pages((unsigned long)karg, memory_pages);
+ dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Firmware Download command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_firmware_download(unsigned long arg)
+{
+ CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+ pMpiFwHeader_t pFwHeader=NULL;
+
+ if (copy_from_user(&karg, uarg,
+ sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_firmware_download struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ /* Default to success.*/
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+ karg.Information.usStatus = CSMI_SAS_FWD_SUCCESS;
+ karg.Information.usSeverity = CSMI_SAS_FWD_INFORMATION;
+
+ /* some checks of the incoming frame */
+ if ((karg.Information.uBufferLength +
+ sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD)) >
+ karg.IoctlHeader.Length) {
+ karg.IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ karg.Information.usStatus = CSMI_SAS_FWD_FAILED;
+ goto cim_firmware_download_exit;
+ }
+
+ if ( karg.Information.uDownloadFlags &
+ (CSMI_SAS_FWD_SOFT_RESET | CSMI_SAS_FWD_VALIDATE)) {
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ karg.Information.usStatus = CSMI_SAS_FWD_REJECT;
+ karg.Information.usSeverity = CSMI_SAS_FWD_ERROR;
+ goto cim_firmware_download_exit;
+ }
+
+ /* now we need to alloc memory so we can pull in the
+ * fw image attached to end of incoming packet.
+ */
+ pFwHeader = kmalloc(karg.Information.uBufferLength, GFP_KERNEL);
+ if (!pFwHeader){
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ karg.Information.usStatus = CSMI_SAS_FWD_REJECT;
+ karg.Information.usSeverity = CSMI_SAS_FWD_ERROR;
+ goto cim_firmware_download_exit;
+ }
+ memset(pFwHeader, 0, sizeof(*pFwHeader));
+
+ if (copy_from_user(pFwHeader, uarg->bDataBuffer,
+ karg.Information.uBufferLength)) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in pFwHeader @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if ( !((pFwHeader->Signature0 == MPI_FW_HEADER_SIGNATURE_0) &&
+ (pFwHeader->Signature1 == MPI_FW_HEADER_SIGNATURE_1) &&
+ (pFwHeader->Signature2 == MPI_FW_HEADER_SIGNATURE_2))) {
+ // the signature check failed
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ karg.Information.usStatus = CSMI_SAS_FWD_REJECT;
+ karg.Information.usSeverity = CSMI_SAS_FWD_ERROR;
+ goto cim_firmware_download_exit;
+ }
+
+ if ( mptctl_do_fw_download(karg.IoctlHeader.IOControllerNumber,
+ uarg->bDataBuffer, karg.Information.uBufferLength)
+ != 0) {
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ karg.Information.usStatus = CSMI_SAS_FWD_FAILED;
+ karg.Information.usSeverity = CSMI_SAS_FWD_FATAL;
+ goto cim_firmware_download_exit;
+ }
+
+ if((karg.Information.uDownloadFlags & CSMI_SAS_FWD_SOFT_RESET) ||
+ (karg.Information.uDownloadFlags & CSMI_SAS_FWD_HARD_RESET)) {
+ if (mpt_HardResetHandler(ioc, CAN_SLEEP) != 0) {
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ karg.Information.usStatus = CSMI_SAS_FWD_FAILED;
+ karg.Information.usSeverity = CSMI_SAS_FWD_FATAL;
+ }
+ }
+
+ cim_firmware_download_exit:
+
+ if(pFwHeader)
+ kfree(pFwHeader);
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_firmware_download @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get RAID Info command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_raid_info(unsigned long arg)
+{
+ CSMI_SAS_RAID_INFO_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_RAID_INFO_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+ u32 raidFlags;
+ u8 maxRaidTypes;
+ u8 maxDrivesPerSet;
+
+ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_INFO_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_get_raid_info struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ if (!ioc->raid_data.pIocPg2)
+ goto csmisas_get_raid_info_out;
+ karg.Information.uNumRaidSets =
+ ioc->raid_data.pIocPg2->NumActiveVolumes;
+ karg.Information.uMaxRaidSets = ioc->raid_data.pIocPg2->MaxVolumes;
+ if( ioc->raid_data.pIocPg6 ) {
+ // get absolute maximum for all RAID sets
+ maxDrivesPerSet = ioc->raid_data.pIocPg6->MaxDrivesIS;
+ maxDrivesPerSet = max(ioc->raid_data.pIocPg6->MaxDrivesIM,
+ maxDrivesPerSet);
+ maxDrivesPerSet = max(ioc->raid_data.pIocPg6->MaxDrivesIME,
+ maxDrivesPerSet);
+ karg.Information.uMaxDrivesPerSet = maxDrivesPerSet;
+ }
+ else
+ karg.Information.uMaxDrivesPerSet = 8;
+ // For bMaxRaidSets, count bits set in bits 0-6 of CapabilitiesFlags
+ raidFlags = ioc->raid_data.pIocPg2->CapabilitiesFlags & 0x0000007F;
+ for( maxRaidTypes=0; raidFlags; maxRaidTypes++ )
+ raidFlags &= raidFlags - 1;
+ karg.Information.bMaxRaidTypes = maxRaidTypes;
+ // ulMinRaidSetBlocks hard coded to 1MB until available from config page
+ karg.Information.ulMinRaidSetBlocks.uLowPart = 2048;
+ karg.Information.ulMinRaidSetBlocks.uHighPart = 0;
+ karg.Information.ulMaxRaidSetBlocks.uLowPart = 0xffffffff;
+ if( ioc->raid_data.pIocPg2->CapabilitiesFlags &
+ MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING )
+ karg.Information.ulMaxRaidSetBlocks.uHighPart = 0xffffffff;
+ else
+ karg.Information.ulMaxRaidSetBlocks.uHighPart = 0;
+ karg.Information.uMaxPhysicalDrives =
+ ioc->raid_data.pIocPg2->MaxPhysDisks;
+ karg.Information.uMaxExtents = 1;
+ karg.Information.uMaxModules = 0;
+ karg.Information.uMaxTransformationMemory = 0;
+ karg.Information.uChangeCount = ioc->csmi_change_count;
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+csmisas_get_raid_info_out:
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_RAID_INFO_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_get_raid_info @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * csmisas_do_raid - Format and Issue a RAID volume request message.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @action: What do be done.
+ * @PhysDiskNum: Logical target id.
+ * @VolumeBus: Target locations bus.
+ * @VolumeId: Volume id
+ *
+ * Returns: < 0 on a fatal error
+ * 0 on success
+ *
+ * Remark: Wait to return until reply processed by the ISR.
+ **/
+static int
+csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus, u8 VolumeId, pMpiRaidActionReply_t reply)
+{
+ MpiRaidActionRequest_t *pReq;
+ MpiRaidActionReply_t *pReply;
+ MPT_FRAME_HDR *mf;
+
+ /* Get and Populate a free Frame
+ */
+ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+ return -EAGAIN;
+ }
+ pReq = (MpiRaidActionRequest_t *)mf;
+ pReq->Action = action;
+ pReq->Reserved1 = 0;
+ pReq->ChainOffset = 0;
+ pReq->Function = MPI_FUNCTION_RAID_ACTION;
+ pReq->VolumeID = VolumeId;
+ pReq->VolumeBus = VolumeBus;
+ pReq->PhysDiskNum = PhysDiskNum;
+ pReq->MsgFlags = 0;
+ pReq->Reserved2 = 0;
+ pReq->ActionDataWord = 0; /* Reserved for this action */
+ //pReq->ActionDataSGE = 0;
+
+ ioc->add_sge((char *)&pReq->ActionDataSGE,
+ MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
+
+ if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0)
+ return -ENODATA;
+
+ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) &&
+ (reply != NULL)){
+ pReply = (MpiRaidActionReply_t *)&(ioc->ioctl_cmds.reply);
+ memcpy(reply, pReply,
+ min(ioc->reply_sz,
+ 4*pReply->MsgLength));
+ }
+
+ return 0;
+}
+
+/**
+ * csmisas_raid_inq
+ * @ioc = per host instance
+ * @opcode = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH or
+ * MPI_FUNCTION_SCSI_IO_REQUEST
+ * @id = target id
+ * @bus = target bus
+ * @inq_vpd = inquiry data, returned
+ * @inq_vpd_sz = maximum size of inquiry data
+ *
+ * Return = 0(sucess), non-zero(failure)
+ **/
+static int
+csmisas_raid_inq(MPT_ADAPTER *ioc, u8 opcode, u8 bus, u8 id, u8 inq_vpd_page,
+ u8 * inq_vpd, u32 inq_vpd_sz)
+{
+ MPT_FRAME_HDR *mf = NULL;
+ MPIHeader_t *mpi_hdr;
+ pSCSIIORequest_t pScsiRequest;
+ u16 req_idx;
+ char *psge;
+ u8 inq_vpd_cdb[6];
+ u8 *request_data=NULL;
+ dma_addr_t request_data_dma;
+ u32 request_data_sz;
+ int rc = 0;
+ u32 MsgContext;
+
+ request_data_sz = inq_vpd_sz;
+
+ /* fill-in cdb */
+ memset(inq_vpd_cdb, 0, sizeof(inq_vpd_cdb));
+ inq_vpd_cdb[0] = 0x12;
+ if (inq_vpd_page) {
+ inq_vpd_cdb[1] = 0x01; /* evpd bit */
+ inq_vpd_cdb[2] = inq_vpd_page;
+ }
+ inq_vpd_cdb[3] = (u8)(request_data_sz >> 8);
+ inq_vpd_cdb[4] = (u8)request_data_sz;
+
+ /* Get a free request frame and save the message context.
+ */
+ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+ goto csmisas_raid_inq_exit;
+ }
+
+ mpi_hdr = (MPIHeader_t *) mf;
+ MsgContext = mpi_hdr->MsgContext;
+ pScsiRequest = (pSCSIIORequest_t) mf;
+ req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+
+ memset(pScsiRequest,0,sizeof(SCSIIORequest_t));
+ pScsiRequest->Function = opcode;
+ pScsiRequest->TargetID = id;
+ pScsiRequest->Bus = bus;
+ pScsiRequest->CDBLength = 6;
+ pScsiRequest->DataLength = cpu_to_le32(request_data_sz);
+ pScsiRequest->MsgContext = MsgContext;
+ memcpy(pScsiRequest->CDB,inq_vpd_cdb,pScsiRequest->CDBLength);
+ pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ);
+ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ);
+ pScsiRequest->MsgFlags = mpt_msg_flags();
+
+ /* setup sense
+ */
+ pScsiRequest->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+ pScsiRequest->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma +
+ (req_idx * MPT_SENSE_BUFFER_ALLOC));
+
+ request_data = pci_alloc_consistent(
+ ioc->pcidev, request_data_sz, &request_data_dma);
+
+ if (request_data == NULL) {
+ mpt_free_msg_frame(ioc, mf);
+ rc=-1;
+ goto csmisas_raid_inq_exit;
+ }
+
+ memset(request_data,0,request_data_sz);
+ psge = (char *)&pScsiRequest->SGL;
+ ioc->add_sge(psge, (MPT_SGE_FLAGS_SSIMPLE_READ | 0xFC) ,
+ request_data_dma);
+
+ if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0) {
+ rc=-1;
+ goto csmisas_raid_inq_exit;
+ }
+
+ /* copy the request_data */
+ memcpy(inq_vpd, request_data, request_data_sz);
+
+ csmisas_raid_inq_exit:
+
+ if (request_data)
+ pci_free_consistent(ioc->pcidev, request_data_sz,
+ request_data, request_data_dma);
+
+ return rc;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get RAID Config command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_raid_config(unsigned long arg)
+{
+ CSMI_SAS_RAID_CONFIG_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_RAID_CONFIG_BUFFER karg,*pKarg=NULL;
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t header;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+ u8 volumeID, VolumeBus;
+ u8 physDiskNum, physDiskNumMax;
+ int volumepage0sz = 0;
+ int physdiskpage0sz = 0, ioc_page5_sz = 0;
+ dma_addr_t volume0_dma, physdisk0_dma;
+ dma_addr_t ioc_page5_dma = 0;
+ pRaidVolumePage0_t pVolume0 = NULL;
+ pRaidPhysDiskPage0_t pPhysDisk0 = NULL;
+ pMpiRaidActionReply_t pRaidActionReply = NULL;
+ u32 device_info = 0;
+ pIOCPage5_t pIocPage5 = NULL;
+ int i, idx, csmi_sas_raid_config_buffer_sz;
+ int memory_pages;
+ int copy_buffer_sz = 0;
+ u64 totalMaxLBA, tmpTotalMaxLBA;
+ u64 sas_address;
+ struct sas_device_info *sas_info;
+
+ if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmisas_get_raid_config struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ csmi_sas_raid_config_buffer_sz = karg.IoctlHeader.Length;
+ memory_pages = get_order(csmi_sas_raid_config_buffer_sz);
+ pKarg = (CSMI_SAS_RAID_CONFIG_BUFFER *)__get_free_pages(
+ GFP_KERNEL, memory_pages);
+ if (!pKarg){
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to malloc RAID_CONFIG_BUFFER "
+ "csmi_sas_raid_config_buffer_sz=%d memory_pages=%d\n",
+ __FILE__, __LINE__, __FUNCTION__,
+ csmi_sas_raid_config_buffer_sz, memory_pages);
+ return -ENOMEM;
+ }
+ memset(pKarg, 0, sizeof(*pKarg));
+
+ if (copy_from_user(pKarg, uarg, csmi_sas_raid_config_buffer_sz)) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmisas_get_raid_config struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ if (pKarg->Configuration.uChangeCount != 0 &&
+ pKarg->Configuration.uChangeCount != ioc->csmi_change_count ) {
+ pKarg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ pKarg->Configuration.uFailureCode =
+ CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID;
+ goto cim_get_raid_config_exit;
+ }
+
+ if (!ioc->raid_data.pIocPg2) {
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_raid_config_exit;
+ }
+
+ /*
+ * Check to see if the input uRaidSetIndex is
+ * greater than the number of RAID sets
+ */
+ if (pKarg->Configuration.uRaidSetIndex >=
+ ioc->raid_data.pIocPg2->NumActiveVolumes) {
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_RAID_SET_OUT_OF_RANGE;
+ goto cim_get_raid_config_exit;
+ }
+
+ /*
+ * get RAID Volume Page 0
+ */
+ volumeID = ioc->raid_data.pIocPg2->RaidVolume[pKarg->Configuration.uRaidSetIndex].VolumeID;
+ VolumeBus = ioc->raid_data.pIocPg2->RaidVolume[pKarg->Configuration.uRaidSetIndex].VolumeBus;
+
+ header.PageVersion = 0;
+ header.PageLength = 0;
+ header.PageNumber = 0;
+ header.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+ cfg.cfghdr.hdr = &header;
+ cfg.physAddr = -1;
+ cfg.pageAddr = (VolumeBus << 8) + volumeID;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+ if (mpt_config(ioc, &cfg) != 0) {
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_raid_config_exit;
+ }
+
+ if (header.PageLength == 0) {
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_raid_config_exit;
+ }
+
+ volumepage0sz = header.PageLength * 4;
+ pVolume0 = pci_alloc_consistent(ioc->pcidev, volumepage0sz,
+ &volume0_dma);
+ if (!pVolume0) {
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_raid_config_exit;
+ }
+
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.physAddr = volume0_dma;
+ if (mpt_config(ioc, &cfg) != 0) {
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_raid_config_exit;
+ }
+
+ totalMaxLBA = (u64)le32_to_cpu(pVolume0->MaxLBA) |
+ ((u64)le32_to_cpu(pVolume0->MaxLBAHigh)) << 32;
+ tmpTotalMaxLBA = totalMaxLBA + 1;
+ do_div(tmpTotalMaxLBA, 2048);
+ pKarg->Configuration.bDriveCount = 0;
+ pKarg->Configuration.uCapacity = tmpTotalMaxLBA;
+ pKarg->Configuration.uStripeSize =
+ le32_to_cpu(pVolume0->StripeSize)/2;
+
+ switch(pVolume0->VolumeType) {
+ case MPI_RAID_VOL_TYPE_IS:
+ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_0;
+ break;
+ case MPI_RAID_VOL_TYPE_IME:
+ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_10;
+ break;
+ case MPI_RAID_VOL_TYPE_IM:
+ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_1;
+ break;
+ default:
+ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_OTHER;
+ break;
+ }
+
+ switch (pVolume0->VolumeStatus.State) {
+ case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
+ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_OK;
+ break;
+ case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
+ /* Volume is degraded, check if Resyncing or Inactive */
+ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_DEGRADED;
+ break;
+ case MPI_RAIDVOL0_STATUS_STATE_FAILED:
+ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_FAILED;
+ break;
+ }
+
+ /* check flags */
+ if (pVolume0->VolumeStatus.Flags &
+ MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)
+ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_OFFLINE;
+ else if (pVolume0->VolumeStatus.Flags &
+ MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
+ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_REBUILDING;
+
+ pKarg->Configuration.bInformation = 0; /* default */
+ if(pVolume0->VolumeStatus.Flags &
+ MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS ) {
+
+ uint64_t * ptrUint64;
+ uint64_t totalBlocks64, blocksRemaining64;
+ uint32_t totalBlocks32, blocksRemaining32;
+
+ /* get percentage complete */
+ pRaidActionReply = kmalloc( sizeof(MPI_RAID_VOL_INDICATOR) +
+ offsetof(MSG_RAID_ACTION_REPLY,ActionData),
+ GFP_KERNEL);
+
+ if (!pRaidActionReply){
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to malloc @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__,pKarg);
+ goto cim_get_raid_config_exit;
+ }
+ memset(pRaidActionReply, 0, sizeof(*pRaidActionReply));
+
+ csmisas_do_raid(ioc,
+ MPI_RAID_ACTION_INDICATOR_STRUCT,
+ 0, VolumeBus, volumeID, pRaidActionReply);
+
+ ptrUint64 = (uint64_t *)&pRaidActionReply->ActionData;
+ totalBlocks64 = *ptrUint64;
+ ptrUint64++;
+ blocksRemaining64 = *ptrUint64;
+ while(totalBlocks64 > 0xFFFFFFFFUL){
+ totalBlocks64 = totalBlocks64 >> 1;
+ blocksRemaining64 = blocksRemaining64 >> 1;
+ }
+ totalBlocks32 = (uint32_t)totalBlocks64;
+ blocksRemaining32 = (uint32_t)blocksRemaining64;
+
+ if(totalBlocks32)
+ pKarg->Configuration.bInformation =
+ (totalBlocks32 - blocksRemaining32) /
+ (totalBlocks32 / 100);
+
+ kfree(pRaidActionReply);
+ }
+
+ /* fill-in more information depending on data type */
+ if (pKarg->Configuration.bDataType ==
+ CSMI_SAS_RAID_DATA_ADDITIONAL_DATA) {
+ pKarg->Configuration.Data->bLabel[0] = '\0';
+ pKarg->Configuration.Data->bRaidSetLun[1] = 0;
+ pKarg->Configuration.Data->bWriteProtection =
+ CSMI_SAS_RAID_SET_WRITE_PROTECT_UNKNOWN;
+ pKarg->Configuration.Data->bCacheSetting =
+ CSMI_SAS_RAID_SET_CACHE_UNKNOWN;
+ pKarg->Configuration.Data->bCacheRatio = 0;
+ pKarg->Configuration.Data->usBlockSize = 512;
+ pKarg->Configuration.Data->ulRaidSetExtentOffset.uLowPart = 0;
+ pKarg->Configuration.Data->ulRaidSetExtentOffset.uHighPart = 0;
+ pKarg->Configuration.Data->ulRaidSetBlocks.uLowPart =
+ le32_to_cpu(pVolume0->MaxLBA);
+ pKarg->Configuration.Data->ulRaidSetBlocks.uHighPart =
+ le32_to_cpu(pVolume0->MaxLBAHigh);
+ if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS ||
+ pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME ) {
+ pKarg->Configuration.Data->uStripeSizeInBlocks =
+ le32_to_cpu(pVolume0->StripeSize);
+ } else {
+ pKarg->Configuration.Data->uStripeSizeInBlocks = 0;
+ }
+ pKarg->Configuration.Data->uSectorsPerTrack = 128;
+ for (i=0; i<16; i++) {
+ // unsupported
+ pKarg->Configuration.Data->bApplicationScratchPad[i] =
+ 0xFF;
+ }
+ pKarg->Configuration.Data->uNumberOfHeads = 16;
+
+ tmpTotalMaxLBA = totalMaxLBA;
+ do_div(tmpTotalMaxLBA,
+ (pKarg->Configuration.Data->uNumberOfHeads *
+ pKarg->Configuration.Data->uSectorsPerTrack));
+ pKarg->Configuration.Data->uNumberOfTracks = tmpTotalMaxLBA;
+ } else if ( pKarg->Configuration.bDataType ==
+ CSMI_SAS_RAID_DATA_DEVICE_ID ) {
+ /* Send inquiry to get VPD Page 0x83 */
+ u32 vpd_page_sz;
+ vpd_page_sz = csmi_sas_raid_config_buffer_sz -
+ offsetof(CSMI_SAS_RAID_CONFIG,DeviceId);
+ if (csmisas_raid_inq(ioc, MPI_FUNCTION_SCSI_IO_REQUEST,
+ VolumeBus, volumeID, 0x83,
+ (u8*)&pKarg->Configuration.DeviceId->bDeviceIdentificationVPDPage,
+ vpd_page_sz) != 0) {
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_raid_config_exit;
+ }
+ } else {
+ /* suppress drive information */
+ if (pKarg->Configuration.bDriveCount ==
+ CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED) {
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+ goto cim_get_raid_config_exit;
+ }
+ }
+
+ /* get hotspare info, used later in this function */
+ if (pVolume0->VolumeSettings.HotSparePool) {
+ /* Read and save IOC Page 5
+ */
+ header.PageVersion = 0;
+ header.PageLength = 0;
+ header.PageNumber = 5;
+ header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+ cfg.cfghdr.hdr = &header;
+ cfg.physAddr = -1;
+ cfg.pageAddr = 0;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+ if ((mpt_config(ioc, &cfg) == 0) && (header.PageLength)) {
+ ioc_page5_sz = header.PageLength * 4;
+ pIocPage5 = pci_alloc_consistent(ioc->pcidev,
+ ioc_page5_sz,
+ &ioc_page5_dma);
+ memset(pIocPage5,0,ioc_page5_sz);
+ if (ioc_page5_dma) {
+ cfg.physAddr = ioc_page5_dma;
+ cfg.action =
+ MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ mpt_config(ioc, &cfg);
+ }
+ }
+ }
+
+ /*
+ * get RAID Physical Disk Page 0
+ */
+ header.PageVersion = 0;
+ header.PageLength = 0;
+ header.PageNumber = 0;
+ header.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+ cfg.cfghdr.hdr = &header;
+ cfg.physAddr = -1;
+ cfg.pageAddr = 0;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+ if (mpt_config(ioc, &cfg) != 0) {
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_raid_config_exit;
+ }
+
+ if (header.PageLength == 0) {
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_raid_config_exit;
+ }
+
+ physdiskpage0sz = header.PageLength * 4;
+ pPhysDisk0 = pci_alloc_consistent(ioc->pcidev, physdiskpage0sz,
+ &physdisk0_dma);
+ if (!pPhysDisk0) {
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_raid_config_exit;
+ }
+ cfg.physAddr = physdisk0_dma;
+
+ physDiskNumMax = (csmi_sas_raid_config_buffer_sz -
+ offsetof(CSMI_SAS_RAID_CONFIG,Drives))
+ / sizeof(CSMI_SAS_RAID_DRIVES);
+
+ tmpTotalMaxLBA = totalMaxLBA;
+ if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS) {
+ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks);
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "IS Volume tmpTotalMaxLBA=%llX\n",
+ (unsigned long long)tmpTotalMaxLBA));
+ }
+ else if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME) {
+ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks * 2);
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "IME Volume tmpTotalMaxLBA=%llX\n",
+ (unsigned long long)tmpTotalMaxLBA));
+ } else {
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "IM Volume tmpTotalMaxLBA=%llX\n",
+ (unsigned long long)tmpTotalMaxLBA));
+ }
+
+ for (i=0; i< min(pVolume0->NumPhysDisks, physDiskNumMax); i++) {
+
+ physDiskNum = pVolume0->PhysDisk[i].PhysDiskNum;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.pageAddr = physDiskNum;
+ if (mpt_config(ioc, &cfg) != 0){
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_raid_config_exit;
+ }
+
+ pKarg->Configuration.bDriveCount++;
+ if (pKarg->Configuration.bDataType != CSMI_SAS_RAID_DATA_DRIVES)
+ continue;
+
+ /* Search the list for the matching SAS address. */
+ sas_info = csmisas_get_device_component_by_fw(ioc, pPhysDisk0->PhysDiskBus,
+ pPhysDisk0->PhysDiskID);
+ if (sas_info) {
+ sas_address = reverse_byte_order64(sas_info->sas_address);
+ memcpy(pKarg->Configuration.Drives[i].bSASAddress,
+ &sas_address,sizeof(u64));
+ if (!device_info)
+ device_info = sas_info->device_info;
+ }
+
+ memcpy(pKarg->Configuration.Drives[i].bModel,
+ pPhysDisk0->InquiryData.VendorID,
+ offsetof(RAID_PHYS_DISK0_INQUIRY_DATA,ProductRevLevel));
+ memcpy(pKarg->Configuration.Drives[i].bFirmware,
+ pPhysDisk0->InquiryData.ProductRevLevel,
+ sizeof(pPhysDisk0->InquiryData.ProductRevLevel));
+ if (csmisas_is_sata(pPhysDisk0)) {
+ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber,
+ &pPhysDisk0->ExtDiskIdentifier[4],
+ 4);
+ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber[4],
+ &pPhysDisk0->DiskIdentifier,
+ sizeof(pPhysDisk0->DiskIdentifier));
+ } else {
+ memcpy(pKarg->Configuration.Drives[i].bSerialNumber,
+ pPhysDisk0->DiskIdentifier,
+ sizeof(pPhysDisk0->DiskIdentifier));
+ }
+
+ pKarg->Configuration.Drives[i].bDriveUsage =
+ (pPhysDisk0->PhysDiskStatus.Flags &
+ MPI_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME) ?
+ CSMI_SAS_DRIVE_CONFIG_NOT_USED :
+ CSMI_SAS_DRIVE_CONFIG_MEMBER;
+
+ pKarg->Configuration.Drives[i].bDriveStatus =
+ CSMI_SAS_DRIVE_STATUS_OK;
+ if (pPhysDisk0->PhysDiskStatus.State ==
+ MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED) {
+ pKarg->Configuration.Drives[i].bDriveStatus =
+ CSMI_SAS_DRIVE_STATUS_OFFLINE;
+ } else if(pPhysDisk0->PhysDiskStatus.State) {
+ pKarg->Configuration.Drives[i].bDriveStatus =
+ CSMI_SAS_DRIVE_STATUS_FAILED;
+ if(pKarg->Configuration.bStatus ==
+ CSMI_SAS_RAID_SET_STATUS_DEGRADED)
+ pKarg->Configuration.bInformation = i;
+ } else if((pVolume0->VolumeStatus.Flags &
+ MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) &&
+ (pPhysDisk0->PhysDiskStatus.Flags &
+ MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC))
+ pKarg->Configuration.Drives[i].bDriveStatus =
+ CSMI_SAS_DRIVE_STATUS_REBUILDING;
+ else if(pPhysDisk0->ErrorData.SmartCount ||
+ (pPhysDisk0->PhysDiskStatus.Flags &
+ MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC))
+ pKarg->Configuration.Drives[i].bDriveStatus =
+ CSMI_SAS_DRIVE_STATUS_DEGRADED;
+
+ memset(pKarg->Configuration.Drives[i].bSASLun,
+ 0, sizeof(pKarg->Configuration.Drives[i].bSASLun));
+ if (csmisas_is_sata(pPhysDisk0)) {
+ pKarg->Configuration.Drives[i].bDriveType =
+ CSMI_SAS_DRIVE_TYPE_SATA;
+ } else { /* drive in a volume can only be SAS/SATA */
+ pKarg->Configuration.Drives[i].bDriveType =
+ CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS;
+ if (mpt_raid_phys_disk_get_num_paths(ioc,
+ pVolume0->PhysDisk[i].PhysDiskNum) > 1)
+ pKarg->Configuration.Drives[i].bDriveType =
+ CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS;
+ }
+
+ pKarg->Configuration.Drives[i].usBlockSize = 512;
+ pKarg->Configuration.Drives[i].uDriveIndex =
+ pPhysDisk0->PhysDiskNum;
+ pKarg->Configuration.Drives[i].ulTotalUserBlocks.uLowPart =
+ (u32)tmpTotalMaxLBA;
+ pKarg->Configuration.Drives[i].ulTotalUserBlocks.uHighPart =
+ (u32)(tmpTotalMaxLBA >> 32);
+ }
+
+ /* adding hot spare info at the end */
+ if ((pVolume0->VolumeSettings.HotSparePool) && (pIocPage5) &&
+ (pVolume0->VolumeType != MPI_RAID_VOL_TYPE_IS)) {
+ for (idx = 0, i = pVolume0->NumPhysDisks ;
+ idx < pIocPage5->NumHotSpares ; idx++) {
+ if (i >= physDiskNumMax)
+ break;
+ if ((pVolume0->VolumeSettings.HotSparePool &
+ pIocPage5->HotSpare[idx].HotSparePool) == 0)
+ continue;
+ if(pIocPage5->HotSpare[idx].Flags !=
+ MPI_IOC_PAGE_5_HOT_SPARE_ACTIVE)
+ continue;
+ physDiskNum = pIocPage5->HotSpare[idx].PhysDiskNum;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.pageAddr = physDiskNum;
+ if (mpt_config(ioc, &cfg) != 0)
+ continue;
+
+ /* don't mix SSP hot spare
+ * in SATA volume
+ */
+ if (!csmisas_is_sata(pPhysDisk0) &&
+ (device_info &
+ MPI_SAS_DEVICE_INFO_SATA_DEVICE))
+ continue;
+
+ /* don't mix SATA hot spare
+ * in SSP volume
+ */
+ if (csmisas_is_sata(pPhysDisk0) &&
+ (device_info &
+ MPI_SAS_DEVICE_INFO_SSP_TARGET))
+ continue;
+
+ /* capacity check for IM volumes*/
+ if ((pVolume0->VolumeType ==
+ MPI_RAID_VOL_TYPE_IM) &&
+ (totalMaxLBA +
+ (64*2*1024) /* metadata = 64MB*/ >
+ le32_to_cpu(pPhysDisk0->MaxLBA)))
+ continue;
+
+ tmpTotalMaxLBA = totalMaxLBA;
+ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks);
+ /* capacity check for IME volumes*/
+ if ((pVolume0->VolumeType ==
+ MPI_RAID_VOL_TYPE_IME) &&
+ (((totalMaxLBA +
+ pVolume0->NumPhysDisks) * 2) +
+ (64*2*1024 ) /*metadata = 64MB*/ >
+ le32_to_cpu(pPhysDisk0->MaxLBA)))
+ continue;
+
+ pKarg->Configuration.bDriveCount++;
+ if (pKarg->Configuration.bDataType !=
+ CSMI_SAS_RAID_DATA_DRIVES) {
+ i++;
+ continue;
+ }
+
+ /* Search the list for the matching SAS address. */
+ sas_info = csmisas_get_device_component_by_fw(ioc,
+ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID);
+ if (sas_info) {
+ sas_address = reverse_byte_order64(sas_info->sas_address);
+ memcpy(pKarg->Configuration.Drives[i].bSASAddress,
+ &sas_address,sizeof(u64));
+ }
+
+ memcpy(pKarg->Configuration.Drives[i].bModel,
+ pPhysDisk0->InquiryData.VendorID,
+ offsetof(RAID_PHYS_DISK0_INQUIRY_DATA,ProductRevLevel));
+ memcpy(pKarg->Configuration.Drives[i].bFirmware,
+ pPhysDisk0->InquiryData.ProductRevLevel,
+ sizeof(pPhysDisk0->InquiryData.ProductRevLevel));
+ if (csmisas_is_sata(pPhysDisk0)) {
+ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber,
+ &pPhysDisk0->ExtDiskIdentifier[4],
+ 4);
+ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber[4],
+ &pPhysDisk0->DiskIdentifier,
+ sizeof(pPhysDisk0->DiskIdentifier));
+ } else {
+ memcpy(pKarg->Configuration.Drives[i].bSerialNumber,
+ pPhysDisk0->DiskIdentifier,
+ sizeof(pPhysDisk0->DiskIdentifier));
+ }
+ pKarg->Configuration.Drives[i].bDriveStatus =
+ CSMI_SAS_DRIVE_STATUS_OK;
+ if(pPhysDisk0->PhysDiskStatus.State)
+ pKarg->Configuration.Drives[i].bDriveStatus =
+ CSMI_SAS_DRIVE_STATUS_FAILED;
+ else if(pPhysDisk0->ErrorData.SmartCount)
+ pKarg->Configuration.Drives[i].bDriveStatus =
+ CSMI_SAS_DRIVE_STATUS_DEGRADED;
+ pKarg->Configuration.Drives[i].bDriveUsage =
+ CSMI_SAS_DRIVE_CONFIG_SPARE;
+ pKarg->Configuration.Drives[i].usBlockSize = 512;
+ pKarg->Configuration.Drives[i].uDriveIndex =
+ pPhysDisk0->PhysDiskNum;
+ if (csmisas_is_sata(pPhysDisk0)) {
+ pKarg->Configuration.Drives[i].bDriveType =
+ CSMI_SAS_DRIVE_TYPE_SATA;
+ } else { /* drive in a volume can only be SAS/SATA */
+ pKarg->Configuration.Drives[i].bDriveType =
+ CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS;
+ if (mpt_raid_phys_disk_get_num_paths(ioc,
+ pVolume0->PhysDisk[i].PhysDiskNum) > 1)
+ pKarg->Configuration.Drives[i].bDriveType =
+ CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS;
+ }
+ i++;
+ }
+ }
+
+ // Only return data on the first 240 drives
+ if( pKarg->Configuration.bDriveCount > 0xF0 )
+ pKarg->Configuration.bDriveCount =
+ CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG;
+
+ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ cim_get_raid_config_exit:
+
+ if (pVolume0 != NULL)
+ pci_free_consistent(ioc->pcidev, volumepage0sz, pVolume0,
+ volume0_dma);
+
+ if(pPhysDisk0 != NULL)
+ pci_free_consistent(ioc->pcidev, physdiskpage0sz, pPhysDisk0,
+ physdisk0_dma);
+
+ if(pIocPage5 != NULL)
+ pci_free_consistent(ioc->pcidev, ioc_page5_sz, pIocPage5,
+ ioc_page5_dma);
+
+ /* Copy the data from kernel memory to user memory
+ */
+
+ /* find the buffer size to copy depending on how much is filled-in */
+ switch (pKarg->Configuration.bDataType) {
+ case CSMI_SAS_RAID_DATA_ADDITIONAL_DATA:
+ copy_buffer_sz = sizeof(IOCTL_HEADER) +
+ offsetof(CSMI_SAS_RAID_CONFIG,Data) +
+ sizeof(CSMI_SAS_RAID_SET_ADDITIONAL_DATA);
+ break;
+ case CSMI_SAS_RAID_DATA_DRIVES:
+ if (pKarg->Configuration.bDriveCount ==
+ CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED)
+ copy_buffer_sz = sizeof(IOCTL_HEADER) +
+ offsetof(CSMI_SAS_RAID_CONFIG,Drives);
+ else
+ copy_buffer_sz = sizeof(IOCTL_HEADER) +
+ offsetof(CSMI_SAS_RAID_CONFIG,Drives) +
+ (pKarg->Configuration.bDriveCount *
+ sizeof(CSMI_SAS_RAID_DRIVES));
+ break;
+ case CSMI_SAS_RAID_DATA_DEVICE_ID:
+ copy_buffer_sz = csmi_sas_raid_config_buffer_sz;
+ break;
+ }
+
+ if (copy_to_user(uarg, pKarg, copy_buffer_sz)) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_get_raid_config @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ free_pages((unsigned long)pKarg, memory_pages);
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get RAID Features command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_raid_features(unsigned long arg)
+{
+ CSMI_SAS_RAID_FEATURES_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_RAID_FEATURES_BUFFER karg, *pKarg=NULL;
+ int csmi_sas_raid_features_buffer_sz, iocnum;
+ int memory_pages;
+ MPT_ADAPTER *ioc = NULL;
+
+ if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_get_raid_features struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ csmi_sas_raid_features_buffer_sz = karg.IoctlHeader.Length;
+ memory_pages = get_order(csmi_sas_raid_features_buffer_sz);
+ pKarg = (CSMI_SAS_RAID_FEATURES_BUFFER *)__get_free_pages(
+ GFP_KERNEL, memory_pages);
+ if (!pKarg){
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to malloc RAID_FEATURES_BUFFER "
+ "csmi_sas_raid_features_buffer_sz=%d memory_pages=%d\n",
+ __FILE__, __LINE__, __FUNCTION__,
+ csmi_sas_raid_features_buffer_sz, memory_pages);
+ return -ENOMEM;
+ }
+ memset(pKarg, 0, sizeof(*pKarg));
+
+ if (copy_from_user(pKarg, uarg, csmi_sas_raid_features_buffer_sz)) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_get_raid_features struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ if (pKarg->Information.uChangeCount != 0 &&
+ pKarg->Information.uChangeCount != ioc->csmi_change_count ) {
+ pKarg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ pKarg->Information.uFailureCode =
+ CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID;
+ goto cim_get_raid_features_exit;
+ }
+
+ pKarg->Information.uFeatures = CSMI_SAS_RAID_FEATURE_REBUILD |
+ CSMI_SAS_RAID_FEATURE_SURFACE_SCAN |
+ CSMI_SAS_RAID_FEATURE_SPARES_SHARED;
+ pKarg->Information.bDefaultTransformPriority =
+ CSMI_SAS_PRIORITY_UNKNOWN;
+ pKarg->Information.bTransformPriority = CSMI_SAS_PRIORITY_UNKNOWN;
+ pKarg->Information.bDefaultRebuildPriority = CSMI_SAS_PRIORITY_UNKNOWN;
+ pKarg->Information.bRebuildPriority =
+ pKarg->Information.bDefaultRebuildPriority;
+ pKarg->Information.bDefaultSurfaceScanPriority =
+ CSMI_SAS_PRIORITY_UNKNOWN;
+ pKarg->Information.bSurfaceScanPriority = CSMI_SAS_PRIORITY_UNKNOWN;
+ pKarg->Information.uRaidSetTransformationRules = 0;
+
+ /* IS */
+ pKarg->Information.RaidType[0].bRaidType = CSMI_SAS_RAID_TYPE_0;
+ pKarg->Information.RaidType[0].uSupportedStripeSizeMap = 0x80;
+
+ /* IM */
+ pKarg->Information.RaidType[1].bRaidType = CSMI_SAS_RAID_TYPE_1;
+ pKarg->Information.RaidType[1].uSupportedStripeSizeMap = 0;
+
+ /* IME */
+ pKarg->Information.RaidType[2].bRaidType = CSMI_SAS_RAID_TYPE_1E;
+ pKarg->Information.RaidType[2].uSupportedStripeSizeMap = 0x80;
+
+ pKarg->Information.RaidType[3].bRaidType = CSMI_SAS_RAID_TYPE_END;
+ pKarg->Information.bCacheRatiosSupported[0] =
+ CSMI_SAS_RAID_CACHE_RATIO_END;
+
+ cim_get_raid_features_exit:
+
+ /*
+ * Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, pKarg,
+ sizeof(CSMI_SAS_RAID_FEATURES_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_get_raid_features @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ free_pages((unsigned long)pKarg, memory_pages);
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Set RAID Control command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_set_raid_control(unsigned long arg)
+{
+ CSMI_SAS_RAID_CONTROL_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_RAID_CONTROL_BUFFER karg, *pKarg=NULL;
+ int csmi_sas_raid_control_buffer_sz, iocnum;
+ int memory_pages;
+ MPT_ADAPTER *ioc = NULL;
+
+ if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_set_raid_control struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ csmi_sas_raid_control_buffer_sz = karg.IoctlHeader.Length;
+ memory_pages = get_order(csmi_sas_raid_control_buffer_sz);
+ pKarg = (CSMI_SAS_RAID_CONTROL_BUFFER *)__get_free_pages(
+ GFP_KERNEL, memory_pages);
+ if (!pKarg){
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to malloc RAID_CONTROL_BUFFER "
+ "csmi_sas_raid_control_buffer_sz=%d memory_pages=%d\n",
+ __FILE__, __LINE__, __FUNCTION__,
+ csmi_sas_raid_control_buffer_sz, memory_pages);
+ return -ENOMEM;
+ }
+ memset(pKarg, 0, sizeof(*pKarg));
+
+ if (copy_from_user(pKarg, uarg, csmi_sas_raid_control_buffer_sz)) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_set_raid_control struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ if (pKarg->Information.uChangeCount != 0 &&
+ pKarg->Information.uChangeCount != ioc->csmi_change_count ) {
+ pKarg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ pKarg->Information.uFailureCode =
+ CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID;
+ goto cim_set_raid_control_exit;
+ }
+
+ if (pKarg->Information.bTransformPriority !=
+ CSMI_SAS_PRIORITY_UNCHANGED) {
+ pKarg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ pKarg->Information.uFailureCode =
+ CSMI_SAS_FAIL_CODE_TRANSFORM_PRIORITY_INVALID;
+ goto cim_set_raid_control_exit;
+ }
+
+ if (pKarg->Information.bRebuildPriority !=
+ CSMI_SAS_PRIORITY_AUTO &&
+ pKarg->Information.bRebuildPriority !=
+ CSMI_SAS_PRIORITY_UNCHANGED) {
+ pKarg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ pKarg->Information.uFailureCode =
+ CSMI_SAS_FAIL_CODE_REBUILD_PRIORITY_INVALID;
+ goto cim_set_raid_control_exit;
+ }
+
+ if (pKarg->Information.bCacheRatioFlag ==
+ CSMI_SAS_RAID_CACHE_RATIO_DISABLE) {
+ pKarg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ pKarg->Information.uFailureCode =
+ CSMI_SAS_FAIL_CODE_CACHE_RATIO_INVALID;
+ goto cim_set_raid_control_exit;
+ }
+
+ if( !strcmp(pKarg->Information.bClearConfiguration,
+ CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE) ) {
+ pKarg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ pKarg->Information.uFailureCode =
+ CSMI_SAS_FAIL_CODE_CLEAR_CONFIGURATION_INVALID;
+ goto cim_set_raid_control_exit;
+ }
+
+ pKarg->Information.bFailureDescription[0] = '\0';
+
+ cim_set_raid_control_exit:
+
+ /*
+ * Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, pKarg,
+ sizeof(CSMI_SAS_RAID_CONTROL_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_set_raid_control @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)pKarg, memory_pages);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ free_pages((unsigned long)pKarg, memory_pages);
+ return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get Raid Element.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_raid_element(unsigned long arg)
+{
+ CSMI_SAS_RAID_ELEMENT_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_RAID_ELEMENT_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+
+ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_ELEMENT_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmisas_get_raid_element struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+/* TODO - implement IOCTL here */
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE;
+ dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n"));
+
+// csmisas_get_raid_element_exit:
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_RAID_ELEMENT_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmisas_get_raid_element @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Set Raid Operation
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_set_raid_operation(unsigned long arg)
+{
+ CSMI_SAS_RAID_SET_OPERATION_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_RAID_SET_OPERATION_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+
+ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_SET_OPERATION_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_set_raid_operation struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+/* TODO - implement IOCTL here */
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE;
+ dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n"));
+
+// cim_set_raid_operation:
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_RAID_SET_OPERATION_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_set_raid_operation @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+
+}
+
+
+/**
+ * Prototype Routine for the CSMI SAS Task Managment Config command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_task_managment(unsigned long arg)
+{
+ CSMI_SAS_SSP_TASK_IU_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_SSP_TASK_IU_BUFFER karg;
+ pSCSITaskMgmt_t pScsiTm;
+ pSCSITaskMgmtReply_t pScsiTmReply;
+ MPT_ADAPTER *ioc = NULL;
+ MPT_SCSI_HOST *hd;
+ MPT_FRAME_HDR *mf = NULL;
+ MPIHeader_t *mpi_hdr;
+ int iocnum;
+ u8 taskType;
+ u8 channel;
+ u8 id;
+ u8 queueTag;
+ u32 TaskMsgContext = 0;
+ int i;
+ u8 found_qtag;
+ struct sas_device_info *sas_info;
+ u16 ioc_status;
+ u32 MsgContext;
+
+ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_SSP_TASK_IU_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_task_managment struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
+
+ sas_info = csmisas_get_device_component_by_os(ioc,
+ karg.Parameters.bPathId, karg.Parameters.bTargetId);
+ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume)
+ goto cim_get_task_managment_exit;
+
+ channel = sas_info->fw.channel;
+ id = sas_info->fw.id;
+ queueTag = (u8)karg.Parameters.uQueueTag & 0xFF;
+ hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
+ /* try to catch an error
+ */
+ if ((karg.Parameters.uFlags & CSMI_SAS_TASK_IU) &&
+ (karg.Parameters.uFlags & CSMI_SAS_HARD_RESET_SEQUENCE))
+ goto cim_get_task_managment_exit;
+
+ if (karg.Parameters.uFlags & CSMI_SAS_TASK_IU) {
+ switch (karg.Parameters.bTaskManagementFunction) {
+
+ case CSMI_SAS_SSP_ABORT_TASK:
+ taskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+ break;
+ case CSMI_SAS_SSP_ABORT_TASK_SET:
+ taskType = MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET;
+ break;
+ case CSMI_SAS_SSP_CLEAR_TASK_SET:
+ taskType = MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET;
+ break;
+ case CSMI_SAS_SSP_LOGICAL_UNIT_RESET:
+ taskType = MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET;
+ break;
+ case CSMI_SAS_SSP_CLEAR_ACA:
+ case CSMI_SAS_SSP_QUERY_TASK:
+ default:
+ goto cim_get_task_managment_exit;
+ }
+ } else if (karg.Parameters.uFlags & CSMI_SAS_HARD_RESET_SEQUENCE)
+ taskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+ else
+ goto cim_get_task_managment_exit;
+
+ switch (karg.Parameters.uInformation) {
+ case CSMI_SAS_SSP_TEST:
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request for test purposes\n"));
+ break;
+ case CSMI_SAS_SSP_EXCEEDED:
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request due to timeout\n"));
+ break;
+ case CSMI_SAS_SSP_DEMAND:
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request demanded by app\n"));
+ break;
+ case CSMI_SAS_SSP_TRIGGER:
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request sent to trigger event\n"));
+ break;
+ }
+
+ switch (taskType) {
+
+ case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
+ /*
+ * look up qtag in the ScsiLookup[] table
+ */
+ for (i = 0, found_qtag = 0; i < hd->ioc->req_depth; i++) {
+ if ((ioc->ScsiLookup[i]) &&
+ (ioc->ScsiLookup[i]->tag == queueTag)) {
+ mf = MPT_INDEX_2_MFPTR(hd->ioc, i);
+ TaskMsgContext =
+ mf->u.frame.hwhdr.msgctxu.MsgContext;
+ found_qtag=1;
+ break;
+ }
+ }
+
+ if(!found_qtag)
+ goto cim_get_task_managment_exit;
+
+ case MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
+ case MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
+ case MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET:
+ /* for now, this should work
+ */
+ case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+
+ /* Single threading ....
+ */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
+ mutex_lock(&ioc->taskmgmt_cmds.mutex);
+ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+ karg.IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_FAILED;
+ goto cim_get_task_managment_exit;
+ }
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
+ if (mptctl_set_tm_flags(hd) != 0) {
+ karg.IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_FAILED;
+ goto cim_get_task_managment_exit;
+ }
+#endif
+ /* Send request
+ */
+ if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
+ mptctl_free_tm_flags(ioc);
+#endif
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_task_managment_exit;
+ }
+
+ mpi_hdr = (MPIHeader_t *) mf;
+ MsgContext = mpi_hdr->MsgContext;
+ pScsiTm = (pSCSITaskMgmt_t ) mf;
+
+ memset(pScsiTm,0,sizeof(SCSITaskMgmt_t));
+ pScsiTm->TaskType = taskType;
+ pScsiTm->Bus = channel;
+ pScsiTm->TargetID = id;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
+ int_to_scsilun(karg.Parameters.bLun,
+ (struct scsi_lun *)pScsiTm->LUN);
+#else
+ pScsiTm->LUN[1] = karg.Parameters.bLun;
+#endif
+ pScsiTm->MsgContext = MsgContext;
+ pScsiTm->TaskMsgContext = TaskMsgContext;
+ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+ if (csmisas_send_handshake_wait(ioc, mf,
+ karg.IoctlHeader.Timeout) != 0) {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+#endif
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_get_task_managment_exit;
+ }
+
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
+
+ pScsiTmReply =
+ (pSCSITaskMgmtReply_t ) ioc->ioctl_cmds.reply;
+
+ ioc_status = le16_to_cpu(pScsiTmReply->IOCStatus)
+ & MPI_IOCSTATUS_MASK;
+
+ memset(&karg.Status,0,
+ sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS));
+
+ if(ioc_status == MPI_IOCSTATUS_SUCCESS) {
+ karg.IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_SUCCESS;
+ karg.Status.bSSPStatus =
+ CSMI_SAS_SSP_STATUS_COMPLETED;
+ }else if(ioc_status == MPI_IOCSTATUS_INSUFFICIENT_RESOURCES) {
+ karg.IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_SUCCESS;
+ karg.Status.bSSPStatus =
+ CSMI_SAS_SSP_STATUS_RETRY;
+ }else {
+ karg.IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_FAILED;
+ karg.Status.bSSPStatus =
+ CSMI_SAS_SSP_STATUS_FATAL_ERROR;
+ }
+ } else
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+
+ break;
+
+ default:
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+#endif
+
+ cim_get_task_managment_exit:
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_SSP_TASK_IU_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_task_managment @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * map_sas_status_to_csmi - Conversion for Connection Status
+ * @mpi_sas_status: Sas status returned by the firmware
+ *
+ * Returns converted connection status
+ *
+ **/
+static u8
+map_sas_status_to_csmi(u8 mpi_sas_status)
+{
+ u8 csmi_connect_status;
+
+ switch (mpi_sas_status) {
+
+ case MPI_SASSTATUS_SUCCESS:
+ csmi_connect_status = CSMI_SAS_OPEN_ACCEPT;
+ break;
+
+ case MPI_SASSTATUS_UTC_BAD_DEST:
+ csmi_connect_status = CSMI_SAS_OPEN_REJECT_BAD_DESTINATION;
+ break;
+
+ case MPI_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED:
+ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RATE_NOT_SUPPORTED;
+ break;
+
+ case MPI_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED:
+ csmi_connect_status =
+ CSMI_SAS_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED;
+ break;
+
+ case MPI_SASSTATUS_UTC_STP_RESOURCES_BUSY:
+ csmi_connect_status = CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY;
+ break;
+
+ case MPI_SASSTATUS_UTC_WRONG_DESTINATION:
+ csmi_connect_status = CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION;
+ break;
+
+ case MPI_SASSTATUS_SDSF_NAK_RECEIVED:
+ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RETRY;
+ break;
+
+ case MPI_SASSTATUS_SDSF_CONNECTION_FAILED:
+ csmi_connect_status = CSMI_SAS_OPEN_REJECT_PATHWAY_BLOCKED;
+ break;
+
+ case MPI_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT:
+ csmi_connect_status = CSMI_SAS_OPEN_REJECT_NO_DESTINATION;
+ break;
+
+ case MPI_SASSTATUS_UNKNOWN_ERROR:
+ case MPI_SASSTATUS_INVALID_FRAME:
+ case MPI_SASSTATUS_UTC_BREAK_RECEIVED:
+ case MPI_SASSTATUS_UTC_PORT_LAYER_REQUEST:
+ case MPI_SASSTATUS_SHORT_INFORMATION_UNIT:
+ case MPI_SASSTATUS_LONG_INFORMATION_UNIT:
+ case MPI_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA:
+ case MPI_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR:
+ case MPI_SASSTATUS_XFER_RDY_NOT_EXPECTED:
+ case MPI_SASSTATUS_DATA_INCORRECT_DATA_LENGTH:
+ case MPI_SASSTATUS_DATA_TOO_MUCH_READ_DATA:
+ case MPI_SASSTATUS_DATA_OFFSET_ERROR:
+ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RESERVE_STOP;
+ break;
+
+ default:
+ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RESERVE_STOP;
+ break;
+ }
+
+ return csmi_connect_status;
+}
+
+/**
+ * csmisas_phy_reset
+ * Issues a phy link reset or phy hard reset
+ *
+ * @ioc - Pointer to MPT_ADAPTER structure
+ * @PhyNum - phy number
+ * @opcode - {MPI_SAS_OP_PHY_LINK_RESET,MPI_SAS_OP_PHY_HARD_RESET}
+ *
+ * Returns: 0 for success, non-zero error
+ **/
+static int
+csmisas_phy_reset(MPT_ADAPTER *ioc, u8 PhyNum, u8 opcode)
+{
+ SasIoUnitControlRequest_t *sasIoUnitCntrReq;
+ SasIoUnitControlReply_t *sasIoUnitCntrReply;
+ MPT_FRAME_HDR *mf = NULL;
+ MPIHeader_t *mpi_hdr;
+ u16 ioc_status;
+ u32 MsgContext;
+
+ if ((opcode != MPI_SAS_OP_PHY_LINK_RESET) &&
+ (opcode != MPI_SAS_OP_PHY_HARD_RESET))
+ return -1;
+
+ /* Get a MF for this command.
+ */
+ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+ return -1;
+ }
+
+ mpi_hdr = (MPIHeader_t *) mf;
+ MsgContext = mpi_hdr->MsgContext;
+ sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
+ memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
+ sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
+ sasIoUnitCntrReq->MsgContext = MsgContext;
+ sasIoUnitCntrReq->Operation = opcode;
+ sasIoUnitCntrReq->PhyNum = PhyNum;
+
+ if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0)
+ return -1;
+
+ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0)
+ return -1;
+
+ /* process the completed Reply Message Frame */
+ sasIoUnitCntrReply = (SasIoUnitControlReply_t *)ioc->ioctl_cmds.reply;
+ ioc_status = le16_to_cpu(sasIoUnitCntrReply->IOCStatus)
+ & MPI_IOCSTATUS_MASK;
+ if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+ printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
+ __FUNCTION__,
+ sasIoUnitCntrReply->IOCStatus,
+ sasIoUnitCntrReply->IOCLogInfo);
+ return -1;
+ }
+ return 0;
+}
+
+/** Prototype Routine for the CSMI SAS Phy Control command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_phy_control(unsigned long arg)
+{
+ CSMI_SAS_PHY_CONTROL_BUFFER __user *uarg = (void __user *) arg;
+ IOCTL_HEADER ioctl_header;
+ PCSMI_SAS_PHY_CONTROL_BUFFER karg;
+ SasIOUnitPage0_t *sasIoUnitPg0=NULL;
+ dma_addr_t sasIoUnitPg0_dma;
+ int sasIoUnitPg0_data_sz=0;
+ SasIOUnitPage1_t *sasIoUnitPg1=NULL;
+ dma_addr_t sasIoUnitPg1_dma;
+ int sasIoUnitPg1_data_sz=0;
+ ConfigExtendedPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum;
+ int csmi_sas_phy_control_buffer_sz;
+ int memory_pages;
+
+ if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in IOCTL_HEADER"
+ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ csmi_sas_phy_control_buffer_sz = ioctl_header.Length;
+ memory_pages = get_order(csmi_sas_phy_control_buffer_sz);
+ karg = (PCSMI_SAS_PHY_CONTROL_BUFFER)__get_free_pages(
+ GFP_KERNEL, memory_pages);
+ if (!karg){
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to malloc SAS_PHY_CONTROL_BUFFER "
+ "csmi_sas_phy_control_buffer_sz=%d memory_pages=%d\n",
+ __FILE__, __LINE__, __FUNCTION__,
+ csmi_sas_phy_control_buffer_sz, memory_pages);
+ return -ENOMEM;
+ }
+ memset(karg, 0, sizeof(*karg));
+
+ if (copy_from_user(karg, uarg, csmi_sas_phy_control_buffer_sz)) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_phy_control_buffer "
+ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(ioctl_header.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)karg, memory_pages);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)karg, memory_pages);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ if (karg->bPhyIdentifier >= ioc->num_ports) {
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ goto cim_sas_phy_control_exit;
+ }
+
+ /*
+ * Retreive SAS IOUNIT PAGE 0
+ */
+
+ hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 0;
+ hdr.Reserved1 = 0;
+ hdr.Reserved2 = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.pageAddr = 0;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+ if (mpt_config(ioc, &cfg) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: READ MPI_SASIOUNITPAGE0: HEADER\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+
+ if (hdr.ExtPageLength == 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+
+ sasIoUnitPg0_data_sz = hdr.ExtPageLength * 4;
+ sasIoUnitPg0 = (SasIOUnitPage0_t *) pci_alloc_consistent(ioc->pcidev,
+ sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma);
+
+ if (!sasIoUnitPg0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+
+ memset((u8 *)sasIoUnitPg0, 0, sasIoUnitPg0_data_sz);
+ cfg.physAddr = sasIoUnitPg0_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if (mpt_config(ioc, &cfg) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: READ MPI_SASIOUNITPAGE0: CURRENT\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+
+ /*
+ * Retreive SAS IOUNIT PAGE 1
+ */
+
+ hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 1;
+ hdr.Reserved1 = 0;
+ hdr.Reserved2 = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.pageAddr = 0;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+ if (mpt_config(ioc, &cfg) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: READ MPI_SASIOUNITPAGE1: HEADER\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+
+ if (hdr.ExtPageLength == 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+
+ sasIoUnitPg1_data_sz = hdr.ExtPageLength * 4;
+ sasIoUnitPg1 = (SasIOUnitPage1_t *) pci_alloc_consistent(ioc->pcidev,
+ sasIoUnitPg1_data_sz, &sasIoUnitPg1_dma);
+
+ if (!sasIoUnitPg1) {
+ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+
+ memset((u8 *)sasIoUnitPg1, 0, sasIoUnitPg1_data_sz);
+ cfg.physAddr = sasIoUnitPg1_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if (mpt_config(ioc, &cfg) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: READ MPI_SASIOUNITPAGE1: CURRENT\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+
+ switch (karg->uFunction) {
+
+ case CSMI_SAS_PC_LINK_RESET:
+ case CSMI_SAS_PC_HARD_RESET:
+ {
+ u8 opcode = (karg->uFunction==CSMI_SAS_PC_LINK_RESET) ?
+ MPI_SAS_OP_PHY_LINK_RESET : MPI_SAS_OP_PHY_HARD_RESET;
+
+ if((karg->uLinkFlags & CSMI_SAS_PHY_ACTIVATE_CONTROL) &&
+ (karg->usLengthOfControl >= sizeof(CSMI_SAS_PHY_CONTROL)) &&
+ (karg->bNumberOfControls > 0)){
+ if(karg->Control[0].bRate ==
+ CSMI_SAS_LINK_RATE_1_5_GBPS) {
+ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate =
+ MPI_SAS_IOUNIT1_MAX_RATE_1_5 |
+ MPI_SAS_IOUNIT1_MIN_RATE_1_5;
+ }
+ else if(karg->Control[0].bRate ==
+ CSMI_SAS_LINK_RATE_3_0_GBPS) {
+ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate =
+ MPI_SAS_IOUNIT1_MAX_RATE_3_0 |
+ MPI_SAS_IOUNIT1_MIN_RATE_3_0;
+ }
+ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].PhyFlags &=
+ ~MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
+ cfg.dir = 1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+ if (mpt_config(ioc, &cfg) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: WRITE MPI_SASIOUNITPAGE1 NVRAM\n"));
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+ if (mpt_config(ioc, &cfg) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: WRITE MPI_SASIOUNITPAGE1 CURRENT\n"));
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+ }
+ if (csmisas_phy_reset(ioc,
+ karg->bPhyIdentifier, opcode) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: csmisas_phy_reset\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+ break;
+
+ }
+ case CSMI_SAS_PC_PHY_DISABLE:
+ if(karg->usLengthOfControl || karg->bNumberOfControls) {
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].PhyFlags |=
+ MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
+ cfg.dir = 1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+ if (mpt_config(ioc, &cfg) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: WRITE MPI_SASIOUNITPAGE1 NVRAM\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+ if (mpt_config(ioc, &cfg) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: WRITE MPI_SASIOUNITPAGE1 CURRENT\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+ if (csmisas_phy_reset(ioc,
+ karg->bPhyIdentifier, MPI_SAS_OP_PHY_HARD_RESET) != 0) {
+ dcsmisasprintk(ioc, printk(KERN_ERR
+ ": FAILED: csmisas_phy_reset\n"));
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_phy_control_exit;
+ }
+ break;
+
+ case CSMI_SAS_PC_GET_PHY_SETTINGS:
+ if(karg->usLengthOfControl || karg->bNumberOfControls) {
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+ if(csmi_sas_phy_control_buffer_sz <
+ offsetof(CSMI_SAS_PHY_CONTROL_BUFFER,Control) +
+ (4* sizeof(CSMI_SAS_PHY_CONTROL))) {
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+ karg->usLengthOfControl = sizeof(CSMI_SAS_PHY_CONTROL);
+ karg->bNumberOfControls = 4;
+ karg->Control[0].bType = CSMI_SAS_SAS;
+ karg->Control[0].bRate = CSMI_SAS_LINK_RATE_1_5_GBPS;
+ karg->Control[1].bType = CSMI_SAS_SAS;
+ karg->Control[1].bRate = CSMI_SAS_LINK_RATE_3_0_GBPS;
+ karg->Control[2].bType = CSMI_SAS_SATA;
+ karg->Control[2].bRate = CSMI_SAS_LINK_RATE_1_5_GBPS;
+ karg->Control[3].bType = CSMI_SAS_SATA;
+ karg->Control[3].bRate = CSMI_SAS_LINK_RATE_3_0_GBPS;
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+ break;
+ default:
+ break;
+ }
+
+ cim_sas_phy_control_exit:
+
+ if (sasIoUnitPg0)
+ pci_free_consistent(ioc->pcidev, sasIoUnitPg0_data_sz,
+ (u8 *) sasIoUnitPg0, sasIoUnitPg0_dma);
+
+ if (sasIoUnitPg1)
+ pci_free_consistent(ioc->pcidev, sasIoUnitPg1_data_sz,
+ (u8 *) sasIoUnitPg1, sasIoUnitPg1_dma);
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, karg,csmi_sas_phy_control_buffer_sz)) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_phy_control_buffer @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ free_pages((unsigned long)karg, memory_pages);
+ return 0;
+}
+
+/**
+ * csmisas_get_manuf_pg_7 - Fetch Manufacturing config Page7.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @mfgpage7_buffer: pointer to ManufacturingPage7_t that returns config
+ * page data
+ * @mfg_size - max size of buffer
+ *
+ * Return: 0 for success
+ * -ENOMEM if no memory available
+ * -EPERM if not allowed due to ISR context
+ * -EAGAIN if no msg frames currently available
+ * -EFAULT for non-successful reply or no reply (timeout)
+ **/
+static int
+csmisas_get_manuf_pg_7(MPT_ADAPTER *ioc, ManufacturingPage7_t *mfgpage7_buffer, int mfg_size)
+{
+ ConfigPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ ManufacturingPage7_t *mfgPage7 = NULL;
+ dma_addr_t mfgPage7_dma;
+ int data_sz = 0;
+ int rc;
+
+ /* Get Manufacturing Page 7 header */
+ hdr.PageVersion = MPI_MANUFACTURING0_PAGEVERSION;
+ hdr.PageLength = 0;
+ hdr.PageNumber = 7;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
+ cfg.cfghdr.hdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.pageAddr = 0;
+ cfg.timeout = 0;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0)
+ goto csmisas_get_manuf_pg_7_exit;
+
+ if (hdr.PageLength == 0) {
+ rc = -EFAULT;
+ goto csmisas_get_manuf_pg_7_exit;
+ }
+
+ data_sz = hdr.PageLength * 4;
+ mfgPage7 = pci_alloc_consistent(ioc->pcidev, data_sz, &mfgPage7_dma);
+ if (!mfgPage7) {
+ rc = -ENOMEM;
+ goto csmisas_get_manuf_pg_7_exit;
+ }
+
+ memset((u8 *)mfgPage7, 0, data_sz);
+ cfg.physAddr = mfgPage7_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0)
+ goto csmisas_get_manuf_pg_7_exit;
+
+ /* copy buffer back to user */
+ memcpy(mfgpage7_buffer, mfgPage7, min(data_sz, mfg_size));
+
+ csmisas_get_manuf_pg_7_exit:
+
+ if (mfgPage7)
+ pci_free_consistent(ioc->pcidev, data_sz, (u8 *)mfgPage7,
+ mfgPage7_dma);
+
+ return rc;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get Connector info command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_connector_info(unsigned long arg)
+{
+ CSMI_SAS_CONNECTOR_INFO_BUFFER __user *uarg = (void __user *) arg;
+ CSMI_SAS_CONNECTOR_INFO_BUFFER karg;
+ MPT_ADAPTER *ioc = NULL;
+ ManufacturingPage7_t *mfgPg7 = NULL;
+ int mfgPg7_sz;
+ int iocnum;
+ int i;
+
+ if (copy_from_user(&karg, uarg,
+ sizeof(CSMI_SAS_CONNECTOR_INFO_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_connector_info_buffer"
+ " struct @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ /* `32` is the sizeof MPI_MANPAGE7_CONNECTOR_INFO */
+ for (i = 0; i < 32; i++) {
+ karg.Reference[i].uPinout = CSMI_SAS_CON_UNKNOWN;
+ strcpy(karg.Reference[i].bConnector,"");
+ karg.Reference[i].bLocation = CSMI_SAS_CON_UNKNOWN;
+ }
+
+ mfgPg7_sz = offsetof(CONFIG_PAGE_MANUFACTURING_7,ConnectorInfo) +
+ (ioc->num_ports * sizeof(MPI_MANPAGE7_CONNECTOR_INFO));
+ mfgPg7 = kmalloc(mfgPg7_sz, GFP_KERNEL);
+ if (!mfgPg7){
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to malloc @ %p\n",
+ __FILE__, __LINE__, __FUNCTION__, mfgPg7);
+ return -EFAULT;
+ }
+ memset(mfgPg7, 0, mfgPg7_sz);
+
+ if (!csmisas_get_manuf_pg_7(ioc, mfgPg7, mfgPg7_sz)) {
+ for (i = 0; i < ioc->num_ports; i++) {
+ karg.Reference[i].uPinout =
+ le32_to_cpu(mfgPg7->ConnectorInfo[i].Pinout);
+ /*endian conversion , this is u8 * 16 ?? */
+ strncpy(karg.Reference[i].bConnector,
+ mfgPg7->ConnectorInfo[i].Connector, 16);
+ karg.Reference[i].bLocation =
+ mfgPg7->ConnectorInfo[i].Location;
+ }
+ }
+
+ kfree(mfgPg7);
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, &karg,
+ sizeof(CSMI_SAS_CONNECTOR_INFO_BUFFER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_connector_info_buffer @"
+ "%p\n",
+ __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return 0;
+}
+
+/**
+ * csmisas_fill_location_data
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ **/
+static int
+csmisas_fill_location_data(MPT_ADAPTER *ioc, u8 bus, u8 id, u8 opcode,
+ CSMI_SAS_LOCATION_IDENTIFIER * location_ident)
+{
+
+ ConfigExtendedPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ int rc;
+ SasDevicePage0_t *sasDevicePg0=NULL;
+ SasEnclosurePage0_t *sasEnclosurePg0=NULL;
+ dma_addr_t sasDevicePg0_dma,sasEnclosurePg0_dma;
+ int sasDevicePg0_data_sz=0;
+ int sasEnclosurePg0_data_sz=0;
+ u64 sas_address;
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+ memset (location_ident, 0, sizeof(*location_ident));
+
+ /* SAS Device Page 0 */
+ hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 0;
+ hdr.Reserved1 = 0;
+ hdr.Reserved2 = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ rc=-1;
+ goto fill_location_data_exit;
+ }
+
+ if (hdr.ExtPageLength == 0) {
+ rc=-1;
+ goto fill_location_data_exit;
+ }
+
+ sasDevicePg0_data_sz = hdr.ExtPageLength * 4;
+ sasDevicePg0 = (SasDevicePage0_t *) pci_alloc_consistent(
+ ioc->pcidev, sasDevicePg0_data_sz, &sasDevicePg0_dma);
+ if (!sasDevicePg0) {
+ rc=-1;
+ goto fill_location_data_exit;
+ }
+
+ memset((u8 *)sasDevicePg0, 0, sasDevicePg0_data_sz);
+ cfg.physAddr = sasDevicePg0_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.pageAddr = (bus << 8) + id
+ + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+ MPI_SAS_DEVICE_PGAD_FORM_SHIFT);
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ rc=-1;
+ goto fill_location_data_exit;
+ }
+
+ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_SAS_ADDRESS_VALID;
+ memcpy(&sas_address, &sasDevicePg0->SASAddress, sizeof(u64));
+ sas_address = reverse_byte_order64(sas_address);
+ memcpy(location_ident->bSASAddress, &sas_address, sizeof(u64));
+
+ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_SAS_LUN_VALID;
+ memset(location_ident->bSASLun, 0, sizeof(location_ident->bSASLun));
+
+ /* SAS Enclosure Page 0 */
+ hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
+ hdr.ExtPageLength = 0;
+ hdr.PageNumber = 0;
+ hdr.Reserved1 = 0;
+ hdr.Reserved2 = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0; /* read */
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ rc=0;
+ goto fill_location_data_exit;
+ }
+
+ if (hdr.ExtPageLength == 0) {
+ rc=0;
+ goto fill_location_data_exit;
+ }
+
+ sasEnclosurePg0_data_sz = hdr.ExtPageLength * 4;
+ sasEnclosurePg0 = (SasEnclosurePage0_t *) pci_alloc_consistent(
+ ioc->pcidev, sasEnclosurePg0_data_sz, &sasEnclosurePg0_dma);
+ if (!sasEnclosurePg0) {
+ rc=0;
+ goto fill_location_data_exit;
+ }
+ cfg.physAddr = sasEnclosurePg0_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.pageAddr = sasDevicePg0->EnclosureHandle
+ + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << MPI_SAS_ENCLOS_PGAD_FORM_SHIFT);
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0) {
+ rc=0;
+ goto fill_location_data_exit;
+ }
+
+ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID;
+ memcpy(&sas_address, &sasEnclosurePg0->EnclosureLogicalID, sizeof(u64));
+ sas_address = reverse_byte_order64(sas_address);
+ if (sas_address)
+ memcpy(location_ident->bEnclosureIdentifier, &sas_address, sizeof(u64));
+ else
+ strcpy(location_ident->bEnclosureIdentifier,"Internal");
+
+// bBayPrefix - not supported
+
+// TODO - We need to look at sasEnclosurePg0-.Flags , to determine
+// whether SEP BUS/TargetID is valid. Ifs its a SES device, then
+// issue internal inquiry to (bus/id) to gather the Enclosure name.
+// If the device is SMP, then issue SMP_MANUFACTURING to get enclosure name
+// If its direct attached, there is no enclosure name
+ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID;
+ strcpy(location_ident->bEnclosureName,"Not Supported");
+
+ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_LOCATION_STATE_VALID;
+ location_ident->bLocationState = CSMI_SAS_LOCATE_UNKNOWN;
+
+ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_BAY_IDENTIFIER_VALID;
+ location_ident->bBayIdentifier = le16_to_cpu(sasDevicePg0->Slot);
+
+
+// TODO - illuminating LEDs,
+// karg->bIdentify = CSMI_SAS_LOCATE_FORCE_OFF, CSMI_SAS_LOCATE_FORCE_ON
+// We can enable/disable LEDs by SCSI Enclosure Processor MPI request message
+// printk("Flags=0x%x\n",sasEnclosurePg0->Flags);
+
+/* check sasEnclosurePg0->Flags -
+ * to validate whether we need to send the SEPRequest
+ * bit:5 should be set
+ * bit:3-0 any bit should be set. If zero, then SEPRequest will fail
+*/
+
+/* MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR
+ * Look in mpi_init.h
+ * SEPRequest_t = structure
+ *
+ * SEPRequest_t->Action should be set to MPI_SEP_REQ_ACTION_WRITE_STATUS
+ *
+ * SEPRequest_t->Flags should be set to
+ * MPI_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS, to pass along enclosure/slot ids
+ *
+ * SEPRequest_t->SlotStatus |= MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST - this
+ * will illuminate the LEDs
+ */
+
+fill_location_data_exit:
+
+ if (sasDevicePg0 != NULL)
+ pci_free_consistent(ioc->pcidev, sasDevicePg0_data_sz,
+ sasDevicePg0, sasDevicePg0_dma);
+
+ if (sasEnclosurePg0 != NULL)
+ pci_free_consistent(ioc->pcidev, sasEnclosurePg0_data_sz,
+ sasEnclosurePg0, sasEnclosurePg0_dma);
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ return rc;
+}
+
+static int
+csmisas_fill_location_data_raid(MPT_ADAPTER *ioc, PCSMI_SAS_GET_LOCATION_BUFFER karg, u8 VolumeBus,
+ u8 volumeID)
+{
+ pRaidVolumePage0_t pVolume0 = NULL;
+ pRaidPhysDiskPage0_t pPhysDisk0 = NULL;
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t header;
+ u8 physDiskNumMax;
+ int volumepage0sz = 0, physdiskpage0sz = 0;
+ dma_addr_t volume0_dma, physdisk0_dma;
+ int csmi_sas_get_location_sz;
+ int rc = 0, i, idx;
+ int num_hotpares;
+ u64 totalMaxLBA, tmpTotalMaxLBA;
+ IOCPage5_t *iocPage5 = NULL;
+ u32 device_info = 0;
+ struct sas_device_info *sas_info;
+
+ int sz;
+
+ csmi_sas_get_location_sz = karg->IoctlHeader.Length;
+ physDiskNumMax = (csmi_sas_get_location_sz -
+ offsetof(CSMI_SAS_GET_LOCATION_BUFFER,Location))
+ / sizeof(CSMI_SAS_LOCATION_IDENTIFIER);
+ karg->bNumberOfLocationIdentifiers=0;
+
+ /*
+ * get RAID Volume Page 0
+ */
+
+ header.PageVersion = 0;
+ header.PageLength = 0;
+ header.PageNumber = 0;
+ header.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+ cfg.cfghdr.hdr = &header;
+ cfg.physAddr = -1;
+ cfg.pageAddr = (VolumeBus << 8) + volumeID;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+ if (mpt_config(ioc, &cfg) != 0) {
+ rc = -1;
+ goto sas_fill_location_data_raid_exit;
+ }
+
+ if (header.PageLength == 0) {
+ rc = -1;
+ goto sas_fill_location_data_raid_exit;
+ }
+
+ volumepage0sz = header.PageLength * 4;
+ pVolume0 = pci_alloc_consistent(ioc->pcidev, volumepage0sz,
+ &volume0_dma);
+ if (!pVolume0) {
+ rc = -1;
+ goto sas_fill_location_data_raid_exit;
+ }
+
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.physAddr = volume0_dma;
+ if (mpt_config(ioc, &cfg) != 0){
+ rc = -1;
+ goto sas_fill_location_data_raid_exit;
+ }
+
+ totalMaxLBA = (u64)le32_to_cpu(pVolume0->MaxLBA) |
+ ((u64)le32_to_cpu(pVolume0->MaxLBAHigh)) << 32;
+
+ /*
+ * get RAID Physical Disk Page 0
+ */
+ header.PageVersion = 0;
+ header.PageLength = 0;
+ header.PageNumber = 0;
+ header.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+ cfg.cfghdr.hdr = &header;
+ cfg.physAddr = -1;
+ cfg.pageAddr = 0;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+ if (mpt_config(ioc, &cfg) != 0) {
+ rc = -1;
+ goto sas_fill_location_data_raid_exit;
+ }
+
+ if (header.PageLength == 0) {
+ rc = -1;
+ goto sas_fill_location_data_raid_exit;
+ }
+
+ physdiskpage0sz = header.PageLength * 4;
+ pPhysDisk0 = pci_alloc_consistent(ioc->pcidev, physdiskpage0sz,
+ &physdisk0_dma);
+ if (!pPhysDisk0) {
+ rc = -1;
+ goto sas_fill_location_data_raid_exit;
+ }
+ cfg.physAddr = physdisk0_dma;
+
+ for (i=0; i < min(pVolume0->NumPhysDisks, physDiskNumMax); i++) {
+
+ /* obtain a refresh of pPhysDisk0 */
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.pageAddr = pVolume0->PhysDisk[i].PhysDiskNum;
+ if (mpt_config(ioc, &cfg) != 0){
+ rc = -1;
+ goto sas_fill_location_data_raid_exit;
+ }
+
+ if((csmisas_fill_location_data(ioc, pPhysDisk0->PhysDiskBus,
+ pPhysDisk0->PhysDiskID, karg->bIdentify,
+ &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0)
+ karg->bNumberOfLocationIdentifiers++;
+
+ if (device_info)
+ continue;
+ sas_info = csmisas_get_device_component_by_fw(ioc,
+ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID);
+ if (!sas_info || sas_info->is_cached)
+ continue;
+ device_info = sas_info->device_info;
+ }
+
+ if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS)
+ goto sas_fill_location_data_raid_exit;
+
+ /*
+ * hot spare support
+ *
+ */
+
+ num_hotpares = csmisas_get_number_hotspares(ioc);
+
+ if (num_hotpares) {
+
+ sz = offsetof(IOCPage5_t, HotSpare) +
+ num_hotpares * sizeof(IOC_5_HOT_SPARE);
+ iocPage5 = kmalloc(sz, GFP_KERNEL);
+
+ if (!iocPage5)
+ goto sas_fill_location_data_raid_exit;
+ memset(iocPage5, 0, sizeof(*iocPage5));
+
+ if (csmisas_get_ioc_pg5(ioc, iocPage5, sz) != 0)
+ goto sas_fill_location_data_raid_exit;
+
+ for(i = 0, idx = pVolume0->NumPhysDisks ; i < num_hotpares;
+ i++, idx++) {
+
+ if (idx >= physDiskNumMax)
+ break;
+
+ /* obtain a refresh of pPhysDisk0 */
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.pageAddr = iocPage5->HotSpare[i].PhysDiskNum;
+ if (mpt_config(ioc, &cfg) != 0)
+ goto sas_fill_location_data_raid_exit;
+
+ /* Search the list for the matching SAS address. */
+ sas_info = csmisas_get_device_component_by_fw(ioc,
+ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID);
+
+ if (!sas_info || sas_info->is_cached)
+ continue;
+
+ /* don't mix SSP hot spare
+ * in SATA volume
+ */
+ if (!csmisas_is_sata(pPhysDisk0) &&
+ (device_info &
+ MPI_SAS_DEVICE_INFO_SATA_DEVICE))
+ continue;
+
+ /* don't mix SATA hot spare
+ * in SSP volume
+ */
+ if (csmisas_is_sata(pPhysDisk0) &&
+ (device_info &
+ MPI_SAS_DEVICE_INFO_SSP_TARGET))
+ continue;
+
+ /* capacity check for IM volumes*/
+ if ((pVolume0->VolumeType ==
+ MPI_RAID_VOL_TYPE_IM) &&
+ (totalMaxLBA +
+ (64*2*1024) /* metadata = 64MB*/ >
+ le32_to_cpu(pPhysDisk0->MaxLBA)))
+ continue;
+
+ tmpTotalMaxLBA = totalMaxLBA;
+ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks);
+ /* capacity check for IME volumes*/
+ if ((pVolume0->VolumeType ==
+ MPI_RAID_VOL_TYPE_IME) &&
+ ((tmpTotalMaxLBA * 2) +
+ (64*2*1024 ) /*metadata = 64MB*/ >
+ le32_to_cpu(pPhysDisk0->MaxLBA)))
+ continue;
+
+ if((csmisas_fill_location_data(ioc,
+ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID,
+ karg->bIdentify,
+ &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0)
+ karg->bNumberOfLocationIdentifiers++;
+ }
+ }
+
+
+ sas_fill_location_data_raid_exit:
+
+ kfree(iocPage5);
+
+ if (pVolume0)
+ pci_free_consistent(ioc->pcidev, volumepage0sz, pVolume0,
+ volume0_dma);
+
+ if(pPhysDisk0)
+ pci_free_consistent(ioc->pcidev, physdiskpage0sz, pPhysDisk0,
+ physdisk0_dma);
+
+ return rc;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get location command.
+ *
+ * Outputs: None.
+ * Return: 0 if successful
+ * -EFAULT if data unavailable
+ * -ENODEV if no such device/adapter
+ */
+static int
+csmisas_get_location(unsigned long arg)
+{
+ CSMI_SAS_GET_LOCATION_BUFFER __user *uarg = (void __user *) arg;
+ PCSMI_SAS_GET_LOCATION_BUFFER karg;
+ IOCTL_HEADER ioctl_header;
+ MPT_ADAPTER *ioc = NULL;
+ int iocnum,i;
+ int csmi_sas_get_location_sz;
+ int memory_pages;
+ struct sas_device_info *sas_info;
+
+ if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in IOCTL_HEADER"
+ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
+ return -EFAULT;
+ }
+
+ csmi_sas_get_location_sz = ioctl_header.Length;
+ memory_pages = get_order(csmi_sas_get_location_sz);
+ karg = (PCSMI_SAS_GET_LOCATION_BUFFER)__get_free_pages(
+ GFP_KERNEL, memory_pages);
+ if (!karg){
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to malloc GET_LOCATION_BUFFER "
+ "csmi_sas_get_location_sz=%d memory_pages=%d\n",
+ __FILE__, __LINE__, __FUNCTION__,
+ csmi_sas_get_location_sz, memory_pages);
+ return -ENOMEM;
+ }
+ memset(karg, 0, sizeof(*karg));
+
+ if (copy_from_user(karg, uarg, csmi_sas_get_location_sz)) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to read in csmi_sas_phy_control_buffer "
+ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EFAULT;
+ }
+
+ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
+ &ioc)) < 0) || (ioc == NULL)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)karg, memory_pages);
+ return -ENODEV;
+ }
+
+ if (!csmisas_is_this_sas_cntr(ioc)) {
+ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+ __FILE__, __FUNCTION__, __LINE__, iocnum);
+ free_pages((unsigned long)karg, memory_pages);
+ return -ENODEV;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
+ if(karg->bLengthOfLocationIdentifier !=
+ sizeof(CSMI_SAS_LOCATION_IDENTIFIER))
+ goto cim_sas_get_location_exit;
+
+ sas_info = csmisas_get_device_component_by_os(ioc, karg->bPathId,
+ karg->bTargetId);
+ if (!sas_info)
+ goto cim_sas_get_location_exit;
+
+ /* RAID SUPPORT */
+ if (ioc->raid_data.pIocPg2 && sas_info->is_logical_volume) {
+ for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++){
+ if (sas_info->fw.id ==
+ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID &&
+ sas_info->fw.channel ==
+ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus) {
+ if(csmisas_fill_location_data_raid(ioc, karg,
+ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus,
+ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) == 0)
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_SUCCESS;
+ else
+ karg->IoctlHeader.ReturnCode =
+ CSMI_SAS_STATUS_FAILED;
+ goto cim_sas_get_location_exit;
+ }
+ }
+ }
+
+ /* NON-RAID SUPPORT */
+ if (sas_info->is_cached || sas_info->is_logical_volume)
+ goto cim_sas_get_location_exit;
+
+ /* make sure there's enough room to populate the Location[] struct */
+ if ((csmi_sas_get_location_sz -
+ offsetof(CSMI_SAS_GET_LOCATION_BUFFER,Location)) <
+ sizeof(CSMI_SAS_LOCATION_IDENTIFIER))
+ goto cim_sas_get_location_exit;
+
+ karg->bNumberOfLocationIdentifiers=1;
+ karg->Location[0].bLocationFlags=0;
+ if((csmisas_fill_location_data(ioc, sas_info->fw.channel,
+ sas_info->fw.id, karg->bIdentify, &karg->Location[0])) == 0)
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+ else
+ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+
+ cim_sas_get_location_exit:
+
+ /* Copy the data from kernel memory to user memory
+ */
+ if (copy_to_user(uarg, karg, csmi_sas_get_location_sz)) {
+ printk(KERN_ERR "%s@%d::%s() - "
+ "Unable to write out csmi_sas_get_location_buffer "
+ "@ %p\n",__FILE__, __LINE__, __FUNCTION__, uarg);
+ free_pages((unsigned long)karg, memory_pages);
+ return -EFAULT;
+ }
+
+ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+ free_pages((unsigned long)karg, memory_pages);
+ return 0;
+}
--- /dev/null
+/**************************************************************************
+
+Module Name:
+
+ CSMISAS.H
+
+
+Abstract:
+
+ This file contains constants and data structure definitions used by drivers
+ that support the Common Storage Management Interface specification for
+ SAS or SATA in either the Windows or Linux.
+
+ This should be considered as a reference implementation only. Changes may
+ be necessary to accommodate a specific build environment or target OS.
+
+Revision History:
+
+ 001 SEF 8/12/03 Initial release.
+ 002 SEF 8/20/03 Cleanup to match documentation.
+ 003 SEF 9/12/03 Additional cleanup, created combined header
+ 004 SEF 9/23/03 Changed base types to match linux defaults
+ Added RAID signature
+ Added bControllerFlags to CSMI_SAS_CNTLR_CONFIG
+ Changed CSMI_SAS_BEGIN_PACK to 8 for common structures
+ Fixed other typos identified in first compilation test
+ 005 SEF 10/03/03 Additions to match first version of CSMI document
+ 006 SEF 10/14/03 Fixed typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER
+ Added defines for bConnectionRate
+ 007 SEF 10/15/03 Added Firmware Download Control Code and support
+ Added CSMI revision support
+ 008 SEF 10/30/03 No functional change, just updated version to track
+ spec changes
+ 009 SEF 12/09/03 No functional change, just updated version to track
+ spec changes
+ 010 SEF 3/11/04 Fixed typedef struct CSMI_SAS_RAID_DRIVES to include the
+ bFirmware member that is defined in the spec, but
+ was missing in this file,
+ added CC_CSMI_SAS_TASK_MANAGEMENT
+ 011 SEF 4/02/04 No functional change, added comment line before
+ CC_CSMI_SAS_TASK_MANAGEMENT
+ 012 SEF 4/16/04 Added IOControllerNumber to linux header,
+ Modified linux control codes to have upper word of
+ 0xCC77.... to indicate CSMI version 77
+ Added bSignalClass to CC_CSMI_SET_PHY_INFO
+ Added CC_CSMI_SAS_PHY_CONTROL support
+ 013 SEF 5/14/04 Added CC_CSMI_SAS_GET_CONNECTOR_INFO support
+ 014 SEF 5/24/04 No functional change, just updated version to track spec
+ changes
+ 015 SEF 6/16/04 changed bPinout to uPinout to reflect proper size,
+ changed width of bLocation defines to reflect size
+ 016 SEF 6/17/04 changed bLengthOfControls in CSMI_SAS_PHY_CONTROL
+ to be proper size
+ 017 SEF 9/17/04 added CSMI_SAS_SATA_PORT_SELECTOR,
+ CSMI_SAS_LINK_VIRTUAL, CSMI_SAS_CON_NOT_PRESENT, and
+ CSMI_SAS_CON_NOT_CONNECTED
+ 018 SEF 9/20/04 added CSMI_SAS_PHY_USER_PATTERN,
+ changed definition of CSMI_SAS_PHY_FIXED_PATTERN to not
+ conflict with activate definition
+ 019 SEF 12/06/04 added CSMI_SAS_GET_LOCATION
+ added bSSPStatus to CSMI_SAS_SSP_PASSTHRU_STATUS
+ structure
+ 020 SEF 5/25/05 added CSMI_SAS_PHY_VIRTUAL_SMP, and changes to
+ CSMI_SAS_GET_LOCATION
+ 021 SEF 11/03/05 added new RAID creation functionality
+ 022 SEF 2/01/06 corrected typo bNegotitiatedLInkRate
+ Added two more RAID_TYPES, 7 and 8
+ 023 SEF 4/04/06 added CSMI_RAID_TYPE_1E
+ changed structures that contained surface scan
+ to priority approach rather than time, causes
+ 0.89 to incompatible with 0.87, so a version
+ check is necessary when interpreting the
+ raid structures
+ Added netware section
+ 024 DRG 5/22/06 Added uFailureCode to CSMI_SAS_RAID_CONFIG and
+ CSMI_SAS_RAID_FEATURES
+ Changed __u64 fields to high and low __u32 fields in
+ order to avoid backward compatibility issues with
+ packing and alignment.
+ Fixed alignment problem in CSMI_SAS_RAID_DRIVES.
+ Added CSMI_SAS_CNTLR_SMART_ARRAY to uControllerFlags
+ Reassigned the value of CSMI_SAS_CNTLR_RAID_CFG_SUPPORT
+ to avoid a conflict.
+
+**************************************************************************/
+
+#ifndef _CSMI_SAS_H_
+#define _CSMI_SAS_H_
+
+// CSMI Specification Revision, the intent is that all versions of the
+// specification will be backward compatible after the 1.00 release.
+// Major revision number, corresponds to xxxx. of CSMI specification
+// Minor revision number, corresponds to .xxxx of CSMI specification
+#define CSMI_MAJOR_REVISION 0
+#define CSMI_MINOR_REVISION 90
+
+/*************************************************************************/
+/* PATCHES FOR TYPOS */
+/*************************************************************************/
+
+#define bNegotitiatedLInkRate bNegotiatedLinkRate
+
+/*************************************************************************/
+/* TARGET OS LINUX SPECIFIC CODE */
+/*************************************************************************/
+
+// EDM #ifdef _linux
+#ifdef __KERNEL__
+
+// Linux base types
+
+#include <linux/types.h>
+
+#define __i8 char
+
+// pack definition
+
+// EDM #define CSMI_SAS_BEGIN_PACK(x) pack(x)
+// EDM #define CSMI_SAS_END_PACK pack()
+
+// IOCTL Control Codes
+// (IoctlHeader.ControlCode)
+
+// Control Codes prior to 0.77
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+// #define CC_CSMI_SAS_GET_DRIVER_INFO 0x12345678
+// #define CC_CSMI_SAS_GET_CNTLR_CONFIG 0x23456781
+// #define CC_CSMI_SAS_GET_CNTLR_STATUS 0x34567812
+// #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0x92345678
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+// #define CC_CSMI_SAS_GET_RAID_INFO 0x45678123
+// #define CC_CSMI_SAS_GET_RAID_CONFIG 0x56781234
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+// #define CC_CSMI_SAS_GET_PHY_INFO 0x67812345
+// #define CC_CSMI_SAS_SET_PHY_INFO 0x78123456
+// #define CC_CSMI_SAS_GET_LINK_ERRORS 0x81234567
+// #define CC_CSMI_SAS_SMP_PASSTHRU 0xA1234567
+// #define CC_CSMI_SAS_SSP_PASSTHRU 0xB1234567
+// #define CC_CSMI_SAS_STP_PASSTHRU 0xC1234567
+// #define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xD1234567
+// #define CC_CSMI_SAS_GET_SCSI_ADDRESS 0xE1234567
+// #define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xF1234567
+// #define CC_CSMI_SAS_TASK_MANAGEMENT 0xA2345678
+
+// Control Codes for 0.77 and later
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+#define CC_CSMI_SAS_GET_DRIVER_INFO 0xCC770001
+#define CC_CSMI_SAS_GET_CNTLR_CONFIG 0xCC770002
+#define CC_CSMI_SAS_GET_CNTLR_STATUS 0xCC770003
+#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0xCC770004
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+#define CC_CSMI_SAS_GET_RAID_INFO 0xCC77000A
+#define CC_CSMI_SAS_GET_RAID_CONFIG 0xCC77000B
+#define CC_CSMI_SAS_GET_RAID_FEATURES 0xCC77000C
+#define CC_CSMI_SAS_SET_RAID_CONTROL 0xCC77000D
+#define CC_CSMI_SAS_GET_RAID_ELEMENT 0xCC77000E
+#define CC_CSMI_SAS_SET_RAID_OPERATION 0xCC77000F
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+#define CC_CSMI_SAS_GET_PHY_INFO 0xCC770014
+#define CC_CSMI_SAS_SET_PHY_INFO 0xCC770015
+#define CC_CSMI_SAS_GET_LINK_ERRORS 0xCC770016
+#define CC_CSMI_SAS_SMP_PASSTHRU 0xCC770017
+#define CC_CSMI_SAS_SSP_PASSTHRU 0xCC770018
+#define CC_CSMI_SAS_STP_PASSTHRU 0xCC770019
+#define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xCC770020
+#define CC_CSMI_SAS_GET_SCSI_ADDRESS 0xCC770021
+#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xCC770022
+#define CC_CSMI_SAS_TASK_MANAGEMENT 0xCC770023
+#define CC_CSMI_SAS_GET_CONNECTOR_INFO 0xCC770024
+#define CC_CSMI_SAS_GET_LOCATION 0xCC770025
+
+
+// Control Codes requiring CSMI_PHY_SIGNATURE
+
+#define CC_CSMI_SAS_PHY_CONTROL 0xCC77003C
+
+// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
+#pragma pack(8)
+
+// IOCTL_HEADER
+typedef struct _IOCTL_HEADER {
+ __u32 IOControllerNumber;
+ __u32 Length;
+ __u32 ReturnCode;
+ __u32 Timeout;
+ __u16 Direction;
+} IOCTL_HEADER,
+ *PIOCTL_HEADER;
+
+// EDM #pragma CSMI_SAS_END_PACK
+#pragma pack()
+
+#endif
+
+/*************************************************************************/
+/* TARGET OS WINDOWS SPECIFIC CODE */
+/*************************************************************************/
+
+#ifdef _WIN32
+
+// windows IOCTL definitions
+
+#ifndef _NTDDSCSIH_
+#include <ntddscsi.h>
+#endif
+
+// pack definition
+
+#if defined _MSC_VER
+ #define CSMI_SAS_BEGIN_PACK(x) pack(push,x)
+ #define CSMI_SAS_END_PACK pack(pop)
+#elif defined __BORLANDC__
+ #define CSMI_SAS_BEGIN_PACK(x) option -a##x
+ #define CSMI_SAS_END_PACK option -a.
+#else
+ #error "CSMISAS.H - Must externally define a pack compiler designator."
+#endif
+
+// base types
+
+#define __u8 unsigned char
+#define __u16 unsigned short
+#define __u32 unsigned long
+#define __u64 unsigned __int64
+
+#define __i8 char
+
+// IOCTL Control Codes
+// (IoctlHeader.ControlCode)
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+#define CC_CSMI_SAS_GET_DRIVER_INFO 1
+#define CC_CSMI_SAS_GET_CNTLR_CONFIG 2
+#define CC_CSMI_SAS_GET_CNTLR_STATUS 3
+#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 4
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+#define CC_CSMI_SAS_GET_RAID_INFO 10
+#define CC_CSMI_SAS_GET_RAID_CONFIG 11
+#define CC_CSMI_SAS_GET_RAID_FEATURES 12
+#define CC_CSMI_SAS_SET_RAID_CONTROL 13
+#define CC_CSMI_SAS_GET_RAID_ELEMENT 14
+#define CC_CSMI_SAS_SET_RAID_OPERATION 15
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+#define CC_CSMI_SAS_GET_PHY_INFO 20
+#define CC_CSMI_SAS_SET_PHY_INFO 21
+#define CC_CSMI_SAS_GET_LINK_ERRORS 22
+#define CC_CSMI_SAS_SMP_PASSTHRU 23
+#define CC_CSMI_SAS_SSP_PASSTHRU 24
+#define CC_CSMI_SAS_STP_PASSTHRU 25
+#define CC_CSMI_SAS_GET_SATA_SIGNATURE 26
+#define CC_CSMI_SAS_GET_SCSI_ADDRESS 27
+#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 28
+#define CC_CSMI_SAS_TASK_MANAGEMENT 29
+#define CC_CSMI_SAS_GET_CONNECTOR_INFO 30
+#define CC_CSMI_SAS_GET_LOCATION 31
+
+// Control Codes requiring CSMI_PHY_SIGNATURE
+
+#define CC_CSMI_SAS_PHY_CONTROL 60
+
+#define IOCTL_HEADER SRB_IO_CONTROL
+#define PIOCTL_HEADER PSRB_IO_CONTROL
+
+#endif
+
+/*************************************************************************/
+/* TARGET OS NETWARE SPECIFIC CODE */
+/*************************************************************************/
+
+#ifdef _NETWARE
+
+// NetWare IOCTL definitions
+
+#define CSMI_SAS_BEGIN_PACK(x) pack(x)
+#define CSMI_SAS_END_PACK pack()
+
+#ifndef LONG
+typedef unsigned long LONG;
+#endif
+
+#ifndef WORD
+typedef unsigned short WORD;
+#endif
+
+#ifndef BYTE
+typedef unsigned char BYTE;
+#endif
+
+/* Need to have these definitions for Netware */
+#define __u8 unsigned char
+#define __u16 unsigned short
+#define __u32 unsigned long
+#define __u64 unsigned __int64
+
+#define __i8 char
+
+
+// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
+#pragma pack(8)
+
+// IOCTL_HEADER
+typedef struct _IOCTL_HEADER {
+ __u32 Length;
+ __u32 ReturnCode;
+} IOCTL_HEADER,
+ *PIOCTL_HEADER;
+
+// EDM #pragma CSMI_SAS_END_PACK
+#pragma pack()
+
+// IOCTL Control Codes
+// (IoctlHeader.ControlCode)
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+#define CC_CSMI_SAS_GET_DRIVER_INFO 0x01FF0001
+#define CC_CSMI_SAS_GET_CNTLR_CONFIG 0x01FF0002
+#define CC_CSMI_SAS_GET_CNTLR_STATUS 0x01FF0003
+#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0x01FF0004
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+#define CC_CSMI_SAS_GET_RAID_INFO 0x01FF000A
+#define CC_CSMI_SAS_GET_RAID_CONFIG 0x01FF000B
+#define CC_CSMI_SAS_GET_RAID_FEATURES 0x01FF000C
+#define CC_CSMI_SAS_SET_RAID_CONTROL 0x01FF000D
+#define CC_CSMI_SAS_GET_RAID_ELEMENT 0x01FF000E
+#define CC_CSMI_SAS_SET_RAID_OPERATION 0x01FF000F
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+#define CC_CSMI_SAS_GET_PHY_INFO 0x01FF0014
+#define CC_CSMI_SAS_SET_PHY_INFO 0x01FF0015
+#define CC_CSMI_SAS_GET_LINK_ERRORS 0x01FF0016
+#define CC_CSMI_SAS_SMP_PASSTHRU 0x01FF0017
+#define CC_CSMI_SAS_SSP_PASSTHRU 0x01FF0018
+#define CC_CSMI_SAS_STP_PASSTHRU 0x01FF0019
+#define CC_CSMI_SAS_GET_SATA_SIGNATURE 0x01FF001A
+#define CC_CSMI_SAS_GET_SCSI_ADDRESS 0x01FF001B
+#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0x01FF001C
+#define CC_CSMI_SAS_TASK_MANAGEMENT 0x01FF001D
+#define CC_CSMI_SAS_GET_CONNECTOR_INFO 0x01FF001E
+#define CC_CSMI_SAS_GET_LOCATION 0x01FF001F
+
+// Control Codes requiring CSMI_PHY_SIGNATURE
+
+#define CC_CSMI_SAS_PHY_CONTROL 60
+
+#endif
+
+/*************************************************************************/
+/* TARGET OS NOT DEFINED ERROR */
+/*************************************************************************/
+
+// EDM
+//#if (!_WIN32 && !_linux && !_NETWARE)
+// #error "Unknown target OS."
+//#endif
+
+/*************************************************************************/
+/* OS INDEPENDENT CODE */
+/*************************************************************************/
+
+/* * * * * * * * * * Class Independent IOCTL Constants * * * * * * * * * */
+
+// Return codes for all IOCTL's regardless of class
+// (IoctlHeader.ReturnCode)
+
+#define CSMI_SAS_STATUS_SUCCESS 0
+#define CSMI_SAS_STATUS_FAILED 1
+#define CSMI_SAS_STATUS_BAD_CNTL_CODE 2
+#define CSMI_SAS_STATUS_INVALID_PARAMETER 3
+#define CSMI_SAS_STATUS_WRITE_ATTEMPTED 4
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_ALL_SIGNATURE "CSMIALL"
+
+// Timeout value default of 60 seconds
+// (IoctlHeader.Timeout)
+
+#define CSMI_ALL_TIMEOUT 60
+
+// Direction values for data flow on this IOCTL
+// (IoctlHeader.Direction, Linux only)
+#define CSMI_SAS_DATA_READ 0
+#define CSMI_SAS_DATA_WRITE 1
+
+// I/O Bus Types
+// ISA and EISA bus types are not supported
+// (bIoBusType)
+
+#define CSMI_SAS_BUS_TYPE_PCI 3
+#define CSMI_SAS_BUS_TYPE_PCMCIA 4
+
+// Controller Status
+// (uStatus)
+
+#define CSMI_SAS_CNTLR_STATUS_GOOD 1
+#define CSMI_SAS_CNTLR_STATUS_FAILED 2
+#define CSMI_SAS_CNTLR_STATUS_OFFLINE 3
+#define CSMI_SAS_CNTLR_STATUS_POWEROFF 4
+
+// Offline Status Reason
+// (uOfflineReason)
+
+#define CSMI_SAS_OFFLINE_REASON_NO_REASON 0
+#define CSMI_SAS_OFFLINE_REASON_INITIALIZING 1
+#define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_DEGRADED 2
+#define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_FAILURE 3
+
+// Controller Class
+// (bControllerClass)
+
+#define CSMI_SAS_CNTLR_CLASS_HBA 5
+
+// Controller Flag bits
+// (uControllerFlags)
+
+#define CSMI_SAS_CNTLR_SAS_HBA 0x00000001
+#define CSMI_SAS_CNTLR_SAS_RAID 0x00000002
+#define CSMI_SAS_CNTLR_SATA_HBA 0x00000004
+#define CSMI_SAS_CNTLR_SATA_RAID 0x00000008
+#define CSMI_SAS_CNTLR_SMART_ARRAY 0x00000010
+
+// for firmware download
+#define CSMI_SAS_CNTLR_FWD_SUPPORT 0x00010000
+#define CSMI_SAS_CNTLR_FWD_ONLINE 0x00020000
+#define CSMI_SAS_CNTLR_FWD_SRESET 0x00040000
+#define CSMI_SAS_CNTLR_FWD_HRESET 0x00080000
+#define CSMI_SAS_CNTLR_FWD_RROM 0x00100000
+
+// for RAID configuration supported
+#define CSMI_SAS_CNTLR_RAID_CFG_SUPPORT 0x01000000
+
+// Download Flag bits
+// (uDownloadFlags)
+#define CSMI_SAS_FWD_VALIDATE 0x00000001
+#define CSMI_SAS_FWD_SOFT_RESET 0x00000002
+#define CSMI_SAS_FWD_HARD_RESET 0x00000004
+
+// Firmware Download Status
+// (usStatus)
+#define CSMI_SAS_FWD_SUCCESS 0
+#define CSMI_SAS_FWD_FAILED 1
+#define CSMI_SAS_FWD_USING_RROM 2
+#define CSMI_SAS_FWD_REJECT 3
+#define CSMI_SAS_FWD_DOWNREV 4
+
+// Firmware Download Severity
+// (usSeverity>
+#define CSMI_SAS_FWD_INFORMATION 0
+#define CSMI_SAS_FWD_WARNING 1
+#define CSMI_SAS_FWD_ERROR 2
+#define CSMI_SAS_FWD_FATAL 3
+
+/* * * * * * * * * * SAS RAID Class IOCTL Constants * * * * * * * * */
+
+// Return codes for the RAID IOCTL's regardless of class
+// (IoctlHeader.ReturnCode)
+
+#define CSMI_SAS_RAID_SET_OUT_OF_RANGE 1000
+#define CSMI_SAS_RAID_SET_BUFFER_TOO_SMALL 1001
+#define CSMI_SAS_RAID_SET_DATA_CHANGED 1002
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_RAID_SIGNATURE "CSMIARY"
+
+// Timeout value default of 60 seconds
+// (IoctlHeader.Timeout)
+
+#define CSMI_RAID_TIMEOUT 60
+
+// RAID Types
+// (bRaidType)
+#define CSMI_SAS_RAID_TYPE_NONE 0
+#define CSMI_SAS_RAID_TYPE_0 1
+#define CSMI_SAS_RAID_TYPE_1 2
+#define CSMI_SAS_RAID_TYPE_10 3
+#define CSMI_SAS_RAID_TYPE_5 4
+#define CSMI_SAS_RAID_TYPE_15 5
+#define CSMI_SAS_RAID_TYPE_6 6
+#define CSMI_SAS_RAID_TYPE_50 7
+#define CSMI_SAS_RAID_TYPE_VOLUME 8
+#define CSMI_SAS_RAID_TYPE_1E 9
+#define CSMI_SAS_RAID_TYPE_OTHER 255
+// the last value 255 was already defined for other
+// so end is defined as 254
+#define CSMI_SAS_RAID_TYPE_END 254
+
+// RAID Status
+// (bStatus)
+#define CSMI_SAS_RAID_SET_STATUS_OK 0
+#define CSMI_SAS_RAID_SET_STATUS_DEGRADED 1
+#define CSMI_SAS_RAID_SET_STATUS_REBUILDING 2
+#define CSMI_SAS_RAID_SET_STATUS_FAILED 3
+#define CSMI_SAS_RAID_SET_STATUS_OFFLINE 4
+#define CSMI_SAS_RAID_SET_STATUS_TRANSFORMING 5
+#define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_REBUILD 6
+#define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_TRANSFORMATION 7
+
+// RAID Drive Count
+// (bDriveCount, 0xF1 to 0xFF are reserved)
+#define CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG 0xF1
+#define CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED 0xF2
+
+// RAID Data Type
+// (bDataType)
+#define CSMI_SAS_RAID_DATA_DRIVES 0
+#define CSMI_SAS_RAID_DATA_DEVICE_ID 1
+#define CSMI_SAS_RAID_DATA_ADDITIONAL_DATA 2
+
+// RAID Drive Status
+// (bDriveStatus)
+#define CSMI_SAS_DRIVE_STATUS_OK 0
+#define CSMI_SAS_DRIVE_STATUS_REBUILDING 1
+#define CSMI_SAS_DRIVE_STATUS_FAILED 2
+#define CSMI_SAS_DRIVE_STATUS_DEGRADED 3
+#define CSMI_SAS_DRIVE_STATUS_OFFLINE 4
+#define CSMI_SAS_DRIVE_STATUS_QUEUED_FOR_REBUILD 5
+
+// RAID Drive Usage
+// (bDriveUsage)
+#define CSMI_SAS_DRIVE_CONFIG_NOT_USED 0
+#define CSMI_SAS_DRIVE_CONFIG_MEMBER 1
+#define CSMI_SAS_DRIVE_CONFIG_SPARE 2
+#define CSMI_SAS_DRIVE_CONFIG_SPARE_ACTIVE 3
+
+// RAID Drive Type
+// (bDriveType)
+#define CSMI_SAS_DRIVE_TYPE_UNKNOWN 0
+#define CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS 1
+#define CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS 2
+#define CSMI_SAS_DRIVE_TYPE_SATA 3
+#define CSMI_SAS_DRIVE_TYPE_SATA_PS 4
+#define CSMI_SAS_DRIVE_TYPE_OTHER 255
+
+// RAID Write Protect
+// (bWriteProtect)
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNKNOWN 0
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNCHANGED 0
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_ENABLED 1
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_DISABLED 2
+
+// RAID Cache Setting
+// (bCacheSetting)
+#define CSMI_SAS_RAID_SET_CACHE_UNKNOWN 0
+#define CSMI_SAS_RAID_SET_CACHE_UNCHANGED 0
+#define CSMI_SAS_RAID_SET_CACHE_ENABLED 1
+#define CSMI_SAS_RAID_SET_CACHE_DISABLED 2
+#define CSMI_SAS_RAID_SET_CACHE_CORRUPT 3
+
+// RAID Features
+// (uFeatures)
+#define CSMI_SAS_RAID_FEATURE_TRANSFORMATION 0x00000001
+#define CSMI_SAS_RAID_FEATURE_REBUILD 0x00000002
+#define CSMI_SAS_RAID_FEATURE_SPLIT_MIRROR 0x00000004
+#define CSMI_SAS_RAID_FEATURE_MERGE_MIRROR 0x00000008
+#define CSMI_SAS_RAID_FEATURE_LUN_RENUMBER 0x00000010
+#define CSMI_SAS_RAID_FEATURE_SURFACE_SCAN 0x00000020
+#define CSMI_SAS_RAID_FEATURE_SPARES_SHARED 0x00000040
+
+// RAID Priority
+// (bDefaultTransformPriority, etc.)
+#define CSMI_SAS_PRIORITY_UNKNOWN 0
+#define CSMI_SAS_PRIORITY_UNCHANGED 0
+#define CSMI_SAS_PRIORITY_AUTO 1
+#define CSMI_SAS_PRIORITY_OFF 2
+#define CSMI_SAS_PRIORITY_LOW 3
+#define CSMI_SAS_PRIORITY_MEDIUM 4
+#define CSMI_SAS_PRIORITY_HIGH 5
+
+// RAID Transformation Rules
+// (uRaidSetTransformationRules)
+#define CSMI_SAS_RAID_RULE_AVAILABLE_MEMORY 0x00000001
+#define CSMI_SAS_RAID_RULE_OVERLAPPED_EXTENTS 0x00000002
+
+// RAID Cache Ratios Supported
+// (bCacheRatiosSupported)
+// from 0 to 100 defines the write to read ratio, 0 is 100% write
+#define CSMI_SAS_RAID_CACHE_RATIO_RANGE 101
+#define CSMI_SAS_RAID_CACHE_RATIO_FIXED 102
+#define CSMI_SAS_RAID_CACHE_RATIO_AUTO 103
+#define CSMI_SAS_RAID_CACHE_RATIO_END 255
+
+// RAID Cache Ratio Flag
+// (bCacheRatioFlag)
+#define CSMI_SAS_RAID_CACHE_RATIO_DISABLE 0
+#define CSMI_SAS_RAID_CACHE_RATIO_ENABLE 1
+
+// RAID Clear Configuration Signature
+// (bClearConfiguration)
+#define CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE "RAIDCLR"
+
+// RAID Failure Codes
+// (uFailureCode)
+#define CSMI_SAS_FAIL_CODE_OK 0
+#define CSMI_SAS_FAIL_CODE_PARAMETER_INVALID 1000
+#define CSMI_SAS_FAIL_CODE_TRANSFORM_PRIORITY_INVALID 1001
+#define CSMI_SAS_FAIL_CODE_REBUILD_PRIORITY_INVALID 1002
+#define CSMI_SAS_FAIL_CODE_CACHE_RATIO_INVALID 1003
+#define CSMI_SAS_FAIL_CODE_SURFACE_SCAN_INVALID 1004
+#define CSMI_SAS_FAIL_CODE_CLEAR_CONFIGURATION_INVALID 1005
+#define CSMI_SAS_FAIL_CODE_ELEMENT_INDEX_INVALID 1006
+#define CSMI_SAS_FAIL_CODE_SUBELEMENT_INDEX_INVALID 1007
+#define CSMI_SAS_FAIL_CODE_EXTENT_INVALID 1008
+#define CSMI_SAS_FAIL_CODE_BLOCK_COUNT_INVALID 1009
+#define CSMI_SAS_FAIL_CODE_DRIVE_INDEX_INVALID 1010
+#define CSMI_SAS_FAIL_CODE_EXISTING_LUN_INVALID 1011
+#define CSMI_SAS_FAIL_CODE_RAID_TYPE_INVALID 1012
+#define CSMI_SAS_FAIL_CODE_STRIPE_SIZE_INVALID 1013
+#define CSMI_SAS_FAIL_CODE_TRANSFORMATION_INVALID 1014
+#define CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID 1015
+#define CSMI_SAS_FAIL_CODE_ENUMERATION_TYPE_INVALID 1016
+
+#define CSMI_SAS_FAIL_CODE_EXCEEDED_RAID_SET_COUNT 2000
+#define CSMI_SAS_FAIL_CODE_DUPLICATE_LUN 2001
+
+#define CSMI_SAS_FAIL_CODE_WAIT_FOR_OPERATION 3000
+
+// RAID Enumeration Types
+// (uEnumerationType)
+#define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE 0
+#define CSMI_SAS_RAID_ELEMENT_TYPE_MODULE 1
+#define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE_RAID_SET 2
+#define CSMI_SAS_RAID_ELEMENT_TYPE_EXTENT_DRIVE 3
+
+// RAID Extent Types
+// (bExtentType)
+#define CSMI_SAS_RAID_EXTENT_RESERVED 0
+#define CSMI_SAS_RAID_EXTENT_METADATA 1
+#define CSMI_SAS_RAID_EXTENT_ALLOCATED 2
+#define CSMI_SAS_RAID_EXTENT_UNALLOCATED 3
+
+// RAID Operation Types
+// (uOperationType)
+#define CSMI_SAS_RAID_SET_CREATE 0
+#define CSMI_SAS_RAID_SET_LABEL 1
+#define CSMI_SAS_RAID_SET_TRANSFORM 2
+#define CSMI_SAS_RAID_SET_DELETE 3
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT 4
+#define CSMI_SAS_RAID_SET_CACHE 5
+#define CSMI_SAS_RAID_SET_ONLINE_STATE 6
+#define CSMI_SAS_RAID_SET_SPARE 7
+
+// RAID Transform Types
+// (bTransformType)
+#define CSMI_SAS_RAID_SET_TRANSFORM_SPLIT_MIRROR 0
+#define CSMI_SAS_RAID_SET_TRANSFORM_MERGE_RAID_0 1
+#define CSMI_SAS_RAID_SET_TRANSFORM_LUN_RENUMBER 2
+#define CSMI_SAS_RAID_SET_TRANSFORM_RAID_SET 3
+
+// RAID Online State
+// (bOnlineState)
+#define CSMI_SAS_RAID_SET_STATE_UNKNOWN 0
+#define CSMI_SAS_RAID_SET_STATE_ONLINE 1
+#define CSMI_SAS_RAID_SET_STATE_OFFLINE 2
+
+/* * * * * * * * * * SAS HBA Class IOCTL Constants * * * * * * * * * */
+
+// Return codes for SAS IOCTL's
+// (IoctlHeader.ReturnCode)
+
+#define CSMI_SAS_PHY_INFO_CHANGED CSMI_SAS_STATUS_SUCCESS
+#define CSMI_SAS_PHY_INFO_NOT_CHANGEABLE 2000
+#define CSMI_SAS_LINK_RATE_OUT_OF_RANGE 2001
+
+#define CSMI_SAS_PHY_DOES_NOT_EXIST 2002
+#define CSMI_SAS_PHY_DOES_NOT_MATCH_PORT 2003
+#define CSMI_SAS_PHY_CANNOT_BE_SELECTED 2004
+#define CSMI_SAS_SELECT_PHY_OR_PORT 2005
+#define CSMI_SAS_PORT_DOES_NOT_EXIST 2006
+#define CSMI_SAS_PORT_CANNOT_BE_SELECTED 2007
+#define CSMI_SAS_CONNECTION_FAILED 2008
+
+#define CSMI_SAS_NO_SATA_DEVICE 2009
+#define CSMI_SAS_NO_SATA_SIGNATURE 2010
+#define CSMI_SAS_SCSI_EMULATION 2011
+#define CSMI_SAS_NOT_AN_END_DEVICE 2012
+#define CSMI_SAS_NO_SCSI_ADDRESS 2013
+#define CSMI_SAS_NO_DEVICE_ADDRESS 2014
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_SAS_SIGNATURE "CSMISAS"
+
+// Timeout value default of 60 seconds
+// (IoctlHeader.Timeout)
+
+#define CSMI_SAS_TIMEOUT 60
+
+// Device types
+// (bDeviceType)
+
+#define CSMI_SAS_PHY_UNUSED 0x00
+#define CSMI_SAS_NO_DEVICE_ATTACHED 0x00
+#define CSMI_SAS_END_DEVICE 0x10
+#define CSMI_SAS_EDGE_EXPANDER_DEVICE 0x20
+#define CSMI_SAS_FANOUT_EXPANDER_DEVICE 0x30
+
+// Protocol options
+// (bInitiatorPortProtocol, bTargetPortProtocol)
+
+#define CSMI_SAS_PROTOCOL_SATA 0x01
+#define CSMI_SAS_PROTOCOL_SMP 0x02
+#define CSMI_SAS_PROTOCOL_STP 0x04
+#define CSMI_SAS_PROTOCOL_SSP 0x08
+
+// Negotiated and hardware link rates
+// (bNegotiatedLinkRate, bMinimumLinkRate, bMaximumLinkRate)
+
+#define CSMI_SAS_LINK_RATE_UNKNOWN 0x00
+#define CSMI_SAS_PHY_DISABLED 0x01
+#define CSMI_SAS_LINK_RATE_FAILED 0x02
+#define CSMI_SAS_SATA_SPINUP_HOLD 0x03
+#define CSMI_SAS_SATA_PORT_SELECTOR 0x04
+#define CSMI_SAS_LINK_RATE_1_5_GBPS 0x08
+#define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09
+#define CSMI_SAS_LINK_VIRTUAL 0x10
+
+// Discover state
+// (bAutoDiscover)
+
+#define CSMI_SAS_DISCOVER_NOT_SUPPORTED 0x00
+#define CSMI_SAS_DISCOVER_NOT_STARTED 0x01
+#define CSMI_SAS_DISCOVER_IN_PROGRESS 0x02
+#define CSMI_SAS_DISCOVER_COMPLETE 0x03
+#define CSMI_SAS_DISCOVER_ERROR 0x04
+
+// Phy features
+
+#define CSMI_SAS_PHY_VIRTUAL_SMP 0x01
+
+// Programmed link rates
+// (bMinimumLinkRate, bMaximumLinkRate)
+// (bProgrammedMinimumLinkRate, bProgrammedMaximumLinkRate)
+
+#define CSMI_SAS_PROGRAMMED_LINK_RATE_UNCHANGED 0x00
+#define CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS 0x08
+#define CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS 0x09
+
+// Link rate
+// (bNegotiatedLinkRate in CSMI_SAS_SET_PHY_INFO)
+
+#define CSMI_SAS_LINK_RATE_NEGOTIATE 0x00
+#define CSMI_SAS_LINK_RATE_PHY_DISABLED 0x01
+
+// Signal class
+// (bSignalClass in CSMI_SAS_SET_PHY_INFO)
+
+#define CSMI_SAS_SIGNAL_CLASS_UNKNOWN 0x00
+#define CSMI_SAS_SIGNAL_CLASS_DIRECT 0x01
+#define CSMI_SAS_SIGNAL_CLASS_SERVER 0x02
+#define CSMI_SAS_SIGNAL_CLASS_ENCLOSURE 0x03
+
+// Link error reset
+// (bResetCounts)
+
+#define CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS 0x00
+#define CSMI_SAS_LINK_ERROR_RESET_COUNTS 0x01
+
+// Phy identifier
+// (bPhyIdentifier)
+
+#define CSMI_SAS_USE_PORT_IDENTIFIER 0xFF
+
+// Port identifier
+// (bPortIdentifier)
+
+#define CSMI_SAS_IGNORE_PORT 0xFF
+
+// Programmed link rates
+// (bConnectionRate)
+
+#define CSMI_SAS_LINK_RATE_NEGOTIATED 0x00
+#define CSMI_SAS_LINK_RATE_1_5_GBPS 0x08
+#define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09
+
+// Connection status
+// (bConnectionStatus)
+
+#define CSMI_SAS_OPEN_ACCEPT 0
+#define CSMI_SAS_OPEN_REJECT_BAD_DESTINATION 1
+#define CSMI_SAS_OPEN_REJECT_RATE_NOT_SUPPORTED 2
+#define CSMI_SAS_OPEN_REJECT_NO_DESTINATION 3
+#define CSMI_SAS_OPEN_REJECT_PATHWAY_BLOCKED 4
+#define CSMI_SAS_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED 5
+#define CSMI_SAS_OPEN_REJECT_RESERVE_ABANDON 6
+#define CSMI_SAS_OPEN_REJECT_RESERVE_CONTINUE 7
+#define CSMI_SAS_OPEN_REJECT_RESERVE_INITIALIZE 8
+#define CSMI_SAS_OPEN_REJECT_RESERVE_STOP 9
+#define CSMI_SAS_OPEN_REJECT_RETRY 10
+#define CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY 11
+#define CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION 12
+
+// SSP Status
+// (bSSPStatus)
+
+#define CSMI_SAS_SSP_STATUS_UNKNOWN 0x00
+#define CSMI_SAS_SSP_STATUS_WAITING 0x01
+#define CSMI_SAS_SSP_STATUS_COMPLETED 0x02
+#define CSMI_SAS_SSP_STATUS_FATAL_ERROR 0x03
+#define CSMI_SAS_SSP_STATUS_RETRY 0x04
+#define CSMI_SAS_SSP_STATUS_NO_TAG 0x05
+
+// SSP Flags
+// (uFlags)
+
+#define CSMI_SAS_SSP_READ 0x00000001
+#define CSMI_SAS_SSP_WRITE 0x00000002
+#define CSMI_SAS_SSP_UNSPECIFIED 0x00000004
+
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_SIMPLE 0x00000000
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE 0x00000010
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED 0x00000020
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA 0x00000040
+
+// SSP Data present
+// (bDataPresent)
+
+#define CSMI_SAS_SSP_NO_DATA_PRESENT 0x00
+#define CSMI_SAS_SSP_RESPONSE_DATA_PRESENT 0x01
+#define CSMI_SAS_SSP_SENSE_DATA_PRESENT 0x02
+
+// STP Flags
+// (uFlags)
+
+#define CSMI_SAS_STP_READ 0x00000001
+#define CSMI_SAS_STP_WRITE 0x00000002
+#define CSMI_SAS_STP_UNSPECIFIED 0x00000004
+#define CSMI_SAS_STP_PIO 0x00000010
+#define CSMI_SAS_STP_DMA 0x00000020
+#define CSMI_SAS_STP_PACKET 0x00000040
+#define CSMI_SAS_STP_DMA_QUEUED 0x00000080
+#define CSMI_SAS_STP_EXECUTE_DIAG 0x00000100
+#define CSMI_SAS_STP_RESET_DEVICE 0x00000200
+
+// Task Management Flags
+// (uFlags)
+
+#define CSMI_SAS_TASK_IU 0x00000001
+#define CSMI_SAS_HARD_RESET_SEQUENCE 0x00000002
+#define CSMI_SAS_SUPPRESS_RESULT 0x00000004
+
+// Task Management Functions
+// (bTaskManagement)
+
+#define CSMI_SAS_SSP_ABORT_TASK 0x01
+#define CSMI_SAS_SSP_ABORT_TASK_SET 0x02
+#define CSMI_SAS_SSP_CLEAR_TASK_SET 0x04
+#define CSMI_SAS_SSP_LOGICAL_UNIT_RESET 0x08
+#define CSMI_SAS_SSP_CLEAR_ACA 0x40
+#define CSMI_SAS_SSP_QUERY_TASK 0x80
+
+// Task Management Information
+// (uInformation)
+
+#define CSMI_SAS_SSP_TEST 1
+#define CSMI_SAS_SSP_EXCEEDED 2
+#define CSMI_SAS_SSP_DEMAND 3
+#define CSMI_SAS_SSP_TRIGGER 4
+
+// Connector Pinout Information
+// (uPinout)
+
+#define CSMI_SAS_CON_UNKNOWN 0x00000001
+#define CSMI_SAS_CON_SFF_8482 0x00000002
+#define CSMI_SAS_CON_SFF_8470_LANE_1 0x00000100
+#define CSMI_SAS_CON_SFF_8470_LANE_2 0x00000200
+#define CSMI_SAS_CON_SFF_8470_LANE_3 0x00000400
+#define CSMI_SAS_CON_SFF_8470_LANE_4 0x00000800
+#define CSMI_SAS_CON_SFF_8484_LANE_1 0x00010000
+#define CSMI_SAS_CON_SFF_8484_LANE_2 0x00020000
+#define CSMI_SAS_CON_SFF_8484_LANE_3 0x00040000
+#define CSMI_SAS_CON_SFF_8484_LANE_4 0x00080000
+
+// Connector Location Information
+// (bLocation)
+
+// same as uPinout above...
+// #define CSMI_SAS_CON_UNKNOWN 0x01
+#define CSMI_SAS_CON_INTERNAL 0x02
+#define CSMI_SAS_CON_EXTERNAL 0x04
+#define CSMI_SAS_CON_SWITCHABLE 0x08
+#define CSMI_SAS_CON_AUTO 0x10
+#define CSMI_SAS_CON_NOT_PRESENT 0x20
+#define CSMI_SAS_CON_NOT_CONNECTED 0x80
+
+// Device location identification
+// (bIdentify)
+
+#define CSMI_SAS_LOCATE_UNKNOWN 0x00
+#define CSMI_SAS_LOCATE_FORCE_OFF 0x01
+#define CSMI_SAS_LOCATE_FORCE_ON 0x02
+
+// Location Valid flags
+// (uLocationFlags)
+
+#define CSMI_SAS_LOCATE_SAS_ADDRESS_VALID 0x00000001
+#define CSMI_SAS_LOCATE_SAS_LUN_VALID 0x00000002
+#define CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID 0x00000004
+#define CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID 0x00000008
+#define CSMI_SAS_LOCATE_BAY_PREFIX_VALID 0x00000010
+#define CSMI_SAS_LOCATE_BAY_IDENTIFIER_VALID 0x00000020
+#define CSMI_SAS_LOCATE_LOCATION_STATE_VALID 0x00000040
+
+/* * * * * * * * SAS Phy Control Class IOCTL Constants * * * * * * * * */
+
+// Return codes for SAS Phy Control IOCTL's
+// (IoctlHeader.ReturnCode)
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_PHY_SIGNATURE "CSMIPHY"
+
+// Phy Control Functions
+// (bFunction)
+
+// values 0x00 to 0xFF are consistent in definition with the SMP PHY CONTROL
+// function defined in the SAS spec
+#define CSMI_SAS_PC_NOP 0x00000000
+#define CSMI_SAS_PC_LINK_RESET 0x00000001
+#define CSMI_SAS_PC_HARD_RESET 0x00000002
+#define CSMI_SAS_PC_PHY_DISABLE 0x00000003
+// 0x04 to 0xFF reserved...
+#define CSMI_SAS_PC_GET_PHY_SETTINGS 0x00000100
+
+// Link Flags
+#define CSMI_SAS_PHY_ACTIVATE_CONTROL 0x00000001
+#define CSMI_SAS_PHY_UPDATE_SPINUP_RATE 0x00000002
+#define CSMI_SAS_PHY_AUTO_COMWAKE 0x00000004
+
+// Device Types for Phy Settings
+// (bType)
+#define CSMI_SAS_UNDEFINED 0x00
+#define CSMI_SAS_SATA 0x01
+#define CSMI_SAS_SAS 0x02
+
+// Transmitter Flags
+// (uTransmitterFlags)
+#define CSMI_SAS_PHY_PREEMPHASIS_DISABLED 0x00000001
+
+// Receiver Flags
+// (uReceiverFlags)
+#define CSMI_SAS_PHY_EQUALIZATION_DISABLED 0x00000001
+
+// Pattern Flags
+// (uPatternFlags)
+// #define CSMI_SAS_PHY_ACTIVATE_CONTROL 0x00000001
+#define CSMI_SAS_PHY_DISABLE_SCRAMBLING 0x00000002
+#define CSMI_SAS_PHY_DISABLE_ALIGN 0x00000004
+#define CSMI_SAS_PHY_DISABLE_SSC 0x00000008
+
+#define CSMI_SAS_PHY_FIXED_PATTERN 0x00000010
+#define CSMI_SAS_PHY_USER_PATTERN 0x00000020
+
+// Fixed Patterns
+// (bFixedPattern)
+#define CSMI_SAS_PHY_CJPAT 0x00000001
+#define CSMI_SAS_PHY_ALIGN 0x00000002
+
+// Type Flags
+// (bTypeFlags)
+#define CSMI_SAS_PHY_POSITIVE_DISPARITY 0x01
+#define CSMI_SAS_PHY_NEGATIVE_DISPARITY 0x02
+#define CSMI_SAS_PHY_CONTROL_CHARACTER 0x04
+
+// Miscellaneous
+#define SLOT_NUMBER_UNKNOWN 0xFFFF
+
+/*************************************************************************/
+/* DATA STRUCTURES */
+/*************************************************************************/
+
+/* * * * * * * * * * Class Independent Structures * * * * * * * * * */
+
+// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
+#pragma pack(8)
+
+// CC_CSMI_SAS_DRIVER_INFO
+
+typedef struct _CSMI_SAS_DRIVER_INFO {
+ __u8 szName[81];
+ __u8 szDescription[81];
+ __u16 usMajorRevision;
+ __u16 usMinorRevision;
+ __u16 usBuildRevision;
+ __u16 usReleaseRevision;
+ __u16 usCSMIMajorRevision;
+ __u16 usCSMIMinorRevision;
+} CSMI_SAS_DRIVER_INFO,
+ *PCSMI_SAS_DRIVER_INFO;
+
+typedef struct _CSMI_SAS_DRIVER_INFO_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_DRIVER_INFO Information;
+} CSMI_SAS_DRIVER_INFO_BUFFER,
+ *PCSMI_SAS_DRIVER_INFO_BUFFER;
+
+// CC_CSMI_SAS_CNTLR_CONFIGURATION
+
+typedef struct _CSMI_SAS_PCI_BUS_ADDRESS {
+ __u8 bBusNumber;
+ __u8 bDeviceNumber;
+ __u8 bFunctionNumber;
+ __u8 bReserved;
+} CSMI_SAS_PCI_BUS_ADDRESS,
+ *PCSMI_SAS_PCI_BUS_ADDRESS;
+
+typedef union _CSMI_SAS_IO_BUS_ADDRESS {
+ CSMI_SAS_PCI_BUS_ADDRESS PciAddress;
+ __u8 bReserved[32];
+} CSMI_SAS_IO_BUS_ADDRESS,
+ *PCSMI_SAS_IO_BUS_ADDRESS;
+
+typedef struct _CSMI_SAS_CNTLR_CONFIG {
+ __u32 uBaseIoAddress;
+ struct {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } BaseMemoryAddress;
+ __u32 uBoardID;
+ __u16 usSlotNumber;
+ __u8 bControllerClass;
+ __u8 bIoBusType;
+ CSMI_SAS_IO_BUS_ADDRESS BusAddress;
+ __u8 szSerialNumber[81];
+ __u16 usMajorRevision;
+ __u16 usMinorRevision;
+ __u16 usBuildRevision;
+ __u16 usReleaseRevision;
+ __u16 usBIOSMajorRevision;
+ __u16 usBIOSMinorRevision;
+ __u16 usBIOSBuildRevision;
+ __u16 usBIOSReleaseRevision;
+ __u32 uControllerFlags;
+ __u16 usRromMajorRevision;
+ __u16 usRromMinorRevision;
+ __u16 usRromBuildRevision;
+ __u16 usRromReleaseRevision;
+ __u16 usRromBIOSMajorRevision;
+ __u16 usRromBIOSMinorRevision;
+ __u16 usRromBIOSBuildRevision;
+ __u16 usRromBIOSReleaseRevision;
+ __u8 bReserved[7];
+} CSMI_SAS_CNTLR_CONFIG,
+ *PCSMI_SAS_CNTLR_CONFIG;
+
+typedef struct _CSMI_SAS_CNTLR_CONFIG_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_CNTLR_CONFIG Configuration;
+} CSMI_SAS_CNTLR_CONFIG_BUFFER,
+ *PCSMI_SAS_CNTLR_CONFIG_BUFFER;
+
+// CC_CSMI_SAS_CNTLR_STATUS
+
+typedef struct _CSMI_SAS_CNTLR_STATUS {
+ __u32 uStatus;
+ __u32 uOfflineReason;
+ __u8 bReserved[28];
+} CSMI_SAS_CNTLR_STATUS,
+ *PCSMI_SAS_CNTLR_STATUS;
+
+typedef struct _CSMI_SAS_CNTLR_STATUS_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_CNTLR_STATUS Status;
+} CSMI_SAS_CNTLR_STATUS_BUFFER,
+ *PCSMI_SAS_CNTLR_STATUS_BUFFER;
+
+// CC_CSMI_SAS_FIRMWARE_DOWNLOAD
+
+typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD {
+ __u32 uBufferLength;
+ __u32 uDownloadFlags;
+ __u8 bReserved[32];
+ __u16 usStatus;
+ __u16 usSeverity;
+} CSMI_SAS_FIRMWARE_DOWNLOAD,
+ *PCSMI_SAS_FIRMWARE_DOWNLOAD;
+
+typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_FIRMWARE_DOWNLOAD Information;
+ __u8 bDataBuffer[1];
+} CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER,
+ *PCSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER;
+
+// CC_CSMI_SAS_RAID_INFO
+
+typedef struct _CSMI_SAS_RAID_INFO {
+ __u32 uNumRaidSets;
+ __u32 uMaxDrivesPerSet;
+ __u32 uMaxRaidSets;
+ __u8 bMaxRaidTypes;
+ __u8 bReservedByteFields[7];
+ struct
+ {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } ulMinRaidSetBlocks;
+ struct
+ {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } ulMaxRaidSetBlocks;
+ __u32 uMaxPhysicalDrives;
+ __u32 uMaxExtents;
+ __u32 uMaxModules;
+ __u32 uMaxTransformationMemory;
+ __u32 uChangeCount;
+ __u8 bReserved[44];
+} CSMI_SAS_RAID_INFO,
+ *PCSMI_SAS_RAID_INFO;
+
+typedef struct _CSMI_SAS_RAID_INFO_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_RAID_INFO Information;
+} CSMI_SAS_RAID_INFO_BUFFER,
+ *PCSMI_SAS_RAID_INFO_BUFFER;
+
+// CC_CSMI_SAS_GET_RAID_CONFIG
+
+typedef struct _CSMI_SAS_RAID_DRIVES {
+ __u8 bModel[40];
+ __u8 bFirmware[8];
+ __u8 bSerialNumber[40];
+ __u8 bSASAddress[8];
+ __u8 bSASLun[8];
+ __u8 bDriveStatus;
+ __u8 bDriveUsage;
+ __u16 usBlockSize;
+ __u8 bDriveType;
+ __u8 bReserved[15];
+ __u32 uDriveIndex;
+ struct
+ {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } ulTotalUserBlocks;
+} CSMI_SAS_RAID_DRIVES,
+ *PCSMI_SAS_RAID_DRIVES;
+
+typedef struct _CSMI_SAS_RAID_DEVICE_ID {
+ __u8 bDeviceIdentificationVPDPage[1];
+} CSMI_SAS_RAID_DEVICE_ID,
+ *PCSMI_SAS_RAID_DEVICE_ID;
+
+typedef struct _CSMI_SAS_RAID_SET_ADDITIONAL_DATA {
+ __u8 bLabel[16];
+ __u8 bRaidSetLun[8];
+ __u8 bWriteProtection;
+ __u8 bCacheSetting;
+ __u8 bCacheRatio;
+ __u16 usBlockSize;
+ __u8 bReservedBytes[11];
+ struct
+ {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } ulRaidSetExtentOffset;
+ struct
+ {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } ulRaidSetBlocks;
+ __u32 uStripeSizeInBlocks;
+ __u32 uSectorsPerTrack;
+ __u8 bApplicationScratchPad[16];
+ __u32 uNumberOfHeads;
+ __u32 uNumberOfTracks;
+ __u8 bReserved[24];
+} CSMI_SAS_RAID_SET_ADDITIONAL_DATA,
+ *PCSMI_SAS_RAID_SET_ADDITIONAL_DATA;
+
+typedef struct _CSMI_SAS_RAID_CONFIG {
+ __u32 uRaidSetIndex;
+ __u32 uCapacity;
+ __u32 uStripeSize;
+ __u8 bRaidType;
+ __u8 bStatus;
+ __u8 bInformation;
+ __u8 bDriveCount;
+ __u8 bDataType;
+ __u8 bReserved[11];
+ __u32 uFailureCode;
+ __u32 uChangeCount;
+ union {
+ CSMI_SAS_RAID_DRIVES Drives[1];
+ CSMI_SAS_RAID_DEVICE_ID DeviceId[1];
+ CSMI_SAS_RAID_SET_ADDITIONAL_DATA Data[1];
+ };
+} CSMI_SAS_RAID_CONFIG,
+ *PCSMI_SAS_RAID_CONFIG;
+
+typedef struct _CSMI_SAS_RAID_CONFIG_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_RAID_CONFIG Configuration;
+} CSMI_SAS_RAID_CONFIG_BUFFER,
+ *PCSMI_SAS_RAID_CONFIG_BUFFER;
+
+// CC_CSMI_SAS_GET_RAID_FEATURES
+
+typedef struct _CSMI_SAS_RAID_TYPE_DESCRIPTION {
+ __u8 bRaidType;
+ __u8 bReservedBytes[7];
+ __u32 uSupportedStripeSizeMap;
+ __u8 bReserved[24];
+} CSMI_SAS_RAID_TYPE_DESCRIPTION,
+ *PCSMI_SAS_RAID_TYPE_DESCRIPTION;
+
+typedef struct _CSMI_SAS_RAID_FEATURES {
+ __u32 uFeatures;
+ __u8 bReservedFeatures[32];
+ __u8 bDefaultTransformPriority;
+ __u8 bTransformPriority;
+ __u8 bDefaultRebuildPriority;
+ __u8 bRebuildPriority;
+ __u8 bDefaultSurfaceScanPriority;
+ __u8 bSurfaceScanPriority;
+ __u16 usReserved;
+ __u32 uRaidSetTransformationRules;
+ __u32 uReserved[11];
+ CSMI_SAS_RAID_TYPE_DESCRIPTION RaidType[24];
+ __u8 bCacheRatiosSupported[104];
+ __u32 uChangeCount;
+ __u32 uFailureCode;
+ __u8 bReserved[120];
+} CSMI_SAS_RAID_FEATURES,
+ *PCSMI_SAS_RAID_FEATURES;
+
+typedef struct _CSMI_SAS_RAID_FEATURES_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_RAID_FEATURES Information;
+} CSMI_SAS_RAID_FEATURES_BUFFER,
+ *PCSMI_SAS_RAID_FEATURES_BUFFER;
+
+// CC_CSMI_SAS_SET_RAID_CONTROL
+
+typedef struct _CSMI_SAS_RAID_CONTROL {
+ __u8 bTransformPriority;
+ __u8 bRebuildPriority;
+ __u8 bCacheRatioFlag;
+ __u8 bCacheRatio;
+ __u8 bSurfaceScanPriority;
+ __u8 bReservedBytes[15];
+ __u8 bClearConfiguration[8];
+ __u32 uChangeCount;
+ __u8 bReserved[88];
+ __u32 uFailureCode;
+ __u8 bFailureDescription[80];
+} CSMI_SAS_RAID_CONTROL,
+ *PCSMI_SAS_RAID_CONTROL;
+
+typedef struct _CSMI_SAS_RAID_CONTROL_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_RAID_CONTROL Information;
+} CSMI_SAS_RAID_CONTROL_BUFFER,
+ *PCSMI_SAS_RAID_CONTROL_BUFFER;
+
+// CC_CSMI_SAS_GET_RAID_ELEMENT
+
+typedef struct _CSMI_SAS_DRIVE_EXTENT_INFO {
+ __u32 uDriveIndex;
+ __u8 bExtentType;
+ __u8 bReservedBytes[7];
+ struct
+ {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } ulExtentOffset;
+ struct
+ {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } ulExtentBlocks;
+ __u32 uRaidSetIndex;
+ __u8 bReserved[96];
+} CSMI_SAS_DRIVE_EXTENT_INFO,
+ *PCSMI_SAS_DRIVE_EXTENT_INFO;
+
+typedef struct _CSMI_SAS_RAID_MODULE_INFO {
+ __u8 bReserved[128];
+} CSMI_SAS_RAID_MODULE_INFO,
+ *PCSMI_SAS_RAID_MODULE_INFO;
+
+typedef struct _CSMI_SAS_DRIVE_LOCATION {
+ __u8 bConnector[16];
+ __u8 bBoxName[16];
+ __u32 uBay;
+ __u8 bReservedBytes[4];
+ __u8 bAttachedSASAddress[8];
+ __u8 bAttachedPhyIdentifier;
+ __u8 bReserved[79];
+} CSMI_SAS_DRIVE_LOCATION,
+ *PCSMI_SAS_DRIVE_LOCATION;
+
+typedef struct _CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA {
+ __u8 bNegotiatedLinkRate[2];
+ __u8 bReserved[126];
+} CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA,
+ *PCSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA;
+
+typedef struct _CSMI_SAS_DRIVE_INFO {
+ CSMI_SAS_RAID_DRIVES Device;
+ CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA Data;
+ CSMI_SAS_DRIVE_LOCATION Location;
+ __u8 bReserved[16];
+} CSMI_SAS_DRIVE_INFO,
+ *PCSMI_SAS_DRIVE_INFO;
+
+typedef struct _CSMI_SAS_RAID_ELEMENT {
+ __u32 uEnumerationType;
+ __u32 uElementIndex;
+ __u32 uNumElements;
+ __u32 uChangeCount;
+ __u32 uSubElementIndex;
+ __u8 bReserved[32];
+ __u32 uFailureCode;
+ __u8 bFailureDescription[80];
+ union {
+ CSMI_SAS_DRIVE_INFO Drive;
+ CSMI_SAS_RAID_MODULE_INFO Module;
+ CSMI_SAS_DRIVE_EXTENT_INFO Extent;
+ } Element;
+} CSMI_SAS_RAID_ELEMENT,
+ *PCSMI_SAS_RAID_ELEMENT;
+
+typedef struct _CSMI_SAS_RAID_ELEMENT_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_RAID_ELEMENT Information;
+} CSMI_SAS_RAID_ELEMENT_BUFFER,
+ *PCSMI_SAS_RAID_ELEMENT_BUFFER;
+
+// CC_CSMI_SAS_SET_RAID_OPERATION
+
+typedef struct _CSMI_SAS_RAID_SET_LIST {
+ __u32 uRaidSetIndex;
+ __u8 bExistingLun[8];
+ __u8 bNewLun[8];
+ __u8 bReserved[12];
+} CSMI_SAS_RAID_SET_LIST,
+ *PCSMI_SAS_RAID_SET_LIST;
+
+typedef struct _CSMI_SAS_RAID_SET_DRIVE_LIST {
+ __u32 uDriveIndex;
+ __u8 bDriveUsage;
+ __u8 bReserved[27];
+} CSMI_SAS_RAID_SET_DRIVE_LIST,
+ *PCSMI_SAS_RAID_SET_DRIVE_LIST;
+
+typedef struct _CSMI_SAS_RAID_SET_SPARE_INFO {
+ __u32 uRaidSetIndex;
+ __u32 uDriveCount;
+ __u8 bApplicationScratchPad[16];
+ __u8 bReserved[104];
+} CSMI_SAS_RAID_SET_SPARE_INFO,
+ *PCSMI_SAS_RAID_SET_SPARE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_ONLINE_STATE_INFO {
+ __u32 uRaidSetIndex;
+ __u8 bOnlineState;
+ __u8 bReserved[123];
+} CSMI_SAS_RAID_SET_ONLINE_STATE_INFO,
+ *PCSMI_SAS_RAID_SET_ONLINE_STATE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_CACHE_INFO {
+ __u32 uRaidSetIndex;
+ __u8 bCacheSetting;
+ __u8 bCacheRatioFlag;
+ __u8 bCacheRatio;
+ __u8 bReserved[121];
+} CSMI_SAS_RAID_SET_CACHE_INFO,
+ *PCSMI_SAS_RAID_SET_CACHE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO {
+ __u32 uRaidSetIndex;
+ __u8 bWriteProtectSetting;
+ __u8 bReserved[123];
+} CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO,
+ *PCSMI_SAS_RAID_SET_WRITE_PROTECT_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_DELETE_INFO {
+ __u32 uRaidSetIndex;
+ __u8 bReserved[124];
+} CSMI_SAS_RAID_SET_DELETE_INFO,
+ *PCSMI_SAS_RAID_SET_DELETE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_MODIFY_INFO {
+ __u8 bRaidType;
+ __u8 bReservedBytes[7];
+ __u32 uStripeSize;
+ struct
+ {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } ulRaidSetBlocks;
+ struct
+ {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } ulRaidSetExtentOffset;
+ __u32 uDriveCount;
+ __u8 bReserved[96];
+} CSMI_SAS_RAID_SET_MODIFY_INFO,
+ *PCSMI_SAS_RAID_SET_MODIFY_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_TRANSFORM_INFO {
+ __u8 bTransformType;
+ __u8 bReservedBytes[3];
+ __u32 uRaidSetIndex;
+ __u8 bRaidType;
+ __u8 bReservedBytes2[11];
+ __u32 uAdditionalRaidSetIndex;
+ __u32 uRaidSetCount;
+ __u8 bApplicationScratchPad[16];
+ CSMI_SAS_RAID_SET_MODIFY_INFO Modify;
+ __u8 bReserved[80];
+} CSMI_SAS_RAID_SET_TRANSFORM_INFO,
+ *PCSMI_SAS_RAID_SET_TRANSFORM_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_LABEL_INFO {
+ __u32 uRaidSetIndex;
+ __u8 bLabel[16];
+ __u8 bReserved[108];
+} CSMI_SAS_RAID_SET_LABEL_INFO,
+ *PCSMI_SAS_RAID_SET_LABEL_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_CREATE_INFO {
+ __u8 bRaidType;
+ __u8 bReservedBytes[7];
+ __u32 uStripeSize;
+ __u32 uTrackSectorCount;
+ struct
+ {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } ulRaidSetBlocks;
+ struct
+ {
+ __u32 uLowPart;
+ __u32 uHighPart;
+ } ulRaidSetExtentOffset;
+ __u32 uDriveCount;
+ __u8 bLabel[16];
+ __u32 uRaidSetIndex;
+ __u8 bApplicationScratchPad[16];
+ __u32 uNumberOfHeads;
+ __u32 uNumberOfTracks;
+ __u8 bReserved[48];
+} CSMI_SAS_RAID_SET_CREATE_INFO,
+ *PCSMI_SAS_RAID_SET_CREATE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_OPERATION {
+ __u32 uOperationType;
+ __u32 uChangeCount;
+ __u32 uFailureCode;
+ __u8 bFailureDescription[80];
+ __u8 bReserved[28];
+ union {
+ CSMI_SAS_RAID_SET_CREATE_INFO Create;
+ CSMI_SAS_RAID_SET_LABEL_INFO Label;
+ CSMI_SAS_RAID_SET_TRANSFORM_INFO Transform;
+ CSMI_SAS_RAID_SET_DELETE_INFO Delete;
+ CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO Protect;
+ CSMI_SAS_RAID_SET_CACHE_INFO Cache;
+ CSMI_SAS_RAID_SET_ONLINE_STATE_INFO State;
+ CSMI_SAS_RAID_SET_SPARE_INFO Spare;
+ } Operation;
+ union {
+ CSMI_SAS_RAID_SET_DRIVE_LIST DriveList[1];
+ CSMI_SAS_RAID_SET_LIST RaidSetList[1];
+ } Parameters;
+} CSMI_SAS_RAID_SET_OPERATION,
+ *PCSMI_SAS_RAID_SET_OPERATION;
+
+typedef struct _CSMI_SAS_RAID_SET_OPERATION_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_RAID_SET_OPERATION Information;
+} CSMI_SAS_RAID_SET_OPERATION_BUFFER,
+ *PCSMI_SAS_RAID_SET_OPERATION_BUFFER;
+
+/* * * * * * * * * * SAS HBA Class Structures * * * * * * * * * */
+
+// CC_CSMI_SAS_GET_PHY_INFO
+
+typedef struct _CSMI_SAS_IDENTIFY {
+ __u8 bDeviceType;
+ __u8 bRestricted;
+ __u8 bInitiatorPortProtocol;
+ __u8 bTargetPortProtocol;
+ __u8 bRestricted2[8];
+ __u8 bSASAddress[8];
+ __u8 bPhyIdentifier;
+ __u8 bSignalClass;
+ __u8 bReserved[6];
+} CSMI_SAS_IDENTIFY,
+ *PCSMI_SAS_IDENTIFY;
+
+typedef struct _CSMI_SAS_PHY_ENTITY {
+ CSMI_SAS_IDENTIFY Identify;
+ __u8 bPortIdentifier;
+ __u8 bNegotiatedLinkRate;
+ __u8 bMinimumLinkRate;
+ __u8 bMaximumLinkRate;
+ __u8 bPhyChangeCount;
+ __u8 bAutoDiscover;
+ __u8 bPhyFeatures;
+ __u8 bReserved;
+ CSMI_SAS_IDENTIFY Attached;
+} CSMI_SAS_PHY_ENTITY,
+ *PCSMI_SAS_PHY_ENTITY;
+
+typedef struct _CSMI_SAS_PHY_INFO {
+ __u8 bNumberOfPhys;
+ __u8 bReserved[3];
+ CSMI_SAS_PHY_ENTITY Phy[32];
+} CSMI_SAS_PHY_INFO,
+ *PCSMI_SAS_PHY_INFO;
+
+typedef struct _CSMI_SAS_PHY_INFO_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_PHY_INFO Information;
+} CSMI_SAS_PHY_INFO_BUFFER,
+ *PCSMI_SAS_PHY_INFO_BUFFER;
+
+// CC_CSMI_SAS_SET_PHY_INFO
+
+typedef struct _CSMI_SAS_SET_PHY_INFO {
+ __u8 bPhyIdentifier;
+ __u8 bNegotiatedLinkRate;
+ __u8 bProgrammedMinimumLinkRate;
+ __u8 bProgrammedMaximumLinkRate;
+ __u8 bSignalClass;
+ __u8 bReserved[3];
+} CSMI_SAS_SET_PHY_INFO,
+ *PCSMI_SAS_SET_PHY_INFO;
+
+typedef struct _CSMI_SAS_SET_PHY_INFO_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_SET_PHY_INFO Information;
+} CSMI_SAS_SET_PHY_INFO_BUFFER,
+ *PCSMI_SAS_SET_PHY_INFO_BUFFER;
+
+// CC_CSMI_SAS_GET_LINK_ERRORS
+
+typedef struct _CSMI_SAS_LINK_ERRORS {
+ __u8 bPhyIdentifier;
+ __u8 bResetCounts;
+ __u8 bReserved[2];
+ __u32 uInvalidDwordCount;
+ __u32 uRunningDisparityErrorCount;
+ __u32 uLossOfDwordSyncCount;
+ __u32 uPhyResetProblemCount;
+} CSMI_SAS_LINK_ERRORS,
+ *PCSMI_SAS_LINK_ERRORS;
+
+typedef struct _CSMI_SAS_LINK_ERRORS_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_LINK_ERRORS Information;
+} CSMI_SAS_LINK_ERRORS_BUFFER,
+ *PCSMI_SAS_LINK_ERRORS_BUFFER;
+
+// CC_CSMI_SAS_SMP_PASSTHRU
+
+typedef struct _CSMI_SAS_SMP_REQUEST {
+ __u8 bFrameType;
+ __u8 bFunction;
+ __u8 bReserved[2];
+ __u8 bAdditionalRequestBytes[1016];
+} CSMI_SAS_SMP_REQUEST,
+ *PCSMI_SAS_SMP_REQUEST;
+
+typedef struct _CSMI_SAS_SMP_RESPONSE {
+ __u8 bFrameType;
+ __u8 bFunction;
+ __u8 bFunctionResult;
+ __u8 bReserved;
+ __u8 bAdditionalResponseBytes[1016];
+} CSMI_SAS_SMP_RESPONSE,
+ *PCSMI_SAS_SMP_RESPONSE;
+
+typedef struct _CSMI_SAS_SMP_PASSTHRU {
+ __u8 bPhyIdentifier;
+ __u8 bPortIdentifier;
+ __u8 bConnectionRate;
+ __u8 bReserved;
+ __u8 bDestinationSASAddress[8];
+ __u32 uRequestLength;
+ CSMI_SAS_SMP_REQUEST Request;
+ __u8 bConnectionStatus;
+ __u8 bReserved2[3];
+ __u32 uResponseBytes;
+ CSMI_SAS_SMP_RESPONSE Response;
+} CSMI_SAS_SMP_PASSTHRU,
+ *PCSMI_SAS_SMP_PASSTHRU;
+
+typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_SMP_PASSTHRU Parameters;
+} CSMI_SAS_SMP_PASSTHRU_BUFFER,
+ *PCSMI_SAS_SMP_PASSTHRU_BUFFER;
+
+// CC_CSMI_SAS_SSP_PASSTHRU
+
+typedef struct _CSMI_SAS_SSP_PASSTHRU {
+ __u8 bPhyIdentifier;
+ __u8 bPortIdentifier;
+ __u8 bConnectionRate;
+ __u8 bReserved;
+ __u8 bDestinationSASAddress[8];
+ __u8 bLun[8];
+ __u8 bCDBLength;
+ __u8 bAdditionalCDBLength;
+ __u8 bReserved2[2];
+ __u8 bCDB[16];
+ __u32 uFlags;
+ __u8 bAdditionalCDB[24];
+ __u32 uDataLength;
+} CSMI_SAS_SSP_PASSTHRU,
+ *PCSMI_SAS_SSP_PASSTHRU;
+
+typedef struct _CSMI_SAS_SSP_PASSTHRU_STATUS {
+ __u8 bConnectionStatus;
+ __u8 bSSPStatus;
+ __u8 bReserved[2];
+ __u8 bDataPresent;
+ __u8 bStatus;
+ __u8 bResponseLength[2];
+ __u8 bResponse[256];
+ __u32 uDataBytes;
+} CSMI_SAS_SSP_PASSTHRU_STATUS,
+ *PCSMI_SAS_SSP_PASSTHRU_STATUS;
+
+typedef struct _CSMI_SAS_SSP_PASSTHRU_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_SSP_PASSTHRU Parameters;
+ CSMI_SAS_SSP_PASSTHRU_STATUS Status;
+ __u8 bDataBuffer[1];
+} CSMI_SAS_SSP_PASSTHRU_BUFFER,
+ *PCSMI_SAS_SSP_PASSTHRU_BUFFER;
+
+// CC_CSMI_SAS_STP_PASSTHRU
+
+typedef struct _CSMI_SAS_STP_PASSTHRU {
+ __u8 bPhyIdentifier;
+ __u8 bPortIdentifier;
+ __u8 bConnectionRate;
+ __u8 bReserved;
+ __u8 bDestinationSASAddress[8];
+ __u8 bReserved2[4];
+ __u8 bCommandFIS[20];
+ __u32 uFlags;
+ __u32 uDataLength;
+} CSMI_SAS_STP_PASSTHRU,
+ *PCSMI_SAS_STP_PASSTHRU;
+
+typedef struct _CSMI_SAS_STP_PASSTHRU_STATUS {
+ __u8 bConnectionStatus;
+ __u8 bReserved[3];
+ __u8 bStatusFIS[20];
+ __u32 uSCR[16];
+ __u32 uDataBytes;
+} CSMI_SAS_STP_PASSTHRU_STATUS,
+ *PCSMI_SAS_STP_PASSTHRU_STATUS;
+
+typedef struct _CSMI_SAS_STP_PASSTHRU_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_STP_PASSTHRU Parameters;
+ CSMI_SAS_STP_PASSTHRU_STATUS Status;
+ __u8 bDataBuffer[1];
+} CSMI_SAS_STP_PASSTHRU_BUFFER,
+ *PCSMI_SAS_STP_PASSTHRU_BUFFER;
+
+// CC_CSMI_SAS_GET_SATA_SIGNATURE
+
+typedef struct _CSMI_SAS_SATA_SIGNATURE {
+ __u8 bPhyIdentifier;
+ __u8 bReserved[3];
+ __u8 bSignatureFIS[20];
+} CSMI_SAS_SATA_SIGNATURE,
+ *PCSMI_SAS_SATA_SIGNATURE;
+
+typedef struct _CSMI_SAS_SATA_SIGNATURE_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_SATA_SIGNATURE Signature;
+} CSMI_SAS_SATA_SIGNATURE_BUFFER,
+ *PCSMI_SAS_SATA_SIGNATURE_BUFFER;
+
+// CC_CSMI_SAS_GET_SCSI_ADDRESS
+
+typedef struct _CSMI_SAS_GET_SCSI_ADDRESS_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ __u8 bSASAddress[8];
+ __u8 bSASLun[8];
+ __u8 bHostIndex;
+ __u8 bPathId;
+ __u8 bTargetId;
+ __u8 bLun;
+} CSMI_SAS_GET_SCSI_ADDRESS_BUFFER,
+ *PCSMI_SAS_GET_SCSI_ADDRESS_BUFFER;
+
+// CC_CSMI_SAS_GET_DEVICE_ADDRESS
+
+typedef struct _CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ __u8 bHostIndex;
+ __u8 bPathId;
+ __u8 bTargetId;
+ __u8 bLun;
+ __u8 bSASAddress[8];
+ __u8 bSASLun[8];
+} CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER,
+ *PCSMI_SAS_GET_DEVICE_ADDRESS_BUFFER;
+
+// CC_CSMI_SAS_TASK_MANAGEMENT
+
+typedef struct _CSMI_SAS_SSP_TASK_IU {
+ __u8 bHostIndex;
+ __u8 bPathId;
+ __u8 bTargetId;
+ __u8 bLun;
+ __u32 uFlags;
+ __u32 uQueueTag;
+ __u32 uReserved;
+ __u8 bTaskManagementFunction;
+ __u8 bReserved[7];
+ __u32 uInformation;
+} CSMI_SAS_SSP_TASK_IU,
+ *PCSMI_SAS_SSP_TASK_IU;
+
+typedef struct _CSMI_SAS_SSP_TASK_IU_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_SSP_TASK_IU Parameters;
+ CSMI_SAS_SSP_PASSTHRU_STATUS Status;
+} CSMI_SAS_SSP_TASK_IU_BUFFER,
+ *PCSMI_SAS_SSP_TASK_IU_BUFFER;
+
+// CC_CSMI_SAS_GET_CONNECTOR_INFO
+
+typedef struct _CSMI_SAS_GET_CONNECTOR_INFO {
+ __u32 uPinout;
+ __u8 bConnector[16];
+ __u8 bLocation;
+ __u8 bReserved[15];
+} CSMI_SAS_CONNECTOR_INFO,
+ *PCSMI_SAS_CONNECTOR_INFO;
+
+typedef struct _CSMI_SAS_CONNECTOR_INFO_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ CSMI_SAS_CONNECTOR_INFO Reference[32];
+} CSMI_SAS_CONNECTOR_INFO_BUFFER,
+ *PCSMI_SAS_CONNECTOR_INFO_BUFFER;
+
+// CC_CSMI_SAS_GET_LOCATION
+
+typedef struct _CSMI_SAS_LOCATION_IDENTIFIER {
+ __u32 bLocationFlags;
+ __u8 bSASAddress[8];
+ __u8 bSASLun[8];
+ __u8 bEnclosureIdentifier[8];
+ __u8 bEnclosureName[32];
+ __u8 bBayPrefix[32];
+ __u8 bBayIdentifier;
+ __u8 bLocationState;
+ __u8 bReserved[2];
+} CSMI_SAS_LOCATION_IDENTIFIER,
+ *PCSMI_SAS_LOCATION_IDENTIFIER;
+
+typedef struct _CSMI_SAS_GET_LOCATION_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ __u8 bHostIndex;
+ __u8 bPathId;
+ __u8 bTargetId;
+ __u8 bLun;
+ __u8 bIdentify;
+ __u8 bNumberOfLocationIdentifiers;
+ __u8 bLengthOfLocationIdentifier;
+ CSMI_SAS_LOCATION_IDENTIFIER Location[1];
+} CSMI_SAS_GET_LOCATION_BUFFER,
+ *PCSMI_SAS_GET_LOCATION_BUFFER;
+
+// CC_CSMI_SAS_PHY_CONTROL
+
+typedef struct _CSMI_SAS_CHARACTER {
+ __u8 bTypeFlags;
+ __u8 bValue;
+} CSMI_SAS_CHARACTER,
+ *PCSMI_SAS_CHARACTER;
+
+typedef struct _CSMI_SAS_PHY_CONTROL {
+ __u8 bType;
+ __u8 bRate;
+ __u8 bReserved[6];
+ __u32 uVendorUnique[8];
+ __u32 uTransmitterFlags;
+ __i8 bTransmitAmplitude;
+ __i8 bTransmitterPreemphasis;
+ __i8 bTransmitterSlewRate;
+ __i8 bTransmitterReserved[13];
+ __u8 bTransmitterVendorUnique[64];
+ __u32 uReceiverFlags;
+ __i8 bReceiverThreshold;
+ __i8 bReceiverEqualizationGain;
+ __i8 bReceiverReserved[14];
+ __u8 bReceiverVendorUnique[64];
+ __u32 uPatternFlags;
+ __u8 bFixedPattern;
+ __u8 bUserPatternLength;
+ __u8 bPatternReserved[6];
+ CSMI_SAS_CHARACTER UserPatternBuffer[16];
+} CSMI_SAS_PHY_CONTROL,
+ *PCSMI_SAS_PHY_CONTROL;
+
+typedef struct _CSMI_SAS_PHY_CONTROL_BUFFER {
+ IOCTL_HEADER IoctlHeader;
+ __u32 uFunction;
+ __u8 bPhyIdentifier;
+ __u16 usLengthOfControl;
+ __u8 bNumberOfControls;
+ __u8 bReserved[4];
+ __u32 uLinkFlags;
+ __u8 bSpinupRate;
+ __u8 bLinkReserved[7];
+ __u32 uVendorUnique[8];
+ CSMI_SAS_PHY_CONTROL Control[1];
+} CSMI_SAS_PHY_CONTROL_BUFFER,
+ *PCSMI_SAS_PHY_CONTROL_BUFFER;
+
+//EDM #pragma CSMI_SAS_END_PACK
+#pragma pack()
+
+#endif // _CSMI_SAS_H_
/* drivers/message/fusion/linux_compat.h */
-
#ifndef FUSION_LINUX_COMPAT_H
#define FUSION_LINUX_COMPAT_H
+#include <linux/version.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_transport_sas.h>
+
+#ifndef PCI_VENDOR_ID_ATTO
+#define PCI_VENDOR_ID_ATTO 0x117c
+#endif
+
+#ifndef PCI_VENDOR_ID_BROCADE
+#define PCI_VENDOR_ID_BROCADE 0x1657
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23))
+static inline void *shost_private(struct Scsi_Host *shost)
+{
+ return (void *)shost->hostdata;
+}
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6))
+static int inline scsi_device_online(struct scsi_device *sdev)
+{
+ return sdev->online;
+}
+#endif
+
+#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 */
* Title: MPI Message independent structures and definitions
* Creation Date: July 27, 2000
*
- * mpi.h Version: 01.05.13
+ * mpi.h Version: 01.05.14
*
* Version History
* ---------------
* 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.
* --------------------------------------------------------------------------
*/
/* Note: The major versions of 0xe0 through 0xff are reserved */
/* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT (0x10)
+#define MPI_HEADER_VERSION_UNIT (0x11)
#define MPI_HEADER_VERSION_DEV (0x00)
#define MPI_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI_HEADER_VERSION_UNIT_SHIFT (8)
* Title: MPI Config message, structures, and Pages
* Creation Date: July 27, 2000
*
- * mpi_cnfg.h Version: 01.05.15
+ * mpi_cnfg.h Version: 01.05.16
*
* Version History
* ---------------
* 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.
* --------------------------------------------------------------------------
*/
/* IOC Page 6 Capabilities Flags */
+#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_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
#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 */
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;
Copyright (c) 2000-2007 LSI Corporation.
---------------------------------------
- Header Set Release Version: 01.05.16
- Header Set Release Date: 05-24-07
+ Header Set Release Version: 01.05.17
+ Header Set Release Date: 08-08-07
---------------------------------------
Filename Current version Prior version
---------- --------------- -------------
- mpi.h 01.05.13 01.05.12
- mpi_ioc.h 01.05.14 01.05.13
- mpi_cnfg.h 01.05.15 01.05.14
+ mpi.h 01.05.14 01.05.13
+ mpi_ioc.h 01.05.15 01.05.14
+ mpi_cnfg.h 01.05.16 01.05.15
mpi_init.h 01.05.09 01.05.09
mpi_targ.h 01.05.06 01.05.06
mpi_fc.h 01.05.01 01.05.01
mpi_lan.h 01.05.01 01.05.01
- mpi_raid.h 01.05.03 01.05.03
+ mpi_raid.h 01.05.04 01.05.03
mpi_tool.h 01.05.03 01.05.03
mpi_inb.h 01.05.01 01.05.01
mpi_sas.h 01.05.04 01.05.04
* 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.
* --------------------------------------------------------------------------
mpi_ioc.h
* added _MULTI_PORT_DOMAIN.
* 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request.
* Added Common Boot Block type to FWUpload Request.
+ * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define.
+ * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and
+ * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data.
+ * Added SASAddress field to SAS Initiator Device Table
+ * Overflow event data structure.
* --------------------------------------------------------------------------
mpi_cnfg.h
* Expander Page 0 Flags field.
* Fixed define for
* MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED.
+ * 08-07-07 01.05.16 Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT
+ * define.
+ * Added BIOS Page 4 structure.
+ * Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID
+ * Physcial Disk Page 1.
* --------------------------------------------------------------------------
mpi_init.h
* _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
* 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and
* associated defines.
+ * 08-07-07 01.05.04 Added Disable Full Rebuild bit to the ActionDataWord
+ * for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME.
* --------------------------------------------------------------------------
mpi_tool.h
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: August 11, 2000
*
- * mpi_ioc.h Version: 01.05.14
+ * mpi_ioc.h Version: 01.05.15
*
* Version History
* ---------------
* 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.
* --------------------------------------------------------------------------
*/
#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)
/* 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)
/* SAS Initiator Device Table Overflow Event data */
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,
/***************************************************************************
* *
- * Copyright 2003 LSI Corporation. All rights reserved. *
+ * Copyright 2007 LSI Corporation. All rights reserved. *
* *
* Description *
* ------------ *
#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_SUB_CODE_OPEN_FAIL_OPEN_TIMEOUT_EXP (0x0000000C)
#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0D (0x0000000D)
#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_DVTBLE_ACCSS_FAIL (0x0000000E)
-#define PL_LOGINFO_SUB CODE_OPEN_FAIL_BAD_DEST (0x00000011)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_BAD_DEST (0x00000011)
#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RATE_NOT_SUPP (0x00000012)
#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PROT_NOT_SUPP (0x00000013)
#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON0 (0x00000014)
#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 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)
/* 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 */
* Title: MPI RAID message and structures
* Creation Date: February 27, 2001
*
- * mpi_raid.h Version: 01.05.03
+ * mpi_raid.h Version: 01.05.04
*
* Version History
* ---------------
* _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.
* --------------------------------------------------------------------------
*/
#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)
* 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
* ---------------
* 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.
* --------------------------------------------------------------------------
*/
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
{
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
+#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/interrupt.h> /* needed for in_interrupt() proto */
#include <linux/dma-mapping.h>
+#include <linux/sort.h>
#include <asm/io.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
#include "mptbase.h"
+#include "linux_compat.h" /* linux-2.6 tweaks */
#include "lsi/mpi_log_fc.h"
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
module_param(mpt_channel_mapping, int, 0);
MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
-static int mpt_debug_level;
+int mpt_debug_level;
static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
&mpt_debug_level, 0600);
MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
+EXPORT_SYMBOL(mpt_debug_level);
+
+int mpt_fwfault_debug;
+module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
+ &mpt_fwfault_debug, 0600);
+MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
+ " and halt Firmware on fault - (default=0)");
+EXPORT_SYMBOL(mpt_fwfault_debug);
+
#ifdef MFCNT
static int mfcounter = 0;
/*
* Public data...
*/
-
struct proc_dir_entry *mpt_proc_root_dir;
#define WHOINIT_UNKNOWN 0xAA
static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
/*
* Driver Callback Index's
*/
/*
* 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);
static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
-static void mpt_timer_expired(unsigned long data);
static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
-static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
+static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag);
static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
#endif
static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
-//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
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);
pci_write_config_word(pdev, PCI_COMMAND, command_reg);
}
-static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
+/**
+ * mpt_set_debug_level - global setting of the mpt_debug_level
+ * found via /sys/module/mptbase/parameters/mpt_debug_level
+ * @val:
+ * @kp:
+ *
+ * Returns
+ **/
+static int
+mpt_set_debug_level(const char *val, struct kernel_param *kp)
{
int ret = param_set_int(val, kp);
MPT_ADAPTER *ioc;
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...
*/
/* Check for (valid) IO callback! */
if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
- MptCallbacks[cb_idx] == NULL) {
+ MptCallbacks[cb_idx] == NULL) {
printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
__FUNCTION__, ioc->name, cb_idx);
goto out;
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
+
DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
/* Check/log IOC log info
mpt_sas_log_info(ioc, log_info);
}
+ /* TODO - add shost_attrs, or command line option, and
+ * extend this to SAS/FC
+ */
if (ioc_stat & MPI_IOCSTATUS_MASK)
mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
/* Check for (valid) IO callback! */
if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
- MptCallbacks[cb_idx] == NULL) {
+ MptCallbacks[cb_idx] == NULL) {
printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
__FUNCTION__, ioc->name, cb_idx);
freeme = 0;
mb();
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
* @irq: irq number (not used)
* @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
+ * @r: pt_regs pointer (not used)
*
* This routine is registered via the request_irq() kernel API call,
* and handles all interrupts generated from a specific MPT adapter
* 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);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
- * 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
* should be freed, or 0 if it shouldn't.
*/
static int
-mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
{
+ EventNotificationReply_t *pEventReply;
+ u8 event;
+ int evHandlers;
int freereq = 1;
- u8 func;
-
- dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
-#ifdef CONFIG_FUSION_LOGGING
- if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
- !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
- dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
- ioc->name, mf));
- DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
- }
-#endif
-
- func = reply->u.hdr.Function;
- dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
- ioc->name, func));
-
- if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
- EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
- int evHandlers = 0;
- int results;
-
- results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
- if (results != evHandlers) {
- /* CHECKME! Any special handling needed here? */
- devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
- ioc->name, evHandlers, results));
- }
- /*
- * Hmmm... It seems that EventNotificationReply is an exception
- * to the rule of one reply per request.
- */
- if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
+ switch (reply->u.hdr.Function) {
+ case MPI_FUNCTION_EVENT_NOTIFICATION:
+ pEventReply = (EventNotificationReply_t *)reply;
+ evHandlers = 0;
+ ProcessEventNotification(ioc, pEventReply, &evHandlers);
+ event = le32_to_cpu(pEventReply->Event) & 0xFF;
+ if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
freereq = 0;
- } else {
- devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
- ioc->name, pEvReply));
- }
-
-#ifdef CONFIG_PROC_FS
-// LogEvent(ioc, pEvReply);
-#endif
-
- } else if (func == MPI_FUNCTION_EVENT_ACK) {
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
- ioc->name));
- } else if (func == MPI_FUNCTION_CONFIG) {
- CONFIGPARMS *pCfg;
- unsigned long flags;
-
- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
- ioc->name, mf, reply));
-
- pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
-
- if (pCfg) {
- /* disable timer and remove from linked list */
- del_timer(&pCfg->timer);
-
- spin_lock_irqsave(&ioc->FreeQlock, flags);
- list_del(&pCfg->linkage);
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
- /*
- * If IOC Status is SUCCESS, save the header
- * and set the status code to GOOD.
- */
- pCfg->status = MPT_CONFIG_ERROR;
- if (reply) {
- ConfigReply_t *pReply = (ConfigReply_t *)reply;
- u16 status;
-
- status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
- dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
- ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
-
- pCfg->status = status;
- if (status == MPI_IOCSTATUS_SUCCESS) {
- if ((pReply->Header.PageType &
- MPI_CONFIG_PAGETYPE_MASK) ==
- MPI_CONFIG_PAGETYPE_EXTENDED) {
- pCfg->cfghdr.ehdr->ExtPageLength =
- le16_to_cpu(pReply->ExtPageLength);
- pCfg->cfghdr.ehdr->ExtPageType =
- pReply->ExtPageType;
- }
- pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
-
- /* If this is a regular header, save PageLength. */
- /* LMP Do this better so not using a reserved field! */
- pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
- pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
- pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
- }
- }
-
- /*
- * Wake up the original calling thread
- */
- pCfg->wait_done = 1;
- wake_up(&mpt_waitq);
+ 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));
}
- } 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 (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;
}
/*
return freereq;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_register - Register protocol-specific main callback handler.
* @cbfunc: callback function pointer
* {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)
{
return last_drv_idx;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_deregister - Deregister a protocol drivers resources.
* @cb_idx: previously registered callback handle
*
* Each protocol-specific driver should call this routine when its
* module is unloaded.
- */
+ **/
void
mpt_deregister(u8 cb_idx)
{
}
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_event_register - Register protocol-specific event callback
* handler.
* if/when they choose to be notified of MPT events.
*
* Returns 0 for success.
- */
+ **/
int
mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
{
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_event_deregister - Deregister protocol-specific event callback
* handler.
* Each protocol-specific driver should call this routine
* when it does not (or can no longer) handle events,
* or when its module is unloaded.
- */
+ **/
void
mpt_event_deregister(u8 cb_idx)
{
MptEvHandlers[cb_idx] = NULL;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_reset_register - Register protocol-specific IOC reset handler.
* @cb_idx: previously registered (via mpt_register) callback handle
* if/when they choose to be notified of IOC resets.
*
* Returns 0 for success.
- */
+ **/
int
mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
{
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
* @cb_idx: previously registered callback handle
* Each protocol-specific driver should call this routine
* when it does not (or can no longer) handle IOC reset handling,
* or when its module is unloaded.
- */
+ **/
void
mpt_reset_deregister(u8 cb_idx)
{
MptResetHandlers[cb_idx] = NULL;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_device_driver_register - Register device driver hooks
* @dd_cbfunc: driver callbacks struct
* @cb_idx: MPT protocol driver index
- */
+ **/
int
mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
{
/* call per pci device probe entry point */
list_for_each_entry(ioc, &ioc_list, list) {
+ if (!pci_get_drvdata(ioc->pcidev))
+ continue;
id = ioc->pcidev->driver ?
ioc->pcidev->driver->id_table : NULL;
if (dd_cbfunc->probe)
dd_cbfunc->probe(ioc->pcidev, id);
- }
+ }
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_device_driver_deregister - DeRegister device driver hooks
* @cb_idx: MPT protocol driver index
- */
+ **/
void
mpt_device_driver_deregister(u8 cb_idx)
{
MptDeviceDriverHandlers[cb_idx] = NULL;
}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
* allocated per MPT adapter.
*
* Returns pointer to a MPT request frame or %NULL if none are available
* or IOC is not active.
- */
+ **/
MPT_FRAME_HDR*
mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
{
mf->u.frame.linkage.arg1 = 0;
mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
- /* u16! */
req_idx = req_offset / ioc->req_sz;
mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
return mf;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_put_msg_frame - Send a protocol specific MPT request frame
* to a IOC.
*
* This routine posts a MPT request frame to the request post FIFO of a
* specific MPT adapter.
- */
+ **/
void
mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
{
/* ensure values are reset properly! */
mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
- /* u16! */
req_idx = req_offset / ioc->req_sz;
mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
- mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
+ mf_dma_addr = (ioc->req_frames_low_dma + req_offset) |
+ ioc->RequestNB[req_idx];
dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
"RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
ioc->RequestNB[req_idx]));
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
*
* 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)
{
/* 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 32 bit SGE at address addr.
- * @addr: virtual address for SGE
+ * 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.
+ **/
static void
-mpt_add_sge(char *addr, u32 flagslength, dma_addr_t dma_addr)
+mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
{
- SGESimple32_t *pSge = (SGESimple32_t *) addr;
+ 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 addr.
- * @addr: virtual address for SGE
+ * 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 *addr, u32 flagslength, dma_addr_t dma_addr)
+mpt_add_sge_64bit(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
{
- SGESimple64_t *pSge = (SGESimple64_t *) addr;
- u32 tmp = dma_addr & 0xFFFFFFFF;
+ SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+ u32 tmp;
- pSge->FlagsLength = cpu_to_le32(flagslength);
+ tmp = dma_addr & 0xFFFFFFFF;
pSge->Address.Low = cpu_to_le32(tmp);
tmp = (u32) ((u64)dma_addr >> 32);
+ pSge->FlagsLength = cpu_to_le32(flagslength);
pSge->Address.High = cpu_to_le32(tmp);
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
/**
- * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address addr
+ * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
* (1078 workaround).
- * @addr: virtual address for SGE
+ * @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 *addr, u32 flagslength, dma_addr_t dma_addr)
+mpt_add_sge_64bit_1078(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
{
- SGESimple64_t *pSge = (SGESimple64_t *) addr;
+ SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
u32 tmp;
tmp = dma_addr & 0xFFFFFFFF;
* request which are greater than 1 byte in size.
*
* Returns 0 for success, non-zero for failure.
- */
+ **/
int
mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
{
- int r = 0;
+ int r = 0;
u8 *req_as_bytes;
int ii;
* is in proper (pre-alloc'd) request buffer range...
*/
ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
- if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
+ if (ii >= 0 && ii < ioc->req_depth) {
MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
return r;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_host_page_access_control - control the IOC's Host Page Buffer access
* @ioc: Pointer to MPT adapter structure
* 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)
{
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_host_page_alloc - allocate system memory for the fw
* @ioc: Pointer to pointer to IOC 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)
{
host_page_buffer_sz,
&ioc->HostPageBuffer_dma)) != NULL) {
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
"host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
ioc->name, ioc->HostPageBuffer,
(u32)ioc->HostPageBuffer_dma,
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
* @iocid: IOC unique identifier (integer)
*
* 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)
{
sprintf(prod_name, "%s", product_str);
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
- * mpt_attach - Install a PCI intelligent MPT adapter.
- * @pdev: Pointer to pci_dev structure
- * @id: PCI device ID information
- *
- * This routine performs all the steps necessary to bring the IOC of
- * a MPT adapter to a OPERATIONAL state. This includes registering
- * memory regions, registering the interrupt, and allocating request
- * and reply memory pools.
- *
- * This routine also pre-fetches the LAN MAC address of a Fibre Channel
- * MPT adapter.
- *
- * Returns 0 for success, non-zero for failure.
+ * mpt_mapresources - map in memory mapped io
+ * @ioc: Pointer to pointer to IOC adapter
*
- * TODO: Add support for polled controllers
- */
-int
-mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+ **/
+static int
+mpt_mapresources(MPT_ADAPTER *ioc)
{
- MPT_ADAPTER *ioc;
u8 __iomem *mem;
- u8 __iomem *pmem;
+ int ii;
unsigned long mem_phys;
unsigned long port;
u32 msize;
u32 psize;
- int ii;
- u8 cb_idx;
int r = -ENODEV;
- u8 revision;
- u8 pcixcmd;
- static int mpt_ids = 0;
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *dent, *ent;
-#endif
+ struct pci_dev *pdev;
- if (mpt_debug_level)
- printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
+ pdev = ioc->pcidev;
- if (pci_enable_device(pdev))
+#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;
-
- ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
- if (ioc == NULL) {
- printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
- return -ENOMEM;
}
- ioc->debug_level = mpt_debug_level;
- ioc->id = mpt_ids++;
- sprintf(ioc->name, "ioc%d", ioc->id);
-
- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
+#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 (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
&& !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
} else {
printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
ioc->name, pci_name(pdev));
- kfree(ioc);
return r;
}
- ioc->alloc_total = sizeof(MPT_ADAPTER);
- ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
- ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
+ 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;
- /*
- * Setting up proper handlers for scatter gather handling
- */
- if (sizeof(dma_addr_t) == sizeof(u64)) {
- if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
- ioc->add_sge = &mpt_add_sge_64bit_1078;
- else
- ioc->add_sge = &mpt_add_sge_64bit;
- } else
+ 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
+ * @id: PCI device ID information
+ *
+ * This routine performs all the steps necessary to bring the IOC of
+ * a MPT adapter to a OPERATIONAL state. This includes registering
+ * memory regions, registering the interrupt, and allocating request
+ * and reply memory pools.
+ *
+ * This routine also pre-fetches the LAN MAC address of a Fibre Channel
+ * MPT adapter.
+ *
+ * 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 cb_idx;
+ int r = -ENODEV;
+ u8 revision;
+ u8 pcixcmd;
+ static int mpt_ids = 0;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *dent, *ent;
+#endif
+
+ 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);
+
+ /*
+ * Setting up proper handlers for scatter gather handling
+ */
+ if (sizeof(dma_addr_t) == sizeof(u64)) {
+ if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
+ ioc->add_sge = &mpt_add_sge_64bit_1078;
+ else
+ ioc->add_sge = &mpt_add_sge_64bit;
+ } else
ioc->add_sge = &mpt_add_sge;
+
ioc->pcidev = pdev;
- ioc->diagPending = 0;
- spin_lock_init(&ioc->diagLock);
- spin_lock_init(&ioc->initializing_hba_lock);
+ if (mpt_mapresources(ioc)) {
+ kfree(ioc);
+ return r;
+ }
+
+ ioc->alloc_total = sizeof(MPT_ADAPTER);
+ ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
+ ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
+
+ 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.
*/
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);
- 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;
+ /* 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
- 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 "Unable to map adapter memory!\n", ioc->name);
+ /* 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 -EINVAL;
+ return -ENOMEM;
}
- ioc->memmap = mem;
- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys));
-
- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
- ioc->name, &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 */
- ioc->pio_mem_phys = port;
- pmem = (u8 __iomem *)port;
- ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
+ 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);
ioc->bus_type = FC;
break;
+
case MPI_MANUFACTPAGE_DEVID_53C1030:
/* 1030 Chip Fix. Disable Split transactions
* for PCIX. Set MOST bits to zero if Rev < C0( = 8).
case MPI_MANUFACTPAGE_DEVID_SAS1064:
case MPI_MANUFACTPAGE_DEVID_SAS1068:
ioc->errata_flag_1064 = 1;
+ ioc->bus_type = SAS;
+ break;
case MPI_MANUFACTPAGE_DEVID_SAS1064E:
case MPI_MANUFACTPAGE_DEVID_SAS1068E:
case MPI_MANUFACTPAGE_DEVID_SAS1078:
ioc->bus_type = SAS;
+ break;
}
+ if (ioc->bus_type == SAS)
+#if defined(SUSE_KERNEL_BASE)
+ ioc->msi_enable = mpt_msi_enable;
+#else
+ ioc->msi_enable = 1;
+#endif
+ else
+ ioc->msi_enable = mpt_msi_enable;
+
if (ioc->errata_flag_1064)
pci_disable_io_access(pdev);
if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
CAN_SLEEP)) != 0){
- printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
- ioc->name, r);
+ 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;
}
#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];
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);
sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
remove_proc_entry(pname, NULL);
}
}
- /* 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)) {
/* 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)
{
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);
- err = pci_enable_device(pdev);
+ ioc->pcidev = pdev;
+ err = mpt_mapresources(ioc);
if (err)
return err;
- /* enable interrupts */
- CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
- ioc->active = 1;
+ 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));
- 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 */
- 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 "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);
- }
-
+ "pci-resume: success\n", ioc->name);
+ out:
return 0;
}
#endif
return (MptResetHandlers[index])(ioc, reset_phase);
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_do_ioc_recovery - Initialize or recover MPT adapter.
* @ioc: Pointer to MPT adapter structure
* -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)
{
int hard;
int rc=0;
int ii;
- u8 cb_idx;
- int handlers;
int ret = 0;
int reset_alt_ioc_active = 0;
int irq_allocated = 0;
u8 *a;
- printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
+ printk(MYIOC_s_DEBUG_FMT "Initiating %s\n", ioc->name,
reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
/* Disable reply interrupts (also blocks FreeQ) */
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 ... */
if (reset_alt_ioc_active && ioc->alt_ioc) {
/* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
- dprintk(ioc, printk(MYIOC_s_INFO_FMT
- "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": alt-ioc reply irq re-enabled\n",
+ ioc->alt_ioc->name));
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
ioc->alt_ioc->active = 1;
}
} else {
- printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT "NOT READY WARNING!\n", ioc->name);
}
- return -1;
+ ret = -1;
+ goto out;
}
/* hard_reset_done = 0 if a soft reset was performed
if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
alt_ioc_ready = 1;
else
- printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
+ printk(MYIOC_s_WARN_FMT
+ ": alt-ioc Not ready WARNING!\n", ioc->alt_ioc->name);
}
for (ii=0; ii<5; ii++) {
}
}
+#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
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);
+ 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,
+ 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)
+ "interrupt %d!\n", ioc->name,
+ ioc->pcidev->irq);
+ if (ioc->msi_enable)
pci_disable_msi(ioc->pcidev);
- return -EBUSY;
+ ret = -EBUSY;
+ goto out;
}
irq_allocated = 1;
ioc->pci_irq = ioc->pcidev->irq;
pci_set_master(ioc->pcidev); /* ?? */
pci_set_drvdata(ioc->pcidev, ioc);
- dprintk(ioc, printk(MYIOC_s_INFO_FMT "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));
}
}
* init as upper addresses are needed for init.
* If fails, continue with alt-ioc processing
*/
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
+ ioc->name));
if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
ret = -3;
/* May need to check/upload firmware & data here!
* If fails, continue with alt-ioc processing
*/
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
+ ioc->name));
if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
ret = -4;
// NEW!
if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
- printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
- ioc->alt_ioc->name, rc);
+ printk(MYIOC_s_WARN_FMT ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
+ ioc->alt_ioc->name, rc);
alt_ioc_ready = 0;
reset_alt_ioc_active = 0;
}
if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
alt_ioc_ready = 0;
reset_alt_ioc_active = 0;
- printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
- ioc->alt_ioc->name, rc);
+ printk(MYIOC_s_WARN_FMT
+ ": alt-ioc: (%d) init failure WARNING!\n",
+ ioc->alt_ioc->name, rc);
}
}
if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
if (ioc->upload_fw) {
ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "firmware upload required!\n", ioc->name));
+ "firmware upload required!\n", ioc->name));
/* Controller is not operational, cannot do upload
*/
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->alt_ioc->cached_fw = NULL;
+ ioc->cached_fw = NULL;
}
} else {
printk(MYIOC_s_WARN_FMT
}
}
+ /* Enable MPT base driver management of EventNotification
+ * and EventAck handling.
+ */
+ if ((ret == 0) && (!ioc->facts.EventState)) {
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendEventNotification\n",
+ ioc->name));
+ ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
+ }
+
+ if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
+ rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
+
if (ret == 0) {
/* Enable! (reply interrupt) */
CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
ioc->active = 1;
}
-
- if (reset_alt_ioc_active && ioc->alt_ioc) {
- /* (re)Enable alt-IOC! (reply interrupt) */
- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
- ioc->alt_ioc->name));
- CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
- ioc->alt_ioc->active = 1;
+ if (rc == 0) { /* alt ioc */
+ if (reset_alt_ioc_active && ioc->alt_ioc) {
+ /* (re)Enable alt-IOC! (reply interrupt) */
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc reply irq re-enabled\n",
+ ioc->alt_ioc->name));
+ CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
+ ioc->alt_ioc->active = 1;
+ }
}
- /* Enable MPT base driver management of EventNotification
- * and EventAck handling.
- */
- if ((ret == 0) && (!ioc->facts.EventState))
- (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
-
- if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
- (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
/* Add additional "reason" check before call to GetLanConfigPages
* (combined with GetIoUnitPage2 call). This prevents a somewhat
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) {
*/
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!
(void) GetLanConfigPages(ioc);
a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
- ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
-
+ "LanAddr = %02X:%02X:%02X"
+ ":%02X:%02X:%02X\n",
+ ioc->name, a[5], a[4],
+ a[3], a[2], a[1], a[0]));
}
- } else {
+ break;
+
+ case SPI:
/* Get NVRAM and adapter maximums from SPP 0 and 2
*/
mpt_GetScsiPortSettings(ioc, 0);
mpt_read_ioc_pg_1(ioc);
mpt_read_ioc_pg_4(ioc);
+
+ break;
}
GetIoUnitPage2(ioc);
mpt_get_manufacturing_pg_0(ioc);
}
- /*
- * Call each currently registered protocol IOC reset handler
- * with post-reset indication.
- * NOTE: If we're doing _IOC_BRINGUP, there can be no
- * MptResetHandlers[] registered yet.
- */
- if (hard_reset_done) {
- rc = handlers = 0;
- for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
- if ((ret == 0) && MptResetHandlers[cb_idx]) {
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Calling IOC post_reset handler #%d\n",
- ioc->name, cb_idx));
- rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
- handlers++;
- }
-
- if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
- drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Calling IOC post_reset handler #%d\n",
- ioc->alt_ioc->name, cb_idx));
- rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
- handlers++;
- }
- }
- /* FIXME? Examine results here? */
- }
-
out:
+
if ((ret != 0) && irq_allocated) {
free_irq(ioc->pci_irq, ioc);
- if (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
*
* 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)
{
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
" searching for devfn match on %x or %x\n",
- ioc->name, pci_name(pdev), pdev->bus->number,
- pdev->devfn, func-1, func+1));
+ ioc->name, pci_name(pdev), pdev->bus->number,
+ pdev->devfn, func-1, func+1));
peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
if (!peer) {
if (_pcidev == peer) {
/* Paranoia checks */
if (ioc->alt_ioc != NULL) {
- printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
- ioc->name, ioc->alt_ioc->name);
+ printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n",
+ ioc->name, ioc->name, ioc->alt_ioc->name);
break;
} else if (ioc_srch->alt_ioc != NULL) {
- printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
- ioc_srch->name, ioc_srch->alt_ioc->name);
+ printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n",
+ ioc_srch->name, ioc_srch->name, ioc_srch->alt_ioc->name);
break;
}
- dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
- ioc->name, ioc_srch->name));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FOUND! binding %s <==> %s\n",
+ ioc->name, ioc->name, ioc_srch->name));
ioc_srch->alt_ioc = ioc;
ioc->alt_ioc = ioc_srch;
}
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)
{
int ret;
if (ioc->cached_fw != NULL) {
- ddlprintk(ioc, printk(MYIOC_s_INFO_FMT
- "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));
- if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
- printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",
- ioc->name, 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(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
- ioc->name, ioc->alloc, ioc->alloc_sz));
+ dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free @ %p, sz=%d bytes\n",
+ ioc->name, ioc->alloc, ioc->alloc_sz));
pci_free_consistent(ioc->pcidev, sz,
ioc->alloc, ioc->alloc_dma);
ioc->reply_frames = NULL;
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;
if((ret = mpt_host_page_access_control(ioc,
MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
printk(MYIOC_s_ERR_FMT
- "host page buffers free failed (%d)!\n",
- ioc->name, ret);
+ ": %s: host page buffers free failed (%d)!\n",
+ ioc->name, __FUNCTION__, ret);
}
- dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
+ dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
- ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
+ ioc->HostPageBuffer,
+ ioc->HostPageBuffer_dma);
ioc->HostPageBuffer = NULL;
ioc->HostPageBuffer_sz = 0;
ioc->alloc_total -= ioc->HostPageBuffer_sz;
}
+
+ pci_set_drvdata(ioc->pcidev, NULL);
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_adapter_dispose - Free all resources associated with an MPT adapter
* @ioc: Pointer to MPT adapter structure
*
* This routine unregisters h/w resources and frees all alloc'd memory
* associated with a MPT adapter structure.
- */
+ **/
static void
mpt_adapter_dispose(MPT_ADAPTER *ioc)
{
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;
}
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(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region de-registered\n", ioc->name));
}
#endif
list_del(&ioc->list);
sz_last = ioc->alloc_total;
- dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
- ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free'd %d of %d bytes\n",
+ ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
if (ioc->alt_ioc)
ioc->alt_ioc->alt_ioc = NULL;
kfree(ioc);
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* MptDisplayIocCapabilities - Disply IOC's capabilities.
* @ioc: Pointer to MPT adapter structure
- */
+ **/
static void
MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
{
printk("}\n");
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* MakeIocReady - Get IOC to a READY state, using KickStart if needed.
* @ioc: Pointer to MPT_ADAPTER structure
* -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)
{
/* Get current [raw] IOC state */
ioc_state = mpt_GetIocState(ioc, 0);
- dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MakeIocReady, [raw] state=%08x\n", ioc->name, ioc_state));
/*
* Check to see if IOC got left/stuck in doorbell handshake
}
/* 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.
if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
statefault = 2;
printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
- ioc->name);
- printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
- ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
+ ioc->name);
+ printk(KERN_WARNING " FAULT code = %04xh\n",
+ ioc_state & MPI_DOORBELL_DATA_MASK);
}
/*
* Else, fall through to KickStart case
*/
whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"whoinit 0x%x statefault %d force %d\n",
ioc->name, whoinit, statefault, force));
if (whoinit == MPI_WHOINIT_PCI_PEER)
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 */
}
}
return hard_reset_done;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_GetIocState - Get the current state of a MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
*
* 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)
{
return cooked ? sc : s;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* GetIocFacts - Send IOCFacts request to MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
* @reason: If recovery, only update facts.
*
* Returns 0 for success, non-zero for failure.
- */
+ **/
static int
GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
{
/* IOC *must* NOT be in RESET state! */
if (ioc->last_state == MPI_IOC_STATE_RESET) {
- printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
- ioc->name, ioc->last_state );
+ printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
+ ioc->name,
+ ioc->last_state );
return -44;
}
get_facts.Function = MPI_FUNCTION_IOC_FACTS;
/* Assert: All other get_facts fields are zero! */
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
"Sending get IocFacts request req_sz=%d reply_sz=%d\n",
ioc->name, req_sz, reply_sz));
}
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);
* 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...
*/
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);
* 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);
}
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* GetPortFacts - Send PortFacts request to MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
* @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)
{
/* IOC *must* NOT be in RESET state! */
if (ioc->last_state == MPI_IOC_STATE_RESET) {
- printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
- ioc->name, ioc->last_state );
+ printk(MYIOC_s_ERR_FMT "Can't get PortFacts, "
+ " NOT READY! (%08x)\n", ioc->name, ioc->last_state );
return -4;
}
get_pfacts.PortNumber = portnum;
/* Assert: All other get_pfacts fields are zero! */
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
- ioc->name, portnum));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
+ ioc->name, portnum));
/* No non-zero fields in the get_pfacts request are greater than
* 1 byte in size, so we can just fire it off as is.
*/
ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
- reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
+ reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
if (ii != 0)
return ii;
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;
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* SendIocInit - Send IOCInit request to MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
* 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)
{
ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
ioc_init.MaxBuses = (U8)ioc->number_of_buses;
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
+
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
ioc->name, ioc->facts.MsgVersion));
if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
// set MsgVersion and HeaderVersion host driver was built with
return r;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* SendPortEnable - Send PortEnable request to MPT adapter port.
* @ioc: Pointer to MPT_ADAPTER structure
* 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)
{
/* port_enable.MsgFlags = 0; */
/* port_enable.MsgContext = 0; */
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
ioc->name, portnum, &port_enable));
/* RAID FW may take a long time to enable
*
* 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(ioc, printk(MYIOC_s_INFO_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));
+ 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
* 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)
{
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(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
- ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
-
- if (ioc->cached_fw == NULL) {
- /* Major Failure.
- */
+ if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
return -ENOMEM;
- }
prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
kzalloc(ioc->req_sz, GFP_KERNEL);
prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
prequest->Function = MPI_FUNCTION_FW_UPLOAD;
-
ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
ptcsge->DetailsLength = 12;
ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
- ptcsge->ImageSize = cpu_to_le32(sz);
+ ptcsge->ImageSize = cpu_to_le32(ioc->facts.FWImageSize);
ptcsge++;
- sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
-
- flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
+ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | ioc->facts.FWImageSize;
ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
-
- sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
- ioc->name, prequest, sgeoffset));
+ request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
+ sizeof(u32) + sizeof(dma_addr_t);
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
+ " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
+ ioc->facts.FWImageSize, request_size));
DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
- ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
- reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
+ ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32*)prequest,
+ reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
+ "rc=%x \n", ioc->name, ii));
cmdStatus = -EFAULT;
if (ii == 0) {
/* Handshake transfer was complete and successful.
* Check the Reply Frame.
*/
- int status, transfer_sz;
- status = le16_to_cpu(preply->IOCStatus);
- if (status == MPI_IOCSTATUS_SUCCESS) {
- transfer_sz = le32_to_cpu(preply->ActualImageSize);
- if (transfer_sz == sz)
- cmdStatus = 0;
- }
+ int status;
+ status = le16_to_cpu(preply->IOCStatus) &
+ MPI_IOCSTATUS_MASK;
+ if (status == MPI_IOCSTATUS_SUCCESS &&
+ ioc->facts.FWImageSize ==
+ le32_to_cpu(preply->ActualImageSize));
+ cmdStatus = 0;
}
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
- ioc->name, cmdStatus));
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "do_upload cmdStatus=%d \n",
+ ioc->name, cmdStatus));
if (cmdStatus) {
-
- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
- ioc->name));
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
+ "freeing image \n", ioc->name));
mpt_free_fw_memory(ioc);
}
kfree(prequest);
return cmdStatus;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_downloadboot - DownloadBoot code
* @ioc: Pointer to MPT_ADAPTER structure
* -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)
{
u32 diagRwData;
u32 nextImage;
u32 load_addr;
- u32 ioc_state=0;
+ u32 doorbell;
ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
- ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
+ ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
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);
break;
}
/* wait .1 sec */
- if (sleepFlag == CAN_SLEEP) {
+ if (sleepFlag == CAN_SLEEP)
msleep (100);
- } else {
+ else
mdelay (100);
- }
}
if ( count == 30 ) {
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;
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
- ioc->name, pFwHeader->LoadStartAddress));
+ ioc->name, pFwHeader->LoadStartAddress));
ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
- ioc->name, fwSize*4, ptrFw));
- while (fwSize--) {
+ ioc->name, fwSize*4, ptrFw));
+ while (fwSize--)
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
- }
nextImage = pFwHeader->NextImageHeaderOffset;
while (nextImage) {
ptrFw = (u32 *)pExtImage;
ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
- ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
+ ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
- while (fwSize--) {
+ while (fwSize--)
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
- }
nextImage = pExtImage->NextImageHeaderOffset;
}
/* Write the IopResetVectorRegAddr */
- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n",
+ ioc->name, pFwHeader->IopResetRegAddr));
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
/* Write the IopResetVectorValue */
- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n",
+ ioc->name, pFwHeader->IopResetVectorValue));
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
/* Clear the internal flash bad bit - autoincrementing register,
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
- } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
- diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
- CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
- MPI_DIAG_CLEAR_FLASH_BAD_SIG);
-
- /* wait 1 msec */
- if (sleepFlag == CAN_SLEEP) {
- msleep (1);
- } else {
- mdelay (1);
- }
}
if (ioc->errata_flag_1064)
pci_disable_io_access(ioc->pcidev);
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
- "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
- ioc->name, diag0val));
- diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
- ioc->name, diag0val));
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "diag0val=%x, turning off"
+ " PREVENT_IOC_BOOT and DISABLE_ARM\n", ioc->name, diag0val));
+ diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM);
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "diag0val=%x\n",
+ ioc->name, diag0val));
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
- /* Write 0xFF to reset the sequencer */
- CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
+ if (ioc->bus_type == SAS ) {
+ /* wait 1 sec */
+ if (sleepFlag == CAN_SLEEP)
+ msleep(1000);
+ else
+ mdelay(1000);
- if (ioc->bus_type == SAS) {
- ioc_state = mpt_GetIocState(ioc, 0);
- if ( (GetIocFacts(ioc, sleepFlag,
- MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
- ioc->name, ioc_state));
- return -EFAULT;
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ ddlprintk(ioc, printk (MYIOC_s_DEBUG_FMT
+ "diag0val=%x, turning off RW_ENABLE\n", ioc->name,
+ diag0val));
+ diag0val &= ~(MPI_DIAG_RW_ENABLE);
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "now diag0val=%x\n", ioc->name, diag0val));
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ if (diag0val & MPI_DIAG_FLASH_BAD_SIG) {
+ diag0val |= MPI_DIAG_CLEAR_FLASH_BAD_SIG;
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
}
+ diag0val &= ~(MPI_DIAG_DISABLE_ARM);
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ CHIPREG_WRITE32(&ioc->chip->DiagRwAddress, 0x3f000004);
}
- for (count=0; count<HZ*20; count++) {
- if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "downloadboot successful! (count=%d) IocState=%x\n",
- ioc->name, count, ioc_state));
- if (ioc->bus_type == SAS) {
+ /* Write 0xFF to reset the sequencer */
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
+
+ for (count = 0; count < 30; count ++) {
+ doorbell = CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_IOC_STATE_MASK;
+ if (doorbell == MPI_IOC_STATE_READY) {
+ if (ioc->bus_type == SAS)
return 0;
- }
if ((SendIocInit(ioc, sleepFlag)) != 0) {
- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "downloadboot: SendIocInit failed\n",
- ioc->name));
+ ddlprintk(ioc, printk(MYIOC_s_WARN_FMT
+ "SendIocInit failed\n", ioc->name));
return -EFAULT;
}
ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "downloadboot: SendIocInit successful\n",
- ioc->name));
+ "SendIocInit successful\n", ioc->name));
return 0;
}
- if (sleepFlag == CAN_SLEEP) {
- msleep (10);
- } else {
- mdelay (10);
- }
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "looking for READY STATE:"
+ " doorbell=%x count=%d\n", ioc->name, doorbell, count));
+ if (sleepFlag == CAN_SLEEP)
+ msleep(1000);
+ else
+ mdelay(1000);
}
- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
+ ddlprintk(ioc, printk(MYIOC_s_WARN_FMT "downloadboot failed! count=%d\n", ioc->name, count));
return -EFAULT;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* KickStart - Perform hard reset of MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
* 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)
{
u32 ioc_state=0;
int cnt,cntdn;
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": KickStart\n", ioc->name));
if (ioc->bus_type == SPI) {
/* Always issue a Msg Unit Reset first. This will clear some
* SCSI bus hang conditions.
if (hard_reset_done < 0)
return hard_reset_done;
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
- ioc->name));
+ /* may not have worked but hard_reset_done doesn't always signal failure */
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Diagnostic reset completed!\n",
+ ioc->name));
cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
for (cnt=0; cnt<cntdn; cnt++) {
ioc_state = mpt_GetIocState(ioc, 1);
if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
ioc->name, cnt));
return hard_reset_done;
}
}
dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
- ioc->name, mpt_GetIocState(ioc, 0)));
+ ioc->name, mpt_GetIocState(ioc, 0)));
return -1;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_diag_reset - Perform hard reset of the adapter.
* @ioc: Pointer to MPT_ADAPTER structure
* 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;
u32 diag1val = 0;
+ MpiFwHeader_t *cached_fw; /* Pointer to FW */
+ u8 cb_idx;
/* Clear any existing interrupts */
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
+
+ if (!ignore)
+ return 0;
+
drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
- "address=%p\n", ioc->name, __FUNCTION__,
- &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
+ "address=%p\n", ioc->name, __FUNCTION__, &ioc->chip->Doorbell,
+ &ioc->chip->Reset_1078));
CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
if (sleepFlag == CAN_SLEEP)
msleep(1);
else
mdelay(1);
+ /*
+ * Call each currently registered protocol IOC reset handler
+ * with pre-reset indication.
+ * NOTE: If we're doing _IOC_BRINGUP, there can be no
+ * MptResetHandlers[] registered yet.
+ */
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptResetHandlers[cb_idx])
+ (*(MptResetHandlers[cb_idx]))(ioc, MPT_IOC_PRE_RESET);
+ }
+
for (count = 0; count < 60; count ++) {
doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
doorbell &= MPI_IOC_STATE_MASK;
"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)
else
mdelay(1000);
}
+
+ if (doorbell != MPI_IOC_STATE_READY)
+ printk(MYIOC_s_ERR_FMT "Failed to come READY after "
+ "reset! IocState=%x", ioc->name, doorbell);
return -1;
}
/* Use "Diagnostic reset" method! (only thing available!) */
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
- if (ioc->debug_level & MPT_DEBUG) {
+ if (ioc->debug_level & MPT_DEBUG_RESET) {
if (ioc->alt_ioc)
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
+ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
ioc->name, diag0val, diag1val));
}
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) {
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
ioc->name, diag0val));
}
- if (ioc->debug_level & MPT_DEBUG) {
+ if (ioc->debug_level & MPT_DEBUG_RESET) {
if (ioc->alt_ioc)
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
+ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
ioc->name, diag0val, diag1val));
}
/*
*/
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
hard_reset_done = 1;
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
+ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
ioc->name));
/*
* NOTE: If we're doing _IOC_BRINGUP, there can be no
* MptResetHandlers[] registered yet.
*/
- {
- u8 cb_idx;
- int r = 0;
-
- for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
- if (MptResetHandlers[cb_idx]) {
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Calling IOC pre_reset handler #%d\n",
- ioc->name, cb_idx));
- r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
- if (ioc->alt_ioc) {
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Calling alt-%s pre_reset handler #%d\n",
- ioc->name, ioc->alt_ioc->name, cb_idx));
- r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
- }
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptResetHandlers[cb_idx]) {
+ mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
+ if (ioc->alt_ioc) {
+ mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
}
}
- /* FIXME? Examine results here? */
}
if (ioc->cached_fw)
- 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(ioc, printk(MYIOC_s_DEBUG_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) {
+ 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.
doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
doorbell &= MPI_IOC_STATE_MASK;
- if (doorbell == MPI_IOC_STATE_READY) {
+ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "looking for READY STATE: doorbell=%x"
+ " count=%d\n", ioc->name, doorbell, count));
+
+ if (doorbell == MPI_IOC_STATE_READY)
+ break;
+
+ /*
+ * Early out for hard fault
+ */
+ if (count && doorbell == MPI_IOC_STATE_FAULT)
break;
- }
/* wait 1 sec */
- if (sleepFlag == CAN_SLEEP) {
+ if (sleepFlag == CAN_SLEEP)
msleep (1000);
- } else {
+ else
mdelay (1000);
- }
}
+
+ if (doorbell != MPI_IOC_STATE_READY)
+ printk(MYIOC_s_ERR_FMT "Failed to come READY "
+ "after reset! IocState=%x", ioc->name,
+ doorbell);
}
}
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
- if (ioc->debug_level & MPT_DEBUG) {
+ if (ioc->debug_level & MPT_DEBUG_RESET) {
if (ioc->alt_ioc)
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
+ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
ioc->name, diag0val, diag1val));
}
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) {
return -3;
}
- if (ioc->debug_level & MPT_DEBUG) {
+ if (ioc->debug_level & MPT_DEBUG_RESET) {
if (ioc->alt_ioc)
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
- ioc->name, diag0val, diag1val));
+ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
+ ioc->name, diag0val, diag1val));
}
/*
return hard_reset_done;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* SendIocReset - Send IOCReset request to MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
* 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)
{
drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
ioc->name, reset_type));
CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
- if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
+ if ((r = WaitForDoorbellAck(ioc, 15, sleepFlag)) < 0)
return r;
/* FW ACK'd request, wait for READY state
if (sleepFlag != CAN_SLEEP)
count *= 10;
- printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
- ioc->name, (int)((count+5)/HZ));
+ printk(MYIOC_s_ERR_FMT "Wait IOC_READY state (0x%x) timeout(%d)!\n",
+ ioc->name, state, (int)((count+5)/HZ));
return -ETIME;
}
if (sleepFlag == CAN_SLEEP) {
msleep(1);
} else {
- mdelay (1); /* 1 msec delay */
+ mdelay(1); /* 1 msec delay */
}
}
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)
{
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) {
return num_chain;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* PrimeIocFifos - Initialize IOC request and reply FIFOs.
* @ioc: Pointer to MPT_ADAPTER structure
* reply frames.
*
* Returns 0 for success, non-zero for failure.
- */
+ **/
static int
PrimeIocFifos(MPT_ADAPTER *ioc)
{
dma_addr_t alloc_dma;
u8 *mem;
int i, reply_sz, sz, total_size, num_chain;
- u64 dma_mask = 0;
+ 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
*/
return 0;
out_fail:
+
if (ioc->alloc != NULL) {
sz = ioc->alloc_sz;
pci_free_consistent(ioc->pcidev,
return -1;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_handshake_req_reply_wait - Send MPT request to and receive reply
* from IOC via doorbell handshake method.
* 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)
return -failcnt;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
* @ioc: Pointer to MPT_ADAPTER structure
* 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)
{
return -1;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
* @ioc: Pointer to MPT_ADAPTER structure
* (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)
{
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++;
}
}
return -1;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
* @ioc: Pointer to MPT_ADAPTER structure
* 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)
{
return u16cnt/2;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* GetLanConfigPages - Fetch LANConfig pages.
* @ioc: Pointer to MPT_ADAPTER structure
* -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)
{
return rc;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
* @ioc: Pointer to MPT_ADAPTER structure
* 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)
{
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) {
break;
default:
- return -1;
- break;
+ ret = -1;
+ goto out;
}
printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
*/
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;
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)
}
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* GetIoUnitPage2 - Retrieve BIOS version and boot order information.
* @ioc: Pointer to MPT_ADAPTER structure
* -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)
{
return rc;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
* @ioc: Pointer to a Adapter Strucutre
* Both valid
* Return 0
* CHECK - what type of locking mechanisms should be used????
- */
+ **/
static int
mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
{
ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
rc = 1;
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Unable to read PortPage0 minSyncFactor=%x\n",
- ioc->name, ioc->spi_data.minSyncFactor));
+ "Unable to read PortPage0 minSyncFactor=%x\n",
+ ioc->name, ioc->spi_data.minSyncFactor));
} else {
/* Save the Port Page 0 data
*/
if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "noQas due to Capabilities=%x\n",
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "noQas due to Capabilities=%x\n",
ioc->name, pPP0->Capabilities));
}
ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
ioc->spi_data.minSyncFactor = (u8) (data >> 8);
- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "PortPage0 minSyncFactor=%x\n",
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PortPage0 minSyncFactor=%x\n",
ioc->name, ioc->spi_data.minSyncFactor));
} else {
ioc->spi_data.maxSyncOffset = 0;
if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
ioc->spi_data.minSyncFactor = MPT_ULTRA;
- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "HVD or SE detected, minSyncFactor=%x\n",
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HVD or SE detected, minSyncFactor=%x\n",
ioc->name, ioc->spi_data.minSyncFactor));
}
}
return rc;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_readScsiDevicePageHeaders - save version and length of SDP1
* @ioc: Pointer to a Adapter Strucutre
*
* Return: -EFAULT if read of config page header fails
* or 0 if success.
- */
+ **/
static int
mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
{
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)
}
/**
- * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume
- *
- * @ioc : pointer to per adapter structure
- * @channel : volume channel
- * @id : volume target id
+ * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums
+ * for devices belonging in an inactive volume
+ *
+ * @ioc : pointer to per adapter structure
+ * @channel : volume channel
+ * @id : volume target id
+ *
**/
static void
mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
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));
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;
memset(&cfg, 0 , sizeof(CONFIGPARMS));
memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+ hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
cfg.cfghdr.hdr = &hdr;
cfg.physAddr = -1;
return rc;
}
+/**
+ * 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
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);
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);
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
if (mpt_config(ioc, &cfg) == 0) {
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Reset NVRAM Coalescing Timeout to = %d\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
ioc->name, MPT_COALESCING_TIMEOUT));
} else {
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Reset NVRAM Coalescing Timeout Failed\n",
- ioc->name));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset NVRAM Coalescing Timeout Failed\n",
+ ioc->name));
}
} else {
- dprintk(ioc, printk(MYIOC_s_WARN_FMT
- "Reset of Current Coalescing Timeout Failed!\n",
- ioc->name));
+ dprintk(ioc, printk(MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
+ ioc->name));
}
}
pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* SendEventNotification - Send EventNotification (on or off) request to adapter
* @ioc: Pointer to MPT_ADAPTER structure
* @EvSwitch: Event switch flags
- */
+ * @sleepFlag: Specifies whether the process can sleep
+ **/
static int
-SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
+SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
{
- EventNotification_t *evnp;
-
- evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
- if (evnp == NULL) {
- devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
- ioc->name));
- return 0;
- }
- memset(evnp, 0, sizeof(*evnp));
+ EventNotification_t evn;
+ MPIDefaultReply_t reply_buf;
- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
+ memset(&evn, 0, sizeof(EventNotification_t));
+ memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
- evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
- evnp->ChainOffset = 0;
- evnp->MsgFlags = 0;
- evnp->Switch = EvSwitch;
+ evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
+ evn.Switch = EvSwitch;
+ evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
- mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Sending EventNotification (%d) request %p\n",
+ ioc->name, EvSwitch, &evn));
- return 0;
+ return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
+ (u32*)&evn, sizeof(MPIDefaultReply_t), (u16*)&reply_buf, 30,
+ sleepFlag);
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* SendEventAck - Send EventAck request to MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
* @evnp: Pointer to original EventNotification request
- */
+ **/
static int
SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
{
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_config - Generic function to issue config message
* @ioc: Pointer to an adapter structure
* -EPERM if not allowed due to ISR context
* -EAGAIN if no msg frames currently available
* -EFAULT for non-successful reply or no reply (timeout)
- */
+ **/
int
mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
{
Config_t *pReq;
+ ConfigReply_t *pReply;
ConfigExtendedPageHeader_t *pExtHdr = NULL;
MPT_FRAME_HDR *mf;
- unsigned long flags;
- int ii, rc;
+ int ii;
int flagsLength;
- int in_isr;
+ long timeout;
+ int ret;
+ u8 page_type = 0, extend_page;
+ unsigned long timeleft;
+ unsigned long flags;
+ u8 issue_hard_reset = 0;
+ u8 retry_count = 0;
- /* Prevent calling wait_event() (below), if caller happens
- * to be in ISR context, because that is fatal!
- */
- in_isr = in_interrupt();
- if (in_isr) {
- dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
- ioc->name));
+ if (in_interrupt())
return -EPERM;
+
+ /* don't send a config page during diag reset */
+ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ if (ioc->ioc_reset_in_progress) {
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: busy with host reset\n", ioc->name, __FUNCTION__));
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+ return -EBUSY;
+ }
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+ /* don't send if no chance of success */
+ if (!ioc->active ||
+ mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: ioc not operational, %d, %xh\n",
+ ioc->name, __FUNCTION__, ioc->active,
+ mpt_GetIocState(ioc, 0)));
+ return -EFAULT;
}
+ retry_config:
+ mutex_lock(&ioc->mptbase_cmds.mutex);
+ /* init the internal cmd struct */
+ memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
+ INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
+
/* Get and Populate a free Frame
*/
if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
- dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
- ioc->name));
- return -EAGAIN;
+ dcprintk(ioc, printk(MYIOC_s_WARN_FMT
+ "mpt_config: no msg frames!\n", ioc->name));
+ ret = -EAGAIN;
+ goto out;
}
+
pReq = (Config_t *)mf;
pReq->Action = pCfg->action;
pReq->Reserved = 0;
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;
}
else
flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
- if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
+ if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
+ MPI_CONFIG_PAGETYPE_EXTENDED) {
flagsLength |= pExtHdr->ExtPageLength * 4;
-
- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
- ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
- }
- else {
+ page_type = pReq->ExtPageType;
+ extend_page = 1;
+ } else {
flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
-
- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
- ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
+ page_type = pReq->Header.PageType;
+ extend_page = 0;
}
- ioc->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;
+ 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 to end of Q, set timer and then issue this command */
- spin_lock_irqsave(&ioc->FreeQlock, flags);
- list_add_tail(&pCfg->linkage, &ioc->configQ);
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
- add_timer(&pCfg->timer);
+ ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
+ timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
mpt_put_msg_frame(mpt_base_index, ioc, mf);
- wait_event(mpt_waitq, pCfg->wait_done);
-
- /* mf has been freed - do not access */
-
- rc = pCfg->status;
+ timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, timeout);
+ if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ ret = -ETIME;
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Failed Sending Config request type 0x%x, page 0x%x,"
+ " action %d, status %xh, time left %ld\n\n",
+ ioc->name, page_type, pReq->Header.PageNumber,
+ pReq->Action, ioc->mptbase_cmds.status, timeleft));
+ if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+ goto out;
+ if (!timeleft)
+ issue_hard_reset = 1;
+ goto out;
+ }
- return rc;
-}
+ if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+ ret = -1;
+ goto out;
+ }
+ pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
+ ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+ if (ret == MPI_IOCSTATUS_SUCCESS) {
+ if (extend_page) {
+ pCfg->cfghdr.ehdr->ExtPageLength =
+ le16_to_cpu(pReply->ExtPageLength);
+ pCfg->cfghdr.ehdr->ExtPageType =
+ pReply->ExtPageType;
+ }
+ pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
+ pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
+ pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
+ pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- * mpt_timer_expired - Callback for timer process.
- * Used only internal config functionality.
- * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
- */
-static void
-mpt_timer_expired(unsigned long data)
-{
- MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
+ }
- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
+ if (retry_count)
+ printk(MYIOC_s_INFO_FMT "Retry completed ret=0x%x timeleft=%ld\n",
+ ioc->name, ret, timeleft);
- /* Perform a FW reload */
- if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
- printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
+ dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+ ret, le32_to_cpu(pReply->IOCLogInfo)));
- /* No more processing.
- * Hard reset clean-up will wake up
- * process and free all resources.
- */
- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
+ out:
- return;
+ CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
+ mutex_unlock(&ioc->mptbase_cmds.mutex);
+ if (issue_hard_reset) {
+ issue_hard_reset = 0;
+ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+ ioc->name, __FUNCTION__);
+ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
+ mpt_HardResetHandler(ioc, CAN_SLEEP);
+ mpt_free_msg_frame(ioc, mf);
+ /* attempt one retry for a timed out command */
+ if (!retry_count) {
+ printk(MYIOC_s_INFO_FMT
+ "Attempting Retry Config request type 0x%x, page 0x%x,"
+ " action %d\n", ioc->name, page_type,
+ pCfg->cfghdr.hdr->PageNumber, pCfg->action);
+ retry_count++;
+ goto retry_config;
+ }
+ }
+ return ret;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_ioc_reset - Base cleanup for hard reset
* @ioc: Pointer to the adapter structure
* @reset_phase: Indicates pre- or post-reset functionality
*
* Remark: Frees resources with internally generated commands.
- */
+ **/
static int
mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
- CONFIGPARMS *pCfg;
- unsigned long flags;
-
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- ": IOC %s_reset routed to MPT base driver!\n",
- ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
- if (reset_phase == MPT_IOC_SETUP_RESET) {
- ;
- } else if (reset_phase == MPT_IOC_PRE_RESET) {
- /* If the internal config Q is not empty -
- * delete timer. MF resources will be freed when
- * the FIFO's are primed.
- */
- spin_lock_irqsave(&ioc->FreeQlock, flags);
- list_for_each_entry(pCfg, &ioc->configQ, linkage)
- del_timer(&pCfg->timer);
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
- } else {
- CONFIGPARMS *pNext;
-
- /* Search the configQ for internal commands.
- * Flush the Q, and wake up all suspended threads.
- */
- spin_lock_irqsave(&ioc->FreeQlock, flags);
- list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
- list_del(&pCfg->linkage);
-
- pCfg->status = MPT_CONFIG_ERROR;
- pCfg->wait_done = 1;
- wake_up(&mpt_waitq);
+ 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);
}
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+/* 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);
+ }
+ break;
+ default:
+ break;
}
return 1; /* currently means nothing really */
#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)
{
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
*
* Returns 0 for success, non-zero for failure.
- */
+ **/
static void
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
*
* 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)
{
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
* @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)
{
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
* @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)
{
#endif /* CONFIG_PROC_FS } */
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static void
mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
{
}
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
* @ioc: Pointer to MPT_ADAPTER structure
*
* 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)
{
/*
* 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);
+ }
+
+ 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);
+ }
+
+ /* Disable reply interrupts (also blocks FreeQ) */
+ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+ ioc->active = 0;
+ time_count = jiffies;
+ if ((rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
+ sleepFlag)) != 0)
+ 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
* FW reload/initialization failed.
*
* Returns 0 for SUCCESS or -1 if FAILED.
- */
+ **/
int
mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
{
- int rc;
+ int rc;
+ u8 cb_idx;
unsigned long flags;
+ unsigned long time_count;
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
#ifdef MFCNT
printk("MF count 0x%x !\n", ioc->mfcnt);
#endif
+ if(mpt_fwfault_debug)
+ mpt_halt_firmware(ioc);
+
/* Reset the adapter. Prevent more than 1 call to
* mpt_do_ioc_recovery at any instant in time.
*/
- spin_lock_irqsave(&ioc->diagLock, flags);
- if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
- spin_unlock_irqrestore(&ioc->diagLock, flags);
+ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ if (ioc->ioc_reset_in_progress) {
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
return 0;
- } else {
- ioc->diagPending = 1;
}
- spin_unlock_irqrestore(&ioc->diagLock, flags);
+ ioc->ioc_reset_in_progress = 1;
+ if (ioc->alt_ioc)
+ ioc->alt_ioc->ioc_reset_in_progress = 1;
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
- /* FIXME: If do_ioc_recovery fails, repeat....
- */
/* The SCSI driver needs to adjust timeouts on all current
* commands prior to the diagnostic reset being issued.
* Prevents timeouts occurring during a diagnostic reset...very bad.
* For all other protocol drivers, this is a no-op.
*/
- {
- u8 cb_idx;
- int r = 0;
-
- for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
- if (MptResetHandlers[cb_idx]) {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
- ioc->name, cb_idx));
- r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
- if (ioc->alt_ioc) {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
- ioc->name, ioc->alt_ioc->name, cb_idx));
- r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
- }
- }
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptResetHandlers[cb_idx]) {
+ mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
+ if (ioc->alt_ioc)
+ mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
}
}
+ time_count = jiffies;
if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
- printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
+ printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
+ rc, ioc->name);
+ } else {
+ if (ioc->hard_resets < -1)
+ ioc->hard_resets++;
}
- ioc->reload_fw = 0;
- if (ioc->alt_ioc)
- ioc->alt_ioc->reload_fw = 0;
- spin_lock_irqsave(&ioc->diagLock, flags);
- ioc->diagPending = 0;
- if (ioc->alt_ioc)
- ioc->alt_ioc->diagPending = 0;
- spin_unlock_irqrestore(&ioc->diagLock, flags);
+ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ ioc->ioc_reset_in_progress = 0;
+ ioc->taskmgmt_quiesce_io = 0;
+ ioc->taskmgmt_in_progress = 0;
+ if (ioc->alt_ioc) {
+ ioc->alt_ioc->ioc_reset_in_progress = 0;
+ ioc->alt_ioc->taskmgmt_quiesce_io = 0;
+ ioc->alt_ioc->taskmgmt_in_progress = 0;
+ }
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptResetHandlers[cb_idx]) {
+ mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
+ if (ioc->alt_ioc)
+ mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
+ }
+ }
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler: completed (%d seconds): %s\n",
+ ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
+ ((rc == 0) ? "SUCCESS" : "FAILED")));
return rc;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#ifdef CONFIG_FUSION_LOGGING
static void
-EventDescriptionStr(u8 event, u32 evData0, char *evStr)
+mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
{
char *ds = NULL;
+ u32 evData0;
+ int ii;
+ u8 event;
+ char *evStr = ioc->evStr;
+
+ event = le32_to_cpu(pEventReply->Event) & 0xFF;
+ evData0 = le32_to_cpu(pEventReply->Data[0]);
switch(event) {
case MPI_EVENT_NONE:
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";
"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: "
}
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";
{
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;
}
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...
*/
}
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
* Routes a received EventNotificationReply to all currently registered
* event handlers.
* Returns sum of event handlers return values.
- */
+ **/
static int
ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
{
u16 evDataLen;
u32 evData0 = 0;
-// u32 evCtx;
int ii;
u8 cb_idx;
int r = 0;
int handlers = 0;
- char evStr[EVENT_DESCR_STR_SZ];
u8 event;
+
/*
* Do platform normalization of values
*/
event = le32_to_cpu(pEventReply->Event) & 0xFF;
-// evCtx = le32_to_cpu(pEventReply->EventContext);
evDataLen = le16_to_cpu(pEventReply->EventDataLength);
- if (evDataLen) {
+ if (evDataLen)
evData0 = le32_to_cpu(pEventReply->Data[0]);
- }
-
- EventDescriptionStr(event, evData0, evStr);
- devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
- ioc->name,
- event,
- evStr));
#ifdef CONFIG_FUSION_LOGGING
- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- ": Event data:\n", ioc->name));
- for (ii = 0; ii < evDataLen; ii++)
- devtverboseprintk(ioc, printk(" %08x",
- le32_to_cpu(pEventReply->Data[ii])));
- devtverboseprintk(ioc, printk("\n"));
+ if (evDataLen)
+ mpt_display_event_info(ioc, pEventReply);
#endif
/*
*/
for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
if (MptEvHandlers[cb_idx]) {
- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
- ioc->name, cb_idx));
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Routing Event to event handler #%d\n", ioc->name, cb_idx));
r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
handlers++;
}
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
* @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)
{
switch (info) {
case 0x00010000:
desc = "bug! MID not found";
- if (ioc->reload_fw == 0)
- ioc->reload_fw++;
break;
case 0x00020000:
"Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
};
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_sas_log_info - Log information returned from SAS IOC.
* @ioc: Pointer to MPT_ADAPTER structure
sas_loginfo.dw.code, sas_loginfo.dw.subcode);
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_iocstatus_info_config - IOCSTATUS information for config pages
* @ioc: Pointer to MPT_ADAPTER structure
if (!desc)
return;
- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
- ioc->name, status, desc));
+ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc));
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
EXPORT_SYMBOL(mpt_GetIocState);
EXPORT_SYMBOL(mpt_print_ioc_summary);
EXPORT_SYMBOL(mpt_HardResetHandler);
+EXPORT_SYMBOL(mpt_SoftResetHandler);
EXPORT_SYMBOL(mpt_config);
EXPORT_SYMBOL(mpt_findImVolumes);
EXPORT_SYMBOL(mpt_alloc_fw_memory);
EXPORT_SYMBOL(mpt_free_fw_memory);
EXPORT_SYMBOL(mptbase_sas_persist_operation);
EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
+EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
+EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
+EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
+EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
+EXPORT_SYMBOL(mpt_halt_firmware);
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* fusion_init - Fusion MPT base driver initialization routine.
*
* Returns 0 for success, non-zero for failure.
- */
+ **/
static int __init
fusion_init(void)
{
/* 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.
*/
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* fusion_exit - Perform driver unload cleanup.
*
* This routine frees all resources associated with each MPT adapter
* and removes all %MPT_PROCFS_MPTBASEDIR entries.
- */
+ **/
static void __exit
fusion_exit(void)
{
-
mpt_reset_deregister(mpt_base_index);
#ifdef CONFIG_PROC_FS
#define MPTBASE_H_INCLUDED
/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include <linux/kernel.h>
-#include <linux/pci.h>
-
#include "lsi/mpi_type.h"
#include "lsi/mpi.h" /* Fusion MPI(nterface) basic defs */
#include "lsi/mpi_ioc.h" /* Fusion MPT IOC(ontroller) defs */
#define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.05"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.05"
+#define MPT_LINUX_VERSION_COMMON "4.00.38.02"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-4.00.38.02"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
+#define MPT_LINUX_MAJOR_VERSION 4
+#define MPT_LINUX_MINOR_VERSION 00
+#define MPT_LINUX_BUILD_VERSION 38
+#define MPT_LINUX_RELEASE_VERSION 02
#define show_mptmod_ver(s,ver) \
printk(KERN_INFO "%s %s\n", s, ver);
/*
* 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 */
#define MPT_COALESCING_TIMEOUT 0x10
-#define MPT_DMA_35BIT_MASK 0x00000007ffffffffULL
+#define MPT_DMA_35BIT_MASK 0x00000007ffffffffULL
/*
* SCSI transfer rate defines.
#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__ /* { */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
} 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...
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 */
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 {
} 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 */
+#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 */
-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 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
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
u8 flags;
};
-typedef void (*MPT_ADD_SGE)(char *addr, u32 flagslength, dma_addr_t dma_addr);
+typedef void (*MPT_ADD_SGE)(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
/*
* Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
int pci_irq; /* This irq */
char name[MPT_NAME_LENGTH]; /* "iocN" */
char prod_name[MPT_NAME_LENGTH]; /* "LSIFC9x9" */
+#ifdef CONFIG_FUSION_LOGGING
+ char evStr[EVENT_DESCR_STR_SZ]; /* used in mpt_display_event_info */
+#endif
char board_name[16];
char board_assembly[16];
char board_tracer[16];
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;
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;
- u64 dma_mask;
+ MPT_ADD_SGE add_sge; /* Pointer to add_sge function */
/* Pool of buffers for chaining. ReqToChain
* and ChainToChain track index of chain buffers.
* ChainBuffer (DMA) virt/phys addresses.
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;
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
int aen_event_read_flag; /* flag to indicate event log was read*/
u8 FirstWhoInit;
u8 upload_fw; /* If set, do a fw upload */
- u8 reload_fw; /* Force a FW Reload on next reset */
u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */
- u8 pad1[4];
u8 DoneCtx;
u8 TaskCtx;
u8 InternalCtx;
- spinlock_t initializing_hba_lock;
- int initializing_hba_lock_flag;
struct list_head list;
struct net_device *netdev;
struct list_head sas_topology;
struct mutex sas_discovery_mutex;
u8 sas_discovery_runtime;
u8 sas_discovery_ignore_events;
- u16 handle;
+ u8 sas_discovery_quiesce_io;
+ u8 disable_hotplug_remove;
+ struct mptsas_portinfo *hba_port_info; /* port_info object for the host */
+#if defined(CPQ_CIM)
+ struct list_head sas_device_info_list;
+ struct semaphore sas_device_info_mutex;
+#endif
int sas_index; /* index refrencing */
- MPT_SAS_MGMT sas_mgmt;
+ 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
struct work_struct sas_persist_task;
+ 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;
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
} MPT_ADAPTER;
/*
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#define SCSI_STD_SENSE_BYTES 18
-#define SCSI_STD_INQUIRY_BYTES 36
-#define SCSI_MAX_INQUIRY_BYTES 96
-
/*
* MPT_SCSI_HOST defines - Used by the IOCTL and the SCSI drivers
* Private to the driver.
*/
-/* LOCAL structure and fields used when processing
- * internally generated commands. These include:
- * bus scan, dv and config requests.
- */
-typedef struct _MPT_LOCAL_REPLY {
- ConfigPageHeader_t header;
- int completion;
- u8 sense[SCSI_STD_SENSE_BYTES];
- u8 scsiStatus;
- u8 skip;
- u32 pad;
-} MPT_LOCAL_REPLY;
#define MPT_HOST_BUS_UNKNOWN (0xFF)
#define MPT_HOST_TOO_MANY_TM (0x05)
#define MPT_NVRAM_WIDE_DISABLE (0x00100000)
#define MPT_NVRAM_BOOT_CHOICE (0x00200000)
-/* The TM_STATE variable is used to provide strict single threading of TM
- * requests as well as communicate TM error conditions.
- */
-#define TM_STATE_NONE (0)
-#define TM_STATE_IN_PROGRESS (1)
-#define TM_STATE_ERROR (2)
-
typedef enum {
FC,
SPI,
typedef struct _MPT_SCSI_HOST {
MPT_ADAPTER *ioc;
- int port;
- u32 pad0;
- MPT_LOCAL_REPLY *pLocal; /* used for internal commands */
- struct timer_list timer;
- /* Pool of memory for holding SCpnts before doing
- * OS callbacks. freeQ is the free pool.
- */
- u8 tmPending;
- u8 resetPending;
- u8 negoNvram; /* DV disabled, nego NVRAM */
- u8 pad1;
- u8 tmState;
- u8 rsvd[2];
- MPT_FRAME_HDR *cmdPtr; /* Ptr to nonOS request */
- struct scsi_cmnd *abortSCpnt;
- MPT_LOCAL_REPLY localReply; /* internal cmd reply struct */
- unsigned long hard_resets; /* driver forced bus resets count */
- unsigned long soft_resets; /* fw/external bus resets count */
- unsigned long timeouts; /* cmd timeouts */
ushort sel_timeout[MPT_MAX_FC_DEVICES];
char *info_kbuf;
- wait_queue_head_t scandv_waitq;
- int scandv_wait_done;
long last_queue_full;
- u16 tm_iocstatus;
u16 spi_pending;
struct list_head target_reset_list;
} MPT_SCSI_HOST;
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * More Dynamic Multi-Pathing stuff...
- */
-
-/* Forward decl, a strange C thing, to prevent gcc compiler warnings */
-struct scsi_cmnd;
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* Generic structure passed to the base mpt_config function.
*/
typedef struct _x_config_parms {
- struct list_head linkage; /* linked list */
- struct timer_list timer; /* timer function for this request */
union {
ConfigExtendedPageHeader_t *ehdr;
ConfigPageHeader_t *hdr;
} cfghdr;
dma_addr_t physAddr;
- int wait_done; /* wait for this request */
u32 pageAddr; /* properly formatted */
+ u16 status;
u8 action;
u8 dir;
u8 timeout; /* seconds */
- u8 pad1;
- u16 status;
- u16 pad2;
} CONFIGPARMS;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
extern u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
extern int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
+extern int mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
extern int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
-extern void mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
+extern int mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
extern void mpt_free_fw_memory(MPT_ADAPTER *ioc);
extern int mpt_findImVolumes(MPT_ADAPTER *ioc);
extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk);
+extern int mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage1_t phys_disk);
+extern int mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num);
+
+extern int mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
+extern void mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
+extern void mpt_halt_firmware(MPT_ADAPTER *ioc);
/*
* Public data decl's...
*/
extern struct list_head ioc_list;
extern struct proc_dir_entry *mpt_proc_root_dir;
+extern int mpt_debug_level;
+extern int mpt_fwfault_debug;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#endif /* } __KERNEL__ */
-#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__) || defined(__powerpc__)
+#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__) || defined(__powerpc64__)
#define CAST_U32_TO_PTR(x) ((void *)(u64)x)
#define CAST_PTR_TO_U32(x) ((u32)(u64)x)
#else
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#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
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS;
static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
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 *);
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
int rc = 0;
if (nonblock) {
- if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
+ if (!mutex_trylock(&ioc->ioctl_cmds.mutex))
rc = -EAGAIN;
} else {
- if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
+ if (mutex_lock_interruptible(&ioc->ioctl_cmds.mutex))
rc = -ERESTARTSYS;
}
return rc;
static int
mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
{
- char *sense_data;
- int sz, req_index;
- u16 iocStatus;
- u8 cmd;
-
- if (req)
- cmd = req->u.hdr.Function;
- else
- return 1;
- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tcompleting mpi function (0x%02X), req=%p, "
- "reply=%p\n", ioc->name, req->u.hdr.Function, req, reply));
-
- if (ioc->ioctl) {
+ char *sense_data;
+ int req_index;
+ int sz;
- if (reply==NULL) {
+ if (!req)
+ return 0;
- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_reply() NULL Reply "
- "Function=%x!\n", ioc->name, cmd));
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "completing mpi function "
+ "(0x%02X), req=%p, reply=%p\n", ioc->name, req->u.hdr.Function,
+ req, reply));
- ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
- ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
+ /*
+ * Handling continuation of the same reply. Processing the first
+ * reply, and eating the other replys that come later.
+ */
+ if (ioc->ioctl_cmds.msg_context != req->u.hdr.MsgContext)
+ goto out_continuation;
- /* We are done, issue wake up
- */
- ioc->ioctl->wait_done = 1;
- wake_up (&mptctl_wait);
- return 1;
+ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
- }
-
- /* Copy the reply frame (which much exist
- * for non-SCSI I/O) to the IOC structure.
- */
- memcpy(ioc->ioctl->ReplyFrame, reply,
- min(ioc->reply_sz, 4*reply->u.reply.MsgLength));
- ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
+ 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 (iocStatus || reply->u.reply.IOCLogInfo)
- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tiocstatus (0x%04X), "
- "loginfo (0x%08X)\n", ioc->name,
- iocStatus,
- le32_to_cpu(reply->u.reply.IOCLogInfo)));
-
- if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
- (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
-
- if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "\tscsi_status (0x%02x), scsi_state (0x%02x), "
- "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
- reply->u.sreply.SCSIStatus,
- reply->u.sreply.SCSIState,
- le16_to_cpu(reply->u.sreply.TaskTag),
- le32_to_cpu(reply->u.sreply.TransferCount)));
-
- ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
-
- if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) ||
- (iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) {
- ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
- }
- }
+ 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);
- /* 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.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)));
+
+ if (reply->u.sreply.SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
sz = req->u.scsireq.SenseBufferLength;
req_index =
le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
- sense_data =
- ((u8 *)ioc->sense_buf_pool +
+ sense_data = ((u8 *)ioc->sense_buf_pool +
(req_index * MPT_SENSE_BUFFER_ALLOC));
- memcpy(ioc->ioctl->sense, sense_data, sz);
- ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID;
+ memcpy(ioc->ioctl_cmds.sense, sense_data, sz);
+ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_SENSE_VALID;
}
+ }
- if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT)
- mptctl_free_tm_flags(ioc);
-
- /* We are done, issue wake up
- */
- ioc->ioctl->wait_done = 1;
- wake_up (&mptctl_wait);
+ out:
+ /* We are done, issue wake up
+ */
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
+ if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT)
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+ complete(&ioc->ioctl_cmds.done);
}
+
+ out_continuation:
+ if (reply && (reply->u.reply.MsgFlags &
+ MPI_MSGFLAGS_CONTINUATION_REPLY))
+ return 0;
return 1;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* mptctl_timeout_expired
- *
- * Expecting an interrupt, however timed out.
- *
- */
-static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
+static int
+mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
{
- int rc = 1;
+ if (!mf)
+ return 0;
- dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n",
- ioctl->ioc->name, ioctl->ioc->id));
- if (ioctl == NULL)
- return;
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n",
+ ioc->name, mf, mr));
- ioctl->wait_done = 0;
- if (ioctl->reset & MPTCTL_RESET_OK)
- rc = mptctl_bus_reset(ioctl);
+ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
- if (rc) {
- /* Issue a reset for this device.
- * The IOC is not responding.
- */
- dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
- ioctl->ioc->name));
- mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP);
- }
- return;
+ 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
* Bus reset code.
*
*/
-static int mptctl_bus_reset(MPT_IOCTL *ioctl)
+static int
+mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
{
MPT_FRAME_HDR *mf;
SCSITaskMgmt_t *pScsiTm;
- MPT_SCSI_HOST *hd;
+ SCSITaskMgmtReply_t *pScsiTmReply;
int ii;
- int retval=0;
-
-
- ioctl->reset &= ~MPTCTL_RESET_OK;
-
- if (ioctl->ioc->sh == NULL)
+ int retval;
+ unsigned long timeout;
+ unsigned long time_count;
+ u16 iocstatus;
+
+ /* bus reset is only good for SCSI IO, RAID PASSTHRU */
+ if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) ||
+ (function == MPI_FUNCTION_SCSI_IO_REQUEST)) {
+ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, not SCSI_IO!!\n",
+ ioc->name));
return -EPERM;
+ }
- hd = shost_priv(ioctl->ioc->sh);
- if (hd == NULL)
+ mutex_lock(&ioc->taskmgmt_cmds.mutex);
+ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
return -EPERM;
+ }
- /* Single threading ....
- */
- if (mptctl_set_tm_flags(hd) != 0)
- return -EPERM;
+ retval = 0;
/* Send request
*/
- if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) {
- dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt, no msg frames!!\n",
- ioctl->ioc->name));
-
- mptctl_free_tm_flags(ioctl->ioc);
- return -ENOMEM;
+ if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) {
+ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
+ ioc->name));
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ retval = -ENOMEM;
+ goto mptctl_bus_reset_done;
}
- dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
- ioctl->ioc->name, mf));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
+ ioc->name, mf));
pScsiTm = (SCSITaskMgmt_t *) mf;
- pScsiTm->TargetID = ioctl->id;
- pScsiTm->Bus = hd->port; /* 0 */
- pScsiTm->ChainOffset = 0;
+ memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
- pScsiTm->Reserved = 0;
pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
- pScsiTm->Reserved1 = 0;
pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
-
+ pScsiTm->TargetID = 0;
+ pScsiTm->Bus = 0;
+ pScsiTm->ChainOffset = 0;
+ pScsiTm->Reserved = 0;
+ pScsiTm->Reserved1 = 0;
+ pScsiTm->TaskMsgContext = 0;
for (ii= 0; ii < 8; ii++)
pScsiTm->LUN[ii] = 0;
-
for (ii=0; ii < 7; ii++)
pScsiTm->Reserved2[ii] = 0;
- pScsiTm->TaskMsgContext = 0;
- dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT
- "mptctl_bus_reset: issued.\n", ioctl->ioc->name));
-
- DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf);
+ switch (ioc->bus_type) {
+ case FC:
+ timeout = 40;
+ break;
+ case SAS:
+ timeout = 30;
+ break;
+ case SPI:
+ default:
+ timeout = 2;
+ break;
+ }
- ioctl->wait_done=0;
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
+ ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
- if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
- (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05))
- mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf);
+ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+ time_count = jiffies;
+ if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+ (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+ mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf);
else {
- retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+ retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,
+ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
if (retval != 0) {
- dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
- " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
- hd->ioc, mf));
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt send_handshake FAILED!"
+ " (ioc %p, mf %p, rc=%d) \n", ioc->name,
+ ioc, mf, retval));
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
goto mptctl_bus_reset_done;
}
}
/* Now wait for the command to complete */
- ii = wait_event_timeout(mptctl_wait,
- ioctl->wait_done == 1,
- HZ*5 /* 5 second timeout */);
+ 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;
+ }
- if(ii <=0 && (ioctl->wait_done != 1 )) {
- mpt_free_msg_frame(hd->ioc, mf);
- ioctl->wait_done = 0;
+ 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;
+ }
+
+ 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 */
}
-mptctl_bus_reset_done:
- mptctl_free_tm_flags(ioctl->ioc);
+ mptctl_bus_reset_done:
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
return retval;
}
-static int
-mptctl_set_tm_flags(MPT_SCSI_HOST *hd) {
- unsigned long flags;
-
- 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);
- } else {
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
- return -EBUSY;
- }
-
- return 0;
-}
-
static void
-mptctl_free_tm_flags(MPT_ADAPTER *ioc)
+mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
{
- MPT_SCSI_HOST * hd;
unsigned long flags;
- hd = shost_priv(ioc->sh);
- if (hd == NULL)
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
+ ioc->name, __FUNCTION__));
+
+ if(mpt_fwfault_debug)
+ mpt_halt_firmware(ioc);
+
+ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ if (ioc->ioc_reset_in_progress) {
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+ CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+ mpt_free_msg_frame(ioc, mf);
return;
+ }
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
- spin_lock_irqsave(&ioc->FreeQlock, flags);
- hd->tmState = TM_STATE_NONE;
- hd->tmPending = 0;
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+ if (!mptctl_bus_reset(ioc, mf->u.hdr.Function))
+ return;
- return;
+ /* Issue a reset for this device.
+ * The IOC is not responding.
+ */
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
+ ioc->name));
+ CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
+ mpt_HardResetHandler(ioc, CAN_SLEEP);
+ mpt_free_msg_frame(ioc, mf);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static int
mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
- MPT_IOCTL *ioctl = ioc->ioctl;
- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name,
- reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
- if(ioctl == NULL)
- return 1;
-
switch(reset_phase) {
case MPT_IOC_SETUP_RESET:
- ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET;
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
+ break;
+ case MPT_IOC_PRE_RESET:
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
break;
case MPT_IOC_POST_RESET:
- ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET;
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__));
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
+ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
+ complete(&ioc->ioctl_cmds.done);
+ }
break;
- case MPT_IOC_PRE_RESET:
default:
break;
}
int ret;
MPT_ADAPTER *iocp = NULL;
+
if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
printk(KERN_ERR MYNAM "%s::mptctl_ioctl() @%d - "
"Unable to copy mpt_ioctl_header data @ %p\n",
iocnumX = khdr.iocnum & 0xFF;
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnumX);
return -ENODEV;
}
- if (!iocp->active) {
- printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n",
- __FILE__, __LINE__);
- return -EFAULT;
- }
-
/* Handle those commands that are just returning
* information stored in the driver.
* These commands should never time out and are unaffected
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
if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
return ret;
+// dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT ": mptctl_ioctl()\n", iocp->name));
+
if (cmd == MPTFWDOWNLOAD)
ret = mptctl_fw_download(arg);
else if (cmd == MPTCOMMAND)
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;
}
}
if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n",
__FILE__, __LINE__, krinfo.hdr.iocnum);
return -ENODEV; /* (-6) No such device or address */
int sge_offset = 0;
u16 iocstat;
pFWDownloadReply_t ReplyMsg = NULL;
+ unsigned long timeleft;
if (mpt_verify_adapter(ioc, &iocp) < 0) {
- printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n",
- ioc);
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
+ printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n", ioc);
return -ENODEV; /* (-6) No such device or address */
} else {
/ (sizeof(dma_addr_t) + sizeof(u32));
if (numfrags > maxfrags) {
ret = -EMLINK;
- goto fwdl_out;
+ goto fwdl_out;
}
dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: sgl buffer = %p, sgfrags = %d\n",
n++;
if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
- "Unable to copy f/w buffer hunk#%d @ %p\n",
- iocp->name, __FILE__, __LINE__, n, ufwbuf);
+ "Unable to copy f/w buffer hunk#%d @ %p\n",
+ iocp->name, __FILE__, __LINE__, n, ufwbuf);
goto fwdl_out;
}
fw_bytes_copied += bl->len;
* 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);
+ 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(ret <=0 && (iocp->ioctl->wait_done != 1 )) {
- /* Now we need to reset the board */
- mptctl_timeout_expired(iocp->ioctl);
+ 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;
}
if (sgl)
kfree_sgl(sgl, sgl_dma, buflist, iocp);
- ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame;
+ ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply;
iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
if (iocstat == MPI_IOCSTATUS_SUCCESS) {
- printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name);
+ printk(MYIOC_s_INFO_FMT ": F/W update successfully sent!\n", iocp->name);
return 0;
} else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
- printk(MYIOC_s_WARN_FMT "Hmmm... F/W download not supported!?!\n",
- iocp->name);
+ printk(MYIOC_s_WARN_FMT "Hmmm... doesn't support F/W download?\n",
+ iocp->name);
printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n",
- iocp->name);
+ iocp->name);
return -EBADRQC;
} else if (iocstat == MPI_IOCSTATUS_BUSY) {
printk(MYIOC_s_WARN_FMT "IOC_BUSY!\n", iocp->name);
printk(MYIOC_s_WARN_FMT "(try again later?)\n", iocp->name);
return -EBUSY;
} else {
- printk(MYIOC_s_WARN_FMT "ioctl_fwdl() returned [bad] status = %04xh\n",
- iocp->name, iocstat);
+ printk(MYIOC_s_WARN_FMT "returned [bad] status = %04xh\n",
+ iocp->name, iocstat);
printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name);
return -ENOMSG;
}
return 0;
fwdl_out:
- kfree_sgl(sgl, sgl_dma, buflist, iocp);
+
+ CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status);
+ SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0);
+ kfree_sgl(sgl, sgl_dma, buflist, iocp);
return ret;
}
alloc_sz = alloc_sz / 2;
if (alloc_sz == 0) {
printk(MYIOC_s_WARN_FMT "-SG: No can do - "
- "not enough memory! :-(\n", ioc->name);
+ "not enough memory! :-(\n", ioc->name);
printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
- ioc->name, numfrags);
+ ioc->name, numfrags);
goto free_and_fail;
}
continue;
/* Need to chain? */
if (fragcnt == sg_spill) {
- printk(MYIOC_s_WARN_FMT
- "-SG: No can do - " "Chain required! :-(\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT "-SG: No can do - "
+ "Chain required! :-(\n", ioc->name);
printk(MYIOC_s_WARN_FMT "(freeing %d frags)\n", ioc->name, numfrags);
goto free_and_fail;
}
if (numfrags*8 > MAX_SGL_BYTES){
/* GRRRRR... */
printk(MYIOC_s_WARN_FMT "-SG: No can do - "
- "too many SG frags! :-(\n", ioc->name);
+ "too many SG frags! :-(\n", ioc->name);
printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
- ioc->name, numfrags);
+ ioc->name, numfrags);
goto free_and_fail;
}
}
if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
kfree(karg);
/* Verify the data transfer size is correct. */
if (karg->hdr.maxDataSize != data_size) {
printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
- "Structure size mismatch. Command not completed.\n",
- ioc->name, __FILE__, __LINE__);
+ "Structure size mismatch. Command not completed.\n",
+ ioc->name, __FILE__, __LINE__);
kfree(karg);
return -EFAULT;
}
if (ioc->sh) {
shost_for_each_device(sdev, ioc->sh) {
vdevice = sdev->hostdata;
+ if (vdevice == NULL || vdevice->vtarget == NULL)
+ continue;
if (vdevice->vtarget->tflags &
MPT_TARGET_FLAGS_RAID_COMPONENT)
continue;
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
port = karg.hdr.port;
if (maxWordsLeft <= 0) {
- printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
- ioc->name, __FILE__, __LINE__);
+ printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
+ ioc->name, __FILE__, __LINE__);
return -ENOMEM;
}
*/
pmem = kzalloc(numBytes, GFP_KERNEL);
if (!pmem) {
- printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
- ioc->name, __FILE__, __LINE__);
+ printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
+ ioc->name, __FILE__, __LINE__);
return -ENOMEM;
}
pdata = (int *) pmem;
if (!maxWordsLeft)
continue;
vdevice = sdev->hostdata;
+ if (vdevice == NULL || vdevice->vtarget == NULL)
+ continue;
if (vdevice->vtarget->tflags &
MPT_TARGET_FLAGS_RAID_COMPONENT)
continue;
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
ioc->events = kzalloc(sz, GFP_KERNEL);
if (!ioc->events) {
- printk(MYIOC_s_ERR_FMT
- ": ERROR - Insufficient memory to add adapter!\n",
+ printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
ioc->name);
return -ENOMEM;
}
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
+
dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n",
ioc->name));
-
numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
*/
if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) {
printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - "
- "Unable to read in mpt_ioctl_replace_fw image "
- "@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
+ "Unable to read in mpt_ioctl_replace_fw image "
+ "@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
mpt_free_fw_memory(ioc);
return -EFAULT;
}
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
int sz, rc = 0;
int msgContext;
u16 req_idx;
- ulong timeout;
+ unsigned long timeout;
+ unsigned long timeleft;
struct scsi_device *sdev;
+ unsigned long flags;
+ u8 function;
/* bufIn and bufOut are used for user to kernel space transfers
*/
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
- if (!ioc->ioctl) {
- printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
- "No memory available during driver init.\n",
- __FILE__, __LINE__);
- return -ENOMEM;
- } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
+
+ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ if (ioc->ioc_reset_in_progress) {
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
- "Busy with IOC Reset \n", __FILE__, __LINE__);
+ "Busy with diagnostic reset\n", __FILE__, __LINE__);
return -EBUSY;
}
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
/* Verify that the final request frame will not be too large.
*/
printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Unable to read MF from mpt_ioctl_command struct @ %p\n",
ioc->name, __FILE__, __LINE__, mfPtr);
+ function = -1;
rc = -EFAULT;
goto done_free_mem;
}
hdr->MsgContext = cpu_to_le32(msgContext);
-
+ function = hdr->Function;
/* Verify that this request is allowed.
*/
dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n",
- ioc->name, hdr->Function, mf));
+ ioc->name, function, mf));
- switch (hdr->Function) {
+ switch (function) {
case MPI_FUNCTION_IOC_FACTS:
case MPI_FUNCTION_PORT_FACTS:
karg.dataOutSize = karg.dataInSize = 0;
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))
pScsiReq->Control = cpu_to_le32(scsidir | qtag);
pScsiReq->DataLength = cpu_to_le32(dataSize);
- ioc->ioctl->reset = MPTCTL_RESET_OK;
- ioc->ioctl->id = pScsiReq->TargetID;
-
} else {
printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"SCSI driver is not loaded. \n",
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.
*/
pScsiReq->Control = cpu_to_le32(scsidir | qtag);
pScsiReq->DataLength = cpu_to_le32(dataSize);
- ioc->ioctl->reset = MPTCTL_RESET_OK;
- ioc->ioctl->id = pScsiReq->TargetID;
} else {
printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"SCSI driver is not loaded. \n",
break;
case MPI_FUNCTION_SCSI_TASK_MGMT:
- {
- MPT_SCSI_HOST *hd = NULL;
- if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) {
- printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
- "SCSI driver not loaded or SCSI host not found. \n",
- ioc->name, __FILE__, __LINE__);
- rc = -EFAULT;
- goto done_free_mem;
- } else if (mptctl_set_tm_flags(hd) != 0) {
- rc = -EPERM;
- goto done_free_mem;
- }
- }
+ {
+ SCSITaskMgmt_t *pScsiTm;
+ pScsiTm = (SCSITaskMgmt_t *)mf;
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tTaskType=0x%x MsgFlags=0x%x "
+ "TaskMsgContext=0x%x id=%d channel=%d\n", ioc->name, pScsiTm->TaskType,
+ le32_to_cpu(pScsiTm->TaskMsgContext), pScsiTm->MsgFlags,
+ pScsiTm->TargetID, pScsiTm->Bus));
break;
+ }
case MPI_FUNCTION_IOC_INIT:
{
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)) ||
printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Illegal request (function 0x%x) \n",
- ioc->name, __FILE__, __LINE__, hdr->Function);
+ ioc->name, __FILE__, __LINE__, function);
rc = -EFAULT;
goto done_free_mem;
}
ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
}
- ioc->ioctl->wait_done = 0;
- if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
+ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext);
+ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
+ if (function == MPI_FUNCTION_SCSI_TASK_MGMT) {
+
+ mutex_lock(&ioc->taskmgmt_cmds.mutex);
+ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+ goto done_free_mem;
+ }
DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
(ioc->facts.MsgVersion >= MPI_VERSION_01_05))
mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf);
else {
- rc =mpt_send_handshake_request(mptctl_id, ioc,
- sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
+ rc = mpt_send_handshake_request(mptctl_id, ioc,
+ sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
if (rc != 0) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "_send_handshake FAILED! (ioc %p, mf %p)\n",
+ "send_handshake FAILED! (ioc %p, mf %p)\n",
ioc->name, ioc, mf));
- mptctl_free_tm_flags(ioc);
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
rc = -ENODATA;
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
goto done_free_mem;
}
}
-
} else
mpt_put_msg_frame(mptctl_id, ioc, mf);
/* Now wait for the command to complete */
timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT;
- timeout = wait_event_timeout(mptctl_wait,
- ioc->ioctl->wait_done == 1,
- HZ*timeout);
-
- if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) {
- /* Now we need to reset the board */
-
- if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT)
- mptctl_free_tm_flags(ioc);
-
- mptctl_timeout_expired(ioc->ioctl);
- rc = -ENODATA;
+ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*timeout);
+ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ rc = -ETIME;
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n",
+ ioc->name, __FUNCTION__));
+ if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+ goto done_free_mem;
+ }
+ if (!timeleft) {
+ mptctl_timeout_expired(ioc, mf);
+ mf = NULL;
+ }
goto done_free_mem;
}
+ if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+
mf = NULL;
/* If a valid reply frame, copy to the user.
* Offset 2: reply length in U32's
*/
- if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) {
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
if (karg.maxReplyBytes < ioc->reply_sz) {
- sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
+ sz = min(karg.maxReplyBytes, 4*ioc->ioctl_cmds.reply[2]);
} else {
- sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
+ sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]);
}
-
if (sz > 0) {
if (copy_to_user(karg.replyFrameBufPtr,
- &ioc->ioctl->ReplyFrame, sz)){
+ ioc->ioctl_cmds.reply, sz)){
printk(MYIOC_s_ERR_FMT
"%s@%d::mptctl_do_mpt_command - "
"Unable to write out reply frame %p\n",
/* If valid sense data, copy to user.
*/
- if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) {
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) {
sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
if (sz > 0) {
- if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) {
+ if (copy_to_user(karg.senseDataPtr, ioc->ioctl_cmds.sense, sz)) {
printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Unable to write sense data to user %p\n",
ioc->name, __FILE__, __LINE__,
/* If the overall status is _GOOD and data in, copy data
* to user.
*/
- if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) &&
- (karg.dataInSize > 0) && (bufIn.kptr)) {
-
+ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) &&
+ (karg.dataInSize > 0) && (bufIn.kptr)) {
if (copy_to_user(karg.dataInBufPtr,
bufIn.kptr, karg.dataInSize)) {
printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
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.
*/
hp_host_info_t __user *uarg = (void __user *) arg;
MPT_ADAPTER *ioc;
struct pci_dev *pdev;
- char *pbuf=NULL;
+ char *pbuf=NULL;
dma_addr_t buf_dma;
hp_host_info_t karg;
- CONFIGPARMS cfg;
- ConfigPageHeader_t hdr;
int iocnum;
- int rc, cim_rev;
+ int cim_rev;
ToolboxIstwiReadWriteRequest_t *IstwiRWRequest;
MPT_FRAME_HDR *mf = NULL;
MPIHeader_t *mpi_hdr;
+ unsigned long timeleft;
+ int retval;
+ u32 MsgContext;
/* Reset long to int. Should affect IA64 and SPARC only
*/
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
+
dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n",
ioc->name));
-
/* Fill in the data and return the structure to the calling
* program
*/
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, " ", 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) {
+ strncpy(karg.serial_number, ioc->board_tracer, 16);
+
+ switch (mpt_GetIocState(ioc, 1)) {
case MPI_IOC_STATE_OPERATIONAL:
karg.ioc_status = HP_STATUS_OK;
break;
karg.soft_resets = 0;
karg.timeouts = 0;
if (ioc->sh != NULL) {
- MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
if (hd && (cim_rev == 1)) {
- karg.hard_resets = hd->hard_resets;
- karg.soft_resets = hd->soft_resets;
- karg.timeouts = hd->timeouts;
+ karg.hard_resets = ioc->hard_resets;
+ karg.soft_resets = ioc->soft_resets;
+ karg.timeouts = ioc->timeouts;
}
}
if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
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);
IstwiRWRequest->DeviceAddr = 0xB0;
pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma);
- if (!pbuf)
+ if (!pbuf) {
+ retval = -ENOMEM;
goto out;
- ioc->add_sge((char *)&IstwiRWRequest->SGL,
- (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);
+ }
+ ioc->add_sge((char *)&IstwiRWRequest->SGL, (MPT_SGE_FLAGS_SSIMPLE_READ|4),buf_dma);
- ioc->ioctl->wait_done = 0;
+ retval = 0;
+ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, IstwiRWRequest->MsgContext);
+ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
mpt_put_msg_frame(mptctl_id, ioc, mf);
-
- rc = wait_event_timeout(mptctl_wait,
- ioc->ioctl->wait_done == 1,
- HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */);
-
- if(rc <=0 && (ioc->ioctl->wait_done != 1 )) {
- /*
- * Now we need to reset the board
- */
- mpt_free_msg_frame(ioc, mf);
- mptctl_timeout_expired(ioc->ioctl);
+ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*MPT_IOCTL_DEFAULT_TIMEOUT);
+ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ retval = -ETIME;
+ printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __FUNCTION__);
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+ mpt_free_msg_frame(ioc, mf);
+ goto out;
+ }
+ if (!timeleft)
+ mptctl_timeout_expired(ioc, mf);
goto out;
}
- /*
+ /*
*ISTWI Data Definition
* pbuf[0] = FW_VERSION = 0x4
* pbuf[1] = Bay Count = 6 or 4 or 2, depending on
* 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);
return -EFAULT;
}
- return 0;
+ return retval;
}
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
- ioc->name));
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_targetinfo called.\n",
+ ioc->name));
/* There is nothing to do for FCP parts.
*/
if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma);
}
}
- hd = shost_priv(ioc->sh);
+ hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
if (hd != NULL)
karg.select_timeouts = hd->sel_timeout[karg.hdr.id];
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static const struct file_operations mptctl_fops = {
+static struct file_operations mptctl_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.release = mptctl_release,
iocnumX = kfw32.iocnum & 0xFF;
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
- __LINE__, iocnumX);
+ __LINE__, iocnumX);
return -ENODEV;
}
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;
}
iocnumX = karg32.hdr.iocnum & 0xFF;
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
+ if (mpt_debug_level & MPT_DEBUG_IOCTL)
printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
- __LINE__, iocnumX);
+ __LINE__, iocnumX);
return -ENODEV;
}
*/
ret = mptctl_do_mpt_command (karg, &uarg->MF);
- mutex_unlock(&iocp->ioctl->ioctl_mutex);
+ mutex_unlock(&iocp->ioctl_cmds.mutex);
return ret;
}
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;
static int
mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- MPT_IOCTL *mem;
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
- /*
- * Allocate and inite a MPT_IOCTL structure
- */
- mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL);
- if (!mem) {
- mptctl_remove(pdev);
- return -ENOMEM;
- }
+ mutex_init(&ioc->ioctl_cmds.mutex);
+ init_completion(&ioc->ioctl_cmds.done);
- ioc->ioctl = mem;
- ioc->ioctl->ioc = ioc;
- mutex_init(&ioc->ioctl->ioctl_mutex);
return 0;
}
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 = {
goto out_fail;
}
+ mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
mpt_reset_register(mptctl_id, mptctl_ioc_reset);
mpt_event_register(mptctl_id, mptctl_event_process);
/* De-register reset handler from base module */
mpt_reset_deregister(mptctl_id);
+ mpt_reset_deregister(mptctl_taskmgmt_id);
/* De-register callback handler from base module */
mpt_deregister(mptctl_id);
mpt_device_driver_deregister(MPTCTL_DRIVER);
-
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#if defined(CPQ_CIM)
+#include "csmi/csmisas.c"
+#endif // CPQ_CIM
+
+#if defined(DIAG_BUFFER_SUPPORT)
+#include "rejected_ioctls/diag_buffer.c"
+#endif
+
module_init(mptctl_init);
module_exit(mptctl_exit);
/*
- * 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
#define HP_DEV_SPEED_SCSI1 7
#define HP_DEV_SPEED_ULTRA320 8
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#endif
*
* 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
*
* --------------------------------------------------------
#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 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 d36memprintk(IOC, CMD) \
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_36GB_MEM)
-
/*
* Verbose logging
*/
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h> /* for mdelay */
#include <linux/interrupt.h> /* needed for in_interrupt() proto */
#include <linux/reboot.h> /* notifier code */
+#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/sort.h>
+#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport_fc.h>
+#include "linux_compat.h" /* linux-2.6 tweaks */
#include "mptbase.h"
#include "mptscsih.h"
" 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;
.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),
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
unsigned long flags;
int ready;
- MPT_ADAPTER *ioc;
+ MPT_ADAPTER *ioc;
- hd = shost_priv(SCpnt->device->host);
+ 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) {
if (vtarget) {
vtarget->id = pg0->CurrentTargetID;
vtarget->channel = pg0->CurrentBus;
+ vtarget->deleted = 0;
}
}
*((struct mptfc_rport_info **)rport->dd_data) = ri;
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);
return rc;
}
+
/*
* mptfc_dump_lun_info
* @ioc
(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.
VirtDevice *vdevice;
struct scsi_target *starget;
struct fc_rport *rport;
- MPT_ADAPTER *ioc;
+ MPT_ADAPTER *ioc;
starget = scsi_target(sdev);
rport = starget_to_rport(starget);
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
- hd = shost_priv(sdev->host);
+ 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",
- ioc->name, sizeof(VirtDevice));
+ ioc->name, sizeof(VirtDevice));
return -ENOMEM;
}
vdevice->lun = sdev->lun;
vtarget->num_luns++;
-
-
mptfc_dump_lun_info(ioc, rport, sdev, vtarget);
-
return 0;
}
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)
#define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS)
for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
- if (mptfc_GetFcPortPage1(ioc, ii) != 0)
- continue;
+ if ((rc = mptfc_GetFcPortPage1(ioc, ii)) < 0)
+ return rc;
pp1 = ioc->fc_data.fc_port_page1[ii].data;
if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT)
&& (pp1->InitiatorIoPendTimeout == MPTFC_FW_IO_PEND_TIMEOUT)
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;
}
}
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++)
}
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) {
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;
}
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) {
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;
}
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);
+ 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);
sh->this_id = ioc->pfacts[0].PortSCSIID;
+ ioc->sdev_queue_depth = mpt_sdev_queue_depth;
+
/* Required entry.
*/
sh->unique_id = ioc->id;
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
- hd = shost_priv(sh);
+ hd = shost_private(sh);
hd->ioc = ioc;
/* SCSI needs scsi_cmnd lookup table!
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;
for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
(void) mptfc_GetFcPortPage0(ioc, ii);
}
- mptfc_SetFcPortPage1_defaults(ioc);
/*
* scan for rports -
unsigned long flags;
int rc=1;
- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
- ioc->name, event));
-
if (ioc->sh == NULL ||
- ((hd = shost_priv(ioc->sh)) == NULL))
+ ((hd = shost_private(ioc->sh)) == NULL))
return 1;
switch (event) {
unsigned long flags;
rc = mptscsih_ioc_reset(ioc,reset_phase);
- if (rc == 0)
+ if ((ioc->bus_type != FC) || (!rc))
return rc;
-
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- ": IOC %s_reset routed to FC host driver!\n",ioc->name,
- reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
- if (reset_phase == MPT_IOC_SETUP_RESET) {
+ switch(reset_phase) {
+ case MPT_IOC_SETUP_RESET:
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
if (ioc->fc_rescan_work_q) {
queue_work(ioc->fc_rescan_work_q,
&ioc->fc_setup_reset_work);
}
spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
- }
-
- else if (reset_phase == MPT_IOC_PRE_RESET) {
- }
-
- else { /* MPT_IOC_POST_RESET */
- mptfc_SetFcPortPage1_defaults(ioc);
+ break;
+ case MPT_IOC_PRE_RESET:
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
+ break;
+ case MPT_IOC_POST_RESET:
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__));
spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
if (ioc->fc_rescan_work_q) {
queue_work(ioc->fc_rescan_work_q,
&ioc->fc_rescan_work);
}
spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+ break;
+ default:
+ break;
}
return 1;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
*
* Returns 0 for success, non-zero for failure.
- */
+ **/
static int __init
mptfc_init(void)
{
return error;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptfc_remove - Remove fc infrastructure for devices
* @pdev: Pointer to pci_dev structure
*
- */
+ **/
static void __devexit
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);
mpt_reset_deregister(mptfcDoneCtx);
mpt_event_deregister(mptfcDoneCtx);
-
mpt_deregister(mptfcInternalCtx);
mpt_deregister(mptfcTaskCtx);
mpt_deregister(mptfcDoneCtx);
*
* Copyright (c) 2000-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
- *
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#include "mptlan.h"
+#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
u32 total_posted;
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;
};
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);
DEFINE_RWLOCK(bad_naa_lock);
#endif
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Fusion MPT LAN external data
+ */
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* lan_reply - Handle all data sent from the hardware.
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)) {
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);
}
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));
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;
/* 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,
// 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;
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));
}
#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));
(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));
+ pTrans->TransactionDetails[1] = cpu_to_le32((skb->mac.raw[2] << 24) |
+ (skb->mac.raw[3] << 16) |
+ (skb->mac.raw[4] << 8) |
+ (skb->mac.raw[5] << 0));
+#endif
pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2];
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);
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,
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,
/* 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;
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)
{
- struct net_device *dev;
- struct mpt_lan_priv *priv;
+ struct net_device *dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
+ struct mpt_lan_priv *priv = NULL;
u8 HWaddr[FC_ALEN], *a;
- dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
if (!dev)
return NULL;
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",
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);
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)) {
*
* Copyright (c) 2000-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
- *
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
#include <linux/module.h>
#endif
+#include <linux/version.h>
#include <linux/netdevice.h>
#include <linux/errno.h>
// #include <linux/etherdevice.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <linux/pci.h>
/* Override mptbase.h by pre-defining these! */
#define MODULEAUTHOR "LSI Corporation"
*
* Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
- * Copyright (c) 2005-2007 Dell
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
+#include "linux_compat.h" /* linux-2.6 tweaks */
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
-#include <linux/jiffies.h>
+#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/delay.h> /* for mdelay */
+#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_transport_sas.h>
#include <scsi/scsi_dbg.h>
+#include "linux_compat.h" /* linux-2.6 tweaks */
#include "mptbase.h"
#include "mptscsih.h"
-#include "mptsas.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
/*
* 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);
" 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;
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;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+static void mptsas_hotplug_work(struct work_struct *work);
+#else
+static void mptsas_hotplug_work(void *arg);
+#endif
+
+#if defined(CPQ_CIM)
+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);
+#endif
+
+static int mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info);
+
+/**
+ * mptsas_set_sdev_queue_depth - global setting of the mpt_sdev_queue_depth
+ * found via /sys/module/mptsas/parameters/mpt_sdev_queue_depth
+ * @val:
+ * @kp:
+ *
+ * Returns
+ **/
+static int
+mptsas_set_sdev_queue_depth(const char *val, struct kernel_param *kp)
+{
+ int ret = param_set_int(val, kp);
+ MPT_ADAPTER *ioc;
+ struct scsi_device *sdev;
+
+ if (ret)
+ return ret;
-static void mptsas_hotplug_work(void* arg);
+ list_for_each_entry(ioc, &ioc_list, list) {
+ if (ioc->bus_type != SAS)
+ continue;
+ shost_for_each_device(sdev, ioc->sh)
+ mptscsih_change_queue_depth(sdev, mpt_sdev_queue_depth);
+ ioc->sdev_queue_depth = mpt_sdev_queue_depth;
+ }
+ return 0;
+}
static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
le16_to_cpu(pg1->AttachedDevHandle)));
}
-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)
{
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;
+
+ 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)
{
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(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
{
port_info = port_details->port_info;
phy_info = port_info->phy_info;
+#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;
-}
-
-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));
- }
+ return 0xFF;
}
+#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)
{
return NULL;
}
+/**
+ * mptsas_set_port -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @phy_info:
+ * @port:
+ *
+ **/
static inline void
mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
{
ioc->name, port, port->dev.release));
}
}
+#endif
+/**
+ * mptsas_get_starget -
+ * @phy_info:
+ *
+ **/
static inline struct scsi_target *
mptsas_get_starget(struct mptsas_phyinfo *phy_info)
{
return NULL;
}
+/**
+ * mptsas_set_starget -
+ * @phy_info:
+ * @starget:
+ *
+ **/
static inline void
mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
starget)
phy_info->port_details->starget = starget;
}
-
-/*
- * mptsas_setup_wide_ports
+#if defined(CPQ_CIM)
+/**
+ * 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;
- mutex_lock(&ioc->sas_topology_mutex);
+ down(&ioc->sas_device_info_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)
+ /*
+ * Delete all matching sas_address's out of tree
+ */
+ list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, list) {
+ if (sas_info->sas_address != sas_address)
continue;
- /*
- * Removing a phy from a port, letting the last
- * phy be removed by firmware events.
- */
- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "%s: [%p]: deleting phy = %d\n",
- ioc->name, __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;
+ list_del(&sas_info->list);
+ kfree(sas_info);
}
/*
- * Populate and refresh the tree
+ * If there is a matching channel/id, then swap out with new target info
*/
- phy_info = port_info->phy_info;
- for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
- sas_address = phy_info->attached.sas_address;
- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
- ioc->name, i, (unsigned long long)sas_address));
- if (!sas_address)
- continue;
- port_details = phy_info->port_details;
- /*
- * Forming a port
- */
- if (!port_details) {
- port_details = kzalloc(sizeof(*port_details),
- GFP_KERNEL);
- if (!port_details)
- goto out;
- port_details->num_phys = 1;
- port_details->port_info = port_info;
- if (phy_info->phy_id < 64 )
- port_details->phy_bitmask |=
- (1 << phy_info->phy_id);
- phy_info->sas_port_add_phy=1;
- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
- "phy_id=%d sas_address=0x%018llX\n",
- ioc->name, i, (unsigned long long)sas_address));
- phy_info->port_details = port_details;
- }
+ list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
+ if (sas_info->fw.channel == channel && sas_info->fw.id == id)
+ goto initialize_data;
+ }
- if (i == port_info->num_phys - 1)
- continue;
- phy_info_cmp = &port_info->phy_info[i + 1];
- for (j = i + 1 ; j < port_info->num_phys ; j++,
- phy_info_cmp++) {
- if (!phy_info_cmp->attached.sas_address)
- continue;
- if (sas_address != phy_info_cmp->attached.sas_address)
- continue;
- if (phy_info_cmp->port_details == port_details )
- continue;
- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "\t\tphy_id=%d sas_address=0x%018llX\n",
- ioc->name, j, (unsigned long long)
- phy_info_cmp->attached.sas_address));
- if (phy_info_cmp->port_details) {
- port_details->rphy =
- mptsas_get_rphy(phy_info_cmp);
- port_details->port =
- mptsas_get_port(phy_info_cmp);
- port_details->starget =
- mptsas_get_starget(phy_info_cmp);
- port_details->num_phys =
- phy_info_cmp->port_details->num_phys;
- if (!phy_info_cmp->port_details->num_phys)
- kfree(phy_info_cmp->port_details);
- } else
- phy_info_cmp->sas_port_add_phy=1;
- /*
- * Adding a phy to a port
- */
- phy_info_cmp->port_details = port_details;
- if (phy_info_cmp->phy_id < 64 )
- port_details->phy_bitmask |=
- (1 << phy_info_cmp->phy_id);
- port_details->num_phys++;
+ if (!(sas_info = kzalloc(sizeof(*sas_info), GFP_KERNEL)))
+ goto out;
+
+ /*
+ * Set Firmware mapping
+ */
+ sas_info->fw.id = id;
+ sas_info->fw.channel = channel;
+ list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
+
+ initialize_data:
+
+ sas_info->sas_address = sas_address;
+ sas_info->device_info = device_info;
+ sas_info->slot = slot;
+ sas_info->enclosure_logical_id = enclosure_logical_id;
+ sas_info->is_cached = 0;
+ sas_info->is_logical_volume = 0;
+
+ /*
+ * Set OS mapping
+ */
+ shost_for_each_device(sdev, ioc->sh) {
+ starget = scsi_target(sdev);
+ rphy = dev_to_rphy(starget->dev.parent);
+ if (rphy->identify.sas_address == sas_address) {
+ sas_info->os.id = starget->id;
+ sas_info->os.channel = starget->channel;
}
}
out:
+ up(&ioc->sas_device_info_mutex);
+ return;
+}
- for (i = 0; i < port_info->num_phys; i++) {
- port_details = port_info->phy_info[i].port_details;
- if (!port_details)
- continue;
- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "%s: [%p]: phy_id=%02d num_phys=%02d "
- "bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
- port_details, i, port_details->num_phys,
- (unsigned long long)port_details->phy_bitmask));
- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
- ioc->name, port_details->port, port_details->rphy));
- }
- dsaswideprintk(ioc, printk("\n"));
- mutex_unlock(&ioc->sas_topology_mutex);
+/**
+ * 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);
}
/**
- * csmisas_find_vtarget
+ * 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:
*
- * @ioc
- * @volume_id
- * @volume_bus
+ **/
+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;
+
+ memset(&cfg, 0 , sizeof(CONFIGPARMS));
+ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+ cfg.pageAddr = starget->id; /* assumption that all volumes on channel = 0 */
+ 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);
+ }
+
+ /*
+ * Adding entry for logical volume in list
+ */
+ list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
+ if (sas_info->fw.channel == 0 && sas_info->fw.id == starget->id)
+ goto initialize_data;
+ }
+
+ if (!(sas_info = kzalloc(sizeof(*sas_info), GFP_KERNEL)))
+ goto out;
+
+ sas_info->fw.id = starget->id;
+ sas_info->fw.channel = 0; /* channel zero */
+ down(&ioc->sas_device_info_mutex);
+ list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
+ up(&ioc->sas_device_info_mutex);
+
+ initialize_data:
+
+ sas_info->os.id = starget->id;
+ sas_info->os.channel = starget->channel;
+ sas_info->sas_address = 0;
+ sas_info->device_info = 0;
+ sas_info->slot = 0;
+ sas_info->enclosure_logical_id = 0;
+ sas_info->is_logical_volume = 1;
+ sas_info->is_cached = 0;
+
+ 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);
+}
+#endif
+
+/**
+ * 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);
+ phy_info->phy = NULL;
+#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(*port_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;
+#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",
+ 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
+ */
+ phy_info_cmp->port_details = port_details;
+ if (phy_info_cmp->phy_id < 64 )
+ port_details->phy_bitmask |=
+ (1 << phy_info_cmp->phy_id);
+ port_details->num_phys++;
+#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:
+
+ for (i = 0; i < port_info->num_phys; i++) {
+ port_details = port_info->phy_info[i].port_details;
+ if (!port_details)
+ continue;
+#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", ioc->name, __FUNCTION__,
+ port_details, i, port_details->num_phys,
+ (unsigned long long)port_details->phy_bitmask));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
+ ioc->name, port_details->port, port_details->rphy));
+#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: Pointer to MPT_ADAPTER structure
+ * @volume_id:
+ * @volume_bus:
*
**/
static VirtTarget *
VirtTarget *vtarget = NULL;
shost_for_each_device(sdev, ioc->sh) {
- if ((vdevice = sdev->hostdata) == NULL)
+ if ((vdevice = sdev->hostdata) == NULL ||
+ (vdevice->vtarget == NULL))
continue;
if (vdevice->vtarget->id == id &&
vdevice->vtarget->channel == channel)
}
/**
- * 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
MPT_FRAME_HDR *mf;
SCSITaskMgmt_t *pScsiTm;
- if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
+ 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__));
- return 0;
+ 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;
DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
- mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
+ 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 - 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: Pointer to MPT_ADAPTER structure
+ * @sas_event_data:
*
**/
static void
mptsas_target_reset_queue(MPT_ADAPTER *ioc,
EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
{
- MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+ 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;
if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
return;
- vtarget->deleted = 1; /* block IO */
+ if (!ioc->disable_hotplug_remove)
+ vtarget->deleted = 1; /* block IO */
target_reset_list = kzalloc(sizeof(*target_reset_list),
GFP_ATOMIC);
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 = shost_priv(ioc->sh);
+ 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_target_reset_event *target_reset_list;
struct mptsas_hotplug_event *ev;
EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
u8 id, channel;
__le64 sas_address;
+ 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);
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "TaskMgmt: completed (%d seconds)\n",
+ ioc->name, jiffies_to_msecs(jiffies -
+ target_reset_list->time_count)/1000));
sas_event_data = &target_reset_list->sas_event_data;
id = sas_event_data->TargetID;
channel = sas_event_data->Bus;
- hd->resetPending = 0;
+
+ 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;
}
/*
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
- ioc->name,__FUNCTION__, __LINE__));
- return;
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: failed to "
+ "allocate mem @%d..!!\n", ioc->name,__FUNCTION__,
+ __LINE__));
+ return 1;
}
- INIT_WORK(&ev->work, mptsas_hotplug_work,ev);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_DELAYED_WORK(&ev->hotplug_work, mptsas_hotplug_work);
+#else
+ INIT_WORK(&ev->hotplug_work, mptsas_hotplug_work, ev);
+#endif
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->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);
+ schedule_delayed_work(&ev->hotplug_work, 0);
kfree(target_reset_list);
/*
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);
id = sas_event_data->TargetID;
channel = sas_event_data->Bus;
- if (mptsas_target_reset(ioc, channel, id)) {
+ target_reset_list->time_count = jiffies;
+
+ 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;
+ MPT_SCSI_HOST *hd;
struct mptsas_target_reset_event *target_reset_list, *n;
int rc;
rc = mptscsih_ioc_reset(ioc, reset_phase);
+ if ((ioc->bus_type != SAS) || (!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 = shost_priv(ioc->sh);
- if (!hd->ioc)
- goto out;
-
- if (list_empty(&hd->target_reset_list))
- goto out;
-
- /* flush the target_reset_list */
- list_for_each_entry_safe(target_reset_list, n,
- &hd->target_reset_list, list) {
- list_del(&target_reset_list->list);
- kfree(target_reset_list);
+ 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__));
+ 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);
+ }
+ hd = shost_private(ioc->sh);
+ if (!hd->ioc)
+ goto out;
+ if (list_empty(&hd->target_reset_list))
+ break;
+ /* flush the 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);
+ }
+ 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)
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)
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", mpt_scsilun_to_int(lunp));
+ }
+#endif
+
+ out:
+ if (lun_data)
+ pci_free_consistent(ioc->pcidev, lun_data_len, lun_data,
+ lun_data_dma);
+ kfree(iocmd);
+ return rc;
+}
+
+/**
+ * mptsas_test_unit_ready -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @channel:
+ * @id:
+ *
+ **/
+static int
+mptsas_test_unit_ready(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+ INTERNAL_CMD *iocmd;
+ MPT_SCSI_HOST *hd = shost_private(ioc->sh);
+ int rc, retries;
+ u8 skey, asc, ascq;
+
+ 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));
+ return -1;
+ }
+
+ 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;
+
+ for (retries = 0, rc = -1 ; retries < mpt_cmd_retry_count; retries++) {
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_channel=%d "
+ "fw_id=%d lun=%d count=%d\n", ioc->name, __FUNCTION__,
+ channel, id, iocmd->lun, retries));
+ 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:
+ 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));
+ ssleep(1);
+ 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));
+ ssleep(1);
+ 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)
+ break;
+ else if (skey == NOT_READY) {
+ /*
+ * medium isn't present
+ */
+ if (asc == 0x3a) {
+ rc = MPT_SCANDV_GOOD;
+ goto tur_done;
+ }
+ /*
+ * LU becoming ready, or
+ * LU hasn't self-configured yet
+ */
+ if ((asc == 0x04 && ascq == 0x01) ||
+ (asc == 0x3e && ascq == 0x00)) {
+ ssleep(1);
+ 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)
+ continue;
+ }
+ 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 rc;
+}
+
+/**
+ * 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;
- 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) {
+#if defined(CPQ_CIM)
+ mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
+#endif
goto out;
+ }
sas_read_port_mode_page(sdev);
+#if defined(CPQ_CIM)
+ mptsas_add_device_component_starget(ioc, scsi_target(sdev));
+#endif
+
+ 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 = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
VirtTarget *vtarget;
u8 id, channel;
struct sas_rphy *rphy;
* RAID volumes placed beyond the last expected port.
*/
if (starget->channel == MPTSAS_RAID_CHANNEL) {
+ if (!ioc->raid_data.pIocPg2) {
+ kfree(vtarget);
+ return -ENXIO;
+ }
for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
+ vtarget->raidVolume = 1;
goto out;
}
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(ioc, channel, id)) {
id = mptscsih_raid_id_to_num(ioc,
- channel, id);
+ channel, id);
vtarget->tflags |=
MPT_TARGET_FLAGS_RAID_COMPONENT;
p->phy_info[i].attached.phys_disk_num = id;
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 = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
struct sas_rphy *rphy;
struct mptsas_portinfo *p;
int i;
- MPT_ADAPTER *ioc = hd->ioc;
+ MPT_ADAPTER *ioc = hd->ioc;
if (!starget->hostdata)
return;
+#if defined(CPQ_CIM)
+ mptsas_del_device_component_by_os(ioc, starget->channel,
+ starget->id);
+#endif
+
if (starget->channel == MPTSAS_RAID_CHANNEL)
goto out;
if (p->phy_info[i].attached.sas_address !=
rphy->identify.sas_address)
continue;
- mptsas_set_starget(&p->phy_info[i], NULL);
+
+ 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);
+
goto out;
}
}
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 = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
struct sas_rphy *rphy;
struct mptsas_portinfo *p;
VirtDevice *vdevice;
struct scsi_target *starget;
int i;
- MPT_ADAPTER *ioc = hd->ioc;
+ MPT_ADAPTER *ioc = hd->ioc;
vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
if (!vdevice) {
printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
- ioc->name, sizeof(VirtDevice));
+ ioc->name, sizeof(VirtDevice));
return -ENOMEM;
}
starget = scsi_target(sdev);
vdevice->vtarget = starget->hostdata;
+ /*
+ * RAID volumes placed beyond the last expected port.
+ */
if (sdev->channel == MPTSAS_RAID_CHANNEL)
goto out;
return 0;
}
+/**
+ * mptsas_qcmd -
+ * @SCpnt:
+ * @done:
+ *
+ **/
static int
mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
return 0;
}
-// scsi_print_command(SCpnt);
-
+// scsi_print_command(SCpnt);
return mptscsih_qcmd(SCpnt,done);
}
.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);
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;
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)
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);
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)
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;
}
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)
{
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)
{
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)
{
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)
port_info->phy_info[i].portinfo = port_info;
port_info->phy_info[i].handle =
le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
+#if defined(CPQ_CIM)
+ port_info->phy_info[i].port_flags =
+ buffer->PhyData[i].PortFlags;
+#endif
}
out_free_consistent:
return error;
}
+/**
+ * mptsas_sas_io_unit_pg1 -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
static int
mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
{
cfg.cfghdr.ehdr = &hdr;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
- cfg.timeout = 10;
cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
cfg.cfghdr.ehdr->PageNumber = 1;
+ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
error = mpt_config(ioc, &cfg);
if (error)
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)
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)
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);
+#if defined(CPQ_CIM)
+ phy_info->change_count = buffer->ChangeCount;
+#endif
+ phy_info->phy_info = le32_to_cpu(buffer->PhyInfo);
out_free_consistent:
pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
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)
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);
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)
CONFIGPARMS cfg;
SasExpanderPage0_t *buffer;
dma_addr_t dma_handle;
+ __le64 sas_address;
int i, error;
hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
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);
goto out_free_consistent;
/* save config data */
+ if (!buffer->NumPhys) {
+ error = -ENXIO;
+ goto out;
+ }
+
port_info->num_phys = buffer->NumPhys;
port_info->phy_info = kcalloc(port_info->num_phys,
sizeof(*port_info->phy_info),GFP_KERNEL);
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:
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)
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;
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)
phy_info->hw_link_rate = buffer->HwLinkRate;
phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
+#if defined(CPQ_CIM)
+ phy_info->change_count = buffer->ChangeCount;
+#endif
+ phy_info->phy_info = le32_to_cpu(buffer->PhyInfo);
out_free_consistent:
pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
return error;
}
+/**
+ * mptsas_parse_device_info -
+ * @identify:
+ * @device_info:
+ *
+ **/
static void
mptsas_parse_device_info(struct sas_identify *identify,
struct mptsas_devinfo *device_info)
}
}
+/**
+ * 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) {
} 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);
/*
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);
!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) {
goto out;
}
mptsas_set_port(ioc, phy_info, port);
- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "sas_port_alloc: port=%p dev=%p port_id=%d\n",
- ioc->name, port, dev, port->port_identifier));
+ 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(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
- ioc->name, phy_info->phy_id));
sas_port_add_phy(port, phy_info->phy);
phy_info->sas_port_add_phy = 0;
+ devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
+ MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
+ phy_info->phy_id, phy_info->phy));
}
+#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) {
+ if (!ioc->sas_discovery_runtime)
+ mptsas_add_end_device(ioc, phy_info);
+ 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;
return error;
}
+/**
+ * mptsas_probe_hba_phys -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @handle:
+ *
+ **/
static int
mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
{
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;
+ port_info->ioc = ioc;
list_add_tail(&port_info->list, &ioc->sas_topology);
} else {
for (i = 0; i < hba->num_phys; i++) {
hba->phy_info[i].handle;
port_info->phy_info[i].port_id =
hba->phy_info[i].port_id;
+#if defined(CPQ_CIM)
+ port_info->phy_info[i].port_flags =
+ hba->phy_info[i].port_flags;
+#endif
}
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);
port_info->phy_info[i].identify.phy_id =
port_info->phy_info[i].phy_id = i;
if (port_info->phy_info[i].attached.handle)
return error;
}
-static int
-mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
+/**
+ * mptsas_add_expander - refresh or add new expander properties
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @port_info: expander port_info struct
+ * @is_new: is this a new expander being added (1:yes, 0:no)
+ *
+ **/
+static void
+mptsas_add_expander(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, u8 is_new)
{
- struct mptsas_portinfo *port_info, *p, *ex;
- struct device *parent;
- struct sas_rphy *rphy;
- int error = -ENOMEM, i;
- u8 add_new_expander;
- u64 expander_sas_address;
-
- add_new_expander = 0;
- 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);
- add_new_expander = 1;
- } 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);
+ struct mptsas_portinfo *p;
+ struct device *parent;
+ struct sas_rphy *rphy;
+ int i;
+ u64 expander_sas_address;
+ u32 handle;
+ handle = port_info->phy_info[0].handle;
+ expander_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);
+ 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;
- }
+ 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,
}
}
- expander_sas_address = port_info->phy_info[0].identify.sas_address;
-
- if (add_new_expander)
+ if (is_new)
printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
"sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
(unsigned long long)expander_sas_address);
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;
+/**
+ * mptsas_probe_expander_phys - probing for new expanders, and refreshing existing
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @handle:
+ *
+ **/
+static void
+mptsas_probe_expander_phys(MPT_ADAPTER *ioc)
+{
+ struct mptsas_portinfo buffer;
+ struct mptsas_portinfo *port_info;
+ u32 handle;
+ int i;
+ u8 add_new_expander;
- out_free_port_info:
- if (ex) {
- kfree(ex->phy_info);
- kfree(ex);
+ handle = 0xFFFF;
+ while (!mptsas_sas_expander_pg0(ioc, &buffer,
+ (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
+ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
+
+ 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) {
+ port_info = kzalloc(sizeof(*port_info), 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);
+ port_info->ioc = ioc;
+ add_new_expander = 1;
+ } else {
+ add_new_expander = 0;
+ for (i = 0; i < buffer.num_phys; i++) {
+ port_info->phy_info[i].handle =
+ buffer.phy_info[i].handle;
+ port_info->phy_info[i].port_id =
+ buffer.phy_info[i].port_id;
+ }
+ kfree(buffer.phy_info);
+ }
+ mptsas_add_expander(ioc, port_info, add_new_expander);
}
- out:
- return error;
}
-/*
- * mptsas_delete_expander_phys
- *
+/**
+ * mptsas_delete_expander - remove this expander
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @port_info: expander port_info struct
*
- * This will traverse topology, and remove expanders
- * that are no longer present
- */
+ **/
static void
-mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
+mptsas_delete_expander(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
{
- struct mptsas_portinfo buffer;
- struct mptsas_portinfo *port_info, *n, *parent;
+ struct mptsas_portinfo *parent;
+ int i;
+ u64 expander_sas_address;
+ char *ds = NULL;
struct mptsas_phyinfo *phy_info;
+#if defined(MPT_WIDE_PORT_API)
struct sas_port * port;
+ struct mptsas_portinfo_details * port_details;
+#else
+ struct sas_rphy * rphy;
+#endif
+
+ /*
+ * Obtain the port_info instance to the parent port
+ */
+ 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);
+ if (!parent)
+ goto remove_end_devices;
+
+ /*
+ * Delete rphys in the parent that point
+ * to this expander. The transport layer will
+ * cleanup all the children.
+ */
+#if defined(MPT_WIDE_PORT_API)
+ phy_info = parent->phy_info;
+ port_details = NULL;
+ 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;
+ }
+ 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, phy_info->phy);
+ phy_info->phy = NULL;
+ }
+ if (port && port_details) {
+ devtprintk(ioc, 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, phy_info->port_details);
+ }
+#endif
+ remove_end_devices:
+
+ 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);
+
+ /*
+ * removing end devices
+ */
+ phy_info = port_info->phy_info;
+ for (i = 0; i < port_info->num_phys; i++, phy_info++) {
+ if (!phy_info->port_details)
+ continue;
+ if (phy_info->attached.sas_address) {
+ ds = NULL;
+ 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";
+ if (ds)
+ 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)phy_info->attached.sas_address);
+ }
+ mptsas_port_delete(ioc, phy_info->port_details);
+ }
+
+ /*
+ * free link
+ */
+ list_del(&port_info->list);
+ kfree(port_info->phy_info);
+ kfree(port_info);
+}
+
+/**
+ * mptsas_link_status_work -
+ * delayed worktask handling link status change
+ * @work: Pointer to mptsas_link_status_event structure
+ *
+ **/
+static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_link_status_work(struct work_struct *work)
+{
+ struct mptsas_link_status_event *ev =
+ container_of(work, struct mptsas_link_status_event, work);
+#else
+mptsas_link_status_work(void * arg)
+{
+ struct mptsas_link_status_event *ev = arg;
+#endif
+ struct mptsas_portinfo *port_info;
+ struct mptsas_phyinfo *phy_info;
+ __le64 sas_address;
+ MPT_ADAPTER *ioc;
+ u8 phy_num;
+ u8 link_rate;
+
+ ioc = ev->ioc;
+ if (ioc->sas_discovery_ignore_events) {
+ kfree(ev);
+ return;
+ }
+
+ memcpy(&sas_address, &ev->link_data.SASAddress, sizeof(__le64));
+ sas_address = le64_to_cpu(sas_address);
+ link_rate = ev->link_data.LinkRates >> 4;
+ phy_num = ev->link_data.PhyNum;
+
+ mutex_lock(&ioc->sas_discovery_mutex);
+ ioc->sas_discovery_runtime = 1;
+ scsi_block_requests(ioc->sh);
+ port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
+ if (!port_info)
+ goto out;
+ phy_info = &port_info->phy_info[phy_num];
+ if (!phy_info)
+ goto out;
+ 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 == ioc->hba_port_info)
+ mptsas_probe_hba_phys(ioc);
+ else
+ mptsas_add_expander(ioc, port_info, 0);
+ } else if (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:
+ ioc->sas_discovery_runtime = 0;
+ scsi_unblock_requests(ioc->sh);
+ mutex_unlock(&ioc->sas_discovery_mutex);
+ kfree(ev);
+}
+
+/**
+ * mptsas_expander_add_work -
+ * delayed worktask handling adding expanders
+ * @work: Pointer to port_info structure
+ *
+ **/
+static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_expander_add_work(struct work_struct *work)
+{
+ struct mptsas_portinfo *buffer =
+ container_of(work, struct mptsas_portinfo, add_work.work);
+#else
+mptsas_expander_add_work(void * arg)
+{
+ struct mptsas_portinfo *buffer = arg;
+#endif
+ MPT_ADAPTER *ioc;
+ struct mptsas_portinfo *port_info;
int i;
- u64 expander_sas_address;
+
+ ioc = buffer->ioc;
+ mutex_lock(&ioc->sas_discovery_mutex);
+ ioc->sas_discovery_runtime = 1;
+ scsi_block_requests(ioc->sh);
+ port_info = mptsas_find_portinfo_by_sas_address(ioc,
+ buffer->phy_info[0].identify.sas_address);
+
+ 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 =
+ buffer->phy_info[i].handle;
+ port_info->phy_info[i].identify.sas_address =
+ buffer->phy_info[i].identify.sas_address;
+ port_info->phy_info[i].identify.handle_parent =
+ buffer->phy_info[i].identify.handle_parent;
+ }
+ mptsas_add_expander(ioc, port_info, 0);
+ kfree(buffer->phy_info);
+ kfree(buffer);
+ } else {
+ port_info = buffer;
+ mutex_lock(&ioc->sas_topology_mutex);
+ list_add_tail(&port_info->list, &ioc->sas_topology);
+ mutex_unlock(&ioc->sas_topology_mutex);
+ mptsas_add_expander(ioc, port_info, 1);
+ }
+ ioc->sas_discovery_runtime = 0;
+ scsi_unblock_requests(ioc->sh);
+ mutex_unlock(&ioc->sas_discovery_mutex);
+}
+
+/**
+ * mptsas_expander_delete_work -
+ * delayed worktask handling removal of expanders
+ * that are no longer present
+ * @work: Pointer to port_info structure
+ *
+ **/
+static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_expander_delete_work(struct work_struct *work)
+{
+ struct mptsas_portinfo *buffer =
+ container_of(work, struct mptsas_portinfo, del_work.work);
+#else
+mptsas_expander_delete_work(void * arg)
+{
+ struct mptsas_portinfo *buffer = arg;
+#endif
+ MPT_ADAPTER *ioc;
+ int rc;
+ struct mptsas_portinfo *port_info, tmp;
+
+ ioc = buffer->ioc;
+ mutex_lock(&ioc->sas_discovery_mutex);
+ port_info = mptsas_find_portinfo_by_sas_address(ioc,
+ buffer->phy_info[0].identify.sas_address);
+
+ /* In 1.05.12 firmware expander events were added, and we need to free
+ * this memory that was allocated in mptsas_send_expander_event */
+ if ((ioc->facts.HeaderVersion >> 8) >= 0xE) {
+ kfree(buffer->phy_info);
+ kfree(buffer);
+ }
+
+ if (!port_info)
+ goto out;
+
+ rc = mptsas_sas_expander_pg0(ioc, &tmp,
+ (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
+ MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
+ port_info->phy_info[0].handle);
+ kfree(tmp.phy_info);
+ if (rc) {
+ mutex_lock(&ioc->sas_topology_mutex);
+ mptsas_delete_expander(ioc, port_info);
+ mutex_unlock(&ioc->sas_topology_mutex);
+ }
+ port_info->del_work_scheduled=0;
+
+ out:
+ mutex_unlock(&ioc->sas_discovery_mutex);
+}
+
+/**
+ * mptsas_remove_expanders_not_responding -
+ * this will traverse topology removing not responding expanders
+ * that are no longer present
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+static void
+mptsas_remove_expanders_not_responding(MPT_ADAPTER *ioc)
+{
+ struct mptsas_portinfo buffer;
+ struct mptsas_portinfo *port_info, *n;
+ int rc;
mutex_lock(&ioc->sas_topology_mutex);
list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
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;
+ rc = mptsas_sas_expander_pg0(ioc, &buffer,
+ (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
+ MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
+ port_info->phy_info[0].handle);
- /*
- * Delete rphys in the parent that point
- * to this expander. The transport layer will
- * cleanup all the children.
- */
- phy_info = parent->phy_info;
- for (i = 0; i < parent->num_phys; i++, phy_info++) {
- port = mptsas_get_port(phy_info);
- if (!port)
- continue;
- if (phy_info->attached.sas_address !=
- expander_sas_address)
- continue;
- dsaswideprintk(ioc,
- dev_printk(KERN_DEBUG, &port->dev,
- MYIOC_s_FMT "delete port (%d)\n", ioc->name,
- port->port_identifier));
- sas_port_delete(port);
- mptsas_port_delete(ioc, phy_info->port_details);
+ kfree(buffer.phy_info);
+ if (!rc)
+ continue;
+ /* handle missing expanders */
+ if (ioc->device_missing_delay) {
+ if(port_info->del_work_scheduled) {
+ cancel_delayed_work(&port_info->del_work);
+ port_info->del_work_scheduled=0;
}
- next_port:
- phy_info = port_info->phy_info;
- for (i = 0; i < port_info->num_phys; i++, phy_info++)
- mptsas_port_delete(ioc, phy_info->port_details);
-
- list_del(&port_info->list);
- kfree(port_info->phy_info);
- kfree(port_info);
- }
- /*
- * Free this memory allocated from inside
- * mptsas_sas_expander_pg0
- */
- kfree(buffer.phy_info);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_DELAYED_WORK(&port_info->del_work,
+ mptsas_expander_delete_work);
+#else
+ INIT_WORK(&port_info->del_work,
+ mptsas_expander_delete_work, port_info);
+#endif
+ schedule_delayed_work(&port_info->del_work,
+ HZ * ioc->device_missing_delay);
+ port_info->del_work_scheduled=1;
+ } else
+ mptsas_delete_expander(ioc, port_info);
}
mutex_unlock(&ioc->sas_topology_mutex);
}
-/*
- * Start of day discovery
- */
+/**
+ * mptsas_scan_sas_topology - Start of day discovery
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @sas_address:
+ *
+ **/
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))
- ;
+ mptsas_probe_expander_phys(ioc);
/*
Reporting RAID volumes.
*/
goto out;
if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
goto out;
- for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+ for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+ 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);
}
mutex_unlock(&ioc->sas_discovery_mutex);
}
-/*
- * Work queue thread to handle Runtime discovery
- * Mere purpose is the hot add/delete of expanders
- *(Mutex UNLOCKED)
- */
+/**
+ * mptsas_discovery_work - Work queue thread to handle Runtime discovery,
+ * with the mere purpose is the hot add/delete of expanders
+ * @work: work queue payload containing the event info
+ *
+ * (Mutex LOCKED)
+ **/
static void
-__mptsas_discovery_work(MPT_ADAPTER *ioc)
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_discovery_work(struct work_struct *work)
{
- 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
+ struct mptsas_discovery_event *ev =
+ container_of(work, struct mptsas_discovery_event, work);
+#else
mptsas_discovery_work(void * arg)
{
struct mptsas_discovery_event *ev = arg;
+#endif
MPT_ADAPTER *ioc = ev->ioc;
mutex_lock(&ioc->sas_discovery_mutex);
- __mptsas_discovery_work(ioc);
+ ioc->sas_discovery_runtime = 1;
+ if (!ioc->disable_hotplug_remove)
+ mptsas_remove_expanders_not_responding(ioc);
+ scsi_block_requests(ioc->sh);
+ mptsas_probe_hba_phys(ioc);
+ mptsas_probe_expander_phys(ioc);
+ ioc->sas_discovery_runtime = 0;
+ scsi_unblock_requests(ioc->sh);
mutex_unlock(&ioc->sas_discovery_mutex);
kfree(ev);
}
+/**
+ * mptsas_find_phyinfo_by_sas_address -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @sas_address:
+ *
+ **/
static struct mptsas_phyinfo *
mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
{
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
- */
+/**
+ * mptsas_persist_clear_table - Work queue thread to clear the persitency table
+ * @work: work queue payload containing the MPT_ADAPTER structure
+ *
+ **/
static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_persist_clear_table(struct work_struct *work)
+{
+ MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
+#else
mptsas_persist_clear_table(void * arg)
{
MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
+#endif
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)
{
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)
{
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));
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;
buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
continue;
- ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
- if (!ev) {
- printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
- 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:
pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
dma_handle);
}
-/*
- * Work queue thread to handle SAS hotplug events
- */
+
+/**
+ * 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;
+#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 (mptsas_test_unit_ready(ioc, phy_info->attached.channel,
+ phy_info->attached.id) != 0) {
+ memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "%s: fw_id=%d exit at line=%d\n", ioc->name,
+ __FUNCTION__, fw_id, __LINE__));
+ return 4;
+ }
+
+ 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_lookup;
+ int i;
+#endif
+ struct scsi_target * starget;
+ char *ds = NULL;
+ u8 fw_id;
+ u64 sas_address;
+
+ if (!phy_info){
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
+ 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 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_lookup = port_info->phy_info;
+ for (i = 0; i < port_info->num_phys; i++, phy_info_lookup++) {
+ if(!phy_info_lookup->phy)
+ continue;
+ if (phy_info_lookup->attached.sas_address !=
+ sas_address)
+ continue;
+ devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info_lookup->phy->dev,
+ MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
+ ioc->name, phy_info_lookup->phy_id,
+ phy_info_lookup->phy));
+ sas_port_delete_phy(port, phy_info_lookup->phy);
+ phy_info_lookup->phy = NULL;
+ }
+#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";
+
+ starget = mptsas_get_starget(phy_info);
+ if (starget)
+ starget_printk(KERN_INFO, starget, MYIOC_s_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);
+ else
+ 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)
+ devtprintk(ioc, 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);
+}
+
+/**
+ * mptsas_hotplug_work - Work queue thread to handle SAS hotplug events
+ * @work: work queue payload containing info describing the event
+ *
+ **/
static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_hotplug_work(struct work_struct *work)
+{
+ struct mptsas_hotplug_event *ev =
+ container_of(work, struct mptsas_hotplug_event, hotplug_work.work);
+#else
mptsas_hotplug_work(void *arg)
{
struct mptsas_hotplug_event *ev = arg;
+#endif
MPT_ADAPTER *ioc = ev->ioc;
struct mptsas_phyinfo *phy_info;
- struct sas_rphy *rphy;
- struct sas_port *port;
- struct scsi_device *sdev;
struct scsi_target * starget;
- struct sas_identify identify;
- char *ds = NULL;
struct mptsas_devinfo sas_device;
+ struct mptsas_portinfo * port_info;
VirtTarget *vtarget;
- VirtDevice *vdevice;
+ int i;
- mutex_lock(&ioc->sas_discovery_mutex);
switch (ev->event_type) {
- case MPTSAS_DEL_DEVICE:
- phy_info = NULL;
- if (ev->phys_disk_num_valid) {
- if (ev->hidden_raid_component){
- if (mptsas_sas_device_pg0(ioc, &sas_device,
- (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
- MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
- (ev->channel << 8) + ev->id)) {
- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __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_DEVICE:
+ mutex_lock(&ioc->sas_discovery_mutex);
+ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+ ev->sas_address);
+ if (phy_info){
+ port_info = phy_info->portinfo;
+ if (port_info) {
+ for (i = 0; i < port_info->num_phys; i++)
+ if(port_info->phy_info[i].attached.sas_address
+ == ev->sas_address)
+ port_info->phy_info[i].attached.id = ev->id;
+ }
+ mptsas_add_end_device(ioc, phy_info);
+ mutex_unlock(&ioc->sas_discovery_mutex);
+ break;
}
- if (!phy_info)
- phy_info = mptsas_find_phyinfo_by_target(ioc,
- ev->channel, ev->id);
-
+ mutex_unlock(&ioc->sas_discovery_mutex);
/*
- * Sanity checks, for non-existing phys and remote rphys.
+ * retry later if the phy_info wasn't created
*/
- if (!phy_info){
- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
+ if (ev->retries == 12)
break;
- }
- if (!phy_info->port_details) {
- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
- break;
- }
- rphy = mptsas_get_rphy(phy_info);
- if (!rphy) {
- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
- break;
- }
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: line=%d: fw_id=%d retry_add (%d)\n", ioc->name,
+ __FUNCTION__, __LINE__, ev->id, ev->retries));
+ schedule_delayed_work(&ev->hotplug_work, 5*HZ);
+ ev->retries++;
+ return;
- port = mptsas_get_port(phy_info);
- if (!port) {
- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
- break;
+ case MPTSAS_DEL_DEVICE:
+
+ mutex_lock(&ioc->sas_discovery_mutex);
+ if (!ioc->disable_hotplug_remove) {
+ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+ ev->sas_address);
+ mptsas_del_end_device(ioc, phy_info);
}
+ mutex_unlock(&ioc->sas_discovery_mutex);
+ break;
- starget = mptsas_get_starget(phy_info);
- if (starget) {
- vtarget = starget->hostdata;
+ case MPTSAS_ADD_PHYSDISK:
- if (!vtarget) {
+ if (mptsas_sas_device_pg0(ioc, &sas_device,
+ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+ (ev->channel << 8) + ev->id)) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
+ "%s: fw_id=%d exit at line=%d\n",
+ ioc->name, __FUNCTION__, ev->id, __LINE__));
+ break;
+ }
+
+ mutex_lock(&ioc->sas_discovery_mutex);
+ mutex_lock(&ioc->sas_topology_mutex);
+ port_info = mptsas_find_portinfo_by_handle(ioc,
+ sas_device.handle_parent);
+ mutex_unlock(&ioc->sas_topology_mutex);
+ if (port_info) {
+ ioc->sas_discovery_runtime = 1;
+ scsi_block_requests(ioc->sh);
+ mpt_findImVolumes(ioc);
+ if (port_info == ioc->hba_port_info)
+ mptsas_probe_hba_phys(ioc);
+ else
+ mptsas_add_expander(ioc, port_info, 0);
+ scsi_unblock_requests(ioc->sh);
+ ioc->sas_discovery_runtime = 0;
+ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+ sas_device.sas_address);
+ if (phy_info) {
+ phy_info->attached.id = ev->id;
+ mptsas_add_end_device(ioc, phy_info);
+ mutex_unlock(&ioc->sas_discovery_mutex);
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;
- break;
- }
}
+ mutex_unlock(&ioc->sas_discovery_mutex);
+ /*
+ * retry later if the phy_info wasn't created
+ */
+ if (ev->retries == 12)
+ break;
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: line=%d: fw_id=%d retry_add (%d)\n", ioc->name,
+ __FUNCTION__, __LINE__, ev->id, ev->retries));
+ schedule_delayed_work(&ev->hotplug_work, 5*HZ);
+ ev->retries++;
+ return;
- if (phy_info->attached.device_info &
- MPI_SAS_DEVICE_INFO_SSP_TARGET)
- ds = "ssp";
- if (phy_info->attached.device_info &
- MPI_SAS_DEVICE_INFO_STP_TARGET)
- ds = "stp";
- if (phy_info->attached.device_info &
- MPI_SAS_DEVICE_INFO_SATA_DEVICE)
- ds = "sata";
-
- printk(MYIOC_s_INFO_FMT
- "removing %s device, channel %d, id %d, phy %d\n",
- ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
- dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
- "delete port (%d)\n", ioc->name, port->port_identifier);
- sas_port_delete(port);
- mptsas_port_delete(ioc, phy_info->port_details);
+ case MPTSAS_DEL_PHYSDISK:
+
+ mutex_lock(&ioc->sas_discovery_mutex);
+ mpt_findImVolumes(ioc);
+ phy_info = mptsas_find_phyinfo_by_phys_disk_num(
+ ioc, ev->phys_disk_num, ev->channel, ev->id);
+ mptsas_del_end_device(ioc, phy_info);
+ mutex_unlock(&ioc->sas_discovery_mutex);
break;
- case MPTSAS_ADD_DEVICE:
- if (ev->phys_disk_num_valid)
- mpt_findImVolumes(ioc);
+ case MPTSAS_ADD_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(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
+ (ev->channel << 8) + ev->id)) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "%s: fw_id=%d exit at line=%d\n", ioc->name,
+ __FUNCTION__, ev->id, __LINE__));
break;
}
- __mptsas_discovery_work(ioc);
-
- phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
- sas_device.sas_address);
+ mutex_lock(&ioc->sas_discovery_mutex);
+ phy_info = mptsas_find_phyinfo_by_sas_address(
+ ioc, sas_device.sas_address);
+ mutex_unlock(&ioc->sas_discovery_mutex);
- if (!phy_info || !phy_info->port_details) {
+ if (!phy_info){
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
+ "%s: fw_id=%d exit at line=%d\n", ioc->name,
+ __FUNCTION__, ev->id, __LINE__));
break;
}
starget = mptsas_get_starget(phy_info);
- if (starget && (!ev->hidden_raid_component)){
+ if (!starget) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "%s: fw_id=%d exit at line=%d\n", ioc->name,
+ __FUNCTION__, ev->id, __LINE__));
+ break;
+ }
+
+ vtarget = starget->hostdata;
+ if (!vtarget) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "%s: fw_id=%d exit at line=%d\n", ioc->name,
+ __FUNCTION__, ev->id, __LINE__));
+ break;
+ }
- vtarget = starget->hostdata;
+ mpt_findImVolumes(ioc);
- if (!vtarget) {
- dfailprintk(ioc, printk(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;
- }
+ 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, ev->channel, ev->id, ev->phys_disk_num, (unsigned long long)
+ sas_device.sas_address);
+
+ vtarget->id = ev->phys_disk_num;
+ vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
+ phy_info->attached.phys_disk_num = ev->phys_disk_num;
+ mptsas_reprobe_target(starget, 1);
+ break;
+
+ case MPTSAS_DEL_PHYSDISK_REPROBE:
+
+ if (mptsas_sas_device_pg0(ioc, &sas_device,
+ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+ (ev->channel << 8) + ev->id)) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "%s: fw_id=%d exit at line=%d\n", ioc->name,
+ __FUNCTION__, ev->id, __LINE__));
break;
}
- if (mptsas_get_rphy(phy_info)) {
+ mutex_lock(&ioc->sas_discovery_mutex);
+ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+ sas_device.sas_address);
+ mutex_unlock(&ioc->sas_discovery_mutex);
+ if (!phy_info) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
- if (ev->channel) printk("%d\n", __LINE__);
+ "%s: fw_id=%d exit at line=%d\n", ioc->name,
+ __FUNCTION__, ev->id, __LINE__));
break;
}
- port = mptsas_get_port(phy_info);
- if (!port) {
+ starget = mptsas_get_starget(phy_info);
+ if (!starget) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
+ "%s: fw_id=%d exit at line=%d\n", ioc->name,
+ __FUNCTION__, ev->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);
- mptsas_parse_device_info(&identify, &phy_info->attached);
- rphy = sas_end_device_alloc(port);
- if (!rphy) {
+ vtarget = starget->hostdata;
+ if (!vtarget) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
- break; /* non-fatal: an rphy can be added later */
+ "%s: fw_id=%d exit at line=%d\n", ioc->name,
+ __FUNCTION__, ev->id, __LINE__));
+ break;
}
- rphy->identify = identify;
- if (sas_rphy_add(rphy)) {
+ if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
- sas_rphy_free(rphy);
+ "%s: fw_id=%d exit at line=%d\n", ioc->name,
+ __FUNCTION__, ev->id, __LINE__));
break;
}
- mptsas_set_rphy(ioc, phy_info, rphy);
+
+ 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, ev->channel, ev->id, ev->phys_disk_num, (unsigned long long)
+ sas_device.sas_address);
+
+ vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
+ vtarget->id = ev->id;
+ phy_info->attached.phys_disk_num = ~0;
+ mptsas_reprobe_target(starget, 0);
+#if defined(CPQ_CIM)
+ mptsas_add_device_component_by_fw(ioc,
+ ev->channel, ev->id);
+#endif
break;
+
case MPTSAS_ADD_RAID:
- sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
- ev->id, 0);
- if (sdev) {
- scsi_device_put(sdev);
+
+ if (mptsas_test_unit_ready(ioc, ev->channel, ev->id) != 0)
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);
+ 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);
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);
+ printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
+ "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
+ scsi_remove_device(ev->sdev);
+ scsi_device_put(ev->sdev);
break;
+
case MPTSAS_ADD_INACTIVE_VOLUME:
- mptsas_adding_inactive_raid_components(ioc,
- ev->channel, ev->id);
+
+ mpt_findImVolumes(ioc);
+ mutex_lock(&ioc->sas_discovery_mutex);
+ mptsas_adding_inactive_raid_components(ioc, ev->channel,
+ ev->id);
+ mutex_unlock(&ioc->sas_discovery_mutex);
break;
- case MPTSAS_IGNORE_EVENT:
+
default:
break;
}
-
- mutex_unlock(&ioc->sas_discovery_mutex);
kfree(ev);
}
+/**
+ * mptsas_send_sas_event -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @sas_event_data:
+ *
+ **/
static void
mptsas_send_sas_event(MPT_ADAPTER *ioc,
EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
- printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT
+ "mptsas: lost hotplug event\n", ioc->name);
break;
}
- INIT_WORK(&ev->work, mptsas_hotplug_work,ev);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_DELAYED_WORK(&ev->hotplug_work, mptsas_hotplug_work);
+#else
+ INIT_WORK(&ev->hotplug_work, mptsas_hotplug_work, ev);
+#endif
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;
sizeof(__le64));
ev->sas_address = le64_to_cpu(sas_address);
ev->device_info = device_info;
-
- 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);
+ ev->event_type = MPTSAS_ADD_DEVICE;
+ schedule_delayed_work(&ev->hotplug_work, 0);
break;
+
case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
/*
* Persistent table is full.
*/
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
INIT_WORK(&ioc->sas_persist_task,
- mptsas_persist_clear_table,(void *)ioc);
+ mptsas_persist_clear_table);
+#else
+ INIT_WORK(&ioc->sas_persist_task,
+ mptsas_persist_clear_table, (void *)ioc);
+#endif
+
schedule_work(&ioc->sas_persist_task);
break;
/*
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:
+ case MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
default:
break;
}
}
+
+/**
+ * mptsas_send_raid_event -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @raid_event_data:
+ *
+ **/
static void
mptsas_send_raid_event(MPT_ADAPTER *ioc,
EVENT_DATA_RAID *raid_event_data)
struct mptsas_hotplug_event *ev;
int status = le32_to_cpu(raid_event_data->SettingsStatus);
int state = (status >> 8) & 0xff;
+ struct scsi_device *sdev = NULL;
+ VirtDevice *vdevice = NULL;
if (ioc->bus_type != SAS)
return;
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
- printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT
+ "mptsas: lost hotplug event\n", ioc->name);
return;
}
- INIT_WORK(&ev->work, mptsas_hotplug_work,ev);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_DELAYED_WORK(&ev->hotplug_work, mptsas_hotplug_work);
+#else
+ INIT_WORK(&ev->hotplug_work, mptsas_hotplug_work, ev);
+#endif
ev->ioc = ioc;
ev->id = raid_event_data->VolumeID;
ev->channel = raid_event_data->VolumeBus;
ev->event_type = MPTSAS_IGNORE_EVENT;
+ ev->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, ev->id, 0);
+ ev->sdev = sdev;
+ if (sdev)
+ vdevice = sdev->hostdata;
+ }
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;
+ ev->event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
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;
+ ev->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:
- 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;
+ ev->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:
- ev->phys_disk_num_valid = 1;
- ev->phys_disk_num = raid_event_data->PhysDiskNum;
- ev->event_type = MPTSAS_DEL_DEVICE;
+ ev->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 */
ev->event_type = MPTSAS_DEL_RAID;
break;
case MPI_EVENT_RAID_RC_VOLUME_CREATED:
+ if (sdev) {
+ scsi_device_put(sdev);
+ break;
+ }
ev->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 */
+ ev->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 */
ev->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;
+ }
ev->event_type = MPTSAS_ADD_RAID;
break;
default:
default:
break;
}
- schedule_work(&ev->work);
+
+ if (ev->event_type == MPTSAS_IGNORE_EVENT)
+ kfree(ev);
+ else
+ schedule_delayed_work(&ev->hotplug_work, 0);
}
+/**
+ * mptsas_send_discovery_event -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @discovery_data:
+ *
+ **/
static void
mptsas_send_discovery_event(MPT_ADAPTER *ioc,
EVENT_DATA_SAS_DISCOVERY *discovery_data)
{
struct mptsas_discovery_event *ev;
+ u32 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
/*
* DiscoveryStatus
* kicks off discovery, and return to zero
* once its completed.
*/
- if (discovery_data->DiscoveryStatus)
+ ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
+ if (discovery_status)
+ return;
+
+ /* Older firmware look at discovery events to handle expanders */
+ if ((ioc->facts.HeaderVersion >> 8) >= 0xE)
return;
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev)
return;
- INIT_WORK(&ev->work, mptsas_discovery_work,ev);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_WORK(&ev->work, mptsas_discovery_work);
+#else
+ INIT_WORK(&ev->work, mptsas_discovery_work, ev);
+#endif
+
ev->ioc = ioc;
schedule_work(&ev->work);
};
-/*
- * mptsas_send_ir2_event - handle exposing hidden disk when
- * an inactive raid volume is added
+/**
+ * mptsas_issue_tm - send mptsas internal tm request
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @type
+ * @channel
+ * @id
+ * @lun
+ * @task_context
+ * @timeout
*
- * @ioc: Pointer to MPT_ADAPTER structure
- * @ir2_data
+ * 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_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_broadcast_primative_work(struct work_struct *work)
{
- struct mptsas_hotplug_event *ev;
+ struct mptsas_broadcast_primative_event *ev =
+ container_of(work, struct mptsas_broadcast_primative_event, aen_work.work);
+#else
+mptsas_broadcast_primative_work(void *arg)
+{
+ struct mptsas_broadcast_primative_event *ev = arg;
+#endif
+ MPT_ADAPTER *ioc = ev->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);
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s - busy, reschedule task\n", ioc->name, __FUNCTION__));
+ schedule_delayed_work(&ev->aen_work, 1*HZ);
+ 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);
+ kfree(ev);
+
+ 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_send_broadcast_primative_event - processing of event data
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * broadcast_event_data: event data
+ *
+ **/
+static void
+mptsas_send_broadcast_primative_event(MPT_ADAPTER * ioc,
+ EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data)
+{
+ struct mptsas_broadcast_primative_event *ev;
+
+ if (ioc->broadcast_aen_busy)
+ return;
- if (ir2_data->ReasonCode !=
- MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
+ if (broadcast_event_data->Primitive !=
+ MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
return;
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev)
return;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_DELAYED_WORK(&ev->aen_work, mptsas_broadcast_primative_work);
+#else
+ INIT_WORK(&ev->aen_work, mptsas_broadcast_primative_work, ev);
+#endif
+
+ ev->ioc = ioc;
+ ioc->broadcast_aen_busy = 1;
+ schedule_delayed_work(&ev->aen_work, 0);
+}
+
+/**
+ * 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)
+{
+ struct mptsas_hotplug_event *ev;
- INIT_WORK(&ev->work, mptsas_hotplug_work,ev);
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (!ev)
+ return;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_DELAYED_WORK(&ev->hotplug_work, mptsas_hotplug_work);
+#else
+ INIT_WORK(&ev->hotplug_work, mptsas_hotplug_work, ev);
+#endif
ev->ioc = ioc;
ev->id = ir2_data->TargetID;
ev->channel = ir2_data->Bus;
- ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
+ ev->event_type = MPTSAS_IGNORE_EVENT;
+ ev->phys_disk_num = ir2_data->PhysDiskNum;
- schedule_work(&ev->work);
+ switch (ir2_data->ReasonCode) {
+ case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
+ ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
+ break;
+ case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
+ ev->event_type = MPTSAS_DEL_PHYSDISK;
+ break;
+ case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
+ ev->event_type = MPTSAS_ADD_PHYSDISK;
+ break;
+ default:
+ break;
+ }
+
+ if (ev->event_type == MPTSAS_IGNORE_EVENT)
+ kfree(ev);
+ else
+ schedule_delayed_work(&ev->hotplug_work, 0);
};
+/**
+ * mptsas_send_expander_event - handle expanders coming and going
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @expander_data: event data
+ *
+ **/
+static void
+mptsas_send_expander_event(MPT_ADAPTER *ioc, PTR_EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE expander_data)
+{
+ struct mptsas_portinfo *port_info;
+ __le64 sas_address;
+ int i;
+
+ port_info = kzalloc(sizeof(*port_info), GFP_ATOMIC);
+ if (!port_info)
+ return;
+ port_info->ioc = ioc;
+ port_info->num_phys = expander_data->NumPhys;
+ port_info->phy_info = kcalloc(port_info->num_phys,
+ sizeof(*port_info->phy_info),GFP_ATOMIC);
+ if (!port_info->phy_info) {
+ kfree(port_info);
+ return;
+ }
+
+ 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);
+ }
+
+ if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_DELAYED_WORK(&port_info->del_work, mptsas_expander_delete_work);
+#else
+ INIT_WORK(&port_info->del_work, mptsas_expander_delete_work, port_info);
+#endif
+ schedule_delayed_work(&port_info->del_work, HZ * ioc->device_missing_delay);
+ } else {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_DELAYED_WORK(&port_info->add_work, mptsas_expander_add_work);
+#else
+ INIT_WORK(&port_info->add_work, mptsas_expander_add_work, port_info);
+#endif
+ schedule_delayed_work(&port_info->add_work, 0);
+ }
+}
+
+/**
+ * mptsas_send_link_status_event - handle link status change
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * link_data: event data
+ *
+ **/
+static void
+mptsas_send_link_status_event(MPT_ADAPTER *ioc, PTR_EVENT_DATA_SAS_PHY_LINK_STATUS link_data)
+{
+ struct mptsas_link_status_event *ev;
+
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (!ev)
+ return;
+
+ ev->ioc = ioc;
+ memcpy(&ev->link_data, link_data, sizeof(*link_data));
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_WORK(&ev->work, mptsas_link_status_work);
+#else
+ INIT_WORK(&ev->work, mptsas_link_status_work, ev);
+#endif
+ schedule_work(&ev->work);
+}
+
+/**
+ * mptsas_event_process -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @reply:
+ *
+ **/
static int
mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
{
switch (event) {
case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
+#if defined(CPQ_CIM)
+ ioc->csmi_change_count++;
+#endif
mptsas_send_sas_event(ioc,
(EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
break;
case MPI_EVENT_INTEGRATED_RAID:
+#if defined(CPQ_CIM)
+ ioc->csmi_change_count++;
+#endif
mptsas_send_raid_event(ioc,
(EVENT_DATA_RAID *)reply->Data);
break;
case MPI_EVENT_PERSISTENT_TABLE_FULL:
+#if defined(CPQ_CIM)
+ ioc->csmi_change_count++;
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_WORK(&ioc->sas_persist_task,
+ mptsas_persist_clear_table);
+#else
INIT_WORK(&ioc->sas_persist_task,
- mptsas_persist_clear_table,(void *)ioc);
+ mptsas_persist_clear_table, (void *)ioc);
+#endif
schedule_work(&ioc->sas_persist_task);
break;
case MPI_EVENT_SAS_DISCOVERY:
mptsas_send_discovery_event(ioc,
- (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
+ (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
+ break;
+ case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
+ /* In 1.05.12 firmware expander events were added */
+ if ((ioc->facts.HeaderVersion >> 8) >= 0xE)
+ mptsas_send_expander_event(ioc,
+ (EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE *)reply->Data);
+ break;
+ case MPI_EVENT_SAS_PHY_LINK_STATUS:
+ if ((ioc->facts.HeaderVersion >> 8) >= 0xE)
+ mptsas_send_link_status_event(ioc,
+ (EVENT_DATA_SAS_PHY_LINK_STATUS *)reply->Data);
break;
case MPI_EVENT_IR2:
+#if defined(CPQ_CIM)
+ ioc->csmi_change_count++;
+#endif
mptsas_send_ir2_event(ioc,
(PTR_MPI_EVENT_DATA_IR2)reply->Data);
break;
+ case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
+ mptsas_send_broadcast_primative_event(ioc,
+ (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data);
+ break;
default:
rc = mptscsih_event_process(ioc, reply);
break;
return rc;
}
+/**
+ * mptsas_probe -
+ * @pdev:
+ * @id:
+ *
+ **/
static int
mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
ioc->name);
error = -1;
goto out_mptsas_probe;
- }
+ }
spin_lock_irqsave(&ioc->FreeQlock, flags);
/* 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;
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)
sh->sg_tablesize = numSGE;
}
- hd = shost_priv(sh);
+ hd = shost_private(sh);
hd->ioc = ioc;
/* SCSI needs scsi_cmnd lookup table!
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
ioc->name, ioc->ScsiLookup));
- /* Clear the TM flags
- */
- hd->tmPending = 0;
- hd->tmState = TM_STATE_NONE;
- hd->resetPending = 0;
- hd->abortSCpnt = NULL;
-
- /* Clear the pointer used to store
- * single-threaded commands, i.e., those
- * issued during a bus scan, dv and
- * configuration pages.
- */
- hd->cmdPtr = NULL;
-
- /* Initialize this SCSI Hosts' timers
- * To use, set the timer expires field
- * and add_timer
- */
- init_timer(&hd->timer);
- hd->timer.data = (unsigned long) hd;
- hd->timer.function = mptscsih_timer_expired;
-
+ ioc->sdev_queue_depth = mpt_sdev_queue_depth;
ioc->sas_data.ptClear = mpt_pt_clear;
-
- init_waitqueue_head(&hd->scandv_waitq);
- hd->scandv_wait_done = 0;
hd->last_queue_full = 0;
+ ioc->disable_hotplug_remove = mpt_disable_hotplug_remove;
+ if (ioc->disable_hotplug_remove)
+ printk(MYIOC_s_INFO_FMT "disabling hotplug remove\n", ioc->name);
+
INIT_LIST_HEAD(&hd->target_reset_list);
+#if defined(CPQ_CIM)
+ INIT_LIST_HEAD(&ioc->sas_device_info_list);
+ init_MUTEX(&ioc->sas_device_info_mutex);
+#endif
+
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
if (ioc->sas_data.ptClear==1) {
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;
+#if defined(CPQ_CIM)
+ mptsas_del_device_components(ioc);
+#endif
+
ioc->sas_discovery_ignore_events = 1;
sas_remove_host(ioc->sh);
list_del(&p->list);
for (i = 0 ; i < p->num_phys ; i++)
mptsas_port_delete(ioc, p->phy_info[i].port_details);
+
+ if(p->del_work_scheduled) {
+ cancel_delayed_work(&p->del_work);
+ p->del_work_scheduled=0;
+ }
kfree(p->phy_info);
kfree(p);
}
mutex_unlock(&ioc->sas_topology_mutex);
-
+ ioc->hba_port_info = NULL;
mptscsih_remove(pdev);
}
#endif
};
+/**
+ * mptsas_init -
+ *
+ **/
static int __init
mptsas_init(void)
{
return -ENODEV;
mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
- mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
+ mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
mptsasInternalCtx =
mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
+ mptsasDeviceResetCtx =
+ mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
mpt_event_register(mptsasDoneCtx, mptsas_event_process);
mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
return error;
}
+/**
+ * mptsas_exit -
+ *
+ **/
static void __exit
mptsas_exit(void)
{
mpt_deregister(mptsasInternalCtx);
mpt_deregister(mptsasTaskCtx);
mpt_deregister(mptsasDoneCtx);
+ mpt_deregister(mptsasDeviceResetCtx);
}
module_init(mptsas_init);
struct list_head list;
EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
u8 target_reset_issued;
+ unsigned long time_count;
};
enum mptsas_hotplug_action {
MPTSAS_ADD_RAID,
MPTSAS_DEL_RAID,
MPTSAS_ADD_INACTIVE_VOLUME,
+ MPTSAS_ADD_PHYSDISK,
+ MPTSAS_ADD_PHYSDISK_REPROBE,
+ MPTSAS_DEL_PHYSDISK,
+ MPTSAS_DEL_PHYSDISK_REPROBE,
MPTSAS_IGNORE_EVENT,
};
+#if defined(CPQ_CIM)
+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_cached; /* cached data for a removed device */
+};
+#endif
+
struct mptsas_hotplug_event {
- struct work_struct work;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ struct delayed_work hotplug_work;
+#else
+ struct work_struct hotplug_work;
+#endif
MPT_ADAPTER *ioc;
enum mptsas_hotplug_action event_type;
u64 sas_address;
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*/
+ u8 retries;
+ struct scsi_device *sdev;
};
struct mptsas_discovery_event {
MPT_ADAPTER *ioc;
};
+struct mptsas_link_status_event {
+ struct work_struct work;
+ MpiEventDataSasPhyLinkStatus_t link_data;
+ MPT_ADAPTER *ioc;
+};
+
/*
* SAS topology structures
*
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{
- 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 */
+#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; /* unique id to address this */
+ u16 handle; /* handle for this phy */
u8 phy_id; /* phy index */
- u8 port_id; /* firmware port identifier */
+ 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
+#if defined(CPQ_CIM)
+ u8 change_count; /* change count of the phy */
+ u8 port_flags; /* info wrt host sas ports */
+#endif
+ u32 phy_info; /* various info wrt the phy */
struct mptsas_devinfo identify; /* point to phy device info */
struct mptsas_devinfo attached; /* point to attached device info */
- struct sas_phy *phy; /* transport layer phy object */
+ struct sas_phy *phy;
struct mptsas_portinfo *portinfo;
struct mptsas_portinfo_details * port_details;
};
struct mptsas_portinfo {
struct list_head list;
- u16 num_phys; /* number of phys */
+ u16 num_phys; /* number of phys */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ struct delayed_work del_work; /* work for deleting expanders */
+ struct delayed_work add_work; /* work for adding expanders */
+#else
+ struct work_struct del_work;
+ struct work_struct add_work;
+#endif
+ void *ioc; /* ioc ptr */
+ u8 del_work_scheduled;
struct mptsas_phyinfo *phy_info;
};
u8 sep_channel; /* SEP channel logical channel id */
};
+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
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h> /* for mdelay */
#include <linux/interrupt.h> /* needed for in_interrupt() proto */
#include <linux/reboot.h> /* notifier code */
+#include <linux/sched.h>
#include <linux/workqueue.h>
+#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_dbg.h>
+#include "linux_compat.h" /* linux-2.6 tweaks */
#include "mptbase.h"
#include "mptscsih.h"
#include "lsi/mpi_log_sas.h"
MODULE_VERSION(my_VERSION);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+typedef struct _BIG_SENSE_BUF {
+ u8 data[MPT_SENSE_BUFFER_ALLOC];
+} BIG_SENSE_BUF;
+
+
/*
* Other private/forward protos...
*/
-static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
+struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
SCSIIORequest_t *pReq, int req_idx);
static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
-static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
-static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
-
-static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
-
-int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
-static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
-static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
+static void mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice);
void mptscsih_remove(struct pci_dev *);
void mptscsih_shutdown(struct pci_dev *);
*
* 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)
{
} /* 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)
{
int chain_idx;
dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
- ioc->name));
+ ioc->name));
spin_lock_irqsave(&ioc->FreeQlock, flags);
if (!list_empty(&ioc->FreeChainQ)) {
int offset;
offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
chain_idx = offset / ioc->req_sz;
rc = SUCCESS;
- dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
- ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
+ ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
} else {
rc = FAILED;
chain_idx = MPT_HOST_NO_CHAIN;
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
- ioc->name));
+ ioc->name));
}
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
} /* mptscsih_getFreeChainBuffer() */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
* mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
* SCSIIORequest_t Message Frame.
* @ioc: Pointer to MPT_ADAPTER structure
* @pReq: Pointer to SCSIIORequest_t structure
*
* Returns ...
- */
+ **/
static int
mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
SCSIIORequest_t *pReq, int req_idx)
/* Map the data portion, if any.
* sges_left = 0 if no data transfer.
*/
- if ( (sges_left = scsi_sg_count(SCpnt)) ) {
+ if ( (sges_left = SCpnt->use_sg) ) {
sges_left = pci_map_sg(ioc->pcidev,
- scsi_sglist(SCpnt),
- scsi_sg_count(SCpnt),
- SCpnt->sc_data_direction);
+ (struct scatterlist *) SCpnt->request_buffer,
+ SCpnt->use_sg,
+ SCpnt->sc_data_direction);
if (sges_left == 0)
return FAILED;
} else if (SCpnt->request_bufflen) {
SCpnt->request_buffer,
SCpnt->request_bufflen,
SCpnt->sc_data_direction);
- dsgprintk(ioc,printk(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));
ioc->add_sge((char *) &pReq->SGL,
0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
return SUCCESS;
}
-
/* Handle the SG case.
*/
- sg = scsi_sglist(SCpnt);
+ sg = (struct scatterlist *) SCpnt->request_buffer;
sg_done = 0;
sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
chainSge = NULL;
}
scsi_print_command(sc);
- printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
- ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
- printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
- "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
- scsi_get_resid(sc));
- printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
- "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
+ printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n",
+ ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
+ printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, resid = %d\n",
+ ioc->name, 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,
#endif
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
* mptscsih_io_done - Main SCSI IO callback routine registered to
* Fusion MPT (base) driver
* @ioc: Pointer to MPT_ADAPTER structure
* 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)
{
VirtDevice *vdevice;
VirtTarget *vtarget;
- hd = shost_priv(ioc->sh);
+ 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,
mptscsih_get_scsi_lookup(ioc, req_idx_MR));
if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
+ "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task_tag=%d)\n",
ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
}else{
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
;
} else {
u32 xfer_cnt;
+ u32 difftransfer;
u16 status;
u8 scsi_state, scsi_status;
u32 log_info;
scsi_state = pScsiReply->SCSIState;
scsi_status = pScsiReply->SCSIStatus;
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
- scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
+ 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
if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
- /*
- * Look for + dump FCP ResponseInfo[]!
- */
- if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
- pScsiReply->ResponseInfo) {
- printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
- "FCP_ResponseInfo=%08xh\n", ioc->name,
- sc->device->host->host_no, sc->device->channel,
- sc->device->id, sc->device->lun,
- le32_to_cpu(pScsiReply->ResponseInfo));
- }
-
switch(status) {
case MPI_IOCSTATUS_BUSY: /* 0x0002 */
+ case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
/* CHECKME!
* Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
* But not: DID_BUS_BUSY lest one risk
if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
hd->sel_timeout[pScsiReq->TargetID]++;
- vdevice = sc->device->hostdata;
if (!vdevice)
break;
vtarget = vdevice->vtarget;
}
}
} 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;
}
break;
case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
- scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
+ sc->resid = sc->request_bufflen - xfer_cnt;
if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
sc->result=DID_SOFT_ERROR << 16;
else /* Sufficient data transfer occurred */
sc->result = (DID_OK << 16) | scsi_status;
- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
- ioc->name, sc->result, sc->device->channel, sc->device->id));
break;
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
* 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;
}
}
-
- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
- ioc->name, sc->underflow));
- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
-
/* Report Queue Full
*/
if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
break;
case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
- scsi_set_resid(sc, 0);
+ sc->resid=0;
case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
sc->result = (DID_OK << 16) | scsi_status;
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
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 */
/* Unmap the DMA buffers, if any. */
if (sc->use_sg) {
- pci_unmap_sg(ioc->pcidev, scsi_sglist(sc),
- scsi_sg_count(sc), sc->sc_data_direction);
+ 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);
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.
* Returns: None.
*
* Must be called while new I/Os are being queued.
- */
+ **/
static void
mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
{
continue;
if (sc->use_sg) {
pci_unmap_sg(ioc->pcidev,
- scsi_sglist(sc),
- scsi_sg_count(sc),
- sc->sc_data_direction);
+ (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->SCp.dma_handle, sc->request_bufflen,
+ sc->sc_data_direction);
}
sc->result = DID_RESET << 16;
sc->host_scribble = NULL;
- sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
- "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
- " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
+ dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
+ "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
+ "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
sc->scsi_done(sc);
}
}
-/*
+/**
* mptscsih_search_running_cmds - Delete any commands associated
* with the specified target and lun. Function called only
* when a lun is disable by mid-layer.
* Returns: None.
*
* Called from slave_destroy.
- */
+ **/
static void
mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
{
SCSIIORequest_t *mf = NULL;
int ii;
struct scsi_cmnd *sc;
- struct scsi_lun lun;
- MPT_ADAPTER *ioc = hd->ioc;
+ struct scsi_lun lun;
+ MPT_ADAPTER *ioc = hd->ioc;
unsigned long flags;
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
if (mf == NULL)
continue;
- /* If the device is a hidden raid component, then its
- * expected that the mf->function will be RAID_SCSI_IO
+
+ /*
+ * If the device is a hidden raid component,
+ * then its expected that
+ * the function would be raid scsi io
*/
if (vdevice->vtarget->tflags &
MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
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;
- sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
- "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
- vdevice->vtarget->id, sc, mf, ii);
+ dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
+ MYIOC_s_FMT "completing cmds: fw_channel %d, "
+ "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
+ vdevice->vtarget->channel, vdevice->vtarget->id,
+ sc, mf, ii));
sc->scsi_done(sc);
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
* mptscsih_report_queue_full - Report QUEUE_FULL status returned
* from a SCSI target device.
* @sc: Pointer to scsi_cmnd structure
* 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 = shost_priv(sc->device->host)) == NULL)
+ if ((hd = shost_private(sc->device->host)) == NULL)
return;
ioc = hd->ioc;
if (time - hd->last_queue_full > 10 * HZ) {
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
* mptscsih_remove - Removed scsi devices
* @pdev: Pointer to pci_dev structure
*
*
- */
+ **/
void
mptscsih_remove(struct pci_dev *pdev)
{
scsi_remove_host(host);
- if((hd = shost_priv(host)) == NULL)
+ if((hd = shost_private(host)) == NULL)
return;
mptscsih_shutdown(pdev);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
* mptscsih_shutdown - reboot notifier
*
- */
+ **/
void
mptscsih_shutdown(struct pci_dev *pdev)
{
#ifdef CONFIG_PM
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
* mptscsih_suspend - Fusion MPT scsi driver suspend routine.
*
*
- */
+ **/
int
mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
{
+ 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)
{
- return mpt_resume(pdev);
+ MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+ int rc;
+
+ rc = mpt_resume(pdev);
+ scsi_unblock_requests(ioc->sh);
+ return rc;
}
#endif
* (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 = shost_priv(SChost);
+ h = shost_private(SChost);
if (h) {
if (h->info_kbuf == NULL)
mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int func)
{
- MPT_SCSI_HOST *hd = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
int size = 0;
* 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_FRAME_HDR *mf;
SCSIIORequest_t *pScsiReq;
VirtDevice *vdevice = SCpnt->device->hostdata;
- int lun;
u32 datalen;
u32 scsictl;
u32 scsidir;
int ii;
MPT_ADAPTER *ioc;
- hd = shost_priv(SCpnt->device->host);
+ hd = shost_private(SCpnt->device->host);
ioc = hd->ioc;
- lun = SCpnt->device->lun;
SCpnt->scsi_done = done;
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
ioc->name, SCpnt, done));
- if (hd->resetPending) {
- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
- ioc->name, SCpnt));
+ if ((ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) ||
+ ioc->taskmgmt_quiesce_io)
return SCSI_MLQUEUE_HOST_BUSY;
- }
/*
* Put together a MPT SCSI request...
*/
if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
- ioc->name));
+ ioc->name));
return SCSI_MLQUEUE_HOST_BUSY;
}
* will be no data transfer! GRRRRR...
*/
if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
- datalen = scsi_bufflen(SCpnt);
+ datalen = SCpnt->request_bufflen;
scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
- datalen = scsi_bufflen(SCpnt);
+ datalen = SCpnt->request_bufflen;
scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
} else {
datalen = 0;
*/
if (datalen == 0) {
/* Add a NULL SGE */
- ioc->add_sge((char *)&pScsiReq->SGL,
- MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
+ 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(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
* mptscsih_freeChainBuffers - Function to free chain buffers associated
* with a SCSI IO request
* @hd: Pointer to the MPT_SCSI_HOST instance
*
* Called if SG chain buffer allocation fails and mptscsih callbacks.
* No return.
- */
+ **/
static void
mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
{
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- * mptscsih_TMHandler - Generic handler for SCSI Task Management.
- * @hd: Pointer to MPT SCSI HOST structure
- * @type: Task Management type
- * @channel: channel number for task management
- * @id: Logical Target ID for reset (if appropriate)
- * @lun: Logical Unit for reset (if appropriate)
- * @ctx2abort: Context for the task to be aborted (if appropriate)
- * @timeout: timeout for task management control
- *
- * Fall through to mpt_HardResetHandler if: not operational, too many
- * failed TM requests or handshake failure.
- *
- * Remark: Currently invoked from a non-interrupt thread (_bh).
- *
- * 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)
-{
- MPT_ADAPTER *ioc;
- int rc = -1;
- u32 ioc_raw_state;
- unsigned long flags;
-
- ioc = hd->ioc;
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
-
- // SJR - CHECKME - Can we avoid this here?
- // (mpt_HardResetHandler has this check...)
- spin_lock_irqsave(&ioc->diagLock, flags);
- if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
- spin_unlock_irqrestore(&ioc->diagLock, flags);
- return FAILED;
- }
- spin_unlock_irqrestore(&ioc->diagLock, flags);
-
- /* Wait a fixed amount of time for the TM pending flag to be cleared.
- * If we time out and not bus reset, then we return a FAILED status
- * to the caller.
- * The call to mptscsih_tm_pending_wait() will set the pending flag
- * if we are
- * successful. Otherwise, reload the FW.
- */
- if (mptscsih_tm_pending_wait(hd) == FAILED) {
- if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
- "Timed out waiting for last TM (%d) to complete! \n",
- ioc->name, hd->tmPending));
- return FAILED;
- } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
- "reset: Timed out waiting for last TM (%d) "
- "to complete! \n", ioc->name,
- hd->tmPending));
- return FAILED;
- } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
- "Timed out waiting for last TM (%d) to complete! \n",
- ioc->name, hd->tmPending));
- return FAILED;
- }
- } else {
- spin_lock_irqsave(&ioc->FreeQlock, flags);
- hd->tmPending |= (1 << type);
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
- }
-
- ioc_raw_state = mpt_GetIocState(ioc, 0);
-
- if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
- printk(MYIOC_s_WARN_FMT
- "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
- ioc->name, type, ioc_raw_state);
- printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
- if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
- printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
- "FAILED!!\n", ioc->name);
- return FAILED;
- }
-
- if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
- printk(MYIOC_s_WARN_FMT
- "TM Handler for type=%x: ioc_state: "
- "DOORBELL_ACTIVE (0x%x)!\n",
- ioc->name, type, ioc_raw_state);
- return FAILED;
- }
-
- /* Isse the Task Mgmt request.
- */
- if (hd->hard_resets < -1)
- hd->hard_resets++;
-
- rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
- ctx2abort, timeout);
- if (rc)
- printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
- ioc->name);
- else
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
- ioc->name));
-
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "TMHandler rc = %d!\n", ioc->name, rc));
-
- return rc;
-}
-
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- * mptscsih_IssueTaskMgmt - Generic send Task Management function.
- * @hd: Pointer to MPT_SCSI_HOST structure
- * @type: Task Management type
- * @channel: channel number for task management
- * @id: Logical Target ID for reset (if appropriate)
- * @lun: Logical Unit for reset (if appropriate)
- * @ctx2abort: Context for the task to be aborted (if appropriate)
- * @timeout: timeout for task management control
- *
- * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
- * or a non-interrupt thread. In the former, must not call schedule().
- *
- * Not all fields are meaningfull for all task types.
- *
- * Returns 0 for SUCCESS, or FAILED.
- *
- **/
+
static int
-mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
+mptscsih_scandv_bus_reset(MPT_ADAPTER *ioc)
{
MPT_FRAME_HDR *mf;
SCSITaskMgmt_t *pScsiTm;
+ SCSITaskMgmtReply_t *pScsiTmReply;
int ii;
int retval;
- MPT_ADAPTER *ioc = hd->ioc;
+ unsigned long timeout;
+ unsigned long time_count;
+ u16 iocstatus;
- /* Return Fail to calling function if no message frames available.
+ mutex_lock(&ioc->taskmgmt_cmds.mutex);
+ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+ return -EPERM;
+ }
+
+ /* Send request
*/
if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
+ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
ioc->name));
- return FAILED;
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ retval = -ENOMEM;
+ goto out;
}
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
- ioc->name, mf));
- /* Format the Request
- */
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
+ ioc->name, mf));
+
pScsiTm = (SCSITaskMgmt_t *) mf;
- pScsiTm->TargetID = id;
- pScsiTm->Bus = channel;
- pScsiTm->ChainOffset = 0;
+ memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
-
+ pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+ pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+ pScsiTm->TargetID = 0;
+ pScsiTm->Bus = 0;
+ pScsiTm->ChainOffset = 0;
pScsiTm->Reserved = 0;
- pScsiTm->TaskType = type;
pScsiTm->Reserved1 = 0;
- pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
- ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
-
- int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
-
+ pScsiTm->TaskMsgContext = 0;
+ for (ii= 0; ii < 8; ii++)
+ pScsiTm->LUN[ii] = 0;
for (ii=0; ii < 7; ii++)
pScsiTm->Reserved2[ii] = 0;
- pScsiTm->TaskMsgContext = ctx2abort;
-
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
- "type=%d\n", ioc->name, ctx2abort, type));
+ switch (ioc->bus_type) {
+ case FC:
+ timeout = 40;
+ break;
+ case SAS:
+ timeout = 30;
+ break;
+ case SPI:
+ default:
+ timeout = 2;
+ break;
+ }
- DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
+ ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
+ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+ CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+ retval = 0;
+ time_count = jiffies;
if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
(ioc->facts.MsgVersion >= MPI_VERSION_01_05))
mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
else {
retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
- if (retval) {
- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
- " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
- ioc, mf, retval));
- goto fail_out;
+ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+ if (retval != 0) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt send_handshake FAILED!"
+ " (ioc %p, mf %p, rc=%d) \n", ioc->name,
+ ioc, mf, retval));
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ goto out;
}
}
- if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
- " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
- ioc, mf));
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
- ioc->name));
- retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
- ioc->name, retval));
- goto fail_out;
+ /* Now wait for the command to complete */
+ ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "TaskMgmt failed\n", ioc->name));
+ mpt_free_msg_frame(ioc, mf);
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ retval = -1; /* return failure */
+ goto out;
}
- /*
- * Handle success case, see if theres a non-zero ioc_status.
- */
- if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
- hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
- hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
+ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "TaskMgmt failed\n", ioc->name));
+ retval = -1; /* return failure */
+ goto out;
+ }
+
+ pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
+ "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
+ "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
+ pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+ le16_to_cpu(pScsiTmReply->IOCStatus),
+ le32_to_cpu(pScsiTmReply->IOCLogInfo),
+ pScsiTmReply->ResponseCode,
+ le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+ iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+ if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
+ iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED ||
+ iocstatus == MPI_IOCSTATUS_SUCCESS)
retval = 0;
- else
- retval = FAILED;
+ else {
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "TaskMgmt failed\n", ioc->name));
+ retval = -1; /* return failure */
+ }
+ out:
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
return retval;
+}
+
+int
+mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+ MPT_SCSI_HOST *hd;
- fail_out:
+ if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
+ return 0;
- /*
- * Free task managment mf, and corresponding tm flags
- */
- mpt_free_msg_frame(ioc, mf);
- hd->tmPending = 0;
- hd->tmState = TM_STATE_NONE;
- return FAILED;
+ 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 */
}
-static int
-mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
+void
+mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
+{
+ char *desc;
+
+ switch (response_code) {
+ case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
+ desc = "The task completed.";
+ break;
+ case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
+ desc = "The IOC received an invalid frame status.";
+ break;
+ case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
+ desc = "The task type is not supported.";
+ break;
+ case MPI_SCSITASKMGMT_RSP_TM_FAILED:
+ desc = "The requested task failed.";
+ break;
+ case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
+ desc = "The task completed successfully.";
+ break;
+ case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
+ desc = "The LUN request is invalid.";
+ break;
+ case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
+ desc = "The task is in the IOC queue and has not been sent to target.";
+ break;
+ default:
+ desc = "unknown";
+ break;
+ }
+ printk(MYIOC_s_DEBUG_FMT "Response Code(0x%08x): F/W: %s\n",
+ ioc->name, response_code, desc);
+}
+
+static int
+mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, SCSITaskMgmtReply_t *pScsiTmReply)
+{
+ u16 iocstatus;
+ u32 termination_count;
+ int retval;
+
+ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+ retval = FAILED;
+ goto out;
+ }
+
+ DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
+
+ iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+ termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
+
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
+ "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
+ "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
+ pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
+ le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
+ termination_count));
+
+ if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
+ pScsiTmReply->ResponseCode)
+ mptscsih_taskmgmt_response_code(ioc,
+ pScsiTmReply->ResponseCode);
+
+ if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
+ retval = 0;
+ goto out;
+ }
+
+ retval = FAILED;
+ if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+ if (termination_count == 1)
+ retval = 0;
+ goto out;
+ }
+
+ if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
+ iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
+ retval = 0;
+
+ out:
+ return retval;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @mf: Pointer to SCSI task mgmt request frame
+ * @mr: Pointer to SCSI task mgmt reply frame
+ *
+ * This routine is called from mptbase.c::mpt_interrupt() at the completion
+ * of any SCSI task management request.
+ * This routine is registered with the MPT (base) driver at driver
+ * load/init time via the mpt_register() API call.
+ *
+ * Returns 1 indicating alloc'd request frame ptr should be freed.
+ **/
+int
+mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n",
+ ioc->name, mf, mr));
+
+ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+
+ if (!mr)
+ goto out;
+
+ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+ memcpy(ioc->taskmgmt_cmds.reply, mr,
+ min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
+ out:
+ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+ complete(&ioc->taskmgmt_cmds.done);
+ return 1;
+ }
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptscsih_IssueTaskMgmt - Generic send Task Management function.
+ * @hd: Pointer to MPT_SCSI_HOST structure
+ * @type: Task Management type
+ * @channel: channel number for task management
+ * @id: Logical Target ID for reset (if appropriate)
+ * @lun: Logical Unit for reset (if appropriate)
+ * @ctx2abort: Context for the task to be aborted (if appropriate)
+ * @timeout: timeout for task management control
+ *
+ * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
+ * or a non-interrupt thread. In the former, must not call schedule().
+ *
+ * Not all fields are meaningfull for all task types.
+ *
+ * Returns 0 for SUCCESS, or FAILED.
+ *
+ **/
+int
+mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
+{
+ MPT_FRAME_HDR *mf;
+ SCSITaskMgmt_t *pScsiTm;
+ int ii;
+ int retval;
+ MPT_ADAPTER *ioc = hd->ioc;
+ unsigned long timeleft;
+ u8 issue_hard_reset;
+ u32 ioc_raw_state;
+ unsigned long time_count;
+
+ issue_hard_reset = 0;
+ ioc_raw_state = mpt_GetIocState(ioc, 0);
+
+ if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
+ printk(MYIOC_s_WARN_FMT
+ "TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
+ ioc->name, type, ioc_raw_state);
+ printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
+ ioc->name, __FUNCTION__);
+ if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
+ printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
+ "FAILED!!\n", ioc->name);
+ return 0;
+ }
+
+ if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
+ printk(MYIOC_s_WARN_FMT
+ "TaskMgmt type=%x: ioc_state: "
+ "DOORBELL_ACTIVE (0x%x)!\n",
+ ioc->name, type, ioc_raw_state);
+ return FAILED;
+ }
+
+ mutex_lock(&ioc->taskmgmt_cmds.mutex);
+ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+ retval = FAILED;
+ goto out;
+ }
+
+ /* Return Fail to calling function if no message frames available.
+ */
+ if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt no msg frames!!\n",
+ ioc->name));
+ retval = FAILED;
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ goto out;
+ }
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
+ ioc->name, mf));
+
+ /* Format the Request
+ */
+ pScsiTm = (SCSITaskMgmt_t *) mf;
+ pScsiTm->TargetID = id;
+ pScsiTm->Bus = channel;
+ pScsiTm->ChainOffset = 0;
+ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+ pScsiTm->Reserved = 0;
+ pScsiTm->TaskType = type;
+ pScsiTm->Reserved1 = 0;
+ pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
+ ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
+
+ int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
+
+ for (ii=0; ii < 7; ii++)
+ pScsiTm->Reserved2[ii] = 0;
+
+ pScsiTm->TaskMsgContext = ctx2abort;
+
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
+ "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
+ type, timeout));
+
+ DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
+
+ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+ time_count = jiffies;
+ if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+ (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+ mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
+ else {
+ retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
+ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+ if (retval) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt handshake FAILED!"
+ " (mf=%p, rc=%d) \n", ioc->name, mf, retval));
+ mpt_free_msg_frame(ioc, mf);
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ goto out;
+ }
+ }
+
+ timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ retval = FAILED;
+ dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
+ mpt_clear_taskmgmt_in_progress_flag(ioc);
+ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+ goto out;
+ issue_hard_reset = 1;
+ goto out;
+ }
+
+ retval = mptscsih_taskmgmt_reply(ioc, type,
+ (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
+
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "TaskMgmt completed (%d seconds)\n",
+ ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
+
+ out:
+
+ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+ if(issue_hard_reset) {
+ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+ ioc->name, __FUNCTION__);
+ if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0)
+ retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+ mpt_free_msg_frame(ioc, mf);
+ }
+
+ retval = (retval == 0) ? 0 : FAILED;
+ mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+ return retval;
+}
+
+static int
+mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
{
switch (ioc->bus_type) {
case FC:
return 40;
case SAS:
- return 10;
+ return 30;
case SPI:
default:
- return 2;
+ return 10;
}
}
int retval;
VirtDevice *vdevice;
ulong sn = SCpnt->serial_number;
- MPT_ADAPTER *ioc;
+ MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
*/
- if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
+ if ((hd = shost_private(SCpnt->device->host)) == NULL) {
SCpnt->result = DID_RESET << 16;
SCpnt->scsi_done(SCpnt);
printk(KERN_ERR MYNAM ": task abort: "
ioc->name, SCpnt));
SCpnt->result = DID_NO_CONNECT << 16;
SCpnt->scsi_done(SCpnt);
- retval = 0;
+ retval = SUCCESS;
+ goto out;
+ }
+
+ /* Find this command
+ */
+ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
+ /* Cmd not found in ScsiLookup.
+ * Do OS callback.
+ */
+ SCpnt->result = DID_RESET << 16;
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "task abort: command not in the active list! (sc=%p)\n",
+ ioc->name, SCpnt));
+ retval = SUCCESS;
goto out;
}
goto out;
}
- /* Find this command
+ /* Task aborts are not supported for volumes.
*/
- if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
- /* Cmd not found in ScsiLookup.
- * Do OS callback.
- */
+ if (vdevice->vtarget->raidVolume) {
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "task abort: raid volume (sc=%p)\n",
+ ioc->name, SCpnt));
SCpnt->result = DID_RESET << 16;
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
- "Command not in the active list! (sc=%p)\n", ioc->name,
- SCpnt));
- retval = 0;
- goto out;
- }
-
- if (hd->resetPending) {
retval = FAILED;
goto out;
}
- if (hd->timeouts < -1)
- hd->timeouts++;
+ if(mpt_fwfault_debug)
+ mpt_halt_firmware(ioc);
+
+ if (ioc->timeouts < -1)
+ ioc->timeouts++;
+
/* Most important! Set TaskMsgContext to SCpnt's MsgContext!
* (the IO to be ABORT'd)
*/
mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
-
- hd->abortSCpnt = SCpnt;
-
- retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
+ mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
ctx2abort, mptscsih_get_tm_timeout(ioc));
+ /* check to see whether command actually completed and/or
+ * terminated
+ */
if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
- SCpnt->serial_number == sn)
+ SCpnt->serial_number == sn) {
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "task abort: command still in active list! (sc=%p)\n",
+ ioc->name, SCpnt));
retval = FAILED;
+ } else {
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "task abort: command cleared from active list! (sc=%p)\n",
+ ioc->name, SCpnt));
+ retval = SUCCESS;
+ }
out:
printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
- ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+ ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED" ), SCpnt);
- if (retval == 0)
- return SUCCESS;
- else
- return FAILED;
+ return retval;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/* If we can't locate our host adapter structure, return FAILED status.
*/
- if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+ if ((hd = shost_private(SCpnt->device->host)) == NULL){
printk(KERN_ERR MYNAM ": target reset: "
"Can't locate host! (sc=%p)\n", SCpnt);
return FAILED;
ioc->name, SCpnt);
scsi_print_command(SCpnt);
- if (hd->resetPending) {
- retval = FAILED;
- goto out;
- }
-
vdevice = SCpnt->device->hostdata;
if (!vdevice || !vdevice->vtarget) {
- retval = 0;
+ retval = SUCCESS;
goto out;
}
goto out;
}
- retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
- vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
- mptscsih_get_tm_timeout(ioc));
+ retval = mptscsih_IssueTaskMgmt(hd,
+ MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, vdevice->vtarget->channel,
+ vdevice->vtarget->id, 0, 0, mptscsih_get_tm_timeout(ioc));
out:
- printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
+ printk(MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
if (retval == 0)
MPT_SCSI_HOST *hd;
int retval;
VirtDevice *vdevice;
- MPT_ADAPTER *ioc;
+ MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
*/
- if ((hd = shost_priv(SCpnt->device->host)) == NULL){
- printk(KERN_ERR MYNAM ": bus reset: "
+ if ((hd = shost_private(SCpnt->device->host)) == NULL){
+ printk(KERN_ERR MYNAM ": bus_reset: "
"Can't locate host! (sc=%p)\n", SCpnt);
return FAILED;
}
ioc->name, SCpnt);
scsi_print_command(SCpnt);
- if (hd->timeouts < -1)
- hd->timeouts++;
+ if (ioc->timeouts < -1)
+ ioc->timeouts++;
vdevice = SCpnt->device->hostdata;
- retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+ if (!vdevice || !vdevice->vtarget)
+ return SUCCESS;
+ retval = mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
mptscsih_host_reset(struct scsi_cmnd *SCpnt)
{
MPT_SCSI_HOST * hd;
- int retval;
- MPT_ADAPTER *ioc;
+ int status = SUCCESS;
+ MPT_ADAPTER *ioc;
+ int retval;
/* If we can't locate the host to reset, then we failed. */
- if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+ if ((hd = shost_private(SCpnt->device->host)) == NULL){
printk(KERN_ERR MYNAM ": host reset: "
"Can't locate host! (sc=%p)\n", SCpnt);
return FAILED;
ioc = hd->ioc;
printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
- ioc->name, SCpnt);
+ ioc->name, SCpnt);
/* If our attempts to reset the host failed, then return a failed
* status. The host will be taken off line by the SCSI mid-layer.
*/
- if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
- retval = FAILED;
- } else {
- /* Make sure TM pending is cleared and TM state is set to
- * NONE.
- */
- retval = 0;
- hd->tmPending = 0;
- hd->tmState = TM_STATE_NONE;
- }
+ if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0)
+ retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+
+ if (retval < 0)
+ status = FAILED;
+ else
+ status = SUCCESS;
printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
- return retval;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- * mptscsih_tm_pending_wait - wait for pending task management request to complete
- * @hd: Pointer to MPT host structure.
- *
- * Returns {SUCCESS,FAILED}.
- */
-static int
-mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
-{
- unsigned long flags;
- int loop_count = 4 * 10; /* Wait 10 seconds */
- int status = FAILED;
- MPT_ADAPTER *ioc = hd->ioc;
-
- do {
- spin_lock_irqsave(&ioc->FreeQlock, flags);
- if (hd->tmState == TM_STATE_NONE) {
- hd->tmState = TM_STATE_IN_PROGRESS;
- hd->tmPending = 1;
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
- status = SUCCESS;
- break;
- }
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
- msleep(250);
- } while (--loop_count);
-
- return status;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- * mptscsih_tm_wait_for_completion - wait for completion of TM task
- * @hd: Pointer to MPT host structure.
- * @timeout: timeout value
- *
- * Returns {SUCCESS,FAILED}.
- */
-static int
-mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
-{
- unsigned long flags;
- int loop_count = 4 * timeout;
- int status = FAILED;
- MPT_ADAPTER *ioc = hd->ioc;
-
- do {
- spin_lock_irqsave(&ioc->FreeQlock, flags);
- if(hd->tmPending == 0) {
- status = SUCCESS;
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
- break;
- }
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
- msleep(250);
- } while (--loop_count);
-
return status;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static void
-mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
-{
- char *desc;
-
- switch (response_code) {
- case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
- desc = "The task completed.";
- break;
- case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
- desc = "The IOC received an invalid frame status.";
- break;
- case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
- desc = "The task type is not supported.";
- break;
- case MPI_SCSITASKMGMT_RSP_TM_FAILED:
- desc = "The requested task failed.";
- break;
- case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
- desc = "The task completed successfully.";
- break;
- case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
- desc = "The LUN request is invalid.";
- break;
- case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
- desc = "The task is in the IOC queue and has not been sent to target.";
- break;
- default:
- desc = "unknown";
- break;
- }
- printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
- ioc->name, response_code, desc);
-}
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
- * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
- * @ioc: Pointer to MPT_ADAPTER structure
- * @mf: Pointer to SCSI task mgmt request frame
- * @mr: Pointer to SCSI task mgmt reply frame
- *
- * This routine is called from mptbase.c::mpt_interrupt() at the completion
- * of any SCSI task management request.
- * This routine is registered with the MPT (base) driver at driver
- * load/init time via the mpt_register() API call.
- *
- * Returns 1 indicating alloc'd request frame ptr should be freed.
- **/
-int
-mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
-{
- SCSITaskMgmtReply_t *pScsiTmReply;
- SCSITaskMgmt_t *pScsiTmReq;
- MPT_SCSI_HOST *hd;
- unsigned long flags;
- u16 iocstatus;
- u8 tmType;
- u32 termination_count;
-
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
- ioc->name, mf, mr));
- if (!ioc->sh) {
- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
- "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
- return 1;
- }
-
- if (mr == NULL) {
- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
- "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
- return 1;
- }
-
- hd = shost_priv(ioc->sh);
- pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
- pScsiTmReq = (SCSITaskMgmt_t*)mf;
- tmType = pScsiTmReq->TaskType;
- iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
- termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
-
- if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
- pScsiTmReply->ResponseCode)
- mptscsih_taskmgmt_response_code(ioc,
- pScsiTmReply->ResponseCode);
- DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
-
-#ifdef CONFIG_FUSION_LOGGING
- if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
- (ioc->debug_level & MPT_DEBUG_TM ))
- printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
- "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
- "term_cmnds=%d\n", __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(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
- hd->abortSCpnt = NULL;
- goto out;
- }
-
- /* Error? (anything non-zero?) */
-
- /* clear flags and continue.
- */
- switch (tmType) {
-
- case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
- if (termination_count == 1)
- iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
- hd->abortSCpnt = NULL;
- break;
-
- case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
-
- /* If an internal command is present
- * or the TM failed - reload the FW.
- * FC FW may respond FAILED to an ABORT
- */
- if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
- hd->cmdPtr)
- if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
- printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
- break;
-
- case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
- default:
- break;
- }
-
- out:
- spin_lock_irqsave(&ioc->FreeQlock, flags);
- hd->tmPending = 0;
- hd->tmState = TM_STATE_NONE;
- hd->tm_iocstatus = iocstatus;
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
- return 1;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
* This is anyones guess quite frankly.
- */
+ **/
int
mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
sector_t capacity, int geom[])
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
*/
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
*/
}
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 = shost_priv(host);
+ 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 = shost_priv(sdev->host);
+ MPT_SCSI_HOST *hd = shost_private(sdev->host);
VirtTarget *vtarget;
struct scsi_target *starget;
int max_depth;
vtarget = starget->hostdata;
if (ioc->bus_type == SPI) {
- if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
- max_depth = 1;
- else if (sdev->type == TYPE_DISK &&
- vtarget->minSyncFactor <= MPT_ULTRA160)
+ if (sdev->type == TYPE_DISK &&
+ vtarget->minSyncFactor <= MPT_ULTRA160)
max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
else
max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
} else
- max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
+ max_depth = ioc->sh->can_queue;
+
+ if (!sdev->tagged_supported)
+ max_depth = 1;
if (qdepth > max_depth)
qdepth = max_depth;
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)
{
VirtTarget *vtarget;
VirtDevice *vdevice;
struct scsi_target *starget;
- MPT_SCSI_HOST *hd = shost_priv(sh);
- MPT_ADAPTER *ioc = hd->ioc;
+ 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(ioc, printk(MYIOC_s_DEBUG_FMT
- "device @ %p, channel=%d, id=%d, lun=%d\n",
- ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
- if (ioc->bus_type == SPI)
- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "sdtr %d wdtr %d ppr %d inq length=%d\n",
- ioc->name, sdev->sdtr, sdev->wdtr,
- sdev->ppr, sdev->inquiry_len));
-
- if (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(ioc, printk(MYIOC_s_DEBUG_FMT
- "Queue depth=%d, tflags=%x\n",
- ioc->name, sdev->queue_depth, vtarget->tflags));
-
- if (ioc->bus_type == SPI)
- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
- ioc->name, vtarget->negoFlags, vtarget->maxOffset,
- vtarget->minSyncFactor));
+ mptscsih_change_queue_depth(sdev, ioc->sdev_queue_depth);
slave_configure_exit:
- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "tagged %d, simple %d, ordered %d\n",
- ioc->name,sdev->tagged_supported, sdev->simple_tags,
- 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)
{
ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
ioc->eventContext++;
- if (ioc->pcidev->vendor ==
- PCI_VENDOR_ID_IBM) {
- mptscsih_issue_sep_command(ioc,
- vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
- vdevice->vtarget->tflags |=
- MPT_TARGET_FLAGS_LED_ON;
+ if (ioc->pcidev->vendor == PCI_VENDOR_ID_IBM) {
+ mptscsih_issue_sep_command(ioc, vdevice->vtarget,
+ MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
+ vdevice->vtarget->tflags |= MPT_TARGET_FLAGS_LED_ON;
}
}
}
} else {
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
- ioc->name));
+ ioc->name));
}
}
* Returns the scsi_cmd pointer
*
**/
-static struct scsi_cmnd *
+struct scsi_cmnd *
mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
{
unsigned long flags;
}
/**
- * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
+ * SCPNT_TO_LOOKUP_IDX
+ *
+ * search's for a given scmd in the ScsiLookup[] array list
+ *
* @ioc: Pointer to MPT_ADAPTER structure
- * @sc: scsi_cmnd pointer
- */
+ * @scmd: scsi_cmnd pointer
+ *
+ **/
static int
SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
{
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
int
-mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
{
- MPT_SCSI_HOST *hd;
- unsigned long flags;
-
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- ": IOC %s_reset routed to SCSI host driver!\n",
- ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
- /* If a FW reload request arrives after base installed but
- * before all scsi hosts have been attached, then an alt_ioc
- * may have a NULL sh pointer.
- */
- if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
- return 0;
- else
- hd = shost_priv(ioc->sh);
-
- if (reset_phase == MPT_IOC_SETUP_RESET) {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
-
- /* Clean Up:
- * 1. Set Hard Reset Pending Flag
- * All new commands go to doneQ
- */
- hd->resetPending = 1;
-
- } else if (reset_phase == MPT_IOC_PRE_RESET) {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
-
- /* 2. Flush running commands
- * Clean ScsiLookup (and associated memory)
- * AND clean mytaskQ
- */
-
- /* 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(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
+ u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
- } else {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "MPT event (=%02Xh) routed to SCSI host driver!\n",
+ ioc->name, event));
- /* Once a FW reload begins, all new OS commands are
- * redirected to the doneQ w/ a reset status.
- * Init all control structures.
- */
+ if ((event == MPI_EVENT_IOC_BUS_RESET ||
+ event == MPI_EVENT_EXT_BUS_RESET) &&
+ (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
+ ioc->soft_resets++;
- /* 2. Chain Buffer initialization
- */
+ return 1; /* currently means nothing really */
+}
- /* 4. Renegotiate to all devices, if SPI
- */
+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;
- /* 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;
+ mutex_lock(&ioc->internal_cmds.mutex);
- /* 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;
+ /* Get and Populate a free Frame
+ */
+ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+ dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!\n",
+ ioc->name, __FUNCTION__));
+ ret = -EAGAIN;
+ goto out;
+ }
+ pReq = (MpiRaidActionRequest_t *)mf;
+ if (quiesce)
+ pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO;
+ else
+ pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO;
+ pReq->Reserved1 = 0;
+ pReq->ChainOffset = 0;
+ pReq->Function = MPI_FUNCTION_RAID_ACTION;
+ pReq->VolumeID = id;
+ pReq->VolumeBus = channel;
+ pReq->PhysDiskNum = 0;
+ pReq->MsgFlags = 0;
+ pReq->Reserved2 = 0;
+ pReq->ActionDataWord = 0; /* Reserved for this action */
+
+ ioc->add_sge((char *)&pReq->ActionDataSGE,
+ MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
+
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
+ ioc->name, pReq->Action, channel, id));
+
+ INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
+ mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
+ timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ);
+ if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ ret = -ETIME;
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n",
+ ioc->name, __FUNCTION__));
+ if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+ goto out;
+ if (!timeleft) {
+ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+ ioc->name, __FUNCTION__);
+ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
+ mpt_HardResetHandler(ioc, CAN_SLEEP);
+ mpt_free_msg_frame(ioc, mf);
}
-
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
-
+ goto out;
}
- return 1; /* currently means nothing really */
+ ret = ioc->internal_cmds.completion_code;
+
+ out:
+ CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+ mutex_unlock(&ioc->internal_cmds.mutex);
+ return ret;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-int
-mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+/**
+ * mptscsih_get_completion_code -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @reply:
+ * @cmd:
+ *
+ **/
+static int
+mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
{
- MPT_SCSI_HOST *hd;
- u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+ SCSIIOReply_t *pReply;
+ MpiRaidActionReply_t *pr;
+ u8 scsi_status;
+ u16 status;
+ int completion_code;
- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
- ioc->name, event));
+ pReply = (SCSIIOReply_t *)reply;
+ status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+ scsi_status = pReply->SCSIStatus;
- if (ioc->sh == NULL ||
- ((hd = shost_priv(ioc->sh)) == NULL))
- return 1;
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+ ioc->name, status, pReply->SCSIState, scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
- switch (event) {
- case MPI_EVENT_UNIT_ATTENTION: /* 03 */
- /* FIXME! */
- break;
- case MPI_EVENT_IOC_BUS_RESET: /* 04 */
- case MPI_EVENT_EXT_BUS_RESET: /* 05 */
- if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
- hd->soft_resets++;
- break;
- case MPI_EVENT_LOGOUT: /* 09 */
- /* FIXME! */
+ switch(status) {
+
+ case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
+ completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
break;
- case MPI_EVENT_RESCAN: /* 06 */
+ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
+ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
+ case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
+ case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
+ completion_code = MPT_SCANDV_DID_RESET;
break;
- /*
- * CHECKME! Don't think we need to do
- * anything for these, but...
- */
- case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
- case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
- /*
- * CHECKME! Falling thru...
- */
+ case MPI_IOCSTATUS_BUSY:
+ case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
+ completion_code = MPT_SCANDV_BUSY;
break;
- case MPI_EVENT_INTEGRATED_RAID: /* 0B */
+ case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
+ case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
+ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
+ if (pReply->Function == MPI_FUNCTION_CONFIG) {
+ completion_code = MPT_SCANDV_GOOD;
+ } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
+ pr = (MpiRaidActionReply_t *)reply;
+ if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
+ completion_code = MPT_SCANDV_GOOD;
+ else
+ completion_code = MPT_SCANDV_SOME_ERROR;
+ } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
+ completion_code = MPT_SCANDV_SENSE;
+ else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
+ if (req->u.scsireq.CDB[0] == INQUIRY)
+ completion_code = MPT_SCANDV_ISSUE_SENSE;
+ else
+ completion_code = MPT_SCANDV_DID_RESET;
+ }
+ else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
+ completion_code = MPT_SCANDV_DID_RESET;
+ else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+ completion_code = MPT_SCANDV_DID_RESET;
+ else if (scsi_status == MPI_SCSI_STATUS_BUSY)
+ completion_code = MPT_SCANDV_BUSY;
+ else
+ completion_code = MPT_SCANDV_GOOD;
break;
- case MPI_EVENT_NONE: /* 00 */
- case MPI_EVENT_LOG_DATA: /* 01 */
- case MPI_EVENT_STATE_CHANGE: /* 02 */
- case MPI_EVENT_EVENT_CHANGE: /* 0A */
+ case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
+ if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+ completion_code = MPT_SCANDV_DID_RESET;
+ else
+ completion_code = MPT_SCANDV_SOME_ERROR;
+ break;
default:
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
- ioc->name, event));
+ completion_code = MPT_SCANDV_SOME_ERROR;
break;
- }
- return 1; /* currently means nothing really */
-}
+ } /* switch(status) */
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * Bus Scan and Domain Validation functionality ...
- */
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ " completionCode set to %08xh\n", ioc->name, completion_code));
+ return completion_code;
+}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * mptscsih_scandv_complete - Scan and DV callback routine registered
- * to Fustion MPT (base) driver.
- *
+/**
+ * mptscsih_scandv_complete -
* @ioc: Pointer to MPT_ADAPTER structure
- * @mf: Pointer to original MPT request frame
- * @mr: Pointer to MPT reply frame (NULL if TurboReply)
- *
- * This routine is called from mpt.c::mpt_interrupt() at the completion
- * of any SCSI IO request.
- * This routine is registered with the Fusion MPT (base) driver at driver
- * load/init time via the mpt_register() API call.
- *
- * Returns 1 indicating alloc'd request frame ptr should be freed.
+ * @req:
+ * @reply:
*
- * Remark: Sets a completion code and (possibly) saves sense data
- * in the IOC member localReply structure.
- * Used ONLY for DV and other internal commands.
- */
+ **/
int
-mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
{
- MPT_SCSI_HOST *hd;
SCSIIORequest_t *pReq;
- int completionCode;
+ SCSIIOReply_t *pReply;
+ u8 cmd;
u16 req_idx;
+ u8 *sense_data;
+ int sz;
- hd = shost_priv(ioc->sh);
-
- if ((mf == NULL) ||
- (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
- printk(MYIOC_s_ERR_FMT
- "ScanDvComplete, %s req frame ptr! (=%p)\n",
- ioc->name, mf?"BAD":"NULL", (void *) mf);
- goto wakeup;
- }
-
- del_timer(&hd->timer);
- req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
- mptscsih_set_scsi_lookup(ioc, req_idx, NULL);
- pReq = (SCSIIORequest_t *) mf;
+ ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+ ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
+ if (!reply)
+ goto out;
- if (mf != hd->cmdPtr) {
- printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
- ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
+ pReply = (SCSIIOReply_t *) reply;
+ pReq = (SCSIIORequest_t *) req;
+ ioc->internal_cmds.completion_code =
+ mptscsih_get_completion_code(ioc, req, reply);
+ ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+ memcpy(ioc->internal_cmds.reply, reply,
+ min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
+ cmd = reply->u.hdr.Function;
+ if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+ (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
+ (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
+ req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
+ sense_data = ((u8 *)ioc->sense_buf_pool +
+ (req_idx * MPT_SENSE_BUFFER_ALLOC));
+ sz = min_t(int, pReq->SenseBufferLength,
+ MPT_SENSE_BUFFER_ALLOC);
+ memcpy(ioc->internal_cmds.sense, sense_data, sz);
}
- hd->cmdPtr = NULL;
-
- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
- ioc->name, mf, mr, req_idx));
-
- hd->pLocal = &hd->localReply;
- hd->pLocal->scsiStatus = 0;
-
- /* If target struct exists, clear sense valid flag.
- */
- if (mr == NULL) {
- completionCode = MPT_SCANDV_GOOD;
- } else {
- SCSIIOReply_t *pReply;
- u16 status;
- u8 scsi_status;
-
- pReply = (SCSIIOReply_t *) mr;
-
- status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
- scsi_status = pReply->SCSIStatus;
-
-
- switch(status) {
-
- case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
- completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
- break;
-
- case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
- case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
- case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
- case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
- completionCode = MPT_SCANDV_DID_RESET;
- break;
-
- case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
- case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
- case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
- if (pReply->Function == MPI_FUNCTION_CONFIG) {
- ConfigReply_t *pr = (ConfigReply_t *)mr;
- completionCode = MPT_SCANDV_GOOD;
- hd->pLocal->header.PageVersion = pr->Header.PageVersion;
- hd->pLocal->header.PageLength = pr->Header.PageLength;
- hd->pLocal->header.PageNumber = pr->Header.PageNumber;
- hd->pLocal->header.PageType = pr->Header.PageType;
-
- } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
- /* If the RAID Volume request is successful,
- * return GOOD, else indicate that
- * some type of error occurred.
- */
- MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
- if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
- completionCode = MPT_SCANDV_GOOD;
- else
- completionCode = MPT_SCANDV_SOME_ERROR;
- memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
-
- } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
- u8 *sense_data;
- int sz;
-
- /* save sense data in global structure
- */
- completionCode = MPT_SCANDV_SENSE;
- hd->pLocal->scsiStatus = scsi_status;
- sense_data = ((u8 *)ioc->sense_buf_pool +
- (req_idx * MPT_SENSE_BUFFER_ALLOC));
-
- sz = min_t(int, pReq->SenseBufferLength,
- SCSI_STD_SENSE_BYTES);
- memcpy(hd->pLocal->sense, sense_data, sz);
-
- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n",
- ioc->name, sense_data));
- } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
- if (pReq->CDB[0] == INQUIRY)
- completionCode = MPT_SCANDV_ISSUE_SENSE;
- else
- completionCode = MPT_SCANDV_DID_RESET;
- }
- else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
- completionCode = MPT_SCANDV_DID_RESET;
- else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
- completionCode = MPT_SCANDV_DID_RESET;
- else {
- completionCode = MPT_SCANDV_GOOD;
- hd->pLocal->scsiStatus = scsi_status;
- }
- break;
-
- case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
- if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
- completionCode = MPT_SCANDV_DID_RESET;
- else
- completionCode = MPT_SCANDV_SOME_ERROR;
- break;
-
- default:
- completionCode = MPT_SCANDV_SOME_ERROR;
- break;
-
- } /* switch(status) */
-
- } /* end of address reply case */
-
- hd->pLocal->completion = completionCode;
-
- /* MF and RF are freed in mpt_interrupt
- */
-wakeup:
- /* Free Chain buffers (will never chain) in scan or dv */
- //mptscsih_freeChainBuffers(ioc, req_idx);
-
- /*
- * Wake up the original calling thread
- */
- hd->scandv_wait_done = 1;
- wake_up(&hd->scandv_waitq);
-
+ out:
+ if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
+ return 0;
+ ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+ complete(&ioc->internal_cmds.done);
return 1;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* mptscsih_timer_expired - Call back for timer process.
- * Used only for dv functionality.
- * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
- *
- */
-void
-mptscsih_timer_expired(unsigned long data)
-{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
- MPT_ADAPTER *ioc = hd->ioc;
-
- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
-
- if (hd->cmdPtr) {
- MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
-
- if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
- /* Desire to issue a task management request here.
- * TM requests MUST be single threaded.
- * If old eh code and no TM current, issue request.
- * If new eh code, do nothing. Wait for OS cmd timeout
- * for bus reset.
- */
- } else {
- /* Perform a FW reload */
- if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
- printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
- }
- }
- } else {
- /* This should NEVER happen */
- printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
- }
-
- /* No more processing.
- * TM call will generate an interrupt for SCSI TM Management.
- * The FW will reply to all outstanding commands, callback will finish cleanup.
- * Hard reset clean-up will free all resources.
- */
- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
-
- return;
-}
-
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_do_cmd - Do internal command.
* 0 if good
*
* > 0 if command complete but some type of completion error.
- */
-static int
+ **/
+int
mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
{
MPT_FRAME_HDR *mf;
SCSIIORequest_t *pScsiReq;
- SCSIIORequest_t ReqCopy;
int my_idx, ii, dir;
- int rc, cmdTimeout;
- int in_isr;
+ int timeout;
char cmdLen;
char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
- char cmd = io->cmd;
- MPT_ADAPTER *ioc = hd->ioc;
+ u8 cmd = io->cmd;
+ MPT_ADAPTER *ioc = hd->ioc;
+ int ret = 0;
+ unsigned long timeleft;
+ unsigned long flags;
- in_isr = in_interrupt();
- if (in_isr) {
- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
- ioc->name));
- return -EPERM;
+ /* don't send internal command during diag reset */
+ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ if (ioc->ioc_reset_in_progress) {
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: busy with host reset\n", ioc->name, __FUNCTION__));
+ return MPT_SCANDV_BUSY;
}
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+ mutex_lock(&ioc->internal_cmds.mutex);
/* Set command specific information
*/
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:
dir = MPI_SCSIIO_CONTROL_READ;
CDB[0] = cmd;
CDB[4] = 1; /*Spin up the disk */
- cmdTimeout = 15;
+ timeout = 15;
break;
case REQUEST_SENSE:
CDB[0] = cmd;
CDB[4] = io->size;
dir = MPI_SCSIIO_CONTROL_READ;
- cmdTimeout = 10;
+ timeout = 10;
break;
case READ_BUFFER:
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:
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:
dir = MPI_SCSIIO_CONTROL_READ;
CDB[0] = cmd;
// CDB[1] = 0x02; /* set immediate bit */
- cmdTimeout = 10;
+ timeout = 10;
+ break;
+
+ case REPORT_LUNS:
+ cmdLen = 12;
+ dir = MPI_SCSIIO_CONTROL_READ;
+ CDB[0] = cmd;
+ CDB[6] = (io->size >> 24) & 0xFF;
+ CDB[7] = (io->size >> 16) & 0xFF;
+ CDB[8] = (io->size >> 8) & 0xFF;
+ CDB[9] = io->size & 0xFF;
+ timeout = 10;
+ break;
+
+ case TRANSPORT_LAYER_RETRIES:
+ CDB[0] = cmd;
+ CDB[1] = 0x01;
+ cmdLen = 6;
+ dir = MPI_SCSIIO_CONTROL_READ;
+ timeout = 10;
break;
default:
/* Error Case */
- return -EFAULT;
+ ret = -EFAULT;
+ goto out;
}
/* Get and Populate a free Frame
+ * MsgContext set in mpt_get_msg_frame call
*/
if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
- ioc->name));
- return -EBUSY;
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
+ ioc->name, __FUNCTION__));
+ ret = MPT_SCANDV_BUSY;
+ goto out;
}
pScsiReq = (SCSIIORequest_t *) mf;
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 */
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
if (cmd == REQUEST_SENSE) {
pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
- ioc->name, cmd));
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: Untagged! 0x%02x\n", ioc->name, __FUNCTION__, cmd));
}
- for (ii=0; ii < 16; ii++)
- pScsiReq->CDB[ii] = CDB[ii];
+ for (ii = 0; ii < 16; ii++)
+ pScsiReq->CDB[ii] = CDB[ii];
pScsiReq->DataLength = cpu_to_le32(io->size);
pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
- ioc->name, cmd, io->channel, io->id, io->lun));
+ 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) {
+ if (dir == MPI_SCSIIO_CONTROL_READ)
ioc->add_sge((char *) &pScsiReq->SGL,
- MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
- io->data_dma);
- } else {
+ 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);
- }
-
- /* 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;
+ MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
- add_timer(&hd->timer);
+ INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
- wait_event(hd->scandv_waitq, hd->scandv_wait_done);
-
- if (hd->pLocal) {
- rc = hd->pLocal->completion;
- hd->pLocal->skip = 0;
-
- /* Always set fatal error codes in some cases.
- */
- if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
- rc = -ENXIO;
- else if (rc == MPT_SCANDV_SOME_ERROR)
- rc = -rc;
- } else {
- rc = -EFAULT;
- /* This should never happen. */
- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
- ioc->name));
+ timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
+ timeout*HZ);
+ if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ ret = -ETIME;
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __FUNCTION__,
+ cmd));
+ if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+ mpt_free_msg_frame(ioc, mf);
+ goto out;
+ }
+ if (!timeleft) {
+ if (!mptscsih_scandv_bus_reset(ioc))
+ goto out;
+ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+ ioc->name, __FUNCTION__);
+ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
+ mpt_HardResetHandler(ioc, CAN_SLEEP);
+ mpt_free_msg_frame(ioc, mf);
+ }
+ goto out;
}
- return rc;
+ ret = ioc->internal_cmds.completion_code;
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
+ ioc->name, __FUNCTION__, ret));
+
+ out:
+ CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+ mutex_unlock(&ioc->internal_cmds.mutex);
+ return ret;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
*
*/
static void
-mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
+mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice)
{
INTERNAL_CMD iocmd;
+ MPT_ADAPTER *ioc = hd->ioc;
/* Ignore hidden raid components, this is handled when the command
* is sent to the volume
!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_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
mptscsih_version_bios_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
- return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
+ return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
(ioc->biosVersion & 0xFF000000) >> 24,
(ioc->biosVersion & 0x00FF0000) >> 16,
(ioc->biosVersion & 0x0000FF00) >> 8,
mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
- return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
+ if (ioc->facts.MsgVersion >= MPI_VERSION_01_05)
+ return snprintf(buf, PAGE_SIZE, "%03x.%02x\n",
+ ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8);
+ else
+ return snprintf(buf, PAGE_SIZE, "%03x\n",
+ ioc->facts.MsgVersion);
}
static CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
mptscsih_version_product_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02xh\n",
mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
mptscsih_board_name_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
mptscsih_io_delay_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
mptscsih_device_delay_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = shost_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
mptscsih_debug_level_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = shost_priv(host);
+ 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)
+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_priv(host);
+ MPT_SCSI_HOST *hd = shost_private(host);
MPT_ADAPTER *ioc = hd->ioc;
int val = 0;
return -EINVAL;
ioc->debug_level = val;
- printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
- ioc->name, ioc->debug_level);
+ printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n", ioc->name,
+ ioc->debug_level);
return strlen(buf);
}
static 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_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_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);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#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)
#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
#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 {
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);
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);
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h> /* for mdelay */
#include <linux/interrupt.h> /* needed for in_interrupt() proto */
#include <linux/reboot.h> /* notifier code */
+#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/raid_class.h>
+#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_transport_spi.h>
#include <scsi/scsi_dbg.h>
+#include "linux_compat.h" /* linux-2.6 tweaks */
#include "mptbase.h"
#include "mptscsih.h"
-#include "linux_compat.h"
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#define my_NAME "Fusion MPT SPI Host driver"
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 *,
static u8 mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
/**
- * mptspi_setTargetNegoParms - Update the target negotiation parameters
+ * mptspi_setTargetNegoParms - Update the target negotiation parameters
* @hd: Pointer to a SCSI Host Structure
* @target: per target private data
* @sdev: SCSI device
*
- * Update the target negotiation parameters based on the the Inquiry
+ * Update the target negotiation parameters based on the the Inquiry
* data, adapter capabilities, and NVRAM settings.
**/
static void
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))
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.
*/
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
+ "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
}
}
*/
if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
- "writeIOCPage4 : no msg frames!\n",ioc->name));
+ "writeIOCPage4 : no msg frames!\n", ioc->name));
return -EAGAIN;
}
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
- ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
+ ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
* non-zero = true
* zero = false
*
- */
+ **/
static int
mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
{
static int mptspi_target_alloc(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct _MPT_SCSI_HOST *hd = shost_priv(shost);
+ struct _MPT_SCSI_HOST *hd = shost_private(shost);
VirtTarget *vtarget;
- MPT_ADAPTER *ioc;
+ MPT_ADAPTER *ioc = hd->ioc;
if (hd == NULL)
return -ENODEV;
- ioc = hd->ioc;
vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
if (!vtarget)
return -ENOMEM;
spi_max_offset(starget) = ioc->spi_data.maxSyncOffset;
spi_offset(starget) = 0;
+ spi_period(starget) = 0xFF;
mptspi_write_width(starget, 0);
return 0;
static void
mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
{
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Requested = 0x%08x"
+ if (!(hd->ioc->debug_level & MPT_DEBUG_DV))
+ return;
+
+ starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT "Wrote = 0x%08x"
" ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
- hd->ioc->name, starget->id, ii,
+ hd->ioc->name, ii,
ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
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 void
mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
{
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Read = 0x%08x"
+ if (!(hd->ioc->debug_level & MPT_DEBUG_DV))
+ return;
+
+ starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT "Read = 0x%08x"
" ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
- hd->ioc->name, starget->id, ii,
+ hd->ioc->name, ii,
ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
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 = shost_priv(shost);
+ struct _MPT_SCSI_HOST *hd = shost_private(shost);
struct _MPT_ADAPTER *ioc = hd->ioc;
struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0;
dma_addr_t 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, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
+ starget_printk(KERN_ERR, starget,
+ MYIOC_s_FMT "mpt_config failed\n", ioc->name);
goto out_free;
}
err = 0;
spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0;
}
-static int
-mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
-{
- MpiRaidActionRequest_t *pReq;
- MPT_FRAME_HDR *mf;
- MPT_ADAPTER *ioc = hd->ioc;
-
- /* Get and Populate a free Frame
- */
- if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
- ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
- ioc->name));
- return -EAGAIN;
- }
- pReq = (MpiRaidActionRequest_t *)mf;
- if (quiesce)
- pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO;
- else
- pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO;
- pReq->Reserved1 = 0;
- pReq->ChainOffset = 0;
- pReq->Function = MPI_FUNCTION_RAID_ACTION;
- pReq->VolumeID = id;
- pReq->VolumeBus = channel;
- pReq->PhysDiskNum = 0;
- pReq->MsgFlags = 0;
- pReq->Reserved2 = 0;
- pReq->ActionDataWord = 0; /* Reserved for this action */
-
- 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));
-
- hd->pLocal = NULL;
- hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
- hd->scandv_wait_done = 0;
-
- /* Save cmd pointer, for resource free if timeout or
- * FW reload occurs
- */
- hd->cmdPtr = mf;
-
- add_timer(&hd->timer);
- mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
- wait_event(hd->scandv_waitq, hd->scandv_wait_done);
-
- if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0))
- return -1;
-
- return 0;
-}
-
static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
struct scsi_device *sdev)
{
VirtTarget *vtarget = scsi_target(sdev)->hostdata;
+ struct scsi_target *starget = scsi_target(sdev);
MPT_ADAPTER *ioc = hd->ioc;
/* no DV on RAID devices */
mptspi_is_raid(hd, sdev->id))
return;
+ if (ioc->debug_level & MPT_DEBUG_DV)
+ starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT
+ "sdtr=%d, wdtr=%d, ppr=%d, min_period=0x%02x, "
+ "max_offset=0x%02x, max_width=%d, nego_flags=0x%02x, "
+ "tflags=0x%02x\n", ioc->name, sdev->sdtr, sdev->wdtr,
+ sdev->ppr, spi_min_period(starget),
+ spi_max_offset(starget), spi_max_width(starget),
+ vtarget->negoFlags, vtarget->tflags);
+
/* If this is a piece of a RAID, then quiesce first */
if (sdev->channel == 1 &&
mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
- starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
- "Integrated RAID quiesce failed\n", ioc->name);
+ starget_printk(KERN_ERR, scsi_target(sdev),
+ MYIOC_s_FMT "Integrated RAID quiesce failed\n", ioc->name);
return;
}
if (sdev->channel == 1 &&
mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
- starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
- "Integrated RAID resume failed\n", ioc->name);
+ starget_printk(KERN_ERR, scsi_target(sdev),
+ MYIOC_s_FMT "Integrated RAID resume failed\n", ioc->name);
mptspi_read_parameters(sdev->sdev_target);
spi_display_xfer_agreement(sdev->sdev_target);
static int mptspi_slave_alloc(struct scsi_device *sdev)
{
- MPT_SCSI_HOST *hd = shost_priv(sdev->host);
+ MPT_SCSI_HOST *hd = shost_private(sdev->host);
VirtTarget *vtarget;
VirtDevice *vdevice;
struct scsi_target *starget;
vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
if (!vdevice) {
printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
- ioc->name, sizeof(VirtDevice));
+ ioc->name, sizeof(VirtDevice));
return -ENOMEM;
}
static int mptspi_slave_configure(struct scsi_device *sdev)
{
- struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host);
+ 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(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x"
- " max_offset=0x%02x max_width=%d\n", hd->ioc->name,
- sdev->id, spi_min_period(scsi_target(sdev)),
- spi_max_offset(scsi_target(sdev)),
- spi_max_width(scsi_target(sdev))));
-
if ((sdev->channel == 1 ||
!(mptspi_is_raid(hd, sdev->id))) &&
!spi_initial_dv(sdev->sdev_target))
static int
mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
- struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host);
+ struct _MPT_SCSI_HOST *hd = shost_private(SCpnt->device->host);
VirtDevice *vdevice = SCpnt->device->hostdata;
MPT_ADAPTER *ioc = hd->ioc;
struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct _MPT_SCSI_HOST *hd = shost_priv(shost);
+ 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;
pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL);
if (pg1 == NULL) {
- starget_printk(KERN_ERR, starget, MYIOC_s_FMT
- "dma_alloc_coherent for parameters failed\n", ioc->name);
+ starget_printk(KERN_ERR, starget,
+ MYIOC_s_FMT "dma_alloc_coherent for parameters failed\n", ioc->name);
return -EINVAL;
}
mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
if (mpt_config(ioc, &cfg)) {
- starget_printk(KERN_ERR, starget, MYIOC_s_FMT
- "mpt_config failed\n", ioc->name);
+ starget_printk(KERN_ERR, starget,
+ MYIOC_s_FMT "mpt_config failed\n", ioc->name);
goto out_free;
}
err = 0;
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;
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);
{
struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct _MPT_SCSI_HOST *hd = shost_priv(shost);
+ 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;
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;
};
static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mpt_work_wrapper(struct work_struct *work)
+{
+ struct work_queue_wrapper *wqw =
+ container_of(work, struct work_queue_wrapper, work);
+#else
mpt_work_wrapper(void *data)
{
struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
+#endif
struct _MPT_SCSI_HOST *hd = wqw->hd;
MPT_ADAPTER *ioc = hd->ioc;
struct Scsi_Host *shost = ioc->sh;
if(vtarget->id != disk)
continue;
- starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT
- "Integrated RAID requests DV of new device\n", ioc->name);
+ starget_printk(KERN_INFO, vtarget->starget,
+ MYIOC_s_FMT "Integrated RAID requests DV of new device\n", ioc->name);
mptspi_dv_device(hd, sdev);
}
- shost_printk(KERN_INFO, shost, MYIOC_s_FMT
- "Integrated RAID detects new device %d\n", ioc->name, disk);
+ shost_printk(KERN_INFO, shost,
+ MYIOC_s_FMT "Integrated RAID detects new device %d\n", ioc->name, disk);
scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, 1);
}
MPT_ADAPTER *ioc = hd->ioc;
if (!wqw) {
- shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT
- "Failed to act on RAID event for physical disk %d\n",
+ shost_printk(KERN_ERR, ioc->sh,
+ MYIOC_s_FMT "Failed to act on RAID event for physical disk %d\n",
ioc->name, disk);
return;
}
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+ INIT_WORK(&wqw->work, mpt_work_wrapper);
+#else
INIT_WORK(&wqw->work, mpt_work_wrapper, wqw);
+#endif
wqw->hd = hd;
wqw->disk = disk;
mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
{
u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
- struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+ struct _MPT_SCSI_HOST *hd = shost_private(ioc->sh);
if (hd && event == MPI_EVENT_INTEGRATED_RAID) {
int reason
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;
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 = shost_priv(ioc->sh);
+ 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 = shost_priv(ioc->sh);
+ struct _MPT_SCSI_HOST *hd = shost_private(ioc->sh);
int rc;
rc = mptscsih_resume(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)
{
sh->sg_tablesize = numSGE;
}
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
- hd = shost_priv(sh);
+ 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!)
*/
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
ioc->name, ioc->ScsiLookup));
- /* Clear the TM flags
- */
- hd->tmPending = 0;
- hd->tmState = TM_STATE_NONE;
- hd->resetPending = 0;
- hd->abortSCpnt = NULL;
-
- /* Clear the pointer used to store
- * single-threaded commands, i.e., those
- * issued during a bus scan, dv and
- * configuration pages.
- */
- hd->cmdPtr = NULL;
-
- /* Initialize this SCSI Hosts' timers
- * To use, set the timer expires field
- * and add_timer
- */
- init_timer(&hd->timer);
- hd->timer.data = (unsigned long) hd;
- hd->timer.function = mptscsih_timer_expired;
-
+ ioc->sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
ioc->spi_data.Saf_Te = mpt_saf_te;
-
- hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "saf_te %x\n",
- ioc->name,
- mpt_saf_te));
- ioc->spi_data.noQas = 0;
+ "saf_te %x\n", ioc->name, mpt_saf_te));
+ ioc->spi_data.noQas = mpt_qas ? 0 : MPT_TARGET_NO_NEGO_QAS;
- init_waitqueue_head(&hd->scandv_waitq);
- hd->scandv_wait_done = 0;
hd->last_queue_full = 0;
hd->spi_pending = 0;
* 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);
* 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)
{
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptspi_exit - Unregisters MPT adapter(s)
- */
+ *
+ **/
static void __exit
mptspi_exit(void)
{
mpt_reset_deregister(mptspiDoneCtx);
mpt_event_deregister(mptspiDoneCtx);
-
mpt_deregister(mptspiInternalCtx);
mpt_deregister(mptspiTaskCtx);
mpt_deregister(mptspiDoneCtx);
--- /dev/null
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 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 (sizeof(dma_addr_t) == 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 (sizeof(dma_addr_t) == sizeof(u64)) {
+ tmp = (u32)((u64)request_data_dma >> 32);
+ diag_buffer_post_request->BufferAddress.High = cpu_to_le32(tmp);
+ }
+
+ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
+ diag_buffer_post_request->MsgContext);
+ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
+ mpt_put_msg_frame(mptctl_id, ioc, mf);
+ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
+ MPT_IOCTL_DEFAULT_TIMEOUT*HZ);
+ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ rc = -ETIME;
+ printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name,
+ __FUNCTION__);
+ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+ mpt_free_msg_frame(ioc, mf);
+ goto out;
+ }
+ if (!timeleft)
+ mptctl_timeout_expired(ioc, mf);
+ goto out;
+ }
+
+ /* process the completed Reply Message Frame */
+ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n",
+ ioc->name, __FUNCTION__, ioc->ioctl_cmds.status));
+ rc = -EFAULT;
+ }
+
+ diag_buffer_post_reply = (DiagBufferPostReply_t *)ioc->ioctl_cmds.reply;
+ if (le16_to_cpu(diag_buffer_post_reply->IOCStatus) ==
+ MPI_IOCSTATUS_SUCCESS) {
+ if (diag_buffer_post_reply->MsgLength > 5)
+ ioc->DataSize[buffer_type] =
+ le32_to_cpu(diag_buffer_post_reply->TransferLength);
+ ioc->DiagBuffer_Status[buffer_type] |=
+ MPT_DIAG_BUFFER_IS_REGISTERED;
+ } else {
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x "
+ "IOCLogInfo=%x\n", ioc->name, __FUNCTION__,
+ diag_buffer_post_reply->IOCStatus,
+ diag_buffer_post_reply->IOCLogInfo));
+ rc = -EFAULT;
+ }
+
+ out:
+ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
+ return rc;
+}
--- /dev/null
+#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;