Skip to contentSkip to conversation

mpt2sas: mpt2sas_base sources

PATCH In review Eric Moore 5 participants 12 messages Feb 24, 2009 – Mar 4, 2009 SCSI

lore
Share & tools
lore

Eric Moore

author
#0 lore raw

PATCH 1/11 mpt2sas: mpt2sas_base sources

mpt2sas_base

Common API layer interface to MPT (Message Passing Technology) firmware.

---

drivers/scsi/mpt2sas/mpt2sas_base.c +3403 -0
@@ -0,0 +1,3403 @@
+/*
+ * This is the Fusion MPT base driver providing common API layer interface
+ * for access to MPT (Message Passing Technology) firmware.
+ *
+ * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
+ * Copyright (C) 2007-2008  LSI Corporation
+ *  (mailto:[email protected])
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/sort.h>
+#include <linux/io.h>
+
+#include "mpt2sas_base.h"
+
+static MPT_CALLBACK	mpt_callbacks[MPT_MAX_CALLBACKS];
+
+#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
+#define MPT2SAS_MAX_REQUEST_QUEUE 500 /* maximum controller queue depth */
+
+static int max_queue_depth = -1;
+module_param(max_queue_depth, int, 0);
+MODULE_PARM_DESC(max_queue_depth, " max controller queue depth ");
+
+static int max_sgl_entries = -1;
+module_param(max_sgl_entries, int, 0);
+MODULE_PARM_DESC(max_sgl_entries, " max sg entries ");
+
+static int msix_disable = -1;
+module_param(msix_disable, int, 0);
+MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
+
+/**
+ * _base_fault_reset_work - workq handling ioc fault conditions
+ * @work: input argument, used to derive ioc
+ * Context: sleep.
+ *
+ * Return nothing.
+ */
+static void
+_base_fault_reset_work(struct work_struct *work)
+{
+	struct MPT2SAS_ADAPTER *ioc =
+	    container_of(work, struct MPT2SAS_ADAPTER, fault_reset_work.work);
+	unsigned long	 flags;
+	u32 doorbell;
+	int rc;
+
+	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+	if (ioc->ioc_reset_in_progress)
+		goto rearm_timer;
+	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+	doorbell = base_get_iocstate(ioc, 0);
+	if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
+		rc = base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
+		printk(MPT2SAS_WARN_FMT "%s: hard reset: %s\n", ioc->name,
+		    __func__, (rc == 0) ? "success" : "failed");
+		doorbell = base_get_iocstate(ioc, 0);
+		if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
+			base_fault_info(ioc, doorbell &
+			    MPI2_DOORBELL_DATA_MASK);
+	}
+
+	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+ rearm_timer:
+	if (ioc->fault_reset_work_q)
+		queue_delayed_work(ioc->fault_reset_work_q,
+		    &ioc->fault_reset_work,
+		    msecs_to_jiffies(FAULT_POLLING_INTERVAL));
+	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+}
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _base_sas_ioc_info - verbose translation of the ioc status
+ * @ioc: pointer to scsi command object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @request_hdr: request mf
+ *
+ * Return nothing.
+ */
+static void
+_base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
+     MPI2RequestHeader_t *request_hdr)
+{
+	u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
+	    MPI2_IOCSTATUS_MASK;
+	char *desc = NULL;
+	u16 frame_sz;
+	char *func_str = NULL;
+
+	/* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */
+	if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
+	    request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
+	    request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION)
+		return;
+
+	switch (ioc_status) {
+
+/****************************************************************************
+*  Common IOCStatus values for all replies
+****************************************************************************/
+
+	case MPI2_IOCSTATUS_INVALID_FUNCTION:
+		desc = "invalid function";
+		break;
+	case MPI2_IOCSTATUS_BUSY:
+		desc = "busy";
+		break;
+	case MPI2_IOCSTATUS_INVALID_SGL:
+		desc = "invalid sgl";
+		break;
+	case MPI2_IOCSTATUS_INTERNAL_ERROR:
+		desc = "internal error";
+		break;
+	case MPI2_IOCSTATUS_INVALID_VPID:
+		desc = "invalid vpid";
+		break;
+	case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
+		desc = "insufficient resources";
+		break;
+	case MPI2_IOCSTATUS_INVALID_FIELD:
+		desc = "invalid field";
+		break;
+	case MPI2_IOCSTATUS_INVALID_STATE:
+		desc = "invalid state";
+		break;
+	case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
+		desc = "op state not supported";
+		break;
+
+/****************************************************************************
+*  Config IOCStatus values
+****************************************************************************/
+
+	case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION:
+		desc = "config invalid action";
+		break;
+	case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE:
+		desc = "config invalid type";
+		break;
+	case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE:
+		desc = "config invalid page";
+		break;
+	case MPI2_IOCSTATUS_CONFIG_INVALID_DATA:
+		desc = "config invalid data";
+		break;
+	case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS:
+		desc = "config no defaults";
+		break;
+	case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT:
+		desc = "config cant commit";
+		break;
+
+/****************************************************************************
+*  SCSI IO Reply
+****************************************************************************/
+
+	case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
+	case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
+	case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+	case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
+	case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
+	case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
+	case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
+	case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
+	case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
+	case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+	case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
+	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
+		break;
+
+/****************************************************************************
+*  For use by SCSI Initiator and SCSI Target end-to-end data protection
+****************************************************************************/
+
+	case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+		desc = "eedp guard error";
+		break;
+	case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+		desc = "eedp ref tag error";
+		break;
+	case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+		desc = "eedp app tag error";
+		break;
+
+/****************************************************************************
+*  SCSI Target values
+****************************************************************************/
+
+	case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX:
+		desc = "target invalid io index";
+		break;
+	case MPI2_IOCSTATUS_TARGET_ABORTED:
+		desc = "target aborted";
+		break;
+	case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE:
+		desc = "target no conn retryable";
+		break;
+	case MPI2_IOCSTATUS_TARGET_NO_CONNECTION:
+		desc = "target no connection";
+		break;
+	case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH:
+		desc = "target xfer count mismatch";
+		break;
+	case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR:
+		desc = "target data offset error";
+		break;
+	case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA:
+		desc = "target too much write data";
+		break;
+	case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT:
+		desc = "target iu too short";
+		break;
+	case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT:
+		desc = "target ack nak timeout";
+		break;
+	case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED:
+		desc = "target nak received";
+		break;
+
+/****************************************************************************
+*  Serial Attached SCSI values
+****************************************************************************/
+
+	case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED:
+		desc = "smp request failed";
+		break;
+	case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN:
+		desc = "smp data overrun";
+		break;
+
+/****************************************************************************
+*  Diagnostic Buffer Post / Diagnostic Release values
+****************************************************************************/
+
+	case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED:
+		desc = "diagnostic released";
+		break;
+	default:
+		break;
+	}
+
+	if (!desc)
+		return;
+
+	switch (request_hdr->Function) {
+	case MPI2_FUNCTION_CONFIG:
+		frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size;
+		func_str = "config_page";
+		break;
+	case MPI2_FUNCTION_SCSI_TASK_MGMT:
+		frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t);
+		func_str = "task_mgmt";
+		break;
+	case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
+		frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t);
+		func_str = "sas_iounit_ctl";
+		break;
+	case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
+		frame_sz = sizeof(Mpi2SepRequest_t);
+		func_str = "enclosure";
+		break;
+	case MPI2_FUNCTION_IOC_INIT:
+		frame_sz = sizeof(Mpi2IOCInitRequest_t);
+		func_str = "ioc_init";
+		break;
+	case MPI2_FUNCTION_PORT_ENABLE:
+		frame_sz = sizeof(Mpi2PortEnableRequest_t);
+		func_str = "port_enable";
+		break;
+	case MPI2_FUNCTION_SMP_PASSTHROUGH:
+		frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size;
+		func_str = "smp_passthru";
+		break;
+	default:
+		frame_sz = 32;
+		func_str = "unknown";
+		break;
+	}
+
+	printk(MPT2SAS_WARN_FMT "ioc_status: %s(0x%04x), request(0x%p),"
+	    " (%s)\n", ioc->name, desc, ioc_status, request_hdr, func_str);
+
+	_debug_dump_mf(request_hdr, frame_sz/4);
+}
+
+/**
+ * _base_display_event_data - verbose translation of firmware asyn events
+ * @ioc: pointer to scsi command object
+ * @mpi_reply: reply mf payload returned from firmware
+ *
+ * Return nothing.
+ */
+static void
+_base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventNotificationReply_t *mpi_reply)
+{
+	char *desc = NULL;
+	u16 event;
+
+	if (!(ioc->logging_level & MPT_DEBUG_EVENTS))
+		return;
+
+	event = le16_to_cpu(mpi_reply->Event);
+
+	switch (event) {
+	case MPI2_EVENT_LOG_DATA:
+		desc = "Log Data";
+		break;
+	case MPI2_EVENT_STATE_CHANGE:
+		desc = "Status Change";
+		break;
+	case MPI2_EVENT_HARD_RESET_RECEIVED:
+		desc = "Hard Reset Received";
+		break;
+	case MPI2_EVENT_EVENT_CHANGE:
+		desc = "Event Change";
+		break;
+	case MPI2_EVENT_TASK_SET_FULL:
+		desc = "Task Set Full";
+		break;
+	case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
+		desc = "Device Status Change";
+		break;
+	case MPI2_EVENT_IR_OPERATION_STATUS:
+		desc = "IR Operation Status";
+		break;
+	case MPI2_EVENT_SAS_DISCOVERY:
+		desc =  "Discovery";
+		break;
+	case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
+		desc = "SAS Broadcast Primitive";
+		break;
+	case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
+		desc = "SAS Init Device Status Change";
+		break;
+	case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW:
+		desc = "SAS Init Table Overflow";
+		break;
+	case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+		desc = "SAS Topology Change List";
+		break;
+	case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
+		desc = "SAS Enclosure Device Status Change";
+		break;
+	case MPI2_EVENT_IR_VOLUME:
+		desc = "IR Volume";
+		break;
+	case MPI2_EVENT_IR_PHYSICAL_DISK:
+		desc = "IR Physical Disk";
+		break;
+	case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
+		desc = "IR Configuration Change List";
+		break;
+	case MPI2_EVENT_LOG_ENTRY_ADDED:
+		desc = "Log Entry Added";
+		break;
+	}
+
+	if (!desc)
+		return;
+
+	printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, desc);
+}
+#endif
+
+/**
+ * _base_sas_log_info - verbose translation of firmware log info
+ * @ioc: pointer to scsi command object
+ * @log_info: log info
+ *
+ * Return nothing.
+ */
+static void
+_base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info)
+{
+	union loginfo_type {
+		u32	loginfo;
+		struct {
+			u32	subcode:16;
+			u32	code:8;
+			u32	originator:4;
+			u32	bus_type:4;
+		} dw;
+	};
+	union loginfo_type sas_loginfo;
+	char *originator_str = NULL;
+
+	sas_loginfo.loginfo = log_info;
+	if (sas_loginfo.dw.bus_type != 3 /*SAS*/)
+		return;
+
+	/* eat the loginfos associated with task aborts */
+	if (ioc->ignore_loginfos && (log_info == 30050000 || log_info ==
+	    0x31140000 || log_info == 0x31130000))
+		return;
+
+	switch (sas_loginfo.dw.originator) {
+	case 0:
+		originator_str = "IOP";
+		break;
+	case 1:
+		originator_str = "PL";
+		break;
+	case 2:
+		originator_str = "IR";
+		break;
+	}
+
+	printk(MPT2SAS_WARN_FMT "log_info(0x%08x): originator(%s), "
+	    "code(0x%02x), sub_code(0x%04x)\n", ioc->name, log_info,
+	     originator_str, sas_loginfo.dw.code,
+	     sas_loginfo.dw.subcode);
+}
+
+/**
+ * base_fault_info - verbose translation of firmware FAULT code
+ * @ioc: pointer to scsi command object
+ * @fault_code: fault code
+ *
+ * Return nothing.
+ */
+void
+base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
+{
+	printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n",
+	    ioc->name, fault_code);
+}
+
+/**
+ * _base_display_reply_info -
+ * @ioc: pointer to scsi command object
+ * @smid: system request message index
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Return nothing.
+ */
+static void
+_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+    u32 reply)
+{
+	MPI2DefaultReply_t *mpi_reply;
+	u16 ioc_status;
+
+	mpi_reply =  base_get_reply_virt_addr(ioc, reply);
+	ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+	if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
+	    (ioc->logging_level & MPT_DEBUG_REPLY)) {
+		_base_sas_ioc_info(ioc , mpi_reply,
+		    base_get_msg_frame(ioc, smid));
+	}
+#endif
+	if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
+		_base_sas_log_info(ioc, le32_to_cpu(mpi_reply->IOCLogInfo));
+}
+
+/**
+ * base_done - base internal command completion routine
+ * @ioc: pointer to scsi command object
+ * @smid: system request message index
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Return nothing.
+ */
+void
+base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+{
+	MPI2DefaultReply_t *mpi_reply;
+
+	mpi_reply =  base_get_reply_virt_addr(ioc, reply);
+	if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
+		return;
+
+	if (ioc->base_cmds.status == MPT2_CMD_NOT_USED)
+		return;
+
+	ioc->base_cmds.status |= MPT2_CMD_COMPLETE;
+	if (mpi_reply) {
+		ioc->base_cmds.status |= MPT2_CMD_REPLY_VALID;
+		memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
+	}
+	ioc->base_cmds.status &= ~MPT2_CMD_PENDING;
+	complete(&ioc->base_cmds.done);
+}
+
+/**
+ * _base_async_event - main callback handler for firmware asyn events
+ * @ioc: pointer to scsi command object
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Return nothing.
+ */
+static void
+_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
+{
+	Mpi2EventNotificationReply_t *mpi_reply;
+	Mpi2EventAckRequest_t *ack_request;
+	u16 smid;
+
+	mpi_reply =  base_get_reply_virt_addr(ioc, reply);
+	if (!mpi_reply)
+		return;
+	if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
+		return;
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+	_base_display_event_data(ioc, mpi_reply);
+#endif
+	if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED))
+		goto out;
+	smid = base_get_smid(ioc, ioc->base_cb_idx);
+	if (!smid) {
+		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+		    ioc->name, __func__);
+		goto out;
+	}
+
+	ack_request = base_get_msg_frame(ioc, smid);
+	memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t));
+	ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
+	ack_request->Event = mpi_reply->Event;
+	ack_request->EventContext = mpi_reply->EventContext;
+	ack_request->VF_ID = VF_ID;
+	base_put_smid_default(ioc, smid, VF_ID);
+
+ out:
+	scsih_event_callback(ioc, VF_ID, reply); /* scsih callback handler */
+	ctl_event_callback(ioc, VF_ID, reply); /* ctl callback handler */
+}
+
+/**
+ * _base_mask_interrupts - disable interrupts
+ * @ioc: pointer to scsi command object
+ *
+ * Disabling ResetIRQ, Reply and Doorbell Interrupts
+ *
+ * Return nothing.
+ */
+static void
+_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
+{
+	u32 him_register;
+
+	ioc->mask_interrupts = 1;
+	him_register = readl(&ioc->chip->HostInterruptMask);
+	him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK;
+	writel(him_register, &ioc->chip->HostInterruptMask);
+}
+
+/**
+ * _base_unmask_interrupts - enable interrupts
+ * @ioc: pointer to scsi command object
+ *
+ * Enabling only Reply Interrupts
+ *
+ * Return nothing.
+ */
+static void
+_base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc)
+{
+	u32 him_register;
+
+	writel(0, &ioc->chip->HostInterruptStatus);
+	him_register = readl(&ioc->chip->HostInterruptMask);
+	him_register &= ~MPI2_HIM_RIM;
+	writel(him_register, &ioc->chip->HostInterruptMask);
+	ioc->mask_interrupts = 0;
+}
+
+/**
+ * base_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)
+ *
+ * Return IRQ_HANDLE if processed, else IRQ_NONE.
+ */
+static irqreturn_t
+base_interrupt(int irq, void *bus_id)
+{
+	u32 post_index, post_index_next, completed_cmds;
+	u8 request_desript_type;
+	u16 smid;
+	u8 cb_idx;
+	u32 reply;
+	u8 VF_ID;
+	int i;
+	struct MPT2SAS_ADAPTER *ioc = bus_id;
+
+	if (ioc->mask_interrupts)
+		return IRQ_NONE;
+
+	post_index = ioc->reply_post_host_index;
+	request_desript_type = ioc->reply_post_free[post_index].
+	    Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+	if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+		return IRQ_NONE;
+
+	completed_cmds = 0;
+	do {
+		if (ioc->reply_post_free[post_index].Words ==
+		    0xFFFFFFFFFFFFFFFFULL)
+			goto out;
+		reply = 0;
+		cb_idx = 0xFF;
+		smid = le16_to_cpu(ioc->reply_post_free[post_index].
+		    Default.DescriptorTypeDependent1);
+		VF_ID = ioc->reply_post_free[post_index].
+		    Default.VF_ID;
+		if (request_desript_type ==
+		    MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
+			reply = le32_to_cpu(ioc->reply_post_free[post_index].
+			    AddressReply.ReplyFrameAddress);
+		} else if (request_desript_type ==
+		    MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER)
+			goto next;
+		else if (request_desript_type ==
+		    MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS)
+			goto next;
+		if (smid)
+			cb_idx = ioc->scsi_lookup[smid - 1].cb_idx;
+		if (smid && cb_idx != 0xFF) {
+			mpt_callbacks[cb_idx](ioc, smid, VF_ID, reply);
+			if (reply)
+				_base_display_reply_info(ioc, smid, VF_ID,
+				    reply);
+			base_free_smid(ioc, smid);
+		}
+		if (!smid)
+			_base_async_event(ioc, VF_ID, reply);
+
+		/* reply free queue handling */
+		if (reply) {
+			ioc->reply_free_host_index =
+			    (ioc->reply_free_host_index ==
+			    (ioc->reply_free_queue_depth - 1)) ?
+			    0 : ioc->reply_free_host_index + 1;
+			ioc->reply_free[ioc->reply_free_host_index] =
+			    cpu_to_le32(reply);
+			writel(ioc->reply_free_host_index,
+			    &ioc->chip->ReplyFreeHostIndex);
+			wmb();
+		}
+
+ next:
+		post_index_next = (post_index == (ioc->reply_post_queue_depth -
+		    1)) ? 0 : post_index + 1;
+		request_desript_type =
+		    ioc->reply_post_free[post_index_next].Default.ReplyFlags
+		    & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+		completed_cmds++;
+		if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+			goto out;
+		post_index = post_index_next;
+	} while (1);
+
+ out:
+
+	if (!completed_cmds)
+		return IRQ_NONE;
+
+	/* reply post descriptor handling */
+	post_index_next = ioc->reply_post_host_index;
+	for (i = 0 ; i < completed_cmds; i++) {
+		post_index = post_index_next;
+		/* poison the reply post descriptor */
+		ioc->reply_post_free[post_index_next].Words =
+		    0xFFFFFFFFFFFFFFFFULL;
+		post_index_next = (post_index ==
+		    (ioc->reply_post_queue_depth - 1))
+		    ? 0 : post_index + 1;
+	}
+	ioc->reply_post_host_index = post_index_next;
+	writel(post_index_next, &ioc->chip->ReplyPostHostIndex);
+	wmb();
+	return IRQ_HANDLED;
+}
+
+/**
+ * base_release_callback_handler - clear interupt callback handler
+ * @cb_idx: callback index
+ *
+ * Return nothing.
+ */
+void
+base_release_callback_handler(u8 cb_idx)
+{
+	mpt_callbacks[cb_idx] = NULL;
+}
+
+/**
+ * base_register_callback_handler - obtain index for the interrupt callback handler
+ * @cb_func: callback function
+ *
+ * Returns cb_func.
+ */
+u8
+base_register_callback_handler(MPT_CALLBACK cb_func)
+{
+	u8 cb_idx;
+
+	for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--)
+		if (mpt_callbacks[cb_idx] == NULL)
+			break;
+
+	mpt_callbacks[cb_idx] = cb_func;
+	return cb_idx;
+}
+
+/**
+ * base_initialize_callback_handler - initialize the interrupt callback handler
+ *
+ * Return nothing.
+ */
+void
+base_initialize_callback_handler(void)
+{
+	u8 cb_idx;
+
+	for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++)
+		base_release_callback_handler(cb_idx);
+}
+
+/**
+ * base_build_zero_len_sge - build zero length sg entry
+ * @ioc: per adapter object
+ * @paddr: virtual address for SGE
+ *
+ * Create a zero length scatter gather entry to insure the IOCs hardware has
+ * something to use if the target device goes brain dead and tries
+ * to send data even when none is asked for.
+ *
+ * Return nothing.
+ */
+void
+base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr)
+{
+	u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT |
+	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST |
+	    MPI2_SGE_FLAGS_SIMPLE_ELEMENT) <<
+	    MPI2_SGE_FLAGS_SHIFT);
+	ioc->base_add_sg_single(paddr, flags_length, -1);
+}
+
+/**
+ * base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr.
+ * @paddr: virtual address for SGE
+ * @flags_length: SGE flags and data transfer length
+ * @dma_addr: Physical address
+ *
+ * Return nothing.
+ */
+static void
+base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr)
+{
+	Mpi2SGESimple32_t *sgel = paddr;
+
+	flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
+	    MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
+	sgel->FlagsLength = cpu_to_le32(flags_length);
+	sgel->Address = cpu_to_le32(dma_addr);
+}
+
+
+/**
+ * base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr.
+ * @paddr: virtual address for SGE
+ * @flags_length: SGE flags and data transfer length
+ * @dma_addr: Physical address
+ *
+ * Return nothing.
+ */
+static void
+base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr)
+{
+	Mpi2SGESimple64_t *sgel = paddr;
+
+	flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
+	    MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
+	sgel->FlagsLength = cpu_to_le32(flags_length);
+	sgel->Address = cpu_to_le64(dma_addr);
+}
+
+#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10))
+
+/**
+ * _base_config_dma_addressing - set dma addressing
+ * @ioc: per adapter object
+ * @pdev: PCI device struct
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
+{
+	struct sysinfo s;
+	char *desc = NULL;
+
+	if (sizeof(dma_addr_t) > 4) {
+		const uint64_t required_mask =
+		    dma_get_required_mask(&pdev->dev);
+		if ((required_mask > DMA_32BIT_MASK) && !pci_set_dma_mask(pdev,
+		    DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(pdev,
+		    DMA_64BIT_MASK)) {
+			ioc->base_add_sg_single = &base_add_sg_single_64;
+			ioc->sge_size = sizeof(Mpi2SGESimple64_t);
+			desc = "64";
+			goto out;
+		}
+	}
+
+	if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
+	    && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+		ioc->base_add_sg_single = &base_add_sg_single_32;
+		ioc->sge_size = sizeof(Mpi2SGESimple32_t);
+		desc = "32";
+	} else
+		return -ENODEV;
+
+ out:
+	si_meminfo(&s);
+	printk(MPT2SAS_INFO_FMT "%s BIT PCI BUS DMA ADDRESSING SUPPORTED, "
+	    "total mem (%ld kB)\n", ioc->name, desc, convert_to_kb(s.totalram));
+
+	return 0;
+}
+
+/**
+ * base_save_msix_table - backup msix vector table
+ * @ioc: per adapter object
+ *
+ * This address an errata where diag reset clears out the table
+ */
+static void
+base_save_msix_table(struct MPT2SAS_ADAPTER *ioc)
+{
+	int i;
+
+	if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
+		return;
+
+	for (i = 0; i < ioc->msix_vector_count; i++)
+		ioc->msix_table_backup[i] = ioc->msix_table[i];
+}
+
+/**
+ * base_restore_msix_table - this restores the msix vector table
+ * @ioc: per adapter object
+ *
+ */
+static void
+base_restore_msix_table(struct MPT2SAS_ADAPTER *ioc)
+{
+	int i;
+
+	if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
+		return;
+
+	for (i = 0; i < ioc->msix_vector_count; i++)
+		ioc->msix_table[i] = ioc->msix_table_backup[i];
+}
+
+/**
+ * base_check_enable_msix - checks MSIX capabable.
+ * @ioc: per adapter object
+ *
+ * Check to see if card is capable of MSIX, and set number
+ * of avaliable msix vectors
+ */
+static int
+base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)
+{
+	int base;
+	u16 message_control;
+	u32 msix_table_offset;
+
+	base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
+	if (!base) {
+		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not "
+		    "supported\n", ioc->name));
+		return -EINVAL;
+	}
+
+	/* get msix vector count */
+	pci_read_config_word(ioc->pdev, base + 2, &message_control);
+	ioc->msix_vector_count = (message_control & 0x3FF) + 1;
+
+	/* get msix table  */
+	pci_read_config_dword(ioc->pdev, base + 4, &msix_table_offset);
+	msix_table_offset &= 0xFFFFFFF8;
+	ioc->msix_table = (u32 *)((void *)ioc->chip + msix_table_offset);
+
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, "
+	    "vector_count(%d), table_offset(0x%08x), table(%p)\n", ioc->name,
+	    ioc->msix_vector_count, msix_table_offset, ioc->msix_table));
+	return 0;
+}
+
+/**
+ * base_disable_msix - disables msix
+ * @ioc: per adapter object
+ *
+ */
+static void
+base_disable_msix(struct MPT2SAS_ADAPTER *ioc)
+{
+	if (ioc->msix_enable) {
+		pci_disable_msix(ioc->pdev);
+		kfree(ioc->msix_table_backup);
+		ioc->msix_table_backup = NULL;
+		ioc->msix_enable = 0;
+	}
+}
+
+/**
+ * base_enable_msix - enables msix, failback to io_apic
+ * @ioc: per adapter object
+ *
+ */
+static int
+base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
+{
+	struct msix_entry *entries = NULL;
+	int i, r;
+	u8 try_msix = 0;
+
+	if (msix_disable == -1 || msix_disable == 0)
+		try_msix = 1;
+
+	if (!try_msix)
+		goto try_ioapic;
+
+	if (base_check_enable_msix(ioc) != 0)
+		goto try_ioapic;
+
+	entries = kcalloc(ioc->msix_vector_count, sizeof(struct msix_entry),
+	    GFP_KERNEL);
+	if (!entries) {
+		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
+		    "msix_entry failed !!!\n", ioc->name));
+		goto try_ioapic;
+	}
+
+	for (i = 0; i < ioc->msix_vector_count; i++)
+		entries[i].entry = i;
+
+	ioc->msix_table_backup = kcalloc(ioc->msix_vector_count, 4, GFP_KERNEL);
+	if (!ioc->msix_table_backup) {
+		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
+		    "msix_table_backup failed!!!\n", ioc->name));
+		goto try_ioapic;
+	}
+
+	r = pci_enable_msix(ioc->pdev, entries, ioc->msix_vector_count);
+	if (r) {
+		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "pci_enable_msix "
+		    "failed (r=%d) !!!\n", ioc->name, r));
+		goto try_ioapic;
+	}
+
+	/* current HW implemention uses only one interrupt handler */
+	r = request_irq(entries[0].vector, base_interrupt, IRQF_SHARED,
+	    ioc->name, ioc);
+	if (r) {
+		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "unable to allocate "
+		    "interrupt %d !!!\n", ioc->name, entries[0].vector));
+		pci_disable_msix(ioc->pdev);
+		goto try_ioapic;
+	}
+
+	ioc->pci_irq = entries[0].vector;
+	ioc->msix_enable = 1;
+	kfree(entries);
+	return 0;
+
+/* failback to io_apic interrupt routing */
+ try_ioapic:
+	kfree(entries);
+
+	r = request_irq(ioc->pdev->irq, base_interrupt, IRQF_SHARED,
+	    ioc->name, ioc);
+	if (r) {
+		printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n",
+		    ioc->name, ioc->pdev->irq);
+		r = -EBUSY;
+		goto out_fail;
+	}
+
+	ioc->pci_irq = ioc->pdev->irq;
+	return 0;
+
+ out_fail:
+	return r;
+}
+
+/**
+ * base_map_resources - map in controller resources (io/irq/memap)
+ * @ioc: per adapter object
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+base_map_resources(struct MPT2SAS_ADAPTER *ioc)
+{
+	struct pci_dev *pdev = ioc->pdev;
+	u32 memap_sz;
+	u32 pio_sz;
+	int i, r = 0;
+
+	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n",
+	    ioc->name, __func__));
+
+	ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
+	if (pci_enable_device_mem(pdev)) {
+		printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: "
+		    "failed\n", ioc->name);
+		return -ENODEV;
+	}
+
+
+	if (pci_request_selected_regions(pdev, ioc->bars,
+	    MPT2SAS_DRIVER_NAME)) {
+		printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: "
+		    "failed\n", ioc->name);
+		r = -ENODEV;
+		goto out_fail;
+	}
+
+	pci_set_master(pdev);
+
+	if (_base_config_dma_addressing(ioc, pdev) != 0) {
+		printk(MPT2SAS_WARN_FMT "no suitable DMA mask for %s\n",
+		    ioc->name, pci_name(pdev));
+		r = -ENODEV;
+		goto out_fail;
+	}
+
+	for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) {
+		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) {
+			if (pio_sz)
+				continue;
+			ioc->pio_chip = pci_resource_start(pdev, i);
+			pio_sz = pci_resource_len(pdev, i);
+		} else {
+			if (memap_sz)
+				continue;
+			ioc->chip_phys = pci_resource_start(pdev, i);
+			memap_sz = pci_resource_len(pdev, i);
+			ioc->chip = ioremap(ioc->chip_phys, memap_sz);
+			if (ioc->chip == NULL) {
+				printk(MPT2SAS_ERR_FMT "unable to map adapter "
+				    "memory!\n", ioc->name);
+				r = -EINVAL;
+				goto out_fail;
+			}
+		}
+	}
+
+	pci_set_drvdata(pdev, ioc->shost);
+	_base_mask_interrupts(ioc);
+	r = base_enable_msix(ioc);
+	if (r)
+		goto out_fail;
+
+	printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n",
+	    ioc->name,  ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
+	    "IO-APIC enabled"), ioc->pci_irq);
+	printk(MPT2SAS_INFO_FMT "iomem(0x%lx), mapped(0x%p), size(%d)\n",
+	    ioc->name, ioc->chip_phys, ioc->chip, memap_sz);
+	printk(MPT2SAS_INFO_FMT "ioport(0x%lx), size(%d)\n",
+	    ioc->name, ioc->pio_chip, pio_sz);
+
+	return 0;
+
+ out_fail:
+	if (ioc->chip_phys)
+		iounmap(ioc->chip);
+	ioc->chip_phys = 0;
+	ioc->pci_irq = -1;
+	pci_release_selected_regions(ioc->pdev, ioc->bars);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	return r;
+}
+
+/**
+ * base_get_msg_frame_dma - obtain request mf pointer phys addr
+ * @ioc: per adapter object
+ * @smid: system request message index(smid zero is invalid)
+ *
+ * Returns phys pointer to message frame.
+ */
+dma_addr_t
+base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+	return ioc->request_dma + (smid * ioc->request_sz);
+}
+
+/**
+ * base_get_msg_frame - obtain request mf pointer
+ * @ioc: per adapter object
+ * @smid: system request message index(smid zero is invalid)
+ *
+ * Returns virt pointer to message frame.
+ */
+void *
+base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+	return (void *)(ioc->request + (smid * ioc->request_sz));
+}
+
+/**
+ * base_get_sense_buffer - obtain a sense buffer assigned to a mf request
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns virt pointer to sense buffer.
+ */
+void *
+base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+	return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE));
+}
+
+/**
+ * base_get_sense_buffer_dma - obtain a sense buffer assigned to a mf request
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns phys pointer to sense buffer.
+ */
+dma_addr_t
+base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+	return ioc->sense_dma + ((smid - 1) * SCSI_SENSE_BUFFERSIZE);
+}
+
+/**
+ * base_get_reply_virt_addr - obtain reply frames virt address
+ * @ioc: per adapter object
+ * @phys_addr: lower 32 physical addr of the reply
+ *
+ * Converts 32bit lower physical addr into a virt address.
+ */
+void *
+base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr)
+{
+	if (!phys_addr)
+		return NULL;
+	return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
+}
+
+/**
+ * base_get_smid - obtain a free smid
+ * @ioc: per adapter object
+ * @cb_idx: callback index
+ *
+ * Returns smid (zero is invalid)
+ */
+u16
+base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)
+{
+	unsigned long flags;
+	struct request_tracker *request;
+	u16 smid;
+
+	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+	if (list_empty(&ioc->free_list)) {
+		spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+		printk(MPT2SAS_ERR_FMT "%s: smid not available\n",
+		    ioc->name, __func__);
+		return 0;
+	}
+
+	request = list_entry(ioc->free_list.next,
+	    struct request_tracker, tracker_list);
+	request->cb_idx = cb_idx;
+	smid = request->smid;
+	list_del(&request->tracker_list);
+	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+	return smid;
+}
+
+
+/**
+ * base_free_smid - put smid back on free_list
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Return nothing.
+ */
+void
+base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+	ioc->scsi_lookup[smid - 1].cb_idx = 0xFF;
+	list_add_tail(&ioc->scsi_lookup[smid - 1].tracker_list,
+	    &ioc->free_list);
+	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+	/*
+	 * See _wait_for_commands_to_complete() call with regards to this code.
+	 */
+	if (ioc->shost_recovery && ioc->pending_io_count) {
+		if (ioc->pending_io_count == 1)
+			wake_up(&ioc->reset_wq);
+		ioc->pending_io_count--;
+	}
+}
+
+/**
+ * _base_writeq - 64 bit write to MMIO
+ * @ioc: per adapter object
+ * @b: data payload
+ * @addr: address in MMIO space
+ * @writeq_lock: spin lock
+ *
+ * Glue for handling an atomic 64 bit word to MMIO. This special handling takes
+ * care of 32 bit environment where its not quarenteed to send the entire word
+ * in one transfer.
+ */
+#ifndef writeq
+static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
+    spinlock_t *writeq_lock)
+{
+	unsigned long flags;
+	__u64 data_out = cpu_to_le64(b);
+
+	spin_lock_irqsave(writeq_lock, flags);
+	writel((u32)(data_out), addr);
+	writel((u32)(data_out >> 32), (addr + 4));
+	spin_unlock_irqrestore(writeq_lock, flags);
+}
+#else
+static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
+    spinlock_t *writeq_lock)
+{
+	writeq(cpu_to_le64(b), addr);
+}
+#endif
+
+/**
+ * base_put_smid_scsi_io - send SCSI_IO request to firmware
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ * @handle: device handle
+ *
+ * Return nothing.
+ */
+void
+base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
+    u16 handle)
+{
+	Mpi2RequestDescriptorUnion_t descriptor;
+	u64 *request = (u64 *)&descriptor;
+
+
+	descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+	descriptor.SCSIIO.VF_ID = vf_id;
+	descriptor.SCSIIO.SMID = cpu_to_le16(smid);
+	descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
+	descriptor.SCSIIO.LMID = 0;
+	_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+	    &ioc->scsi_lookup_lock);
+}
+
+
+/**
+ * base_put_smid_hi_priority - send Task Managment request to firmware
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ *
+ * Return nothing.
+ */
+void
+base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id)
+{
+	Mpi2RequestDescriptorUnion_t descriptor;
+	u64 *request = (u64 *)&descriptor;
+
+	descriptor.HighPriority.RequestFlags =
+	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+	descriptor.HighPriority.VF_ID = vf_id;
+	descriptor.HighPriority.SMID = cpu_to_le16(smid);
+	descriptor.HighPriority.LMID = 0;
+	descriptor.HighPriority.Reserved1 = 0;
+	_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+	    &ioc->scsi_lookup_lock);
+}
+
+/**
+ * base_put_smid_default - Default, primarily used for config pages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ *
+ * Return nothing.
+ */
+void
+base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id)
+{
+	Mpi2RequestDescriptorUnion_t descriptor;
+	u64 *request = (u64 *)&descriptor;
+
+	descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+	descriptor.Default.VF_ID = vf_id;
+	descriptor.Default.SMID = cpu_to_le16(smid);
+	descriptor.Default.LMID = 0;
+	descriptor.Default.DescriptorTypeDependent = 0;
+	_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+	    &ioc->scsi_lookup_lock);
+}
+
+/**
+ * base_put_smid_target_assist - send Target Assist/Status to firmware
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ * @io_index: value used to track the IO
+ *
+ * Return nothing.
+ */
+void
+base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
+    u16 io_index)
+{
+	Mpi2RequestDescriptorUnion_t descriptor;
+	u64 *request = (u64 *)&descriptor;
+
+	descriptor.SCSITarget.RequestFlags =
+	    MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET;
+	descriptor.SCSITarget.VF_ID = vf_id;
+	descriptor.SCSITarget.SMID = cpu_to_le16(smid);
+	descriptor.SCSITarget.LMID = 0;
+	descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index);
+	_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+	    &ioc->scsi_lookup_lock);
+}
+
+/**
+ * _base_display_ioc_capabilities - Disply IOC's capabilities.
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
+{
+	int i = 0;
+	char desc[16];
+	u8 revision;
+	u32 iounit_pg1_flags;
+
+	pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision);
+	strncpy(desc, ioc->manu_pg0.ChipName, 16);
+	printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "
+	   "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n",
+	    ioc->name, desc,
+	   (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
+	   (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
+	   (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
+	   ioc->facts.FWVersion.Word & 0x000000FF,
+	   revision,
+	   (ioc->bios_pg3.BiosVersion & 0xFF000000) >> 24,
+	   (ioc->bios_pg3.BiosVersion & 0x00FF0000) >> 16,
+	   (ioc->bios_pg3.BiosVersion & 0x0000FF00) >> 8,
+	    ioc->bios_pg3.BiosVersion & 0x000000FF);
+
+	printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name);
+
+	if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) {
+		printk("Initiator");
+		i++;
+	}
+
+	if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) {
+		printk("%sTarget", i ? "," : "");
+		i++;
+	}
+
+	i = 0;
+	printk("), ");
+	printk("Capabilities=(");
+
+	if (ioc->facts.IOCCapabilities &
+	    MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
+		printk("Raid");
+		i++;
+	}
+
+	if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) {
+		printk("%sTLR", i ? "," : "");
+		i++;
+	}
+
+	if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) {
+		printk("%sMulticast", i ? "," : "");
+		i++;
+	}
+
+	if (ioc->facts.IOCCapabilities &
+	    MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) {
+		printk("%sBIDI Target", i ? "," : "");
+		i++;
+	}
+
+	if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) {
+		printk("%sEEDP", i ? "," : "");
+		i++;
+	}
+
+	if (ioc->facts.IOCCapabilities &
+	    MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) {
+		printk("%sSnapshot Buffer", i ? "," : "");
+		i++;
+	}
+
+	if (ioc->facts.IOCCapabilities &
+	    MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
+		printk("%sDiag Trace Buffer", i ? "," : "");
+		i++;
+	}
+
+	if (ioc->facts.IOCCapabilities &
+	    MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) {
+		printk("%sTask Set Full", i ? "," : "");
+		i++;
+	}
+
+	iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
+	if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) {
+		printk("%sNCQ", i ? "," : "");
+		i++;
+	}
+
+	printk(")\n");
+}
+
+/**
+ * _base_static_config_pages - static start of day config pages
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
+{
+	Mpi2ConfigReply_t mpi_reply;
+	u32 iounit_pg1_flags;
+
+	config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0);
+	config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
+	config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
+	config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
+	config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0);
+	config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+	_base_display_ioc_capabilities(ioc);
+
+	/*
+	 * Enable task_set_full handling in iounit_pg1 when the
+	 * facts capabilities indicate that its supported.
+	 */
+	iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
+	if ((ioc->facts.IOCCapabilities &
+	    MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING))
+		iounit_pg1_flags &=
+		    ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
+	else
+		iounit_pg1_flags |=
+		    MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
+	ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
+	config_set_iounit_pg1(ioc, &mpi_reply, ioc->iounit_pg1);
+}
+
+/**
+ * _base_release_memory_pools - release memory
+ * @ioc: per adapter object
+ *
+ * Free memory allocated from _base_allocate_memory_pools.
+ *
+ * Return nothing.
+ */
+static void
+_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
+{
+	dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	    __func__));
+
+	if (ioc->request) {
+		pci_free_consistent(ioc->pdev, ioc->request_dma_sz,
+		    ioc->request,  ioc->request_dma);
+		dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "request_pool(0x%p)"
+		    ": free\n", ioc->name, ioc->request));
+		ioc->request = NULL;
+	}
+
+	if (ioc->sense) {
+		pci_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma);
+		if (ioc->sense_dma_pool)
+			pci_pool_destroy(ioc->sense_dma_pool);
+		dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_pool(0x%p)"
+		    ": free\n", ioc->name, ioc->sense));
+		ioc->sense = NULL;
+	}
+
+	if (ioc->reply) {
+		pci_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma);
+		if (ioc->reply_dma_pool)
+			pci_pool_destroy(ioc->reply_dma_pool);
+		dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_pool(0x%p)"
+		     ": free\n", ioc->name, ioc->reply));
+		ioc->reply = NULL;
+	}
+
+	if (ioc->reply_free) {
+		pci_pool_free(ioc->reply_free_dma_pool, ioc->reply_free,
+		    ioc->reply_free_dma);
+		if (ioc->reply_free_dma_pool)
+			pci_pool_destroy(ioc->reply_free_dma_pool);
+		dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_pool"
+		    "(0x%p): free\n", ioc->name, ioc->reply_free));
+		ioc->reply_free = NULL;
+	}
+
+	if (ioc->reply_post_free) {
+		pci_pool_free(ioc->reply_post_free_dma_pool,
+		    ioc->reply_post_free, ioc->reply_post_free_dma);
+		if (ioc->reply_post_free_dma_pool)
+			pci_pool_destroy(ioc->reply_post_free_dma_pool);
+		dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "reply_post_free_pool(0x%p): free\n", ioc->name,
+		    ioc->reply_post_free));
+		ioc->reply_post_free = NULL;
+	}
+
+	if (ioc->config_page) {
+		dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "config_page(0x%p): free\n", ioc->name,
+		    ioc->config_page));
+		pci_free_consistent(ioc->pdev, ioc->config_page_sz,
+		    ioc->config_page, ioc->config_page_dma);
+	}
+
+	kfree(ioc->scsi_lookup);
+}
+
+
+/**
+ * _base_allocate_memory_pools - allocate start of day memory pools
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 success, anything else error
+ */
+static int
+_base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
+{
+	Mpi2IOCFactsReply_t *facts;
+	u32 queue_size, queue_diff;
+	u16 max_sge_elements;
+	u16 num_of_reply_frames;
+	u16 chains_needed_per_io;
+	u32 sz, total_sz;
+	u16 i;
+	u32 retry_sz;
+	u16 max_request_credit;
+
+	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	    __func__));
+
+	retry_sz = 0;
+	facts = &ioc->facts;
+
+	/* command line tunables  for max sgl entries */
+	if (max_sgl_entries != -1) {
+		ioc->shost->sg_tablesize = (max_sgl_entries <
+		    MPT2SAS_SG_DEPTH) ? max_sgl_entries :
+		    MPT2SAS_SG_DEPTH;
+	} else {
+		ioc->shost->sg_tablesize = MPT2SAS_SG_DEPTH;
+	}
+
+	/* command line tunables  for max controller queue depth */
+	if (max_queue_depth != -1) {
+		max_request_credit = (max_queue_depth < facts->RequestCredit)
+		    ? max_queue_depth : facts->RequestCredit;
+	} else {
+		max_request_credit = (facts->RequestCredit >
+		    MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE :
+		    facts->RequestCredit;
+	}
+	ioc->request_depth = max_request_credit;
+
+	/* request frame size */
+	ioc->request_sz = facts->IOCRequestFrameSize * 4;
+
+	/* reply frame size */
+	ioc->reply_sz = facts->ReplyFrameSize * 4;
+
+ retry_allocation:
+	total_sz = 0;
+	/* calculate number of sg elements left over in the 1st frame */
+	max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) -
+	    sizeof(Mpi2SGEIOUnion_t)) + ioc->sge_size);
+	ioc->max_sges_in_main_message = max_sge_elements/ioc->sge_size;
+
+	/* now do the same for a chain buffer */
+	max_sge_elements = ioc->request_sz - ioc->sge_size;
+	ioc->max_sges_in_chain_message = max_sge_elements/ioc->sge_size;
+
+	ioc->chain_offset_value_for_main_message =
+	    ((sizeof(Mpi2SCSIIORequest_t) - sizeof(Mpi2SGEIOUnion_t)) +
+	     (ioc->max_sges_in_chain_message * ioc->sge_size)) / 4;
+
+	/*
+	 *  MPT2SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE
+	 */
+	chains_needed_per_io = ((ioc->shost->sg_tablesize -
+	   ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message)
+	    + 1;
+	if (chains_needed_per_io > facts->MaxChainDepth) {
+		chains_needed_per_io = facts->MaxChainDepth;
+		ioc->shost->sg_tablesize = min_t(u16,
+		ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message
+		* chains_needed_per_io), ioc->shost->sg_tablesize);
+	}
+	ioc->chains_needed_per_io = chains_needed_per_io;
+
+	/* reply free queue sizing - taking into account for events */
+	num_of_reply_frames = ioc->request_depth + 32;
+
+	/* number of replies frames can't be a multiple of 16 */
+	/* decrease number of reply frames by 1 */
+	if (!(num_of_reply_frames % 16))
+		num_of_reply_frames--;
+
+	/* calculate number of reply free queue entries
+	 *  (must be multiple of 16)
+	 */
+
+	/* (we know reply_free_queue_depth is not a multiple of 16) */
+	queue_size = num_of_reply_frames;
+	queue_size += 16 - (queue_size % 16);
+	ioc->reply_free_queue_depth = queue_size;
+
+	/* reply descriptor post queue sizing */
+	/* this size should be the number of request frames + number of reply
+	 * frames
+	 */
+
+	queue_size = ioc->request_depth + num_of_reply_frames + 1;
+	/* round up to 16 byte boundary */
+	if (queue_size % 16)
+		queue_size += 16 - (queue_size % 16);
+
+	/* check against IOC maximum reply post queue depth */
+	if (queue_size > facts->MaxReplyDescriptorPostQueueDepth) {
+		queue_diff = queue_size -
+		    facts->MaxReplyDescriptorPostQueueDepth;
+
+		/* round queue_diff up to multiple of 16 */
+		if (queue_diff % 16)
+			queue_diff += 16 - (queue_diff % 16);
+
+		/* adjust request_depth, reply_free_queue_depth,
+		 * and queue_size
+		 */
+		ioc->request_depth -= queue_diff;
+		ioc->reply_free_queue_depth -= queue_diff;
+		queue_size -= queue_diff;
+	}
+	ioc->reply_post_queue_depth = queue_size;
+
+	/* max scsi host queue depth */
+	ioc->shost->can_queue = ioc->request_depth - INTERNAL_CMDS_COUNT;
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host queue: depth"
+	    "(%d)\n", ioc->name, ioc->shost->can_queue));
+
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: "
+	    "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), "
+	    "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message,
+	    ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
+	    ioc->chains_needed_per_io));
+
+	/* contiguous pool for request and chains, 16 byte align, one extra "
+	 * "frame for smid=0
+	 */
+	ioc->chain_depth = ioc->chains_needed_per_io * ioc->request_depth;
+	sz = ((ioc->request_depth + 1 + ioc->chain_depth) * ioc->request_sz);
+
+	ioc->request_dma_sz = sz;
+	ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma);
+	if (!ioc->request) {
+		printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
+		    "failed: req_depth(%d), chains_per_io(%d), frame_sz(%d), "
+		    "total(%d kB)\n", ioc->name, ioc->request_depth,
+		    ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
+		if (ioc->request_depth < MPT2SAS_SAS_QUEUE_DEPTH)
+			goto out;
+		retry_sz += 64;
+		ioc->request_depth = max_request_credit - retry_sz;
+		goto retry_allocation;
+	}
+
+	if (retry_sz)
+		printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
+		    "succeed: req_depth(%d), chains_per_io(%d), frame_sz(%d), "
+		    "total(%d kb)\n", ioc->name, ioc->request_depth,
+		    ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
+
+	ioc->chain = ioc->request + ((ioc->request_depth + 1) *
+	    ioc->request_sz);
+	ioc->chain_dma = ioc->request_dma + ((ioc->request_depth + 1) *
+	    ioc->request_sz);
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): "
+	    "depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
+	    ioc->request, ioc->request_depth, ioc->request_sz,
+	    ((ioc->request_depth + 1) * ioc->request_sz)/1024));
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth"
+	    "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain,
+	    ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
+	    ioc->request_sz))/1024));
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n",
+	    ioc->name, (unsigned long long) ioc->request_dma));
+	total_sz += sz;
+
+	ioc->scsi_lookup = kcalloc(ioc->request_depth,
+	    sizeof(struct request_tracker), GFP_KERNEL);
+	if (!ioc->scsi_lookup) {
+		printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n",
+		    ioc->name);
+		goto out;
+	}
+
+	 /* initialize some bits */
+	for (i = 0; i < ioc->request_depth; i++)
+		ioc->scsi_lookup[i].smid = i + 1;
+
+	/* sense buffers, 4 byte align */
+	sz = ioc->request_depth * SCSI_SENSE_BUFFERSIZE;
+	ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4,
+	    0);
+	if (!ioc->sense_dma_pool) {
+		printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_create failed\n",
+		    ioc->name);
+		goto out;
+	}
+	ioc->sense = pci_pool_alloc(ioc->sense_dma_pool , GFP_KERNEL,
+	    &ioc->sense_dma);
+	if (!ioc->sense) {
+		printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_alloc failed\n",
+		    ioc->name);
+		goto out;
+	}
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+	    "sense pool(0x%p): depth(%d), element_size(%d), pool_size"
+	    "(%d kB)\n", ioc->name, ioc->sense, ioc->request_depth,
+	    SCSI_SENSE_BUFFERSIZE, sz/1024));
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_dma(0x%llx)\n",
+	    ioc->name, (unsigned long long)ioc->sense_dma));
+	total_sz += sz;
+
+	/* reply pool, 4 byte align */
+	sz = ioc->reply_free_queue_depth * ioc->reply_sz;
+	ioc->reply_dma_pool = pci_pool_create("reply pool", ioc->pdev, sz, 4,
+	    0);
+	if (!ioc->reply_dma_pool) {
+		printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_create failed\n",
+		    ioc->name);
+		goto out;
+	}
+	ioc->reply = pci_pool_alloc(ioc->reply_dma_pool , GFP_KERNEL,
+	    &ioc->reply_dma);
+	if (!ioc->reply) {
+		printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_alloc failed\n",
+		    ioc->name);
+		goto out;
+	}
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply pool(0x%p): depth"
+	    "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->reply,
+	    ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024));
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_dma(0x%llx)\n",
+	    ioc->name, (unsigned long long)ioc->reply_dma));
+	total_sz += sz;
+
+	/* reply free queue, 16 byte align */
+	sz = ioc->reply_free_queue_depth * 4;
+	ioc->reply_free_dma_pool = pci_pool_create("reply_free pool",
+	    ioc->pdev, sz, 16, 0);
+	if (!ioc->reply_free_dma_pool) {
+		printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_create "
+		    "failed\n", ioc->name);
+		goto out;
+	}
+	ioc->reply_free = pci_pool_alloc(ioc->reply_free_dma_pool , GFP_KERNEL,
+	    &ioc->reply_free_dma);
+	if (!ioc->reply_free) {
+		printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_alloc "
+		    "failed\n", ioc->name);
+		goto out;
+	}
+	memset(ioc->reply_free, 0, sz);
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free pool(0x%p): "
+	    "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name,
+	    ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024));
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_dma"
+	    "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
+	total_sz += sz;
+
+	/* reply post queue, 16 byte align */
+	sz = ioc->reply_post_queue_depth * sizeof(Mpi2DefaultReplyDescriptor_t);
+	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
+	    ioc->pdev, sz, 16, 0);
+	if (!ioc->reply_post_free_dma_pool) {
+		printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create "
+		    "failed\n", ioc->name);
+		goto out;
+	}
+	ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
+	    GFP_KERNEL, &ioc->reply_post_free_dma);
+	if (!ioc->reply_post_free) {
+		printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc "
+		    "failed\n", ioc->name);
+		goto out;
+	}
+	memset(ioc->reply_post_free, 0, sz);
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
+	    "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
+	    ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
+	    sz/1024));
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = "
+	    "(0x%llx)\n", ioc->name, (unsigned long long)
+	    ioc->reply_post_free_dma));
+	total_sz += sz;
+
+	ioc->config_page_sz = 512;
+	ioc->config_page = pci_alloc_consistent(ioc->pdev,
+	    ioc->config_page_sz, &ioc->config_page_dma);
+	if (!ioc->config_page) {
+		printk(MPT2SAS_ERR_FMT "config page: pci_pool_alloc "
+		    "failed\n", ioc->name);
+		goto out;
+	}
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size"
+	    "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz));
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma"
+	    "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma));
+	total_sz += ioc->config_page_sz;
+
+	printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n",
+	    ioc->name, total_sz/1024);
+	printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), "
+	    "Max Controller Queue Depth(%d)\n",
+	    ioc->name, ioc->shost->can_queue, facts->RequestCredit);
+	printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n",
+	    ioc->name, ioc->shost->sg_tablesize);
+	return 0;
+
+ out:
+	_base_release_memory_pools(ioc);
+	return -ENOMEM;
+}
+
+
+/**
+ * base_get_iocstate - Get the current state of a MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @cooked: Request raw or cooked IOC state
+ *
+ * Returns all IOC Doorbell register bits if cooked==0, else just the
+ * Doorbell bits in MPI_IOC_STATE_MASK.
+ */
+u32
+base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked)
+{
+	u32 s, sc;
+
+	s = readl(&ioc->chip->Doorbell);
+	sc = s & MPI2_IOC_STATE_MASK;
+	return cooked ? sc : s;
+}
+
+/**
+ * _base_wait_on_iocstate - waiting on a particular ioc state
+ * @ioc_state: controller state { READY, OPERATIONAL, or RESET }
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_wait_on_iocstate(struct MPT2SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
+    int sleep_flag)
+{
+	u32 count, cntdn;
+	u32 current_state;
+
+	count = 0;
+	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+	do {
+		current_state = base_get_iocstate(ioc, 1);
+		if (current_state == ioc_state)
+			return 0;
+		if (count && current_state == MPI2_IOC_STATE_FAULT)
+			break;
+		if (sleep_flag == CAN_SLEEP)
+			msleep(1);
+		else
+			udelay(500);
+		count++;
+	} while (--cntdn);
+
+	return current_state;
+}
+
+/**
+ * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
+ * a write to the doorbell)
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_DOORBELL_INTERRUPT - set to one when IOC writes to doorbell.
+ */
+static int
+_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
+    int sleep_flag)
+{
+	u32 cntdn, count;
+	u32 int_status;
+
+	count = 0;
+	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+	do {
+		int_status = readl(&ioc->chip->HostInterruptStatus);
+		if (int_status & MPI2_HIS_DOORBELL_INTERRUPT) {
+			dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+			    "successfull count(%d), timeout(%d)\n", ioc->name,
+			    __func__, count, timeout));
+			return 0;
+		}
+		if (sleep_flag == CAN_SLEEP)
+			msleep(1);
+		else
+			udelay(500);
+		count++;
+	} while (--cntdn);
+
+	printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
+	    "int_status(%x)!\n", ioc->name, __func__, count, int_status);
+	return -EFAULT;
+}
+
+/**
+ * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_IOP_DOORBELL_STATUS - set to one when host writes to
+ * doorbell.
+ */
+static int
+_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
+    int sleep_flag)
+{
+	u32 cntdn, count;
+	u32 int_status;
+	u32 doorbell;
+
+	count = 0;
+	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+	do {
+		int_status = readl(&ioc->chip->HostInterruptStatus);
+		if (!(int_status & MPI2_HIS_IOP_DOORBELL_STATUS)) {
+			dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+			    "successfull count(%d), timeout(%d)\n", ioc->name,
+			    __func__, count, timeout));
+			return 0;
+		} else if (int_status & MPI2_HIS_DOORBELL_INTERRUPT) {
+			doorbell = readl(&ioc->chip->Doorbell);
+			if ((doorbell & MPI2_IOC_STATE_MASK) ==
+			    MPI2_IOC_STATE_FAULT) {
+				base_fault_info(ioc , doorbell);
+				return -EFAULT;
+			}
+		} else if (int_status == 0xFFFFFFFF)
+			goto out;
+
+		if (sleep_flag == CAN_SLEEP)
+			msleep(1);
+		else
+			udelay(500);
+		count++;
+	} while (--cntdn);
+
+ out:
+	printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
+	    "int_status(%x)!\n", ioc->name, __func__, count, int_status);
+	return -EFAULT;
+}
+
+#if defined(MUR)
+/**
+ * _base_send_ioc_reset - send doorbell reset
+ * @ioc: per adapter object
+ * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_send_ioc_reset(struct MPT2SAS_ADAPTER *ioc, u8 reset_type, int timeout,
+    int sleep_flag)
+{
+	u32 ioc_state;
+	int r = 0;
+
+	if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) {
+		printk(MPT2SAS_ERR_FMT "%s: unknown reset_type\n",
+		    ioc->name, __func__);
+		return -EFAULT;
+	}
+
+	if (!(ioc->facts.IOCCapabilities &
+	   MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY))
+		return -EFAULT;
+
+	printk(MPT2SAS_INFO_FMT "sending message unit reset !!\n", ioc->name);
+
+	writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT,
+	    &ioc->chip->Doorbell);
+	if ((_base_wait_for_doorbell_ack(ioc, 15, sleep_flag))) {
+		r = -EFAULT;
+		goto out;
+	}
+	ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY,
+	    timeout, sleep_flag);
+	if (ioc_state) {
+		printk(MPT2SAS_ERR_FMT "%s: failed going to ready state "
+		    " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
+		r = -EFAULT;
+		goto out;
+	}
+ out:
+	printk(MPT2SAS_INFO_FMT "message unit reset: %s\n",
+	    ioc->name, ((r == 0) ? "SUCCESS" : "FAILED"));
+	return r;
+}
+#endif
+
+/**
+ * _base_handshake_req_reply_wait - send request thru doorbell interface
+ * @ioc: per adapter object
+ * @request_bytes: request length
+ * @request: pointer having request payload
+ * @reply_bytes: reply length
+ * @reply: pointer to reply payload
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
+    u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
+{
+	MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
+	int i;
+	u8 failed;
+	u16 dummy;
+	u32 *mfp;
+
+	/* make sure doorbell is not in use */
+	if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
+		printk(MPT2SAS_ERR_FMT "doorbell is in use "
+		    " (line=%d)\n", ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* clear pending doorbell interrupts from previous state changes */
+	if (readl(&ioc->chip->HostInterruptStatus) &
+	    MPI2_HIS_IOC2SYS_DB_STATUS)
+		writel(0, &ioc->chip->HostInterruptStatus);
+
+	/* send message to ioc */
+	writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
+	    ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
+	    &ioc->chip->Doorbell);
+
+	if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+		printk(MPT2SAS_ERR_FMT "doorbell handshake "
+		   "int failed (line=%d)\n", ioc->name, __LINE__);
+		return -EFAULT;
+	}
+	writel(0, &ioc->chip->HostInterruptStatus);
+
+	if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
+		printk(MPT2SAS_ERR_FMT "doorbell handshake "
+		    "ack failed (line=%d)\n", ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* send message 32-bits at a time */
+	for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
+		writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
+		if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
+			failed = 1;
+	}
+
+	if (failed) {
+		printk(MPT2SAS_ERR_FMT "doorbell handshake "
+		    "sending request failed (line=%d)\n", ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* now wait for the reply */
+	if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
+		printk(MPT2SAS_ERR_FMT "doorbell handshake "
+		   "int failed (line=%d)\n", ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* read the first two 16-bits, it gives the total length of the reply */
+	reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+	    & MPI2_DOORBELL_DATA_MASK);
+	writel(0, &ioc->chip->HostInterruptStatus);
+	if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+		printk(MPT2SAS_ERR_FMT "doorbell handshake "
+		   "int failed (line=%d)\n", ioc->name, __LINE__);
+		return -EFAULT;
+	}
+	reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+	    & MPI2_DOORBELL_DATA_MASK);
+	writel(0, &ioc->chip->HostInterruptStatus);
+
+	for (i = 2; i < default_reply->MsgLength * 2; i++)  {
+		if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+			printk(MPT2SAS_ERR_FMT "doorbell "
+			    "handshake int failed (line=%d)\n", ioc->name,
+			    __LINE__);
+			return -EFAULT;
+		}
+		if (i >=  reply_bytes/2) /* overflow case */
+			dummy = readl(&ioc->chip->Doorbell);
+		else
+			reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+			    & MPI2_DOORBELL_DATA_MASK);
+		writel(0, &ioc->chip->HostInterruptStatus);
+	}
+
+	_base_wait_for_doorbell_int(ioc, 5, sleep_flag);
+	if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
+		dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "doorbell is in use "
+		    " (line=%d)\n", ioc->name, __LINE__));
+	}
+
+	if (ioc->logging_level & MPT_DEBUG_INIT) {
+		mfp = (u32 *)reply;
+		printk(KERN_DEBUG "\toffset:data\n");
+		for (i = 0; i < reply_bytes/4; i++)
+			printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+			    le32_to_cpu(mfp[i]));
+	}
+	return 0;
+}
+
+/**
+ * base_sas_iounit_control - send sas iounit control to FW
+ * @ioc: per adapter object
+ * @mpi_reply: the reply payload from FW
+ * @mpi_request: the request payload sent to FW
+ *
+ * The SAS IO Unit Control Request message allows the host to perform low-level
+ * operations, such as resets on the PHYs of the IO Unit, also allows the host
+ * to obtain the IOC assigned device handles for a device if it has other
+ * identifying information about the device, in addition allows the host to
+ * remove IOC resources associated with the device.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, Mpi2SasIoUnitControlReply_t
+    *mpi_reply, Mpi2SasIoUnitControlRequest_t *mpi_request)
+{
+	u16 smid;
+	u32 ioc_state;
+	unsigned long timeleft;
+	u8 issue_reset;
+	int rc;
+	void *request;
+	u16 wait_state_count;
+
+	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	    __func__));
+
+	mutex_lock(&ioc->base_cmds.mutex);
+
+	if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) {
+		printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n",
+		    ioc->name, __func__);
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	wait_state_count = 0;
+	ioc_state = base_get_iocstate(ioc, 1);
+	while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+		if (wait_state_count++ == 10) {
+			printk(MPT2SAS_ERR_FMT
+			    "%s: failed due to ioc not operational\n",
+			    ioc->name, __func__);
+			rc = -EFAULT;
+			goto out;
+		}
+		ssleep(1);
+		ioc_state = base_get_iocstate(ioc, 1);
+		printk(MPT2SAS_INFO_FMT "%s: waiting for "
+		    "operational state(count=%d)\n", ioc->name,
+		    __func__, wait_state_count);
+	}
+
+	smid = base_get_smid(ioc, ioc->base_cb_idx);
+	if (!smid) {
+		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+		    ioc->name, __func__);
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	rc = 0;
+	ioc->base_cmds.status = MPT2_CMD_PENDING;
+	request = base_get_msg_frame(ioc, smid);
+	ioc->base_cmds.smid = smid;
+	memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t));
+	if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
+	    mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
+		ioc->ioc_link_reset_in_progress = 1;
+	base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
+	    msecs_to_jiffies(10000));
+	if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
+	    mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) &&
+	    ioc->ioc_link_reset_in_progress)
+		ioc->ioc_link_reset_in_progress = 0;
+	if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+		printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+		    ioc->name, __func__);
+		_debug_dump_mf(mpi_request,
+		    sizeof(Mpi2SasIoUnitControlRequest_t)/4);
+		if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
+			issue_reset = 1;
+		goto issue_host_reset;
+	}
+	if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
+		memcpy(mpi_reply, ioc->base_cmds.reply,
+		    sizeof(Mpi2SasIoUnitControlReply_t));
+	else
+		memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t));
+	ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+	goto out;
+
+ issue_host_reset:
+	if (issue_reset)
+		base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
+	ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+	rc = -EFAULT;
+ out:
+	mutex_unlock(&ioc->base_cmds.mutex);
+	return rc;
+}
+
+
+/**
+ * base_scsi_enclosure_processor - sending request to sep device
+ * @ioc: per adapter object
+ * @mpi_reply: the reply payload from FW
+ * @mpi_request: the request payload sent to FW
+ *
+ * The SCSI Enclosure Processor request message causes the IOC to
+ * communicate with SES devices to control LED status signals.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, Mpi2SepReply_t
+    *mpi_reply, Mpi2SepRequest_t *mpi_request)
+{
+	u16 smid;
+	u32 ioc_state;
+	unsigned long timeleft;
+	u8 issue_reset;
+	int rc;
+	void *request;
+	u16 wait_state_count;
+
+	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	    __func__));
+
+	mutex_lock(&ioc->base_cmds.mutex);
+
+	if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) {
+		printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n",
+		    ioc->name, __func__);
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	wait_state_count = 0;
+	ioc_state = base_get_iocstate(ioc, 1);
+	while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+		if (wait_state_count++ == 10) {
+			printk(MPT2SAS_ERR_FMT
+			    "%s: failed due to ioc not operational\n",
+			    ioc->name, __func__);
+			rc = -EFAULT;
+			goto out;
+		}
+		ssleep(1);
+		ioc_state = base_get_iocstate(ioc, 1);
+		printk(MPT2SAS_INFO_FMT "%s: waiting for "
+		    "operational state(count=%d)\n", ioc->name,
+		    __func__, wait_state_count);
+	}
+
+	smid = base_get_smid(ioc, ioc->base_cb_idx);
+	if (!smid) {
+		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+		    ioc->name, __func__);
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	rc = 0;
+	ioc->base_cmds.status = MPT2_CMD_PENDING;
+	request = base_get_msg_frame(ioc, smid);
+	ioc->base_cmds.smid = smid;
+	memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
+	base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
+	    msecs_to_jiffies(10000));
+	if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+		printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+		    ioc->name, __func__);
+		_debug_dump_mf(mpi_request,
+		    sizeof(Mpi2SepRequest_t)/4);
+		if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
+			issue_reset = 1;
+		goto issue_host_reset;
+	}
+	if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
+		memcpy(mpi_reply, ioc->base_cmds.reply,
+		    sizeof(Mpi2SepReply_t));
+	else
+		memset(mpi_reply, 0, sizeof(Mpi2SepReply_t));
+	ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+	goto out;
+
+ issue_host_reset:
+	if (issue_reset)
+		base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
+	ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+	rc = -EFAULT;
+ out:
+	mutex_unlock(&ioc->base_cmds.mutex);
+	return rc;
+}
+
+/**
+ * _base_get_port_facts - obtain port facts reply and save in ioc
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)
+{
+	Mpi2PortFactsRequest_t mpi_request;
+	Mpi2PortFactsReply_t mpi_reply, *pfacts;
+	int mpi_reply_sz, mpi_request_sz, r;
+
+	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	    __func__));
+
+	mpi_reply_sz = sizeof(Mpi2PortFactsReply_t);
+	mpi_request_sz = sizeof(Mpi2PortFactsRequest_t);
+	memset(&mpi_request, 0, mpi_request_sz);
+	mpi_request.Function = MPI2_FUNCTION_PORT_FACTS;
+	mpi_request.PortNumber = port;
+	r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
+	    (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
+
+	if (r != 0) {
+		printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
+		    ioc->name, __func__, r);
+		return r;
+	}
+
+	pfacts = &ioc->pfacts[port];
+	memset(pfacts, 0, sizeof(Mpi2PortFactsReply_t));
+	pfacts->PortNumber = mpi_reply.PortNumber;
+	pfacts->VP_ID = mpi_reply.VP_ID;
+	pfacts->VF_ID = mpi_reply.VF_ID;
+	pfacts->MaxPostedCmdBuffers =
+	    le16_to_cpu(mpi_reply.MaxPostedCmdBuffers);
+
+	return 0;
+}
+
+/**
+ * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
+{
+	Mpi2IOCFactsRequest_t mpi_request;
+	Mpi2IOCFactsReply_t mpi_reply, *facts;
+	int mpi_reply_sz, mpi_request_sz, r;
+
+	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	    __func__));
+
+	mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
+	mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
+	memset(&mpi_request, 0, mpi_request_sz);
+	mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
+	r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
+	    (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
+
+	if (r != 0) {
+		printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
+		    ioc->name, __func__, r);
+		return r;
+	}
+
+	facts = &ioc->facts;
+	memset(facts, 0, sizeof(Mpi2IOCFactsReply_t));
+	facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
+	facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
+	facts->VP_ID = mpi_reply.VP_ID;
+	facts->VF_ID = mpi_reply.VF_ID;
+	facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
+	facts->MaxChainDepth = mpi_reply.MaxChainDepth;
+	facts->WhoInit = mpi_reply.WhoInit;
+	facts->NumberOfPorts = mpi_reply.NumberOfPorts;
+	facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
+	facts->MaxReplyDescriptorPostQueueDepth =
+	    le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
+	facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
+	facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
+	if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
+		ioc->ir_firmware = 1;
+	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
+	facts->IOCRequestFrameSize =
+	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
+	facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
+	facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
+	ioc->shost->max_id = -1;
+	facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
+	facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
+	facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
+	facts->HighPriorityCredit =
+	    le16_to_cpu(mpi_reply.HighPriorityCredit);
+	facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
+	facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
+
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hba queue depth(%d), "
+	    "max chains per io(%d)\n", ioc->name, facts->RequestCredit,
+	    facts->MaxChainDepth));
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request frame size(%d), "
+	    "reply frame size(%d)\n", ioc->name,
+	    facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
+	return 0;
+}
+
+/**
+ * _base_send_ioc_init - send ioc_init to firmware
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+{
+	Mpi2IOCInitRequest_t mpi_request;
+	Mpi2IOCInitReply_t mpi_reply;
+	int r;
+
+	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	    __func__));
+
+	memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));
+	mpi_request.Function = MPI2_FUNCTION_IOC_INIT;
+	mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
+	mpi_request.VF_ID = VF_ID;
+	mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
+	mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
+
+	/* In MPI Revision I (0xA), the SystemReplyFrameSize(offset 0x18) was
+	 * removed and made reserved.  For those with older firmware will need
+	 * this fix. It was decided that the Reply and Request frame sizes are
+	 * the same.
+	 */
+	if ((ioc->facts.HeaderVersion >> 8) < 0xA) {
+		mpi_request.Reserved7 = cpu_to_le16(ioc->reply_sz);
+/*		mpi_request.SystemReplyFrameSize =
+ *		 cpu_to_le16(ioc->reply_sz);
+ */
+	}
+
+	mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4);
+	mpi_request.ReplyDescriptorPostQueueDepth =
+	    cpu_to_le16(ioc->reply_post_queue_depth);
+	mpi_request.ReplyFreeQueueDepth =
+	    cpu_to_le16(ioc->reply_free_queue_depth);
+
+#if BITS_PER_LONG > 32
+	mpi_request.SenseBufferAddressHigh =
+	    cpu_to_le32(ioc->sense_dma >> 32);
+	mpi_request.SystemReplyAddressHigh =
+	    cpu_to_le32(ioc->reply_dma >> 32);
+	mpi_request.SystemRequestFrameBaseAddress =
+	    cpu_to_le64(ioc->request_dma);
+	mpi_request.ReplyFreeQueueAddress =
+	    cpu_to_le64(ioc->reply_free_dma);
+	mpi_request.ReplyDescriptorPostQueueAddress =
+	    cpu_to_le64(ioc->reply_post_free_dma);
+#else
+	mpi_request.SystemRequestFrameBaseAddress =
+	    cpu_to_le32(ioc->request_dma);
+	mpi_request.ReplyFreeQueueAddress =
+	    cpu_to_le32(ioc->reply_free_dma);
+	mpi_request.ReplyDescriptorPostQueueAddress =
+	    cpu_to_le32(ioc->reply_post_free_dma);
+#endif
+
+	if (ioc->logging_level & MPT_DEBUG_INIT) {
+		u32 *mfp;
+		int i;
+
+		mfp = (u32 *)&mpi_request;
+		printk(KERN_DEBUG "\toffset:data\n");
+		for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
+			printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+			    le32_to_cpu(mfp[i]));
+	}
+
+	r = _base_handshake_req_reply_wait(ioc,
+	    sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request,
+	    sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10,
+	    sleep_flag);
+
+	if (r != 0) {
+		printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
+		    ioc->name, __func__, r);
+		return r;
+	}
+
+	if (mpi_reply.IOCStatus != MPI2_IOCSTATUS_SUCCESS ||
+	    mpi_reply.IOCLogInfo) {
+		printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__);
+		r = -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * _base_send_port_enable - send port_enable(discovery stuff) to firmware
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+{
+	Mpi2PortEnableRequest_t *mpi_request;
+	u32 ioc_state;
+	unsigned long timeleft;
+	int r = 0;
+	u16 smid;
+
+	printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name);
+
+	if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
+		printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
+		    ioc->name, __func__);
+		return -EAGAIN;
+	}
+
+	smid = base_get_smid(ioc, ioc->base_cb_idx);
+	if (!smid) {
+		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+		    ioc->name, __func__);
+		return -EAGAIN;
+	}
+
+	ioc->base_cmds.status = MPT2_CMD_PENDING;
+	mpi_request = base_get_msg_frame(ioc, smid);
+	ioc->base_cmds.smid = smid;
+	memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
+	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
+	mpi_request->VF_ID = VF_ID;
+
+	base_put_smid_default(ioc, smid, VF_ID);
+	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
+	    300*HZ);
+	if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+		printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+		    ioc->name, __func__);
+		_debug_dump_mf(mpi_request,
+		    sizeof(Mpi2PortEnableRequest_t)/4);
+		if (ioc->base_cmds.status & MPT2_CMD_RESET)
+			r = -EFAULT;
+		else
+			r = -ETIME;
+		goto out;
+	} else
+		dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+		    ioc->name, __func__));
+
+	ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL,
+	    60, sleep_flag);
+	if (ioc_state) {
+		printk(MPT2SAS_ERR_FMT "%s: failed going to operational state "
+		    " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
+		r = -EFAULT;
+	}
+ out:
+	ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+	printk(MPT2SAS_INFO_FMT "port enable: %s\n",
+	    ioc->name, ((r == 0) ? "SUCCESS" : "FAILED"));
+	return r;
+}
+
+/**
+ * _base_unmask_events - turn on notification for this event
+ * @ioc: per adapter object
+ * @event: firmware event
+ *
+ * The mask is stored in ioc->event_masks.
+ */
+static void
+_base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event)
+{
+	u32 desired_event;
+
+	if (event >= 128)
+		return;
+
+	desired_event = (1 << (event % 32));
+
+	if (event < 32)
+		ioc->event_masks[0] &= ~desired_event;
+	else if (event < 64)
+		ioc->event_masks[1] &= ~desired_event;
+	else if (event < 96)
+		ioc->event_masks[2] &= ~desired_event;
+	else if (event < 128)
+		ioc->event_masks[3] &= ~desired_event;
+}
+
+/**
+ * _base_event_notification - send event notification
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+{
+	Mpi2EventNotificationRequest_t *mpi_request;
+	unsigned long timeleft;
+	u16 smid;
+	int r = 0;
+	int i;
+
+	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	    __func__));
+
+	if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
+		printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
+		    ioc->name, __func__);
+		return -EAGAIN;
+	}
+
+	smid = base_get_smid(ioc, ioc->base_cb_idx);
+	if (!smid) {
+		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+		    ioc->name, __func__);
+		return -EAGAIN;
+	}
+	ioc->base_cmds.status = MPT2_CMD_PENDING;
+	mpi_request = base_get_msg_frame(ioc, smid);
+	ioc->base_cmds.smid = smid;
+	memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t));
+	mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
+	mpi_request->VF_ID = VF_ID;
+	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
+		mpi_request->EventMasks[i] =
+		    le32_to_cpu(ioc->event_masks[i]);
+	base_put_smid_default(ioc, smid, VF_ID);
+	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
+	if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+		printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+		    ioc->name, __func__);
+		_debug_dump_mf(mpi_request,
+		    sizeof(Mpi2EventNotificationRequest_t)/4);
+		if (ioc->base_cmds.status & MPT2_CMD_RESET)
+			r = -EFAULT;
+		else
+			r = -ETIME;
+	} else
+		dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+		    ioc->name, __func__));
+	ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+	return r;
+}
+
+/**
+ * base_validate_event_type - validating event types
+ * @ioc: per adapter object
+ * @event: firmware event
+ *
+ * This will turn on firmware event notification when application
+ * ask for that event. We don't mask events that are already enabled.
+ */
+void
+base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type)
+{
+	int i, j;
+	u32 event_mask, desired_event;
+	u8 send_update_to_fw;
+
+	for (i = 0, send_update_to_fw = 0; i <
+	    MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) {
+		event_mask = ~event_type[i];
+		desired_event = 1;
+		for (j = 0; j < 32; j++) {
+			if (!(event_mask & desired_event) &&
+			    (ioc->event_masks[i] & desired_event)) {
+				ioc->event_masks[i] &= ~desired_event;
+				send_update_to_fw = 1;
+			}
+			desired_event = (desired_event << 1);
+		}
+	}
+
+	if (!send_update_to_fw)
+		return;
+
+	mutex_lock(&ioc->base_cmds.mutex);
+	_base_event_notification(ioc, 0, CAN_SLEEP);
+	mutex_unlock(&ioc->base_cmds.mutex);
+}
+
+/**
+ * _base_diag_reset - the "big hammer" start of day reset
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
+{
+	u32 host_diagnostic;
+	u32 ioc_state;
+	u32 count;
+	u32 hcb_size;
+
+	printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name);
+
+	base_save_msix_table(ioc);
+
+	drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n",
+	    ioc->name));
+	writel(0, &ioc->chip->HostInterruptStatus);
+
+	count = 0;
+	do {
+		/* Write magic sequence to WriteSequence register
+		 * Loop until in diagnostic mode
+		 */
+		drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "write magic "
+		    "sequence\n", ioc->name));
+		writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
+		writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence);
+		writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence);
+		writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence);
+		writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence);
+		writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence);
+		writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence);
+
+		/* wait 100 msec */
+		if (sleep_flag == CAN_SLEEP)
+			msleep(100);
+		else
+			mdelay(100);
+
+		if (count++ > 20)
+			goto out;
+
+		host_diagnostic = readl(&ioc->chip->HostDiagnostic);
+		drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "wrote magic "
+		    "sequence: count(%d), host_diagnostic(0x%08x)\n",
+		    ioc->name, count, host_diagnostic));
+
+	} while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0);
+
+	hcb_size = readl(&ioc->chip->HCBSize);
+
+	drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "diag reset: issued\n",
+	    ioc->name));
+	writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
+	     &ioc->chip->HostDiagnostic);
+
+	/* don't access any registers for 50 milliseconds */
+	msleep(50);
+
+	/* 300 second max wait */
+	for (count = 0; count < 3000000 ; count++) {
+
+		host_diagnostic = readl(&ioc->chip->HostDiagnostic);
+
+		if (host_diagnostic == 0xFFFFFFFF)
+			goto out;
+		if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
+			break;
+
+		/* wait 100 msec */
+		if (sleep_flag == CAN_SLEEP)
+			msleep(1);
+		else
+			mdelay(1);
+	}
+
+	if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
+
+		drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter "
+		    "assuming the HCB Address points to good F/W\n",
+		    ioc->name));
+		host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
+		host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
+		writel(host_diagnostic, &ioc->chip->HostDiagnostic);
+
+		drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+		    "re-enable the HCDW\n", ioc->name));
+		writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE,
+		    &ioc->chip->HCBSize);
+	}
+
+	drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter\n",
+	    ioc->name));
+	writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET,
+	    &ioc->chip->HostDiagnostic);
+
+	drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "disable writes to the "
+	    "diagnostic register\n", ioc->name));
+	writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
+
+	drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "Wait for FW to go to the "
+	    "READY state\n", ioc->name));
+	ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20,
+	    sleep_flag);
+	if (ioc_state) {
+		printk(MPT2SAS_ERR_FMT "%s: failed going to ready state "
+		    " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
+		goto out;
+	}
+
+	base_restore_msix_table(ioc);
+	printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name);
+	return 0;
+
+ out:
+	printk(MPT2SAS_ERR_FMT "diag reset: FAILED\n", ioc->name);
+	return -EFAULT;
+}
+
+/**
+ * _base_make_ioc_ready - put controller in READY state
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ * @type: FORCE_BIG_HAMMER or SOFT_RESET
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
+    enum reset_type type)
+{
+	u32 ioc_state;
+
+	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	    __func__));
+
+	ioc_state = base_get_iocstate(ioc, 0);
+	dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: ioc_state(0x%08x)\n",
+	    ioc->name, __func__, ioc_state));
+
+	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY)
+		return 0;
+
+	if (ioc_state & MPI2_DOORBELL_USED) {
+		dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
+		    "active!\n", ioc->name));
+		goto issue_diag_reset;
+	}
+
+	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
+		base_fault_info(ioc, ioc_state & MPI2_DOORBELL_DATA_MASK);
+		goto issue_diag_reset;
+	}
+
+	if (type == FORCE_BIG_HAMMER)
+		goto issue_diag_reset;
+
+#if defined(MUR)
+	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
+		if (!(_base_send_ioc_reset(ioc,
+		    MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP)))
+			return 0;
+#endif
+
+ issue_diag_reset:
+	return _base_diag_reset(ioc, CAN_SLEEP);
+}
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

drivers/scsi/mpt2sas/mpt2sas_base.h +781 -0

781 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#1 lore raw
Quoted 503 lines · Eric Moore

mpt2sas_base

Common API layer interface to MPT (Message Passing Technology) firmware.

---

drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +493 -0
@@ -0,0 +1,3403 @@
+/*
+ * This is the Fusion MPT base driver providing common API layer interface
+ * for access to MPT (Message Passing Technology) firmware.
+ *
+ * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
+ * Copyright (C) 2007-2008  LSI Corporation
+ *  (mailto:[email protected])
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/sort.h>
+#include <linux/io.h>
+
+#include "mpt2sas_base.h"
+
+static MPT_CALLBACK    mpt_callbacks[MPT_MAX_CALLBACKS];
+
+#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
+#define MPT2SAS_MAX_REQUEST_QUEUE 500 /* maximum controller queue depth */
+
+static int max_queue_depth = -1;
+module_param(max_queue_depth, int, 0);
+MODULE_PARM_DESC(max_queue_depth, " max controller queue depth ");
+
+static int max_sgl_entries = -1;
+module_param(max_sgl_entries, int, 0);
+MODULE_PARM_DESC(max_sgl_entries, " max sg entries ");
+
+static int msix_disable = -1;
+module_param(msix_disable, int, 0);
+MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
+
+/**
+ * _base_fault_reset_work - workq handling ioc fault conditions
+ * @work: input argument, used to derive ioc
+ * Context: sleep.
+ *
+ * Return nothing.
+ */
+static void
+_base_fault_reset_work(struct work_struct *work)
+{
+       struct MPT2SAS_ADAPTER *ioc =
+           container_of(work, struct MPT2SAS_ADAPTER, fault_reset_work.work);
+       unsigned long    flags;
+       u32 doorbell;
+       int rc;
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       if (ioc->ioc_reset_in_progress)
+               goto rearm_timer;
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+
+       doorbell = base_get_iocstate(ioc, 0);
+       if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
+               rc = base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
+               printk(MPT2SAS_WARN_FMT "%s: hard reset: %s\n", ioc->name,
+                   __func__, (rc == 0) ? "success" : "failed");
+               doorbell = base_get_iocstate(ioc, 0);
+               if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
+                       base_fault_info(ioc, doorbell &
+                           MPI2_DOORBELL_DATA_MASK);
+       }
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+ rearm_timer:
+       if (ioc->fault_reset_work_q)
+               queue_delayed_work(ioc->fault_reset_work_q,
+                   &ioc->fault_reset_work,
+                   msecs_to_jiffies(FAULT_POLLING_INTERVAL));
+       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+}
+
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+/**
+ * _base_sas_ioc_info - verbose translation of the ioc status
+ * @ioc: pointer to scsi command object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @request_hdr: request mf
+ *
+ * Return nothing.
+ */
+static void
+_base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
+     MPI2RequestHeader_t *request_hdr)
+{
+       u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       char *desc = NULL;
+       u16 frame_sz;
+       char *func_str = NULL;
+
+       /* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */
+       if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
+           request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
+           request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION)
+               return;
+
+       switch (ioc_status) {
+
+/****************************************************************************
+*  Common IOCStatus values for all replies
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_INVALID_FUNCTION:
+               desc = "invalid function";
+               break;
+       case MPI2_IOCSTATUS_BUSY:
+               desc = "busy";
+               break;
+       case MPI2_IOCSTATUS_INVALID_SGL:
+               desc = "invalid sgl";
+               break;
+       case MPI2_IOCSTATUS_INTERNAL_ERROR:
+               desc = "internal error";
+               break;
+       case MPI2_IOCSTATUS_INVALID_VPID:
+               desc = "invalid vpid";
+               break;
+       case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
+               desc = "insufficient resources";
+               break;
+       case MPI2_IOCSTATUS_INVALID_FIELD:
+               desc = "invalid field";
+               break;
+       case MPI2_IOCSTATUS_INVALID_STATE:
+               desc = "invalid state";
+               break;
+       case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
+               desc = "op state not supported";
+               break;
+
+/****************************************************************************
+*  Config IOCStatus values
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION:
+               desc = "config invalid action";
+               break;
+       case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE:
+               desc = "config invalid type";
+               break;
+       case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE:
+               desc = "config invalid page";
+               break;
+       case MPI2_IOCSTATUS_CONFIG_INVALID_DATA:
+               desc = "config invalid data";
+               break;
+       case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS:
+               desc = "config no defaults";
+               break;
+       case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT:
+               desc = "config cant commit";
+               break;
+
+/****************************************************************************
+*  SCSI IO Reply
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
+       case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
+       case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+       case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
+       case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
+       case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
+       case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
+       case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
+       case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
+       case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+       case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
+       case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
+               break;
+
+/****************************************************************************
+*  For use by SCSI Initiator and SCSI Target end-to-end data protection
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+               desc = "eedp guard error";
+               break;
+       case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+               desc = "eedp ref tag error";
+               break;
+       case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+               desc = "eedp app tag error";
+               break;
+
+/****************************************************************************
+*  SCSI Target values
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX:
+               desc = "target invalid io index";
+               break;
+       case MPI2_IOCSTATUS_TARGET_ABORTED:
+               desc = "target aborted";
+               break;
+       case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE:
+               desc = "target no conn retryable";
+               break;
+       case MPI2_IOCSTATUS_TARGET_NO_CONNECTION:
+               desc = "target no connection";
+               break;
+       case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH:
+               desc = "target xfer count mismatch";
+               break;
+       case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR:
+               desc = "target data offset error";
+               break;
+       case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA:
+               desc = "target too much write data";
+               break;
+       case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT:
+               desc = "target iu too short";
+               break;
+       case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT:
+               desc = "target ack nak timeout";
+               break;
+       case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED:
+               desc = "target nak received";
+               break;
+
+/****************************************************************************
+*  Serial Attached SCSI values
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED:
+               desc = "smp request failed";
+               break;
+       case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN:
+               desc = "smp data overrun";
+               break;
+
+/****************************************************************************
+*  Diagnostic Buffer Post / Diagnostic Release values
+****************************************************************************/
+
+       case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED:
+               desc = "diagnostic released";
+               break;
+       default:
+               break;
+       }
+
+       if (!desc)
+               return;
+
+       switch (request_hdr->Function) {
+       case MPI2_FUNCTION_CONFIG:
+               frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size;
+               func_str = "config_page";
+               break;
+       case MPI2_FUNCTION_SCSI_TASK_MGMT:
+               frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t);
+               func_str = "task_mgmt";
+               break;
+       case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
+               frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t);
+               func_str = "sas_iounit_ctl";
+               break;
+       case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
+               frame_sz = sizeof(Mpi2SepRequest_t);
+               func_str = "enclosure";
+               break;
+       case MPI2_FUNCTION_IOC_INIT:
+               frame_sz = sizeof(Mpi2IOCInitRequest_t);
+               func_str = "ioc_init";
+               break;
+       case MPI2_FUNCTION_PORT_ENABLE:
+               frame_sz = sizeof(Mpi2PortEnableRequest_t);
+               func_str = "port_enable";
+               break;
+       case MPI2_FUNCTION_SMP_PASSTHROUGH:
+               frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size;
+               func_str = "smp_passthru";
+               break;
+       default:
+               frame_sz = 32;
+               func_str = "unknown";
+               break;
+       }
+
+       printk(MPT2SAS_WARN_FMT "ioc_status: %s(0x%04x), request(0x%p),"
+           " (%s)\n", ioc->name, desc, ioc_status, request_hdr, func_str);
+
+       _debug_dump_mf(request_hdr, frame_sz/4);
+}
+
+/**
+ * _base_display_event_data - verbose translation of firmware asyn events
+ * @ioc: pointer to scsi command object
+ * @mpi_reply: reply mf payload returned from firmware
+ *
+ * Return nothing.
+ */
+static void
+_base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventNotificationReply_t *mpi_reply)
+{
+       char *desc = NULL;
+       u16 event;
+
+       if (!(ioc->logging_level & MPT_DEBUG_EVENTS))
+               return;
+
+       event = le16_to_cpu(mpi_reply->Event);
+
+       switch (event) {
+       case MPI2_EVENT_LOG_DATA:
+               desc = "Log Data";
+               break;
+       case MPI2_EVENT_STATE_CHANGE:
+               desc = "Status Change";
+               break;
+       case MPI2_EVENT_HARD_RESET_RECEIVED:
+               desc = "Hard Reset Received";
+               break;
+       case MPI2_EVENT_EVENT_CHANGE:
+               desc = "Event Change";
+               break;
+       case MPI2_EVENT_TASK_SET_FULL:
+               desc = "Task Set Full";
+               break;
+       case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
+               desc = "Device Status Change";
+               break;
+       case MPI2_EVENT_IR_OPERATION_STATUS:
+               desc = "IR Operation Status";
+               break;
+       case MPI2_EVENT_SAS_DISCOVERY:
+               desc =  "Discovery";
+               break;
+       case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
+               desc = "SAS Broadcast Primitive";
+               break;
+       case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
+               desc = "SAS Init Device Status Change";
+               break;
+       case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW:
+               desc = "SAS Init Table Overflow";
+               break;
+       case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+               desc = "SAS Topology Change List";
+               break;
+       case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
+               desc = "SAS Enclosure Device Status Change";
+               break;
+       case MPI2_EVENT_IR_VOLUME:
+               desc = "IR Volume";
+               break;
+       case MPI2_EVENT_IR_PHYSICAL_DISK:
+               desc = "IR Physical Disk";
+               break;
+       case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
+               desc = "IR Configuration Change List";
+               break;
+       case MPI2_EVENT_LOG_ENTRY_ADDED:
+               desc = "Log Entry Added";
+               break;
+       }
+
+       if (!desc)
+               return;
+
+       printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, desc);
+}
+#endif
+
+/**
+ * _base_sas_log_info - verbose translation of firmware log info
+ * @ioc: pointer to scsi command object
+ * @log_info: log info
+ *
+ * Return nothing.
+ */
+static void
+_base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info)
+{
+       union loginfo_type {
+               u32     loginfo;
+               struct {
+                       u32     subcode:16;
+                       u32     code:8;
+                       u32     originator:4;
+                       u32     bus_type:4;
+               } dw;
+       };
+       union loginfo_type sas_loginfo;
+       char *originator_str = NULL;
+
+       sas_loginfo.loginfo = log_info;
+       if (sas_loginfo.dw.bus_type != 3 /*SAS*/)
+               return;
+
+       /* eat the loginfos associated with task aborts */
+       if (ioc->ignore_loginfos && (log_info == 30050000 || log_info ==
+           0x31140000 || log_info == 0x31130000))
+               return;
+
+       switch (sas_loginfo.dw.originator) {
+       case 0:
+               originator_str = "IOP";
+               break;
+       case 1:
+               originator_str = "PL";
+               break;
+       case 2:
+               originator_str = "IR";
+               break;
+       }
+
+       printk(MPT2SAS_WARN_FMT "log_info(0x%08x): originator(%s), "
+           "code(0x%02x), sub_code(0x%04x)\n", ioc->name, log_info,
+            originator_str, sas_loginfo.dw.code,
+            sas_loginfo.dw.subcode);
+}
+
+/**
+ * base_fault_info - verbose translation of firmware FAULT code
+ * @ioc: pointer to scsi command object
+ * @fault_code: fault code
+ *
+ * Return nothing.
+ */
+void
+base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
+{
+       printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n",
+           ioc->name, fault_code);
+}
+
+/**
+ * _base_display_reply_info -
+ * @ioc: pointer to scsi command object
+ * @smid: system request message index
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Return nothing.
+ */
+static void
+_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+    u32 reply)
+{
+       MPI2DefaultReply_t *mpi_reply;
+       u16 ioc_status;

drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 line 503

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +10 -0
+
+       mpi_reply =  base_get_reply_virt_addr(ioc, reply);
+       ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
+           (ioc->logging_level & MPT_DEBUG_REPLY)) {
+               _base_sas_ioc_info(ioc , mpi_reply,
+                   base_get_msg_frame(ioc, smid));
+       }
+#endif

Can all the "if (ioc_status...)" gunk get wrapped into a macro that is conditionally defined?
e.g. the logging level could become a compile time option instead of a runtime option.

I was able to cut 1% CPU utilization from another driver by allowing the compiler to get
rid of all the debug messages that would never get printed because they were below
a particular threshold.

Maybe it doesn't matter in this case. But I've no clue yet how often/when _base_display_reply_info()
is called.

Quoted 86 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +86 -0
+       if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
+               _base_sas_log_info(ioc, le32_to_cpu(mpi_reply->IOCLogInfo));
+}
+
+/**
+ * base_done - base internal command completion routine
+ * @ioc: pointer to scsi command object
+ * @smid: system request message index
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Return nothing.
+ */
+void
+base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+{
+       MPI2DefaultReply_t *mpi_reply;
+
+       mpi_reply =  base_get_reply_virt_addr(ioc, reply);
+       if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
+               return;
+
+       if (ioc->base_cmds.status == MPT2_CMD_NOT_USED)
+               return;
+
+       ioc->base_cmds.status |= MPT2_CMD_COMPLETE;
+       if (mpi_reply) {
+               ioc->base_cmds.status |= MPT2_CMD_REPLY_VALID;
+               memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
+       }
+       ioc->base_cmds.status &= ~MPT2_CMD_PENDING;
+       complete(&ioc->base_cmds.done);
+}
+
+/**
+ * _base_async_event - main callback handler for firmware asyn events
+ * @ioc: pointer to scsi command object
+ * @VF_ID: virtual function id
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Return nothing.
+ */
+static void
+_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
+{
+       Mpi2EventNotificationReply_t *mpi_reply;
+       Mpi2EventAckRequest_t *ack_request;
+       u16 smid;
+
+       mpi_reply =  base_get_reply_virt_addr(ioc, reply);
+       if (!mpi_reply)
+               return;
+       if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
+               return;
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       _base_display_event_data(ioc, mpi_reply);
+#endif
+       if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED))
+               goto out;
+       smid = base_get_smid(ioc, ioc->base_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               goto out;
+       }
+
+       ack_request = base_get_msg_frame(ioc, smid);
+       memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t));
+       ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
+       ack_request->Event = mpi_reply->Event;
+       ack_request->EventContext = mpi_reply->EventContext;
+       ack_request->VF_ID = VF_ID;
+       base_put_smid_default(ioc, smid, VF_ID);
+
+ out:
+       scsih_event_callback(ioc, VF_ID, reply); /* scsih callback handler */
+       ctl_event_callback(ioc, VF_ID, reply); /* ctl callback handler */
+}
+
+/**
+ * _base_mask_interrupts - disable interrupts
+ * @ioc: pointer to scsi command object
+ *
+ * Disabling ResetIRQ, Reply and Doorbell Interrupts
+ *
+ * Return nothing.

drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 line 599

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +10 -0
+ */
+static void
+_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
+{
+       u32 him_register;
+
+       ioc->mask_interrupts = 1;
+       him_register = readl(&ioc->chip->HostInterruptMask);
+       him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK;
+       writel(him_register, &ioc->chip->HostInterruptMask);

This is a posted write. Does it need to be flushed?
ie do other parts of the driver require this take effect immediately or will they tolerate some late arriving interrupt?

Quoted 45 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +45 -0
+}
+
+/**
+ * _base_unmask_interrupts - enable interrupts
+ * @ioc: pointer to scsi command object
+ *
+ * Enabling only Reply Interrupts
+ *
+ * Return nothing.
+ */
+static void
+_base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc)
+{
+       u32 him_register;
+
+       writel(0, &ioc->chip->HostInterruptStatus);
+       him_register = readl(&ioc->chip->HostInterruptMask);
+       him_register &= ~MPI2_HIM_RIM;
+       writel(him_register, &ioc->chip->HostInterruptMask);
+       ioc->mask_interrupts = 0;
+}
+
+/**
+ * base_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)
+ *
+ * Return IRQ_HANDLE if processed, else IRQ_NONE.
+ */
+static irqreturn_t
+base_interrupt(int irq, void *bus_id)
+{
+       u32 post_index, post_index_next, completed_cmds;
+       u8 request_desript_type;
+       u16 smid;
+       u8 cb_idx;
+       u32 reply;
+       u8 VF_ID;
+       int i;
+       struct MPT2SAS_ADAPTER *ioc = bus_id;
+
+       if (ioc->mask_interrupts)
+               return IRQ_NONE;
+

drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 line 654

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +10 -0
+       post_index = ioc->reply_post_host_index;
+       request_desript_type = ioc->reply_post_free[post_index].
+           Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+       if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+               return IRQ_NONE;
+
+       completed_cmds = 0;
+       do {
+               if (ioc->reply_post_free[post_index].Words ==
+                   0xFFFFFFFFFFFFFFFFULL)

Would this be better written as "~0ULL" or as a predefined constant?

Quoted 63 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +63 -0
+                       goto out;
+               reply = 0;
+               cb_idx = 0xFF;
+               smid = le16_to_cpu(ioc->reply_post_free[post_index].
+                   Default.DescriptorTypeDependent1);
+               VF_ID = ioc->reply_post_free[post_index].
+                   Default.VF_ID;
+               if (request_desript_type ==
+                   MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
+                       reply = le32_to_cpu(ioc->reply_post_free[post_index].
+                           AddressReply.ReplyFrameAddress);
+               } else if (request_desript_type ==
+                   MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER)
+                       goto next;
+               else if (request_desript_type ==
+                   MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS)
+                       goto next;
+               if (smid)
+                       cb_idx = ioc->scsi_lookup[smid - 1].cb_idx;
+               if (smid && cb_idx != 0xFF) {
+                       mpt_callbacks[cb_idx](ioc, smid, VF_ID, reply);
+                       if (reply)
+                               _base_display_reply_info(ioc, smid, VF_ID,
+                                   reply);
+                       base_free_smid(ioc, smid);
+               }
+               if (!smid)
+                       _base_async_event(ioc, VF_ID, reply);
+
+               /* reply free queue handling */
+               if (reply) {
+                       ioc->reply_free_host_index =
+                           (ioc->reply_free_host_index ==
+                           (ioc->reply_free_queue_depth - 1)) ?
+                           0 : ioc->reply_free_host_index + 1;
+                       ioc->reply_free[ioc->reply_free_host_index] =
+                           cpu_to_le32(reply);
+                       writel(ioc->reply_free_host_index,
+                           &ioc->chip->ReplyFreeHostIndex);
+                       wmb();
+               }
+
+ next:
+               post_index_next = (post_index == (ioc->reply_post_queue_depth -
+                   1)) ? 0 : post_index + 1;
+               request_desript_type =
+                   ioc->reply_post_free[post_index_next].Default.ReplyFlags
+                   & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+               completed_cmds++;
+               if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+                       goto out;
+               post_index = post_index_next;
+       } while (1);
+
+ out:
+
+       if (!completed_cmds)
+               return IRQ_NONE;
+
+       /* reply post descriptor handling */
+       post_index_next = ioc->reply_post_host_index;
+       for (i = 0 ; i < completed_cmds; i++) {
+               post_index = post_index_next;

drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 line 727

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +10 -0
+               /* poison the reply post descriptor */
+               ioc->reply_post_free[post_index_next].Words =
+                   0xFFFFFFFFFFFFFFFFULL;
+               post_index_next = (post_index ==
+                   (ioc->reply_post_queue_depth - 1))
+                   ? 0 : post_index + 1;
+       }
+       ioc->reply_post_host_index = post_index_next;
+       writel(post_index_next, &ioc->chip->ReplyPostHostIndex);
+       wmb();

What is the wmb() protecting here? Add a comment?

My impression is the wmb() belongs in front of the writel() and not behind it. That is, we want to make sure the updates to ioc->reply_post_free[] are visible before sending out the writel().

Quoted 141 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +141 -0
+       return IRQ_HANDLED;
+}
+
+/**
+ * base_release_callback_handler - clear interupt callback handler
+ * @cb_idx: callback index
+ *
+ * Return nothing.
+ */
+void
+base_release_callback_handler(u8 cb_idx)
+{
+       mpt_callbacks[cb_idx] = NULL;
+}
+
+/**
+ * base_register_callback_handler - obtain index for the interrupt callback handler
+ * @cb_func: callback function
+ *
+ * Returns cb_func.
+ */
+u8
+base_register_callback_handler(MPT_CALLBACK cb_func)
+{
+       u8 cb_idx;
+
+       for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--)
+               if (mpt_callbacks[cb_idx] == NULL)
+                       break;
+
+       mpt_callbacks[cb_idx] = cb_func;
+       return cb_idx;
+}
+
+/**
+ * base_initialize_callback_handler - initialize the interrupt callback handler
+ *
+ * Return nothing.
+ */
+void
+base_initialize_callback_handler(void)
+{
+       u8 cb_idx;
+
+       for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++)
+               base_release_callback_handler(cb_idx);
+}
+
+/**
+ * base_build_zero_len_sge - build zero length sg entry
+ * @ioc: per adapter object
+ * @paddr: virtual address for SGE
+ *
+ * Create a zero length scatter gather entry to insure the IOCs hardware has
+ * something to use if the target device goes brain dead and tries
+ * to send data even when none is asked for.
+ *
+ * Return nothing.
+ */
+void
+base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr)
+{
+       u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT |
+           MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST |
+           MPI2_SGE_FLAGS_SIMPLE_ELEMENT) <<
+           MPI2_SGE_FLAGS_SHIFT);
+       ioc->base_add_sg_single(paddr, flags_length, -1);
+}
+
+/**
+ * base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr.
+ * @paddr: virtual address for SGE
+ * @flags_length: SGE flags and data transfer length
+ * @dma_addr: Physical address
+ *
+ * Return nothing.
+ */
+static void
+base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr)
+{
+       Mpi2SGESimple32_t *sgel = paddr;
+
+       flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
+           MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
+       sgel->FlagsLength = cpu_to_le32(flags_length);
+       sgel->Address = cpu_to_le32(dma_addr);
+}
+
+
+/**
+ * base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr.
+ * @paddr: virtual address for SGE
+ * @flags_length: SGE flags and data transfer length
+ * @dma_addr: Physical address
+ *
+ * Return nothing.
+ */
+static void
+base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr)
+{
+       Mpi2SGESimple64_t *sgel = paddr;
+
+       flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
+           MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
+       sgel->FlagsLength = cpu_to_le32(flags_length);
+       sgel->Address = cpu_to_le64(dma_addr);
+}
+
+#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10))
+
+/**
+ * _base_config_dma_addressing - set dma addressing
+ * @ioc: per adapter object
+ * @pdev: PCI device struct
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
+{
+       struct sysinfo s;
+       char *desc = NULL;
+
+       if (sizeof(dma_addr_t) > 4) {
+               const uint64_t required_mask =
+                   dma_get_required_mask(&pdev->dev);
+               if ((required_mask > DMA_32BIT_MASK) && !pci_set_dma_mask(pdev,
+                   DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(pdev,
+                   DMA_64BIT_MASK)) {
+                       ioc->base_add_sg_single = &base_add_sg_single_64;
+                       ioc->sge_size = sizeof(Mpi2SGESimple64_t);
+                       desc = "64";
+                       goto out;
+               }
+       }
+
+       if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
+           && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+               ioc->base_add_sg_single = &base_add_sg_single_32;
+               ioc->sge_size = sizeof(Mpi2SGESimple32_t);
+               desc = "32";

drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 line 878

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +10 -0
+       } else
+               return -ENODEV;
+
+ out:
+       si_meminfo(&s);
+       printk(MPT2SAS_INFO_FMT "%s BIT PCI BUS DMA ADDRESSING SUPPORTED, "
+           "total mem (%ld kB)\n", ioc->name, desc, convert_to_kb(s.totalram));
+
+       return 0;
+}

Interesting. I would have expected the dma_mask and consistent_dma_mask to not depend on each other. ie set dma_mask to 64, if that fails, set dma_mask to 32-bit.
Rinse and repeat for consistent_dma_mask.

Quoted 50 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +50 -0
+
+/**
+ * base_save_msix_table - backup msix vector table
+ * @ioc: per adapter object
+ *
+ * This address an errata where diag reset clears out the table
+ */
+static void
+base_save_msix_table(struct MPT2SAS_ADAPTER *ioc)
+{
+       int i;
+
+       if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
+               return;
+
+       for (i = 0; i < ioc->msix_vector_count; i++)
+               ioc->msix_table_backup[i] = ioc->msix_table[i];
+}
+
+/**
+ * base_restore_msix_table - this restores the msix vector table
+ * @ioc: per adapter object
+ *
+ */
+static void
+base_restore_msix_table(struct MPT2SAS_ADAPTER *ioc)
+{
+       int i;
+
+       if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
+               return;
+
+       for (i = 0; i < ioc->msix_vector_count; i++)
+               ioc->msix_table[i] = ioc->msix_table_backup[i];
+}
+
+/**
+ * base_check_enable_msix - checks MSIX capabable.
+ * @ioc: per adapter object
+ *
+ * Check to see if card is capable of MSIX, and set number
+ * of avaliable msix vectors
+ */
+static int
+base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)
+{
+       int base;
+       u16 message_control;
+       u32 msix_table_offset;
+

drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 line 938

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +10 -0
+       base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
+       if (!base) {
+               dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not "
+                   "supported\n", ioc->name));
+               return -EINVAL;
+       }
+
+       /* get msix vector count */
+       pci_read_config_word(ioc->pdev, base + 2, &message_control);
+       ioc->msix_vector_count = (message_control & 0x3FF) + 1;

Any comments on why the return value from pci_enable_msix() isn't used here?

I wasn't expecting the drivers would need to read the MSIX table directly.

/**
* pci_enable_msix - configure device's MSI-X capability structure
* @dev: pointer to the pci_dev data structure of MSI-X device function
* @entries: pointer to an array of MSI-X entries
* @nvec: number of MSI-X irqs requested for allocation by device driver *
* Setup the MSI-X capability structure of device function with the number
* of requested irqs upon its software driver call to request for
* MSI-X mode enabled on its hardware device function. A return of zero
* indicates the successful configuration of MSI-X capability structure
* with new allocated MSI-X irqs. A return of < 0 indicates a failure.
* Or a return of > 0 indicates that driver request is exceeding the number
* of irqs available. Driver should use the returned value to re-send
* its request.
**/

Quoted 65 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +65 -0
+
+       /* get msix table  */
+       pci_read_config_dword(ioc->pdev, base + 4, &msix_table_offset);
+       msix_table_offset &= 0xFFFFFFF8;
+       ioc->msix_table = (u32 *)((void *)ioc->chip + msix_table_offset);
+
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, "
+           "vector_count(%d), table_offset(0x%08x), table(%p)\n", ioc->name,
+           ioc->msix_vector_count, msix_table_offset, ioc->msix_table));
+       return 0;
+}
+
+/**
+ * base_disable_msix - disables msix
+ * @ioc: per adapter object
+ *
+ */
+static void
+base_disable_msix(struct MPT2SAS_ADAPTER *ioc)
+{
+       if (ioc->msix_enable) {
+               pci_disable_msix(ioc->pdev);
+               kfree(ioc->msix_table_backup);
+               ioc->msix_table_backup = NULL;
+               ioc->msix_enable = 0;
+       }
+}
+
+/**
+ * base_enable_msix - enables msix, failback to io_apic
+ * @ioc: per adapter object
+ *
+ */
+static int
+base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
+{
+       struct msix_entry *entries = NULL;
+       int i, r;
+       u8 try_msix = 0;
+
+       if (msix_disable == -1 || msix_disable == 0)
+               try_msix = 1;
+
+       if (!try_msix)
+               goto try_ioapic;
+
+       if (base_check_enable_msix(ioc) != 0)
+               goto try_ioapic;
+
+       entries = kcalloc(ioc->msix_vector_count, sizeof(struct msix_entry),
+           GFP_KERNEL);
+       if (!entries) {
+               dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
+                   "msix_entry failed !!!\n", ioc->name));
+               goto try_ioapic;
+       }
+
+       for (i = 0; i < ioc->msix_vector_count; i++)
+               entries[i].entry = i;
+
+       ioc->msix_table_backup = kcalloc(ioc->msix_vector_count, 4, GFP_KERNEL);
+       if (!ioc->msix_table_backup) {
+               dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
+                   "msix_table_backup failed!!!\n", ioc->name));
+               goto try_ioapic;

drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 line 1013

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +10 -0
+       }
+
+       r = pci_enable_msix(ioc->pdev, entries, ioc->msix_vector_count);
+       if (r) {
+               dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "pci_enable_msix "
+                   "failed (r=%d) !!!\n", ioc->name, r));
+               goto try_ioapic;
+       }
+
+       /* current HW implemention uses only one interrupt handler */

Which implementation?
This comment sounds like it expects to be obsolete soon. Specifying the implementation makes it clear even when other implementations become available.

drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 line 1015

Quoted 2 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +2 -0
+       r = request_irq(entries[0].vector, base_interrupt, IRQF_SHARED,
+           ioc->name, ioc);

MSI is never shared. IRQF_SHARED flag is still correct?

I have to stop looking now...back to work. :(

hth,
grant

Quoted 2,399 lines
drivers/scsi/mpt2sas/mpt2sas_base.c       2009-02-24 14:27:01.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.c       1969-12-31 17:00:00.000000000 -0700 +2388 -0
+       if (r) {
+               dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "unable to allocate "
+                   "interrupt %d !!!\n", ioc->name, entries[0].vector));
+               pci_disable_msix(ioc->pdev);
+               goto try_ioapic;
+       }
+
+       ioc->pci_irq = entries[0].vector;
+       ioc->msix_enable = 1;
+       kfree(entries);
+       return 0;
+
+/* failback to io_apic interrupt routing */
+ try_ioapic:
+       kfree(entries);
+
+       r = request_irq(ioc->pdev->irq, base_interrupt, IRQF_SHARED,
+           ioc->name, ioc);
+       if (r) {
+               printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n",
+                   ioc->name, ioc->pdev->irq);
+               r = -EBUSY;
+               goto out_fail;
+       }
+
+       ioc->pci_irq = ioc->pdev->irq;
+       return 0;
+
+ out_fail:
+       return r;
+}
+
+/**
+ * base_map_resources - map in controller resources (io/irq/memap)
+ * @ioc: per adapter object
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+base_map_resources(struct MPT2SAS_ADAPTER *ioc)
+{
+       struct pci_dev *pdev = ioc->pdev;
+       u32 memap_sz;
+       u32 pio_sz;
+       int i, r = 0;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n",
+           ioc->name, __func__));
+
+       ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       if (pci_enable_device_mem(pdev)) {
+               printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: "
+                   "failed\n", ioc->name);
+               return -ENODEV;
+       }
+
+
+       if (pci_request_selected_regions(pdev, ioc->bars,
+           MPT2SAS_DRIVER_NAME)) {
+               printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: "
+                   "failed\n", ioc->name);
+               r = -ENODEV;
+               goto out_fail;
+       }
+
+       pci_set_master(pdev);
+
+       if (_base_config_dma_addressing(ioc, pdev) != 0) {
+               printk(MPT2SAS_WARN_FMT "no suitable DMA mask for %s\n",
+                   ioc->name, pci_name(pdev));
+               r = -ENODEV;
+               goto out_fail;
+       }
+
+       for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) {
+               if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) {
+                       if (pio_sz)
+                               continue;
+                       ioc->pio_chip = pci_resource_start(pdev, i);
+                       pio_sz = pci_resource_len(pdev, i);
+               } else {
+                       if (memap_sz)
+                               continue;
+                       ioc->chip_phys = pci_resource_start(pdev, i);
+                       memap_sz = pci_resource_len(pdev, i);
+                       ioc->chip = ioremap(ioc->chip_phys, memap_sz);
+                       if (ioc->chip == NULL) {
+                               printk(MPT2SAS_ERR_FMT "unable to map adapter "
+                                   "memory!\n", ioc->name);
+                               r = -EINVAL;
+                               goto out_fail;
+                       }
+               }
+       }
+
+       pci_set_drvdata(pdev, ioc->shost);
+       _base_mask_interrupts(ioc);
+       r = base_enable_msix(ioc);
+       if (r)
+               goto out_fail;
+
+       printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n",
+           ioc->name,  ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
+           "IO-APIC enabled"), ioc->pci_irq);
+       printk(MPT2SAS_INFO_FMT "iomem(0x%lx), mapped(0x%p), size(%d)\n",
+           ioc->name, ioc->chip_phys, ioc->chip, memap_sz);
+       printk(MPT2SAS_INFO_FMT "ioport(0x%lx), size(%d)\n",
+           ioc->name, ioc->pio_chip, pio_sz);
+
+       return 0;
+
+ out_fail:
+       if (ioc->chip_phys)
+               iounmap(ioc->chip);
+       ioc->chip_phys = 0;
+       ioc->pci_irq = -1;
+       pci_release_selected_regions(ioc->pdev, ioc->bars);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       return r;
+}
+
+/**
+ * base_get_msg_frame_dma - obtain request mf pointer phys addr
+ * @ioc: per adapter object
+ * @smid: system request message index(smid zero is invalid)
+ *
+ * Returns phys pointer to message frame.
+ */
+dma_addr_t
+base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       return ioc->request_dma + (smid * ioc->request_sz);
+}
+
+/**
+ * base_get_msg_frame - obtain request mf pointer
+ * @ioc: per adapter object
+ * @smid: system request message index(smid zero is invalid)
+ *
+ * Returns virt pointer to message frame.
+ */
+void *
+base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       return (void *)(ioc->request + (smid * ioc->request_sz));
+}
+
+/**
+ * base_get_sense_buffer - obtain a sense buffer assigned to a mf request
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns virt pointer to sense buffer.
+ */
+void *
+base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE));
+}
+
+/**
+ * base_get_sense_buffer_dma - obtain a sense buffer assigned to a mf request
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns phys pointer to sense buffer.
+ */
+dma_addr_t
+base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       return ioc->sense_dma + ((smid - 1) * SCSI_SENSE_BUFFERSIZE);
+}
+
+/**
+ * base_get_reply_virt_addr - obtain reply frames virt address
+ * @ioc: per adapter object
+ * @phys_addr: lower 32 physical addr of the reply
+ *
+ * Converts 32bit lower physical addr into a virt address.
+ */
+void *
+base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr)
+{
+       if (!phys_addr)
+               return NULL;
+       return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
+}
+
+/**
+ * base_get_smid - obtain a free smid
+ * @ioc: per adapter object
+ * @cb_idx: callback index
+ *
+ * Returns smid (zero is invalid)
+ */
+u16
+base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)
+{
+       unsigned long flags;
+       struct request_tracker *request;
+       u16 smid;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       if (list_empty(&ioc->free_list)) {
+               spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+               printk(MPT2SAS_ERR_FMT "%s: smid not available\n",
+                   ioc->name, __func__);
+               return 0;
+       }
+
+       request = list_entry(ioc->free_list.next,
+           struct request_tracker, tracker_list);
+       request->cb_idx = cb_idx;
+       smid = request->smid;
+       list_del(&request->tracker_list);
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+       return smid;
+}
+
+
+/**
+ * base_free_smid - put smid back on free_list
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Return nothing.
+ */
+void
+base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       ioc->scsi_lookup[smid - 1].cb_idx = 0xFF;
+       list_add_tail(&ioc->scsi_lookup[smid - 1].tracker_list,
+           &ioc->free_list);
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+       /*
+        * See _wait_for_commands_to_complete() call with regards to this code.
+        */
+       if (ioc->shost_recovery && ioc->pending_io_count) {
+               if (ioc->pending_io_count == 1)
+                       wake_up(&ioc->reset_wq);
+               ioc->pending_io_count--;
+       }
+}
+
+/**
+ * _base_writeq - 64 bit write to MMIO
+ * @ioc: per adapter object
+ * @b: data payload
+ * @addr: address in MMIO space
+ * @writeq_lock: spin lock
+ *
+ * Glue for handling an atomic 64 bit word to MMIO. This special handling takes
+ * care of 32 bit environment where its not quarenteed to send the entire word
+ * in one transfer.
+ */
+#ifndef writeq
+static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
+    spinlock_t *writeq_lock)
+{
+       unsigned long flags;
+       __u64 data_out = cpu_to_le64(b);
+
+       spin_lock_irqsave(writeq_lock, flags);
+       writel((u32)(data_out), addr);
+       writel((u32)(data_out >> 32), (addr + 4));
+       spin_unlock_irqrestore(writeq_lock, flags);
+}
+#else
+static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
+    spinlock_t *writeq_lock)
+{
+       writeq(cpu_to_le64(b), addr);
+}
+#endif
+
+/**
+ * base_put_smid_scsi_io - send SCSI_IO request to firmware
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ * @handle: device handle
+ *
+ * Return nothing.
+ */
+void
+base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
+    u16 handle)
+{
+       Mpi2RequestDescriptorUnion_t descriptor;
+       u64 *request = (u64 *)&descriptor;
+
+
+       descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+       descriptor.SCSIIO.VF_ID = vf_id;
+       descriptor.SCSIIO.SMID = cpu_to_le16(smid);
+       descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
+       descriptor.SCSIIO.LMID = 0;
+       _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+           &ioc->scsi_lookup_lock);
+}
+
+
+/**
+ * base_put_smid_hi_priority - send Task Managment request to firmware
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ *
+ * Return nothing.
+ */
+void
+base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id)
+{
+       Mpi2RequestDescriptorUnion_t descriptor;
+       u64 *request = (u64 *)&descriptor;
+
+       descriptor.HighPriority.RequestFlags =
+           MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+       descriptor.HighPriority.VF_ID = vf_id;
+       descriptor.HighPriority.SMID = cpu_to_le16(smid);
+       descriptor.HighPriority.LMID = 0;
+       descriptor.HighPriority.Reserved1 = 0;
+       _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+           &ioc->scsi_lookup_lock);
+}
+
+/**
+ * base_put_smid_default - Default, primarily used for config pages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ *
+ * Return nothing.
+ */
+void
+base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id)
+{
+       Mpi2RequestDescriptorUnion_t descriptor;
+       u64 *request = (u64 *)&descriptor;
+
+       descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+       descriptor.Default.VF_ID = vf_id;
+       descriptor.Default.SMID = cpu_to_le16(smid);
+       descriptor.Default.LMID = 0;
+       descriptor.Default.DescriptorTypeDependent = 0;
+       _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+           &ioc->scsi_lookup_lock);
+}
+
+/**
+ * base_put_smid_target_assist - send Target Assist/Status to firmware
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @vf_id: virtual function id
+ * @io_index: value used to track the IO
+ *
+ * Return nothing.
+ */
+void
+base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
+    u16 io_index)
+{
+       Mpi2RequestDescriptorUnion_t descriptor;
+       u64 *request = (u64 *)&descriptor;
+
+       descriptor.SCSITarget.RequestFlags =
+           MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET;
+       descriptor.SCSITarget.VF_ID = vf_id;
+       descriptor.SCSITarget.SMID = cpu_to_le16(smid);
+       descriptor.SCSITarget.LMID = 0;
+       descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index);
+       _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+           &ioc->scsi_lookup_lock);
+}
+
+/**
+ * _base_display_ioc_capabilities - Disply IOC's capabilities.
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
+{
+       int i = 0;
+       char desc[16];
+       u8 revision;
+       u32 iounit_pg1_flags;
+
+       pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision);
+       strncpy(desc, ioc->manu_pg0.ChipName, 16);
+       printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "
+          "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n",
+           ioc->name, desc,
+          (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
+          (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
+          (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
+          ioc->facts.FWVersion.Word & 0x000000FF,
+          revision,
+          (ioc->bios_pg3.BiosVersion & 0xFF000000) >> 24,
+          (ioc->bios_pg3.BiosVersion & 0x00FF0000) >> 16,
+          (ioc->bios_pg3.BiosVersion & 0x0000FF00) >> 8,
+           ioc->bios_pg3.BiosVersion & 0x000000FF);
+
+       printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name);
+
+       if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) {
+               printk("Initiator");
+               i++;
+       }
+
+       if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) {
+               printk("%sTarget", i ? "," : "");
+               i++;
+       }
+
+       i = 0;
+       printk("), ");
+       printk("Capabilities=(");
+
+       if (ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
+               printk("Raid");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) {
+               printk("%sTLR", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) {
+               printk("%sMulticast", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) {
+               printk("%sBIDI Target", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) {
+               printk("%sEEDP", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) {
+               printk("%sSnapshot Buffer", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
+               printk("%sDiag Trace Buffer", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) {
+               printk("%sTask Set Full", i ? "," : "");
+               i++;
+       }
+
+       iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
+       if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) {
+               printk("%sNCQ", i ? "," : "");
+               i++;
+       }
+
+       printk(")\n");
+}
+
+/**
+ * _base_static_config_pages - static start of day config pages
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
+{
+       Mpi2ConfigReply_t mpi_reply;
+       u32 iounit_pg1_flags;
+
+       config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0);
+       config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
+       config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
+       config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
+       config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0);
+       config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+       _base_display_ioc_capabilities(ioc);
+
+       /*
+        * Enable task_set_full handling in iounit_pg1 when the
+        * facts capabilities indicate that its supported.
+        */
+       iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
+       if ((ioc->facts.IOCCapabilities &
+           MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING))
+               iounit_pg1_flags &=
+                   ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
+       else
+               iounit_pg1_flags |=
+                   MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
+       ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
+       config_set_iounit_pg1(ioc, &mpi_reply, ioc->iounit_pg1);
+}
+
+/**
+ * _base_release_memory_pools - release memory
+ * @ioc: per adapter object
+ *
+ * Free memory allocated from _base_allocate_memory_pools.
+ *
+ * Return nothing.
+ */
+static void
+_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
+{
+       dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       if (ioc->request) {
+               pci_free_consistent(ioc->pdev, ioc->request_dma_sz,
+                   ioc->request,  ioc->request_dma);
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "request_pool(0x%p)"
+                   ": free\n", ioc->name, ioc->request));
+               ioc->request = NULL;
+       }
+
+       if (ioc->sense) {
+               pci_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma);
+               if (ioc->sense_dma_pool)
+                       pci_pool_destroy(ioc->sense_dma_pool);
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_pool(0x%p)"
+                   ": free\n", ioc->name, ioc->sense));
+               ioc->sense = NULL;
+       }
+
+       if (ioc->reply) {
+               pci_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma);
+               if (ioc->reply_dma_pool)
+                       pci_pool_destroy(ioc->reply_dma_pool);
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_pool(0x%p)"
+                    ": free\n", ioc->name, ioc->reply));
+               ioc->reply = NULL;
+       }
+
+       if (ioc->reply_free) {
+               pci_pool_free(ioc->reply_free_dma_pool, ioc->reply_free,
+                   ioc->reply_free_dma);
+               if (ioc->reply_free_dma_pool)
+                       pci_pool_destroy(ioc->reply_free_dma_pool);
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_pool"
+                   "(0x%p): free\n", ioc->name, ioc->reply_free));
+               ioc->reply_free = NULL;
+       }
+
+       if (ioc->reply_post_free) {
+               pci_pool_free(ioc->reply_post_free_dma_pool,
+                   ioc->reply_post_free, ioc->reply_post_free_dma);
+               if (ioc->reply_post_free_dma_pool)
+                       pci_pool_destroy(ioc->reply_post_free_dma_pool);
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+                   "reply_post_free_pool(0x%p): free\n", ioc->name,
+                   ioc->reply_post_free));
+               ioc->reply_post_free = NULL;
+       }
+
+       if (ioc->config_page) {
+               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+                   "config_page(0x%p): free\n", ioc->name,
+                   ioc->config_page));
+               pci_free_consistent(ioc->pdev, ioc->config_page_sz,
+                   ioc->config_page, ioc->config_page_dma);
+       }
+
+       kfree(ioc->scsi_lookup);
+}
+
+
+/**
+ * _base_allocate_memory_pools - allocate start of day memory pools
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 success, anything else error
+ */
+static int
+_base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
+{
+       Mpi2IOCFactsReply_t *facts;
+       u32 queue_size, queue_diff;
+       u16 max_sge_elements;
+       u16 num_of_reply_frames;
+       u16 chains_needed_per_io;
+       u32 sz, total_sz;
+       u16 i;
+       u32 retry_sz;
+       u16 max_request_credit;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       retry_sz = 0;
+       facts = &ioc->facts;
+
+       /* command line tunables  for max sgl entries */
+       if (max_sgl_entries != -1) {
+               ioc->shost->sg_tablesize = (max_sgl_entries <
+                   MPT2SAS_SG_DEPTH) ? max_sgl_entries :
+                   MPT2SAS_SG_DEPTH;
+       } else {
+               ioc->shost->sg_tablesize = MPT2SAS_SG_DEPTH;
+       }
+
+       /* command line tunables  for max controller queue depth */
+       if (max_queue_depth != -1) {
+               max_request_credit = (max_queue_depth < facts->RequestCredit)
+                   ? max_queue_depth : facts->RequestCredit;
+       } else {
+               max_request_credit = (facts->RequestCredit >
+                   MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE :
+                   facts->RequestCredit;
+       }
+       ioc->request_depth = max_request_credit;
+
+       /* request frame size */
+       ioc->request_sz = facts->IOCRequestFrameSize * 4;
+
+       /* reply frame size */
+       ioc->reply_sz = facts->ReplyFrameSize * 4;
+
+ retry_allocation:
+       total_sz = 0;
+       /* calculate number of sg elements left over in the 1st frame */
+       max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) -
+           sizeof(Mpi2SGEIOUnion_t)) + ioc->sge_size);
+       ioc->max_sges_in_main_message = max_sge_elements/ioc->sge_size;
+
+       /* now do the same for a chain buffer */
+       max_sge_elements = ioc->request_sz - ioc->sge_size;
+       ioc->max_sges_in_chain_message = max_sge_elements/ioc->sge_size;
+
+       ioc->chain_offset_value_for_main_message =
+           ((sizeof(Mpi2SCSIIORequest_t) - sizeof(Mpi2SGEIOUnion_t)) +
+            (ioc->max_sges_in_chain_message * ioc->sge_size)) / 4;
+
+       /*
+        *  MPT2SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE
+        */
+       chains_needed_per_io = ((ioc->shost->sg_tablesize -
+          ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message)
+           + 1;
+       if (chains_needed_per_io > facts->MaxChainDepth) {
+               chains_needed_per_io = facts->MaxChainDepth;
+               ioc->shost->sg_tablesize = min_t(u16,
+               ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message
+               * chains_needed_per_io), ioc->shost->sg_tablesize);
+       }
+       ioc->chains_needed_per_io = chains_needed_per_io;
+
+       /* reply free queue sizing - taking into account for events */
+       num_of_reply_frames = ioc->request_depth + 32;
+
+       /* number of replies frames can't be a multiple of 16 */
+       /* decrease number of reply frames by 1 */
+       if (!(num_of_reply_frames % 16))
+               num_of_reply_frames--;
+
+       /* calculate number of reply free queue entries
+        *  (must be multiple of 16)
+        */
+
+       /* (we know reply_free_queue_depth is not a multiple of 16) */
+       queue_size = num_of_reply_frames;
+       queue_size += 16 - (queue_size % 16);
+       ioc->reply_free_queue_depth = queue_size;
+
+       /* reply descriptor post queue sizing */
+       /* this size should be the number of request frames + number of reply
+        * frames
+        */
+
+       queue_size = ioc->request_depth + num_of_reply_frames + 1;
+       /* round up to 16 byte boundary */
+       if (queue_size % 16)
+               queue_size += 16 - (queue_size % 16);
+
+       /* check against IOC maximum reply post queue depth */
+       if (queue_size > facts->MaxReplyDescriptorPostQueueDepth) {
+               queue_diff = queue_size -
+                   facts->MaxReplyDescriptorPostQueueDepth;
+
+               /* round queue_diff up to multiple of 16 */
+               if (queue_diff % 16)
+                       queue_diff += 16 - (queue_diff % 16);
+
+               /* adjust request_depth, reply_free_queue_depth,
+                * and queue_size
+                */
+               ioc->request_depth -= queue_diff;
+               ioc->reply_free_queue_depth -= queue_diff;
+               queue_size -= queue_diff;
+       }
+       ioc->reply_post_queue_depth = queue_size;
+
+       /* max scsi host queue depth */
+       ioc->shost->can_queue = ioc->request_depth - INTERNAL_CMDS_COUNT;
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host queue: depth"
+           "(%d)\n", ioc->name, ioc->shost->can_queue));
+
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: "
+           "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), "
+           "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message,
+           ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
+           ioc->chains_needed_per_io));
+
+       /* contiguous pool for request and chains, 16 byte align, one extra "
+        * "frame for smid=0
+        */
+       ioc->chain_depth = ioc->chains_needed_per_io * ioc->request_depth;
+       sz = ((ioc->request_depth + 1 + ioc->chain_depth) * ioc->request_sz);
+
+       ioc->request_dma_sz = sz;
+       ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma);
+       if (!ioc->request) {
+               printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
+                   "failed: req_depth(%d), chains_per_io(%d), frame_sz(%d), "
+                   "total(%d kB)\n", ioc->name, ioc->request_depth,
+                   ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
+               if (ioc->request_depth < MPT2SAS_SAS_QUEUE_DEPTH)
+                       goto out;
+               retry_sz += 64;
+               ioc->request_depth = max_request_credit - retry_sz;
+               goto retry_allocation;
+       }
+
+       if (retry_sz)
+               printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
+                   "succeed: req_depth(%d), chains_per_io(%d), frame_sz(%d), "
+                   "total(%d kb)\n", ioc->name, ioc->request_depth,
+                   ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
+
+       ioc->chain = ioc->request + ((ioc->request_depth + 1) *
+           ioc->request_sz);
+       ioc->chain_dma = ioc->request_dma + ((ioc->request_depth + 1) *
+           ioc->request_sz);
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): "
+           "depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
+           ioc->request, ioc->request_depth, ioc->request_sz,
+           ((ioc->request_depth + 1) * ioc->request_sz)/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth"
+           "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain,
+           ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
+           ioc->request_sz))/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n",
+           ioc->name, (unsigned long long) ioc->request_dma));
+       total_sz += sz;
+
+       ioc->scsi_lookup = kcalloc(ioc->request_depth,
+           sizeof(struct request_tracker), GFP_KERNEL);
+       if (!ioc->scsi_lookup) {
+               printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n",
+                   ioc->name);
+               goto out;
+       }
+
+        /* initialize some bits */
+       for (i = 0; i < ioc->request_depth; i++)
+               ioc->scsi_lookup[i].smid = i + 1;
+
+       /* sense buffers, 4 byte align */
+       sz = ioc->request_depth * SCSI_SENSE_BUFFERSIZE;
+       ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4,
+           0);
+       if (!ioc->sense_dma_pool) {
+               printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_create failed\n",
+                   ioc->name);
+               goto out;
+       }
+       ioc->sense = pci_pool_alloc(ioc->sense_dma_pool , GFP_KERNEL,
+           &ioc->sense_dma);
+       if (!ioc->sense) {
+               printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_alloc failed\n",
+                   ioc->name);
+               goto out;
+       }
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+           "sense pool(0x%p): depth(%d), element_size(%d), pool_size"
+           "(%d kB)\n", ioc->name, ioc->sense, ioc->request_depth,
+           SCSI_SENSE_BUFFERSIZE, sz/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_dma(0x%llx)\n",
+           ioc->name, (unsigned long long)ioc->sense_dma));
+       total_sz += sz;
+
+       /* reply pool, 4 byte align */
+       sz = ioc->reply_free_queue_depth * ioc->reply_sz;
+       ioc->reply_dma_pool = pci_pool_create("reply pool", ioc->pdev, sz, 4,
+           0);
+       if (!ioc->reply_dma_pool) {
+               printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_create failed\n",
+                   ioc->name);
+               goto out;
+       }
+       ioc->reply = pci_pool_alloc(ioc->reply_dma_pool , GFP_KERNEL,
+           &ioc->reply_dma);
+       if (!ioc->reply) {
+               printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_alloc failed\n",
+                   ioc->name);
+               goto out;
+       }
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply pool(0x%p): depth"
+           "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->reply,
+           ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_dma(0x%llx)\n",
+           ioc->name, (unsigned long long)ioc->reply_dma));
+       total_sz += sz;
+
+       /* reply free queue, 16 byte align */
+       sz = ioc->reply_free_queue_depth * 4;
+       ioc->reply_free_dma_pool = pci_pool_create("reply_free pool",
+           ioc->pdev, sz, 16, 0);
+       if (!ioc->reply_free_dma_pool) {
+               printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_create "
+                   "failed\n", ioc->name);
+               goto out;
+       }
+       ioc->reply_free = pci_pool_alloc(ioc->reply_free_dma_pool , GFP_KERNEL,
+           &ioc->reply_free_dma);
+       if (!ioc->reply_free) {
+               printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_alloc "
+                   "failed\n", ioc->name);
+               goto out;
+       }
+       memset(ioc->reply_free, 0, sz);
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free pool(0x%p): "
+           "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name,
+           ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_dma"
+           "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
+       total_sz += sz;
+
+       /* reply post queue, 16 byte align */
+       sz = ioc->reply_post_queue_depth * sizeof(Mpi2DefaultReplyDescriptor_t);
+       ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
+           ioc->pdev, sz, 16, 0);
+       if (!ioc->reply_post_free_dma_pool) {
+               printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create "
+                   "failed\n", ioc->name);
+               goto out;
+       }
+       ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
+           GFP_KERNEL, &ioc->reply_post_free_dma);
+       if (!ioc->reply_post_free) {
+               printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc "
+                   "failed\n", ioc->name);
+               goto out;
+       }
+       memset(ioc->reply_post_free, 0, sz);
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
+           "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
+           ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
+           sz/1024));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = "
+           "(0x%llx)\n", ioc->name, (unsigned long long)
+           ioc->reply_post_free_dma));
+       total_sz += sz;
+
+       ioc->config_page_sz = 512;
+       ioc->config_page = pci_alloc_consistent(ioc->pdev,
+           ioc->config_page_sz, &ioc->config_page_dma);
+       if (!ioc->config_page) {
+               printk(MPT2SAS_ERR_FMT "config page: pci_pool_alloc "
+                   "failed\n", ioc->name);
+               goto out;
+       }
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size"
+           "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma"
+           "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma));
+       total_sz += ioc->config_page_sz;
+
+       printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n",
+           ioc->name, total_sz/1024);
+       printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), "
+           "Max Controller Queue Depth(%d)\n",
+           ioc->name, ioc->shost->can_queue, facts->RequestCredit);
+       printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n",
+           ioc->name, ioc->shost->sg_tablesize);
+       return 0;
+
+ out:
+       _base_release_memory_pools(ioc);
+       return -ENOMEM;
+}
+
+
+/**
+ * base_get_iocstate - Get the current state of a MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @cooked: Request raw or cooked IOC state
+ *
+ * Returns all IOC Doorbell register bits if cooked==0, else just the
+ * Doorbell bits in MPI_IOC_STATE_MASK.
+ */
+u32
+base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked)
+{
+       u32 s, sc;
+
+       s = readl(&ioc->chip->Doorbell);
+       sc = s & MPI2_IOC_STATE_MASK;
+       return cooked ? sc : s;
+}
+
+/**
+ * _base_wait_on_iocstate - waiting on a particular ioc state
+ * @ioc_state: controller state { READY, OPERATIONAL, or RESET }
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_wait_on_iocstate(struct MPT2SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
+    int sleep_flag)
+{
+       u32 count, cntdn;
+       u32 current_state;
+
+       count = 0;
+       cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+       do {
+               current_state = base_get_iocstate(ioc, 1);
+               if (current_state == ioc_state)
+                       return 0;
+               if (count && current_state == MPI2_IOC_STATE_FAULT)
+                       break;
+               if (sleep_flag == CAN_SLEEP)
+                       msleep(1);
+               else
+                       udelay(500);
+               count++;
+       } while (--cntdn);
+
+       return current_state;
+}
+
+/**
+ * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
+ * a write to the doorbell)
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_DOORBELL_INTERRUPT - set to one when IOC writes to doorbell.
+ */
+static int
+_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
+    int sleep_flag)
+{
+       u32 cntdn, count;
+       u32 int_status;
+
+       count = 0;
+       cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+       do {
+               int_status = readl(&ioc->chip->HostInterruptStatus);
+               if (int_status & MPI2_HIS_DOORBELL_INTERRUPT) {
+                       dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                           "successfull count(%d), timeout(%d)\n", ioc->name,
+                           __func__, count, timeout));
+                       return 0;
+               }
+               if (sleep_flag == CAN_SLEEP)
+                       msleep(1);
+               else
+                       udelay(500);
+               count++;
+       } while (--cntdn);
+
+       printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
+           "int_status(%x)!\n", ioc->name, __func__, count, int_status);
+       return -EFAULT;
+}
+
+/**
+ * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_IOP_DOORBELL_STATUS - set to one when host writes to
+ * doorbell.
+ */
+static int
+_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
+    int sleep_flag)
+{
+       u32 cntdn, count;
+       u32 int_status;
+       u32 doorbell;
+
+       count = 0;
+       cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+       do {
+               int_status = readl(&ioc->chip->HostInterruptStatus);
+               if (!(int_status & MPI2_HIS_IOP_DOORBELL_STATUS)) {
+                       dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                           "successfull count(%d), timeout(%d)\n", ioc->name,
+                           __func__, count, timeout));
+                       return 0;
+               } else if (int_status & MPI2_HIS_DOORBELL_INTERRUPT) {
+                       doorbell = readl(&ioc->chip->Doorbell);
+                       if ((doorbell & MPI2_IOC_STATE_MASK) ==
+                           MPI2_IOC_STATE_FAULT) {
+                               base_fault_info(ioc , doorbell);
+                               return -EFAULT;
+                       }
+               } else if (int_status == 0xFFFFFFFF)
+                       goto out;
+
+               if (sleep_flag == CAN_SLEEP)
+                       msleep(1);
+               else
+                       udelay(500);
+               count++;
+       } while (--cntdn);
+
+ out:
+       printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
+           "int_status(%x)!\n", ioc->name, __func__, count, int_status);
+       return -EFAULT;
+}
+
+#if defined(MUR)
+/**
+ * _base_send_ioc_reset - send doorbell reset
+ * @ioc: per adapter object
+ * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_send_ioc_reset(struct MPT2SAS_ADAPTER *ioc, u8 reset_type, int timeout,
+    int sleep_flag)
+{
+       u32 ioc_state;
+       int r = 0;
+
+       if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) {
+               printk(MPT2SAS_ERR_FMT "%s: unknown reset_type\n",
+                   ioc->name, __func__);
+               return -EFAULT;
+       }
+
+       if (!(ioc->facts.IOCCapabilities &
+          MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY))
+               return -EFAULT;
+
+       printk(MPT2SAS_INFO_FMT "sending message unit reset !!\n", ioc->name);
+
+       writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT,
+           &ioc->chip->Doorbell);
+       if ((_base_wait_for_doorbell_ack(ioc, 15, sleep_flag))) {
+               r = -EFAULT;
+               goto out;
+       }
+       ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY,
+           timeout, sleep_flag);
+       if (ioc_state) {
+               printk(MPT2SAS_ERR_FMT "%s: failed going to ready state "
+                   " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
+               r = -EFAULT;
+               goto out;
+       }
+ out:
+       printk(MPT2SAS_INFO_FMT "message unit reset: %s\n",
+           ioc->name, ((r == 0) ? "SUCCESS" : "FAILED"));
+       return r;
+}
+#endif
+
+/**
+ * _base_handshake_req_reply_wait - send request thru doorbell interface
+ * @ioc: per adapter object
+ * @request_bytes: request length
+ * @request: pointer having request payload
+ * @reply_bytes: reply length
+ * @reply: pointer to reply payload
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
+    u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
+{
+       MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
+       int i;
+       u8 failed;
+       u16 dummy;
+       u32 *mfp;
+
+       /* make sure doorbell is not in use */
+       if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
+               printk(MPT2SAS_ERR_FMT "doorbell is in use "
+                   " (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+
+       /* clear pending doorbell interrupts from previous state changes */
+       if (readl(&ioc->chip->HostInterruptStatus) &
+           MPI2_HIS_IOC2SYS_DB_STATUS)
+               writel(0, &ioc->chip->HostInterruptStatus);
+
+       /* send message to ioc */
+       writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
+           ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
+           &ioc->chip->Doorbell);
+
+       if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+               printk(MPT2SAS_ERR_FMT "doorbell handshake "
+                  "int failed (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+       writel(0, &ioc->chip->HostInterruptStatus);
+
+       if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
+               printk(MPT2SAS_ERR_FMT "doorbell handshake "
+                   "ack failed (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+
+       /* send message 32-bits at a time */
+       for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
+               writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
+               if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
+                       failed = 1;
+       }
+
+       if (failed) {
+               printk(MPT2SAS_ERR_FMT "doorbell handshake "
+                   "sending request failed (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+
+       /* now wait for the reply */
+       if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
+               printk(MPT2SAS_ERR_FMT "doorbell handshake "
+                  "int failed (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+
+       /* read the first two 16-bits, it gives the total length of the reply */
+       reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+           & MPI2_DOORBELL_DATA_MASK);
+       writel(0, &ioc->chip->HostInterruptStatus);
+       if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+               printk(MPT2SAS_ERR_FMT "doorbell handshake "
+                  "int failed (line=%d)\n", ioc->name, __LINE__);
+               return -EFAULT;
+       }
+       reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+           & MPI2_DOORBELL_DATA_MASK);
+       writel(0, &ioc->chip->HostInterruptStatus);
+
+       for (i = 2; i < default_reply->MsgLength * 2; i++)  {
+               if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+                       printk(MPT2SAS_ERR_FMT "doorbell "
+                           "handshake int failed (line=%d)\n", ioc->name,
+                           __LINE__);
+                       return -EFAULT;
+               }
+               if (i >=  reply_bytes/2) /* overflow case */
+                       dummy = readl(&ioc->chip->Doorbell);
+               else
+                       reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+                           & MPI2_DOORBELL_DATA_MASK);
+               writel(0, &ioc->chip->HostInterruptStatus);
+       }
+
+       _base_wait_for_doorbell_int(ioc, 5, sleep_flag);
+       if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
+               dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "doorbell is in use "
+                   " (line=%d)\n", ioc->name, __LINE__));
+       }
+
+       if (ioc->logging_level & MPT_DEBUG_INIT) {
+               mfp = (u32 *)reply;
+               printk(KERN_DEBUG "\toffset:data\n");
+               for (i = 0; i < reply_bytes/4; i++)
+                       printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+                           le32_to_cpu(mfp[i]));
+       }
+       return 0;
+}
+
+/**
+ * base_sas_iounit_control - send sas iounit control to FW
+ * @ioc: per adapter object
+ * @mpi_reply: the reply payload from FW
+ * @mpi_request: the request payload sent to FW
+ *
+ * The SAS IO Unit Control Request message allows the host to perform low-level
+ * operations, such as resets on the PHYs of the IO Unit, also allows the host
+ * to obtain the IOC assigned device handles for a device if it has other
+ * identifying information about the device, in addition allows the host to
+ * remove IOC resources associated with the device.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, Mpi2SasIoUnitControlReply_t
+    *mpi_reply, Mpi2SasIoUnitControlRequest_t *mpi_request)
+{
+       u16 smid;
+       u32 ioc_state;
+       unsigned long timeleft;
+       u8 issue_reset;
+       int rc;
+       void *request;
+       u16 wait_state_count;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       mutex_lock(&ioc->base_cmds.mutex);
+
+       if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       wait_state_count = 0;
+       ioc_state = base_get_iocstate(ioc, 1);
+       while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+               if (wait_state_count++ == 10) {
+                       printk(MPT2SAS_ERR_FMT
+                           "%s: failed due to ioc not operational\n",
+                           ioc->name, __func__);
+                       rc = -EFAULT;
+                       goto out;
+               }
+               ssleep(1);
+               ioc_state = base_get_iocstate(ioc, 1);
+               printk(MPT2SAS_INFO_FMT "%s: waiting for "
+                   "operational state(count=%d)\n", ioc->name,
+                   __func__, wait_state_count);
+       }
+
+       smid = base_get_smid(ioc, ioc->base_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       rc = 0;
+       ioc->base_cmds.status = MPT2_CMD_PENDING;
+       request = base_get_msg_frame(ioc, smid);
+       ioc->base_cmds.smid = smid;
+       memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t));
+       if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
+           mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
+               ioc->ioc_link_reset_in_progress = 1;
+       base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
+           msecs_to_jiffies(10000));
+       if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
+           mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) &&
+           ioc->ioc_link_reset_in_progress)
+               ioc->ioc_link_reset_in_progress = 0;
+       if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2SasIoUnitControlRequest_t)/4);
+               if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
+                       issue_reset = 1;
+               goto issue_host_reset;
+       }
+       if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
+               memcpy(mpi_reply, ioc->base_cmds.reply,
+                   sizeof(Mpi2SasIoUnitControlReply_t));
+       else
+               memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t));
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       goto out;
+
+ issue_host_reset:
+       if (issue_reset)
+               base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       rc = -EFAULT;
+ out:
+       mutex_unlock(&ioc->base_cmds.mutex);
+       return rc;
+}
+
+
+/**
+ * base_scsi_enclosure_processor - sending request to sep device
+ * @ioc: per adapter object
+ * @mpi_reply: the reply payload from FW
+ * @mpi_request: the request payload sent to FW
+ *
+ * The SCSI Enclosure Processor request message causes the IOC to
+ * communicate with SES devices to control LED status signals.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, Mpi2SepReply_t
+    *mpi_reply, Mpi2SepRequest_t *mpi_request)
+{
+       u16 smid;
+       u32 ioc_state;
+       unsigned long timeleft;
+       u8 issue_reset;
+       int rc;
+       void *request;
+       u16 wait_state_count;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       mutex_lock(&ioc->base_cmds.mutex);
+
+       if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       wait_state_count = 0;
+       ioc_state = base_get_iocstate(ioc, 1);
+       while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+               if (wait_state_count++ == 10) {
+                       printk(MPT2SAS_ERR_FMT
+                           "%s: failed due to ioc not operational\n",
+                           ioc->name, __func__);
+                       rc = -EFAULT;
+                       goto out;
+               }
+               ssleep(1);
+               ioc_state = base_get_iocstate(ioc, 1);
+               printk(MPT2SAS_INFO_FMT "%s: waiting for "
+                   "operational state(count=%d)\n", ioc->name,
+                   __func__, wait_state_count);
+       }
+
+       smid = base_get_smid(ioc, ioc->base_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       rc = 0;
+       ioc->base_cmds.status = MPT2_CMD_PENDING;
+       request = base_get_msg_frame(ioc, smid);
+       ioc->base_cmds.smid = smid;
+       memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
+       base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
+           msecs_to_jiffies(10000));
+       if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2SepRequest_t)/4);
+               if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
+                       issue_reset = 1;
+               goto issue_host_reset;
+       }
+       if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
+               memcpy(mpi_reply, ioc->base_cmds.reply,
+                   sizeof(Mpi2SepReply_t));
+       else
+               memset(mpi_reply, 0, sizeof(Mpi2SepReply_t));
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       goto out;
+
+ issue_host_reset:
+       if (issue_reset)
+               base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       rc = -EFAULT;
+ out:
+       mutex_unlock(&ioc->base_cmds.mutex);
+       return rc;
+}
+
+/**
+ * _base_get_port_facts - obtain port facts reply and save in ioc
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)
+{
+       Mpi2PortFactsRequest_t mpi_request;
+       Mpi2PortFactsReply_t mpi_reply, *pfacts;
+       int mpi_reply_sz, mpi_request_sz, r;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       mpi_reply_sz = sizeof(Mpi2PortFactsReply_t);
+       mpi_request_sz = sizeof(Mpi2PortFactsRequest_t);
+       memset(&mpi_request, 0, mpi_request_sz);
+       mpi_request.Function = MPI2_FUNCTION_PORT_FACTS;
+       mpi_request.PortNumber = port;
+       r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
+           (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
+
+       if (r != 0) {
+               printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
+                   ioc->name, __func__, r);
+               return r;
+       }
+
+       pfacts = &ioc->pfacts[port];
+       memset(pfacts, 0, sizeof(Mpi2PortFactsReply_t));
+       pfacts->PortNumber = mpi_reply.PortNumber;
+       pfacts->VP_ID = mpi_reply.VP_ID;
+       pfacts->VF_ID = mpi_reply.VF_ID;
+       pfacts->MaxPostedCmdBuffers =
+           le16_to_cpu(mpi_reply.MaxPostedCmdBuffers);
+
+       return 0;
+}
+
+/**
+ * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
+{
+       Mpi2IOCFactsRequest_t mpi_request;
+       Mpi2IOCFactsReply_t mpi_reply, *facts;
+       int mpi_reply_sz, mpi_request_sz, r;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
+       mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
+       memset(&mpi_request, 0, mpi_request_sz);
+       mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
+       r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
+           (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
+
+       if (r != 0) {
+               printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
+                   ioc->name, __func__, r);
+               return r;
+       }
+
+       facts = &ioc->facts;
+       memset(facts, 0, sizeof(Mpi2IOCFactsReply_t));
+       facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
+       facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
+       facts->VP_ID = mpi_reply.VP_ID;
+       facts->VF_ID = mpi_reply.VF_ID;
+       facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
+       facts->MaxChainDepth = mpi_reply.MaxChainDepth;
+       facts->WhoInit = mpi_reply.WhoInit;
+       facts->NumberOfPorts = mpi_reply.NumberOfPorts;
+       facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
+       facts->MaxReplyDescriptorPostQueueDepth =
+           le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
+       facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
+       facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
+       if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
+               ioc->ir_firmware = 1;
+       facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
+       facts->IOCRequestFrameSize =
+           le16_to_cpu(mpi_reply.IOCRequestFrameSize);
+       facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
+       facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
+       ioc->shost->max_id = -1;
+       facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
+       facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
+       facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
+       facts->HighPriorityCredit =
+           le16_to_cpu(mpi_reply.HighPriorityCredit);
+       facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
+       facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
+
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hba queue depth(%d), "
+           "max chains per io(%d)\n", ioc->name, facts->RequestCredit,
+           facts->MaxChainDepth));
+       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request frame size(%d), "
+           "reply frame size(%d)\n", ioc->name,
+           facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
+       return 0;
+}
+
+/**
+ * _base_send_ioc_init - send ioc_init to firmware
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+{
+       Mpi2IOCInitRequest_t mpi_request;
+       Mpi2IOCInitReply_t mpi_reply;
+       int r;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_IOC_INIT;
+       mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
+       mpi_request.VF_ID = VF_ID;
+       mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
+       mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
+
+       /* In MPI Revision I (0xA), the SystemReplyFrameSize(offset 0x18) was
+        * removed and made reserved.  For those with older firmware will need
+        * this fix. It was decided that the Reply and Request frame sizes are
+        * the same.
+        */
+       if ((ioc->facts.HeaderVersion >> 8) < 0xA) {
+               mpi_request.Reserved7 = cpu_to_le16(ioc->reply_sz);
+/*             mpi_request.SystemReplyFrameSize =
+ *              cpu_to_le16(ioc->reply_sz);
+ */
+       }
+
+       mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4);
+       mpi_request.ReplyDescriptorPostQueueDepth =
+           cpu_to_le16(ioc->reply_post_queue_depth);
+       mpi_request.ReplyFreeQueueDepth =
+           cpu_to_le16(ioc->reply_free_queue_depth);
+
+#if BITS_PER_LONG > 32
+       mpi_request.SenseBufferAddressHigh =
+           cpu_to_le32(ioc->sense_dma >> 32);
+       mpi_request.SystemReplyAddressHigh =
+           cpu_to_le32(ioc->reply_dma >> 32);
+       mpi_request.SystemRequestFrameBaseAddress =
+           cpu_to_le64(ioc->request_dma);
+       mpi_request.ReplyFreeQueueAddress =
+           cpu_to_le64(ioc->reply_free_dma);
+       mpi_request.ReplyDescriptorPostQueueAddress =
+           cpu_to_le64(ioc->reply_post_free_dma);
+#else
+       mpi_request.SystemRequestFrameBaseAddress =
+           cpu_to_le32(ioc->request_dma);
+       mpi_request.ReplyFreeQueueAddress =
+           cpu_to_le32(ioc->reply_free_dma);
+       mpi_request.ReplyDescriptorPostQueueAddress =
+           cpu_to_le32(ioc->reply_post_free_dma);
+#endif
+
+       if (ioc->logging_level & MPT_DEBUG_INIT) {
+               u32 *mfp;
+               int i;
+
+               mfp = (u32 *)&mpi_request;
+               printk(KERN_DEBUG "\toffset:data\n");
+               for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
+                       printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+                           le32_to_cpu(mfp[i]));
+       }
+
+       r = _base_handshake_req_reply_wait(ioc,
+           sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request,
+           sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10,
+           sleep_flag);
+
+       if (r != 0) {
+               printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
+                   ioc->name, __func__, r);
+               return r;
+       }
+
+       if (mpi_reply.IOCStatus != MPI2_IOCSTATUS_SUCCESS ||
+           mpi_reply.IOCLogInfo) {
+               printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__);
+               r = -EIO;
+       }
+
+       return 0;
+}
+
+/**
+ * _base_send_port_enable - send port_enable(discovery stuff) to firmware
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+{
+       Mpi2PortEnableRequest_t *mpi_request;
+       u32 ioc_state;
+       unsigned long timeleft;
+       int r = 0;
+       u16 smid;
+
+       printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name);
+
+       if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
+               printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
+                   ioc->name, __func__);
+               return -EAGAIN;
+       }
+
+       smid = base_get_smid(ioc, ioc->base_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               return -EAGAIN;
+       }
+
+       ioc->base_cmds.status = MPT2_CMD_PENDING;
+       mpi_request = base_get_msg_frame(ioc, smid);
+       ioc->base_cmds.smid = smid;
+       memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
+       mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
+       mpi_request->VF_ID = VF_ID;
+
+       base_put_smid_default(ioc, smid, VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
+           300*HZ);
+       if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2PortEnableRequest_t)/4);
+               if (ioc->base_cmds.status & MPT2_CMD_RESET)
+                       r = -EFAULT;
+               else
+                       r = -ETIME;
+               goto out;
+       } else
+               dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+                   ioc->name, __func__));
+
+       ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL,
+           60, sleep_flag);
+       if (ioc_state) {
+               printk(MPT2SAS_ERR_FMT "%s: failed going to operational state "
+                   " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
+               r = -EFAULT;
+       }
+ out:
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       printk(MPT2SAS_INFO_FMT "port enable: %s\n",
+           ioc->name, ((r == 0) ? "SUCCESS" : "FAILED"));
+       return r;
+}
+
+/**
+ * _base_unmask_events - turn on notification for this event
+ * @ioc: per adapter object
+ * @event: firmware event
+ *
+ * The mask is stored in ioc->event_masks.
+ */
+static void
+_base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event)
+{
+       u32 desired_event;
+
+       if (event >= 128)
+               return;
+
+       desired_event = (1 << (event % 32));
+
+       if (event < 32)
+               ioc->event_masks[0] &= ~desired_event;
+       else if (event < 64)
+               ioc->event_masks[1] &= ~desired_event;
+       else if (event < 96)
+               ioc->event_masks[2] &= ~desired_event;
+       else if (event < 128)
+               ioc->event_masks[3] &= ~desired_event;
+}
+
+/**
+ * _base_event_notification - send event notification
+ * @ioc: per adapter object
+ * @VF_ID: virtual function id
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+{
+       Mpi2EventNotificationRequest_t *mpi_request;
+       unsigned long timeleft;
+       u16 smid;
+       int r = 0;
+       int i;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
+               printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
+                   ioc->name, __func__);
+               return -EAGAIN;
+       }
+
+       smid = base_get_smid(ioc, ioc->base_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               return -EAGAIN;
+       }
+       ioc->base_cmds.status = MPT2_CMD_PENDING;
+       mpi_request = base_get_msg_frame(ioc, smid);
+       ioc->base_cmds.smid = smid;
+       memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t));
+       mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
+       mpi_request->VF_ID = VF_ID;
+       for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
+               mpi_request->EventMasks[i] =
+                   le32_to_cpu(ioc->event_masks[i]);
+       base_put_smid_default(ioc, smid, VF_ID);
+       timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
+       if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               _debug_dump_mf(mpi_request,
+                   sizeof(Mpi2EventNotificationRequest_t)/4);
+               if (ioc->base_cmds.status & MPT2_CMD_RESET)
+                       r = -EFAULT;
+               else
+                       r = -ETIME;
+       } else
+               dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+                   ioc->name, __func__));
+       ioc->base_cmds.status = MPT2_CMD_NOT_USED;
+       return r;
+}
+
+/**
+ * base_validate_event_type - validating event types
+ * @ioc: per adapter object
+ * @event: firmware event
+ *
+ * This will turn on firmware event notification when application
+ * ask for that event. We don't mask events that are already enabled.
+ */
+void
+base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type)
+{
+       int i, j;
+       u32 event_mask, desired_event;
+       u8 send_update_to_fw;
+
+       for (i = 0, send_update_to_fw = 0; i <
+           MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) {
+               event_mask = ~event_type[i];
+               desired_event = 1;
+               for (j = 0; j < 32; j++) {
+                       if (!(event_mask & desired_event) &&
+                           (ioc->event_masks[i] & desired_event)) {
+                               ioc->event_masks[i] &= ~desired_event;
+                               send_update_to_fw = 1;
+                       }
+                       desired_event = (desired_event << 1);
+               }
+       }
+
+       if (!send_update_to_fw)
+               return;
+
+       mutex_lock(&ioc->base_cmds.mutex);
+       _base_event_notification(ioc, 0, CAN_SLEEP);
+       mutex_unlock(&ioc->base_cmds.mutex);
+}
+
+/**
+ * _base_diag_reset - the "big hammer" start of day reset
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
+{
+       u32 host_diagnostic;
+       u32 ioc_state;
+       u32 count;
+       u32 hcb_size;
+
+       printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name);
+
+       base_save_msix_table(ioc);
+
+       drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n",
+           ioc->name));
+       writel(0, &ioc->chip->HostInterruptStatus);
+
+       count = 0;
+       do {
+               /* Write magic sequence to WriteSequence register
+                * Loop until in diagnostic mode
+                */
+               drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "write magic "
+                   "sequence\n", ioc->name));
+               writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence);
+               writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence);
+
+               /* wait 100 msec */
+               if (sleep_flag == CAN_SLEEP)
+                       msleep(100);
+               else
+                       mdelay(100);
+
+               if (count++ > 20)
+                       goto out;
+
+               host_diagnostic = readl(&ioc->chip->HostDiagnostic);
+               drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "wrote magic "
+                   "sequence: count(%d), host_diagnostic(0x%08x)\n",
+                   ioc->name, count, host_diagnostic));
+
+       } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0);
+
+       hcb_size = readl(&ioc->chip->HCBSize);
+
+       drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "diag reset: issued\n",
+           ioc->name));
+       writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
+            &ioc->chip->HostDiagnostic);
+
+       /* don't access any registers for 50 milliseconds */
+       msleep(50);
+
+       /* 300 second max wait */
+       for (count = 0; count < 3000000 ; count++) {
+
+               host_diagnostic = readl(&ioc->chip->HostDiagnostic);
+
+               if (host_diagnostic == 0xFFFFFFFF)
+                       goto out;
+               if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
+                       break;
+
+               /* wait 100 msec */
+               if (sleep_flag == CAN_SLEEP)
+                       msleep(1);
+               else
+                       mdelay(1);
+       }
+
+       if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
+
+               drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter "
+                   "assuming the HCB Address points to good F/W\n",
+                   ioc->name));
+               host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
+               host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
+               writel(host_diagnostic, &ioc->chip->HostDiagnostic);
+
+               drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+                   "re-enable the HCDW\n", ioc->name));
+               writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE,
+                   &ioc->chip->HCBSize);
+       }
+
+       drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter\n",
+           ioc->name));
+       writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET,
+           &ioc->chip->HostDiagnostic);
+
+       drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "disable writes to the "
+           "diagnostic register\n", ioc->name));
+       writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
+
+       drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "Wait for FW to go to the "
+           "READY state\n", ioc->name));
+       ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20,
+           sleep_flag);
+       if (ioc_state) {
+               printk(MPT2SAS_ERR_FMT "%s: failed going to ready state "
+                   " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
+               goto out;
+       }
+
+       base_restore_msix_table(ioc);
+       printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name);
+       return 0;
+
+ out:
+       printk(MPT2SAS_ERR_FMT "diag reset: FAILED\n", ioc->name);
+       return -EFAULT;
+}
+
+/**
+ * _base_make_ioc_ready - put controller in READY state
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ * @type: FORCE_BIG_HAMMER or SOFT_RESET
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
+    enum reset_type type)
+{
+       u32 ioc_state;
+
+       dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+           __func__));
+
+       ioc_state = base_get_iocstate(ioc, 0);
+       dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: ioc_state(0x%08x)\n",
+           ioc->name, __func__, ioc_state));
+
+       if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY)
+               return 0;
+
+       if (ioc_state & MPI2_DOORBELL_USED) {
+               dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
+                   "active!\n", ioc->name));
+               goto issue_diag_reset;
+       }
+
+       if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
+               base_fault_info(ioc, ioc_state & MPI2_DOORBELL_DATA_MASK);
+               goto issue_diag_reset;
+       }
+
+       if (type == FORCE_BIG_HAMMER)
+               goto issue_diag_reset;
+
+#if defined(MUR)
+       if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
+               if (!(_base_send_ioc_reset(ioc,
+                   MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP)))
+                       return 0;
+#endif
+
+ issue_diag_reset:
+       return _base_diag_reset(ioc, CAN_SLEEP);
+}
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

drivers/scsi/mpt2sas/mpt2sas_base.h       2009-02-24 14:17:02.000000000 -0700 renamed from drivers/scsi/mpt2sas/mpt2sas_base.h       1969-12-31 17:00:00.000000000 -0700 +7 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Quoted 1 line

[Message clipped]

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Part of the diff is not shown here. View the raw message.

#2 lore raw
Quoted 29 lines · Grant Grundler

Review

Quoted 2 lines
(quoted diff) +2 -0
+static void
+_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 

smid, u8 VF_ID,

Quoted 4 lines

+    u32 reply)

drivers/scsi/mpt2sas/mpt2sas_base.c +3 -0
+{
+       MPI2DefaultReply_t *mpi_reply;
+       u16 ioc_status;

drivers/scsi/mpt2sas/mpt2sas_base.c line 503

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +10 -0
+
+       mpi_reply =  base_get_reply_virt_addr(ioc, reply);
+       ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+       if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
+           (ioc->logging_level & MPT_DEBUG_REPLY)) {
+               _base_sas_ioc_info(ioc , mpi_reply,
+                   base_get_msg_frame(ioc, smid));
+       }
+#endif

Can all the "if (ioc_status...)" gunk get wrapped into a macro that is conditionally defined?
e.g. the logging level could become a compile time option instead of a runtime option.

I was able to cut 1% CPU utilization from another driver by allowing the compiler to get
rid of all the debug messages that would never get printed because they were below
a particular threshold.

Quoted 3 lines

Maybe it doesn't matter in this case. But I've no clue yet how often/when _base_display_reply_info()
is called.

I have already implemented macros for all the debug prints in the driver. In addition, these debug prints are designed to be compile time options, as you have suggested. There are logging levels to designate different type of debug that one would be interested in. There is an option in the Kconfig via CONFIG_SCSI_MPT2SAS_LOGGING for this. Please refer to mpt2sas_debug.h and Kconfig.

Also, this particular function needs to be called all the time becuase at the end of it we are printing out the loginfos returned by controller firmware. The loginfos are needed as a way to be informed when problems resonating below the driver in controller firmware.

Quoted 9 lines

drivers/scsi/mpt2sas/mpt2sas_base.c

Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +8 -0
+static void
+_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
+{
+       u32 him_register;
+
+       ioc->mask_interrupts = 1;
+       him_register = readl(&ioc->chip->HostInterruptMask);
+       him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + 

MPI2_HIM_RESET_IRQ_MASK;

Quoted 5 lines
Quoted 1 line

+       writel(him_register, &ioc->chip->HostInterruptMask);

This is a posted write. Does it need to be flushed?
ie do other parts of the driver require this take effect immediately or will they tolerate some late arriving interrupt?

What are you suggesting? Calling wmb()?

I thought I was handling this case. I'm setting the flag "ioc->mask_interrupts". If there are any spurious interrupts that occur following this calling this function, I will ignore them from the interrupt routine -> base_interrupt() where I have this sanity check.

Quoted 7 lines
Quoted 4 lines

+       completed_cmds = 0;
+       do {
+               if (ioc->reply_post_free[post_index].Words ==
+                   0xFFFFFFFFFFFFFFFFULL)

Would this be better written as "~0ULL" or as a predefined constant?

I guess your right, that would be better becuase its shorter.

Quoted 15 lines
Quoted 6 lines

+       /* reply post descriptor handling */
+       post_index_next = ioc->reply_post_host_index;
+       for (i = 0 ; i < completed_cmds; i++) {
+               post_index = post_index_next;
+               /* poison the reply post descriptor */
+               ioc->reply_post_free[post_index_next].Words =

Quoted 8 lines

+                   0xFFFFFFFFFFFFFFFFULL;
+               post_index_next = (post_index ==
+                   (ioc->reply_post_queue_depth - 1))
+                   ? 0 : post_index + 1;
+       }
+       ioc->reply_post_host_index = post_index_next;
+       writel(post_index_next, &ioc->chip->ReplyPostHostIndex);
+       wmb();

Quoted 7 lines

What is the wmb() protecting here? Add a comment?

My impression is the wmb() belongs in front of the writel() and not behind it.
That is, we want to make sure the updates to ioc->reply_post_free[] are visible before sending out the writel().

I'm doing is a 64bit write to pcie memory. On some systems this is broken out to two 32bit writes. So I put the barrier there to insure the entire 64bits was written out to the ReplyPostHostIndex register before another write was done.

Quoted 37 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+static int
+_base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, 

struct pci_dev *pdev)

drivers/scsi/mpt2sas/mpt2sas_base.c

Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +8 -0
+{
+       struct sysinfo s;
+       char *desc = NULL;
+
+       if (sizeof(dma_addr_t) > 4) {
+               const uint64_t required_mask =
+                   dma_get_required_mask(&pdev->dev);
+               if ((required_mask > DMA_32BIT_MASK) && 

!pci_set_dma_mask(pdev,

Quoted 1 line

+                   DMA_64BIT_MASK) &&

!pci_set_consistent_dma_mask(pdev,

Quoted 2 lines

+                   DMA_64BIT_MASK)) {
+                       ioc->base_add_sg_single =

&base_add_sg_single_64;

Quoted 7 lines

+                       ioc->sge_size = sizeof(Mpi2SGESimple64_t);
+                       desc = "64";
+                       goto out;
+               }
+       }

drivers/scsi/mpt2sas/mpt2sas_base.c +2 -0
+
+       if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)

drivers/scsi/mpt2sas/mpt2sas_base.c

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +10 -0
+           && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+               ioc->base_add_sg_single = &base_add_sg_single_32;
+               ioc->sge_size = sizeof(Mpi2SGESimple32_t);
+               desc = "32";
+       } else
+               return -ENODEV;
+
+ out:
+       si_meminfo(&s);
+       printk(MPT2SAS_INFO_FMT "%s BIT PCI BUS DMA 

ADDRESSING SUPPORTED, "

Quoted 1 line

+           "total mem (%ld kB)\n", ioc->name, desc,

convert_to_kb(s.totalram));

Quoted 10 lines

drivers/scsi/mpt2sas/mpt2sas_base.c line 878

Quoted 3 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +3 -0
+
+       return 0;
+}

Interesting. I would have expected the dma_mask and consistent_dma_mask
to not depend on each other. ie set dma_mask to 64, if that fails, set dma_mask to 32-bit.
Rinse and repeat for consistent_dma_mask.

I'm not clear what your point is. My algorithm is to find out if the system has addressable memory above 32bit boundary, then set that mask for 64bit, else go for 32bit addressing.

Quoted 20 lines
Quoted 20 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +20 -0
+/**
+ * base_check_enable_msix - checks MSIX capabable.
+ * @ioc: per adapter object
+ *
+ * Check to see if card is capable of MSIX, and set number
+ * of avaliable msix vectors
+ */
+static int
+base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)
+{
+       int base;
+       u16 message_control;
+       u32 msix_table_offset;
+
+       base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
+       if (!base) {
+               dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not "
+                   "supported\n", ioc->name));
+               return -EINVAL;
+       }
Quoted 8 lines
Quoted 4 lines

+
+       /* get msix vector count */
+       pci_read_config_word(ioc->pdev, base + 2, &message_control);
+       ioc->msix_vector_count = (message_control & 0x3FF) + 1;

Any comments on why the return value from pci_enable_msix() isn't used here?

I'm calling pci_enable_msix() from base_enable_msix(), and from that function I'm checking the return value. I'm not clear what your point is.

Quoted 3 lines

I wasn't expecting the drivers would need to read the MSIX table directly.

There is a bug in the hardware, where the msix table is cleared out during host reset. So the architechs here at LSI decided to address this errata by having all the device driver writters back and restore this table during host reset. I made reference to this errata from the comments in base_save_msix_table().

Quoted 9 lines
Quoted 2 lines

+
+       /* current HW implemention uses only one interrupt

handler */

Which implementation?
This comment sounds like it expects to be obsolete soon. Specifying the implementation makes it clear even when other implementations become available.

The explanation is currently we only map the first MSIX vector for all interrupts In future products we may have more expand to use more vectors, however that has not been decided upon yet. What I mean by more vectors is we might map the 1st vector for initiator mode, and the 2nd for target mode, or maybe in virtualization, each VF port is assigned its own handler.

Quoted 9 lines
Quoted 2 lines

+       r = request_irq(entries[0].vector, base_interrupt,

IRQF_SHARED,

Quoted 1 line

+           ioc->name, ioc);

MSI is never shared. IRQF_SHARED flag is still correct?

I have to stop looking now...back to work. :(

There are two drivers that currently implement MSIX in the scsi tree. I found the emulex driver doing IRQF_SHARED, and qlogic is zero. Since we suport shared interrupts, I set it up for that. I didn't know if it mattered, does it?

     --

To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#3 lore raw
Quoted 9 lines · Eric
Quoted 9 lines

drivers/scsi/mpt2sas/mpt2sas_base.c

Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +8 -0
+static void
+_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
+{
+ ? ? ? u32 him_register;
+
+ ? ? ? ioc->mask_interrupts = 1;
+ ? ? ? him_register = readl(&ioc->chip->HostInterruptMask);
+ ? ? ? him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + 

MPI2_HIM_RESET_IRQ_MASK;

Quoted 7 lines
Quoted 5 lines
Quoted 1 line

+ ? ? ? writel(him_register, &ioc->chip->HostInterruptMask);

This is a posted write. Does it need to be flushed?
ie do other parts of the driver require this take effect immediately or will they tolerate some late arriving interrupt?

What are you suggesting? Calling wmb()?

PCI writes can be posted, so the him_register writel() may not complete for a few thousand cycles. wmb() isn't going to solve the problem. A readl() from the device would, as would your current solution of ignoring subsequent interrupts.

Quoted 17 lines

I thought I was handling this case. I'm setting the flag "ioc->mask_interrupts". If there are any spurious interrupts that occur following this calling this function, I will ignore them from the interrupt routine -> base_interrupt() where I have this sanity check.

Quoted 15 lines
Quoted 14 lines

+ ? ? ? /* reply post descriptor handling */
+ ? ? ? post_index_next = ioc->reply_post_host_index;
+ ? ? ? for (i = 0 ; i < completed_cmds; i++) {
+ ? ? ? ? ? ? ? post_index = post_index_next;
+ ? ? ? ? ? ? ? /* poison the reply post descriptor */
+ ? ? ? ? ? ? ? ioc->reply_post_free[post_index_next].Words =
+ ? ? ? ? ? ? ? ? ? 0xFFFFFFFFFFFFFFFFULL;
+ ? ? ? ? ? ? ? post_index_next = (post_index ==
+ ? ? ? ? ? ? ? ? ? (ioc->reply_post_queue_depth - 1))
+ ? ? ? ? ? ? ? ? ? ? 0 : post_index + 1;
+ ? ? ? }
+ ? ? ? ioc->reply_post_host_index = post_index_next;
+ ? ? ? writel(post_index_next, &ioc->chip->ReplyPostHostIndex);
+ ? ? ? wmb();

Quoted 8 lines
Quoted 6 lines

What is the wmb() protecting here? Add a comment?

My impression is the wmb() belongs in front of the writel() and not behind it.
That is, we want to make sure the updates to ioc->reply_post_free[] are visible before sending out the writel().

I'm doing is a 64bit write to pcie memory. On some systems this is broken out to two 32bit writes. So I put the barrier there to insure the entire 64bits was written out to the ReplyPostHostIndex register before another write was done.

Um, you're doing a writel(), not a writeq(), so you're doing a 32-bit write. Also, PCI writes can't be reordered, so you don't need a wmb() here.

Quoted 9 lines
Quoted 7 lines
Quoted 1 line

+ ? ? ? /* current HW implemention uses only one interrupt

handler */

Which implementation?
This comment sounds like it expects to be obsolete soon. Specifying the implementation makes it clear even when other implementations become available.

The explanation is currently we only map the first MSIX vector for all interrupts In future products we may have more expand to use more vectors, however that has not been decided upon yet. What I mean by more vectors is we might map the 1st vector for initiator mode, and the 2nd for target mode, or maybe in virtualization, each VF port is assigned its own handler.

It's also worth considering a mode where each CPU gets its own interrupt. That lets us complete IOs on the CPU which submitted them and can be a real performance win.

Quoted 11 lines
Quoted 9 lines
Quoted 2 lines

+ ? ? ? r = request_irq(entries[0].vector, base_interrupt,

IRQF_SHARED,

Quoted 1 line

+ ? ? ? ? ? ioc->name, ioc);

MSI is never shared. IRQF_SHARED flag is still correct?

I have to stop looking now...back to work. :(

There are two drivers that currently implement MSIX in the scsi tree. I found the emulex driver doing IRQF_SHARED, and qlogic is zero. Since we suport shared interrupts, I set it up for that. I didn't know if it mattered, does it?

It doesn't matter.

I'm somewhat puzzled that you request four MSI-X interrupts, then only use one of them. Why not just request one?

Are there any currently shipping products using this chip? It'd be nice to get hold of some. Also, is there any documentation available to the public (or under NDA) on programming this hardware?

Signature · 4 lines
Matthew Wilcox				Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."
#4 lore raw

On Wednesday, February 25, 2009 2:12 PM, Matthew Wilcox wrote:
are visible before sending out the writel().

Quoted 8 lines
Quoted 2 lines

I'm doing is a 64bit write to pcie memory. On some systems

this is broken out to two 32bit writes. So I put the barrier there to insure the entire 64bits was written out to the ReplyPostHostIndex register before another write was done. Um, you're doing a writel(), not a writeq(), so you're doing a 32-bit write. Also, PCI writes can't be reordered, so you don't need a wmb() here.

my mistake, I meant 32bit write. I was thinking about another place where I do 64bit writeq.

Quoted 4 lines

It's also worth considering a mode where each CPU gets its own interrupt. That lets us complete IOs on the CPU which submitted them and can be a real performance win.

right, I was wondering if we could do that. Perhaps we could discuss that further in how do to that.

Quoted 4 lines

I'm somewhat puzzled that you request four MSI-X interrupts, then only use one of them. Why not just request one?

I wasn't sure if we pci_enable_msix would work when passed 1 in the 2nd parameter when we have 15 vectors available.

Quoted 7 lines

Are there any currently shipping products using this chip? It'd be nice
to get hold of some. Also, is there any documentation available to the
public (or under NDA) on programming this hardware?

We have not released the production version of the chip yet. You could contact the LSI/Intel FAE rep. If you don't already have that, let me know.

#5 lore raw
Quoted 6 lines · Eric
Quoted 3 lines · Matthew Wilcox

It's also worth considering a mode where each CPU gets its own interrupt. That lets us complete IOs on the CPU which submitted them and can be a real performance win.

right, I was wondering if we could do that. Perhaps we could discuss that further in how do to that.

It's something that's being worked on. I'm not quite sure where we are on it with the SCSI side. From the PCI side, we're at a point where you can request however many vectors you want and then assign them however you want. I think we need a higher-level API than that, but we're not quite sure what it should look like yet (and I want to redesign the lower-level API anyway, because it's horrible for drivers to use).

Quoted 4 lines
Quoted 2 lines

I'm somewhat puzzled that you request four MSI-X interrupts, then only use one of them. Why not just request one?

I wasn't sure if we pci_enable_msix would work when passed 1 in the 2nd parameter when we have 15 vectors available.

Yes, that works fine.

Signature · 4 lines
Matthew Wilcox				Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."
maintainer
#6 lore raw
In reply to Matthew Wilcox
Quoted 16 lines · Matthew Wilcox
Quoted 15 lines · Eric
Quoted 14 lines

drivers/scsi/mpt2sas/mpt2sas_base.c

Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +8 -0
+static void
+_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
+{
+ ? ? ? u32 him_register;
+
+ ? ? ? ioc->mask_interrupts = 1;
+ ? ? ? him_register = readl(&ioc->chip->HostInterruptMask);
+ ? ? ? him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + 

MPI2_HIM_RESET_IRQ_MASK;

Quoted 1 line

+ ? ? ? writel(him_register, &ioc->chip->HostInterruptMask);

This is a posted write. Does it need to be flushed?
ie do other parts of the driver require this take effect immediately or will they tolerate some late arriving interrupt?

Quoted 6 lines
Quoted 1 line

What are you suggesting? Calling wmb()?

PCI writes can be posted, so the him_register writel() may not complete for a few thousand cycles. wmb() isn't going to solve the problem. A readl() from the device would, as would your current solution of ignoring subsequent interrupts.

This seems to be the most serious issue with the current patch set. If you repost with that fixed, I can put it into scsi-misc and we can address the other issues later.

James

#7 lore raw
Quoted 19 lines · James Bottomley
Quoted 18 lines · Matthew Wilcox
Quoted 16 lines · Eric
Quoted 9 lines

drivers/scsi/mpt2sas/mpt2sas_base.c

Quoted 8 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +8 -0
+static void
+_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
+{
+ ? ? ? u32 him_register;
+
+ ? ? ? ioc->mask_interrupts = 1;
+ ? ? ? him_register = readl(&ioc->chip->HostInterruptMask);
+ ? ? ? him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + 

MPI2_HIM_RESET_IRQ_MASK;

Quoted 5 lines
Quoted 1 line

+ ? ? ? writel(him_register, &ioc->chip->HostInterruptMask);

This is a posted write. Does it need to be flushed?
ie do other parts of the driver require this take effect immediately or will they tolerate some late arriving interrupt?

What are you suggesting? Calling wmb()?

Quoted 8 lines
Quoted 4 lines

PCI writes can be posted, so the him_register writel() may not complete for a few thousand cycles. wmb() isn't going to solve the problem. A readl() from the device would, as would your current solution of ignoring subsequent interrupts.

This seems to be the most serious issue with the current patch set. If you repost with that fixed, I can put it into scsi-misc and we can address the other issues later.

I'm confused. There's no issue with the code that Eric posted. Grant asked if he needs to readl() in order to flush the posted write, but the answer is no, because if a spurious interrupt comes in, the interrupt handler will ignore it. So I don't see what Eric needs to fix.

Signature · 4 lines
Matthew Wilcox				Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."
#11 lore raw
In reply to Moore, Eric

I think of the issues was clarified...a few more are still open (below) but shouldn't
preclude inclusion in scsi-misc and continue the dialog around that code.

On Wed, Feb 25, 2009 at 12:27 PM, Moore, Eric <[email protected]> wrote:
...
[ re _base_display_reply_info() function ]

Quoted 1 line

Also, this particular function needs to be called all the time becuase at the end of it we are printing out the loginfos returned by controller firmware.  The loginfos are needed as a way to be informed when  problems resonating below the driver in controller firmware.

Ok. The frequency this gets called will dictate if it's a problem or not. The design choice makes sense though.

Diagnostic logging is something linux still sucks at but is getting better (dev_printk is a good step).

Quoted 11 lines
Quoted 11 lines

drivers/scsi/mpt2sas/mpt2sas_base.c

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_base.c +8 -0
+static void
+_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
+{
+       u32 him_register;
+
+       ioc->mask_interrupts = 1;
+       him_register = readl(&ioc->chip->HostInterruptMask);
+       him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM +

MPI2_HIM_RESET_IRQ_MASK;

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

+       writel(him_register, &ioc->chip->HostInterruptMask);

This is a posted write. Does it need to be flushed?
ie do other parts of the driver require this take effect immediately or will they tolerate some late arriving interrupt?

What are you suggesting?   Calling wmb()?

No. "Flushing" meant "readl()".

Quoted 1 line

I thought I was handling this case.   I'm setting the flag "ioc->mask_interrupts".  If there are any spurious interrupts that occur following this calling this function, I will ignore them from the interrupt routine -> base_interrupt() where I have this sanity check.

No change required then. My preference would be to flush the writel in base_mask_interrupts and avoid adding code to the interrupt routine. But this will work too.

...

Quoted 6 lines
Quoted 6 lines
Quoted 3 lines

+       ioc->reply_post_host_index = post_index_next;
+       writel(post_index_next, &ioc->chip->ReplyPostHostIndex);
+       wmb();

What is the wmb() protecting here? Add a comment?

Quoted 7 lines
Quoted 5 lines

My impression is the wmb() belongs in front of the writel() and not behind it.
That is, we want to make sure the updates to ioc->reply_post_free[] are visible before sending out the writel().

I'm doing is a 64bit write to pcie memory. On some systems this is broken out to two 32bit writes.  So I put the barrier there to insure the entire 64bits was written out to the ReplyPostHostIndex register before another write was done.

Can you add a comment what the wmb() is protecting against? The above explanation wasn't quite right and I still have the feeling this wmb() is misplaced. FWIW, I expect this would only cause problems on alpha/ia64 (machines which have weak memory ordering).

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
(quoted diff) +2 -0
+static int
+_base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc,

...

Quoted 6 lines
Quoted 4 lines

Interesting. I would have expected the dma_mask and consistent_dma_mask to not depend on each other. ie set dma_mask to 64, if that fails, set dma_mask to 32-bit. Rinse and repeat for consistent_dma_mask.

I'm not clear what your point is.   My algorithm is to find out if the system has addressable memory above 32bit boundary, then set that mask for 64bit, else go for 32bit addressing.

Yeah, this ok. It's just a little more convoluted than other drivers I've looked at in the past.

My preference would be the driver not try to optimize in this case since the pci_set_dma_mask(DMA_64_MASK) could fail in the case where 32-BIT DMA mask would be sufficient. However, most drivers won't change API because of this.

Again, this is an issue for future discussion and not something that would block adoption of this driver.

...

Quoted 1 line
Quoted 1 line
Quoted 1 line

+base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)

...

Quoted 9 lines
Quoted 7 lines
Quoted 3 lines

+       /* get msix vector count */
+       pci_read_config_word(ioc->pdev, base + 2, &message_control);
+       ioc->msix_vector_count = (message_control & 0x3FF) + 1;

Any comments on why the return value from pci_enable_msix() isn't used here?

I'm calling pci_enable_msix() from base_enable_msix(), and from that function I'm checking the return value.   I'm not clear what your point is.

My point is device drivers in general shouldn't need to frob MSI config space. ioc->msix_vector_count should be set in the same function that is calling pci_enable_msix(). But I haven't looked at all of the code (including base_save_msix_table() mentioned below) and will drop this part of the thread until I do.

Quoted 8 lines
Quoted 3 lines

I wasn't expecting the drivers would need to read the MSIX table directly.

There is a bug in the hardware, where the msix table is cleared out during host reset. So the architects here at LSI decided to address this errata by having all the device driver writters back and restore this table during host reset. I made reference to this errata from the comments in base_save_msix_table().

Ah ok - I didn't see those (yet). Sounds good.

Quoted 5 lines
Quoted 5 lines
Quoted 3 lines

+
+       /* current HW implemention uses only one interrupt

handler */

Quoted 7 lines
Quoted 5 lines

Which implementation?
This comment sounds like it expects to be obsolete soon. Specifying the implementation makes it clear even when other implementations become available.

The explanation is currently we only map the first MSIX vector for all interrupts

The "current implementation" has a name or revision. I'm just asking a specific name or version be used instead of "current".

Quoted 4 lines

  In future products we may have more expand to use more vectors, however that has not been decided upon yet. What I mean by more vectors is we might map the 1st vector for initiator mode, and the 2nd for target mode, or maybe in virtualization, each VF port is assigned its own handler.

Yup - reserving those for future use is fine. I think willy already pointed out if the driver knows only one is used, the driver should only allocate one vector.

...

Quoted 1 line
Quoted 1 line

MSI is never shared. IRQF_SHARED flag is still correct?

...

Quoted 2 lines

There are two drivers that currently implement MSIX in the scsi tree.  I found the emulex driver doing IRQF_SHARED, and qlogic is zero.

There are more in drivers/net:
grundler <2034>find -name \*.c | xargs fgrep -l pci_enable_msix | xargs fgrep -l request_irq
./bnx2.c
./bnx2x_main.c
./cxgb3/cxgb3_main.c
./e1000e/netdev.c
./enic/enic_main.c
./forcedeth.c
./igb/igb_main.c
./ixgbe/ixgbe_main.c
./myri10ge/myri10ge.c
./netxen/netxen_nic_main.c
./niu.c
./qlge/qlge_main.c
./s2io.c

But one has to manually check IRQF_SHARED usage. I don't know how to script something that verifies request_irq() is called in the MSI-X enabled case.

Quoted 1 line

Since we support shared interrupts, I set it up for that.  I didn't know if it mattered, does it?

I don't think it's correct but I don't know if it matters either. I doubt it does.
I was hoping someone else would "just know".

I hope that clarifies my concerns and apologies for not responding sooner.

thanks,
grant
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#8 lore raw
In reply to James Bottomley
Quoted 7 lines · James Bottomley
Quoted 4 lines · Matthew Wilcox
Quoted 1 line · Eric

What are you suggesting? Calling wmb()?

PCI writes can be posted, so the him_register writel() may

not complete

Quoted 1 line

for a few thousand cycles. wmb() isn't going to solve the

Quoted 9 lines

problem. A

Quoted 2 lines

readl() from the device would, as would your current solution of ignoring subsequent interrupts.

This seems to be the most serious issue with the current patch set. If
you repost with that fixed, I can put it into scsi-misc and we can address the other issues later.

I will repost the patch set tommorrow with the following changes

(1) Add readl following writel from the function that disables interrupts

(2) Replace 0xFFFFFFFFFFFFFFFFULL with ~0ULL

(3) when calling pci_enable_msix, only pass one msix entry (instead of 15).

(4) remove the "current HW implementation uses..... " comment in the sources

(5) merge in a bug fix for SIGIO/POLLIN notifcation reported by the storlib team.

Eric Moore

#9 lore raw
Quoted 25 lines · Eric
Quoted 12 lines · James Bottomley
Quoted 6 lines · Matthew Wilcox
Quoted 2 lines · Eric

What are you suggesting? Calling wmb()?

PCI writes can be posted, so the him_register writel() may

not complete

Quoted 2 lines

for a few thousand cycles. wmb() isn't going to solve the

Quoted 10 lines

problem. A

Quoted 3 lines

readl() from the device would, as would your current solution of ignoring subsequent interrupts.

This seems to be the most serious issue with the current patch set. If you repost with that fixed, I can put it into scsi-misc and we can address the other issues later.

Quoted 4 lines

I will repost the patch set tommorrow with the following changes

(1) Add readl following writel from the function that disables interrupts

Is a memory barrier required after the writel and before the readl to ensure that the writel executes before the readl on processors other than x86_64 and ia32?

Quoted 13 lines

(2) Replace 0xFFFFFFFFFFFFFFFFULL with ~0ULL

(3) when calling pci_enable_msix, only pass one msix entry (instead of 15).

(4) remove the "current HW implementation uses..... " comment in the sources

(5) merge in a bug fix for SIGIO/POLLIN notifcation reported by the storlib team.

Eric Moore--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#10 lore raw
Quoted 5 lines · Rob Evers
Quoted 1 line

(1) Add readl following writel from the function that disables interrupts

Is a memory barrier required after the writel and before the readl to ensure that the writel executes before the readl on processors other than x86_64 and ia32?

No. Architectures such as PowerPC and Altix which have the potential to issue writes out of order wrt io memory are required to implement barriers in their writel() implementation.

Signature · 4 lines
Matthew Wilcox				Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."