cregit-Linux how code gets into the kernel

Release 4.14 drivers/message/fusion/mptbase.c

/*
 *  linux/drivers/message/fusion/mptbase.c
 *      This is the Fusion MPT base driver which supports multiple
 *      (SCSI + LAN) specialized protocol drivers.
 *      For use with LSI PCI chip/adapter(s)
 *      running LSI Fusion MPT (Message Passing Technology) firmware.
 *
 *  Copyright (c) 1999-2008 LSI Corporation
 *  (mailto:DL-MPTFusionLinux@lsi.com)
 *
 */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    NO WARRANTY
    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
    solely responsible for determining the appropriateness of using and
    distributing the Program and assumes all risks associated with its
    exercise of rights under this Agreement, including but not limited to
    the risks and costs of program errors, damage to or loss of data,
    programs or equipment, and unavailability or interruption of operations.

    DISCLAIMER OF LIABILITY
    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/seq_file.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>		/* needed for in_interrupt() proto */
#include <linux/dma-mapping.h>
#include <linux/kthread.h>
#include <scsi/scsi_host.h>

#include "mptbase.h"
#include "lsi/mpi_log_fc.h"

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

#define my_NAME		"Fusion MPT base driver"

#define my_VERSION	MPT_LINUX_VERSION_COMMON

#define MYNAM		"mptbase"


MODULE_AUTHOR(MODULEAUTHOR);

MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");

MODULE_VERSION(my_VERSION);

/*
 *  cmd line parameters
 */


static int mpt_msi_enable_spi;
module_param(mpt_msi_enable_spi, int, 0);
MODULE_PARM_DESC(mpt_msi_enable_spi,
		 " Enable MSI Support for SPI controllers (default=0)");


static int mpt_msi_enable_fc;
module_param(mpt_msi_enable_fc, int, 0);
MODULE_PARM_DESC(mpt_msi_enable_fc,
		 " Enable MSI Support for FC controllers (default=0)");


static int mpt_msi_enable_sas;
module_param(mpt_msi_enable_sas, int, 0);
MODULE_PARM_DESC(mpt_msi_enable_sas,
		 " Enable MSI Support for SAS controllers (default=0)");


static int mpt_channel_mapping;
module_param(mpt_channel_mapping, int, 0);
MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");


static int mpt_debug_level;
static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
		  &mpt_debug_level, 0600);
MODULE_PARM_DESC(mpt_debug_level,
		 " debug level - refer to mptdebug.h - (default=0)");


int mpt_fwfault_debug;

EXPORT_SYMBOL(mpt_fwfault_debug);
module_param(mpt_fwfault_debug, int, 0600);
MODULE_PARM_DESC(mpt_fwfault_debug,
		 "Enable detection of Firmware fault and halt Firmware on fault - (default=0)");


static char	MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS]
				[MPT_MAX_CALLBACKNAME_LEN+1];

#ifdef MFCNT

static int mfcounter = 0;

#define PRINT_MF_COUNT 20000
#endif

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
 *  Public data...
 */


#define WHOINIT_UNKNOWN		0xAA

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
 *  Private data...
 */
					/* Adapter link list */

LIST_HEAD(ioc_list);
					/* Callback lookup table */

static MPT_CALLBACK		 MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
					/* Protocol driver class lookup table */

static int			 MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
					/* Event handler lookup table */

static MPT_EVHANDLER		 MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
					/* Reset handler lookup table */

static MPT_RESETHANDLER		 MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];

static struct mpt_pci_driver 	*MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];

#ifdef CONFIG_PROC_FS

static struct proc_dir_entry 	*mpt_proc_root_dir;
#endif

/*
 *  Driver Callback Index's
 */

static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;

static u8 last_drv_idx;

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
 *  Forward protos...
 */
static irqreturn_t mpt_interrupt(int irq, void *bus_id);
static int	mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
		MPT_FRAME_HDR *reply);
static int	mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
			u32 *req, int replyBytes, u16 *u16reply, int maxwait,
			int sleepFlag);
static int	mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
static void	mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
static void	mpt_adapter_disable(MPT_ADAPTER *ioc);
static void	mpt_adapter_dispose(MPT_ADAPTER *ioc);

static void	MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
static int	MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
static int	GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
static int	GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
static int	SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
static int	SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
static int	mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
static int	mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
static int	mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
static int	KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
static int	SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
static int	PrimeIocFifos(MPT_ADAPTER *ioc);
static int	WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
static int	WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
static int	WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
static int	GetLanConfigPages(MPT_ADAPTER *ioc);
static int	GetIoUnitPage2(MPT_ADAPTER *ioc);
int		mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
static int	mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
static int	mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
static void 	mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
static void 	mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
static void	mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
static int	SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
	int sleepFlag);
static int	SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
static int	mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
static int	mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);

#ifdef CONFIG_PROC_FS

static const struct file_operations mpt_summary_proc_fops;

static const struct file_operations mpt_version_proc_fops;

static const struct file_operations mpt_iocinfo_proc_fops;
#endif
static void	mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);

static int	ProcessEventNotification(MPT_ADAPTER *ioc,
		EventNotificationReply_t *evReply, int *evHandlers);
static void	mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
static void	mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
static void	mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
static void	mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);
static int	mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
static void	mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);

/* module entry point */
static int  __init    fusion_init  (void);
static void __exit    fusion_exit  (void);


#define CHIPREG_READ32(addr) 		readl_relaxed(addr)

#define CHIPREG_READ32_dmasync(addr)	readl(addr)

#define CHIPREG_WRITE32(addr,val) 	writel(val, addr)

#define CHIPREG_PIO_WRITE32(addr,val)	outl(val, (unsigned long)addr)

#define CHIPREG_PIO_READ32(addr) 	inl((unsigned long)addr)


static void pci_disable_io_access(struct pci_dev *pdev) { u16 command_reg; pci_read_config_word(pdev, PCI_COMMAND, &command_reg); command_reg &= ~1; pci_write_config_word(pdev, PCI_COMMAND, command_reg); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Moore38100.00%1100.00%
Total38100.00%1100.00%


static void pci_enable_io_access(struct pci_dev *pdev) { u16 command_reg; pci_read_config_word(pdev, PCI_COMMAND, &command_reg); command_reg |= 1; pci_write_config_word(pdev, PCI_COMMAND, command_reg); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Moore37100.00%1100.00%
Total37100.00%1100.00%


static int mpt_set_debug_level(const char *val, struct kernel_param *kp) { int ret = param_set_int(val, kp); MPT_ADAPTER *ioc; if (ret) return ret; list_for_each_entry(ioc, &ioc_list, list) ioc->debug_level = mpt_debug_level; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
James Bottomley54100.00%1100.00%
Total54100.00%1100.00%

/** * mpt_get_cb_idx - obtain cb_idx for registered driver * @dclass: class driver enum * * Returns cb_idx, or zero means it wasn't found **/
static u8 mpt_get_cb_idx(MPT_DRIVER_CLASS dclass) { u8 cb_idx; for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) if (MptDriverClass[cb_idx] == dclass) return cb_idx; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sathya Prakash M R40100.00%1100.00%
Total40100.00%1100.00%

/** * mpt_is_discovery_complete - determine if discovery has completed * @ioc: per adatper instance * * Returns 1 when discovery completed, else zero. */
static int mpt_is_discovery_complete(MPT_ADAPTER *ioc) { ConfigExtendedPageHeader_t hdr; CONFIGPARMS cfg; SasIOUnitPage0_t *buffer; dma_addr_t dma_handle; int rc = 0; memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); memset(&cfg, 0, sizeof(CONFIGPARMS)); hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; cfg.cfghdr.ehdr = &hdr; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; if ((mpt_config(ioc, &cfg))) goto out; if (!hdr.ExtPageLength) goto out; buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, &dma_handle); if (!buffer) goto out; cfg.physAddr = dma_handle; cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; if ((mpt_config(ioc, &cfg))) goto out_free_consistent; if (!(buffer->PhyData[0].PortFlags & MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS)) rc = 1; out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, buffer, dma_handle); out: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Kashyap Desai209100.00%1100.00%
Total209100.00%1100.00%

/** * mpt_remove_dead_ioc_func - kthread context to remove dead ioc * @arg: input argument, used to derive ioc * * Return 0 if controller is removed from pci subsystem. * Return -1 for other case. */
static int mpt_remove_dead_ioc_func(void *arg) { MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; struct pci_dev *pdev; if ((ioc == NULL)) return -1; pdev = ioc->pcidev; if ((pdev == NULL)) return -1; pci_stop_and_remove_bus_device_locked(pdev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kashyap Desai6298.41%150.00%
Rafael J. Wysocki11.59%150.00%
Total63100.00%2100.00%

/** * mpt_fault_reset_work - work performed on workq after ioc fault * @work: input argument, used to derive ioc * **/
static void mpt_fault_reset_work(struct work_struct *work) { MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, fault_reset_work.work); u32 ioc_raw_state; int rc; unsigned long flags; MPT_SCSI_HOST *hd; struct task_struct *p; if (ioc->ioc_reset_in_progress || !ioc->active) goto out; ioc_raw_state = mpt_GetIocState(ioc, 0); if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_MASK) { printk(MYIOC_s_INFO_FMT "%s: IOC is non-operational !!!!\n", ioc->name, __func__); /* * Call mptscsih_flush_pending_cmds callback so that we * flush all pending commands back to OS. * This call is required to aovid deadlock at block layer. * Dead IOC will fail to do diag reset,and this call is safe * since dead ioc will never return any command back from HW. */ hd = shost_priv(ioc->sh); ioc->schedule_dead_ioc_flush_running_cmds(hd); /*Remove the Dead Host */ p = kthread_run(mpt_remove_dead_ioc_func, ioc, "mpt_dead_ioc_%d", ioc->id); if (IS_ERR(p)) { printk(MYIOC_s_ERR_FMT "%s: Running mpt_dead_ioc thread failed !\n", ioc->name, __func__); } else { printk(MYIOC_s_WARN_FMT "%s: Running mpt_dead_ioc thread success !\n", ioc->name, __func__); } return; /* don't rearm timer */ } if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", ioc->name, __func__); rc = mpt_HardResetHandler(ioc, CAN_SLEEP); printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name, __func__, (rc == 0) ? "success" : "failed"); ioc_raw_state = mpt_GetIocState(ioc, 0); if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " "reset (%04xh)\n", ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) { if ((mpt_is_discovery_complete(ioc))) { devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing " "discovery_quiesce_io flag\n", ioc->name)); ioc->sas_discovery_quiesce_io = 0; } } out: /* * Take turns polling alternate controller */ if (ioc->alt_ioc) ioc = ioc->alt_ioc; /* rearm the timer */ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); if (ioc->reset_work_q) queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, msecs_to_jiffies(MPT_POLLING_INTERVAL)); spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Sathya Prakash M R21657.91%116.67%
Kashyap Desai15541.55%466.67%
Harvey Harrison20.54%116.67%
Total373100.00%6100.00%

/* * Process turbo (context) reply... */
static void mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) { MPT_FRAME_HDR *mf = NULL; MPT_FRAME_HDR *mr = NULL; u16 req_idx = 0; u8 cb_idx; dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n", ioc->name, pa)); switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) { case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT: req_idx = pa & 0x0000FFFF; cb_idx = (pa & 0x00FF0000) >> 16; mf = MPT_INDEX_2_MFPTR(ioc, req_idx); break; case MPI_CONTEXT_REPLY_TYPE_LAN: cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER); /* * Blind set of mf to NULL here was fatal * after lan_reply says "freeme" * Fix sort of combined with an optimization here; * added explicit check for case where lan_reply * was just returning 1 and doing nothing else. * For this case skip the callback, but set up * proper mf value first here:-) */ if ((pa & 0x58000000) == 0x58000000) { req_idx = pa & 0x0000FFFF; mf = MPT_INDEX_2_MFPTR(ioc, req_idx); mpt_free_msg_frame(ioc, mf); mb(); return; break; } mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); break; case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET: cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER); mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); break; default: cb_idx = 0; BUG(); } /* Check for (valid) IO callback! */ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || MptCallbacks[cb_idx] == NULL) { printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", __func__, ioc->name, cb_idx); goto out; } if (MptCallbacks[cb_idx](ioc, mf, mr)) mpt_free_msg_frame(ioc, mf); out: mb(); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Moore16367.63%114.29%
Linus Torvalds5121.16%114.29%
Sathya Prakash M R197.88%228.57%
Pam Delaney62.49%114.29%
Harvey Harrison10.41%114.29%
Christoph Hellwig10.41%114.29%
Total241100.00%7100.00%


static void mpt_reply(MPT_ADAPTER *ioc, u32 pa) { MPT_FRAME_HDR *mf; MPT_FRAME_HDR *mr; u16 req_idx; u8 cb_idx; int freeme; u32 reply_dma_low; u16 ioc_stat; /* non-TURBO reply! Hmmm, something may be up... * Newest turbo reply mechanism; get address * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)! */ /* Map DMA address of reply header to cpu address. * pa is 32 bits - but the dma address may be 32 or 64 bits * get offset based only only the low addresses */ reply_dma_low = (pa <<= 1); mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames + (reply_dma_low - ioc->reply_frames_low_dma)); req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx); cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; mf = MPT_INDEX_2_MFPTR(ioc, req_idx); dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n", ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function)); DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr); /* Check/log IOC log info */ ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); if (ioc->bus_type == FC) mpt_fc_log_info(ioc, log_info); else if (ioc->bus_type == SPI) mpt_spi_log_info(ioc, log_info); else if (ioc->bus_type == SAS) mpt_sas_log_info(ioc, log_info, cb_idx); } if (ioc_stat & MPI_IOCSTATUS_MASK) mpt_iocstatus_info(ioc, (u32)ioc_stat, mf); /* Check for (valid) IO callback! */ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || MptCallbacks[cb_idx] == NULL) { printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", __func__, ioc->name, cb_idx); freeme = 0; goto out; } freeme = MptCallbacks[cb_idx](ioc, mf, mr); out: /* Flush (non-TURBO) reply with a WRITE! */ CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa); if (freeme) mpt_free_msg_frame(ioc, mf); mb(); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Moore19958.53%535.71%
Linus Torvalds9026.47%17.14%
James Bottomley288.24%214.29%
Sathya Prakash M R154.41%214.29%
Christoph Hellwig30.88%17.14%
Kashyap Desai20.59%17.14%
Pam Delaney20.59%17.14%
Harvey Harrison10.29%17.14%
Total340100.00%14100.00%

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. * @irq: irq number (not used) * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure * * This routine is registered via the request_irq() kernel API call, * and handles all interrupts generated from a specific MPT adapter * (also referred to as a IO Controller or IOC). * This routine must clear the interrupt from the adapter and does * so by reading the reply FIFO. Multiple replies may be processed * per single call to this routine. * * This routine handles register-level access of the adapter but * dispatches (calls) a protocol-specific callback routine to handle * the protocol-specific details of the MPT request completion. */
static irqreturn_t mpt_interrupt(int irq, void *bus_id) { MPT_ADAPTER *ioc = bus_id; u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); if (pa == 0xFFFFFFFF) return IRQ_NONE; /* * Drain the reply FIFO! */ do { if (pa & MPI_ADDRESS_REPLY_A_BIT) mpt_reply(ioc, pa); else mpt_turbo_reply(ioc, pa); pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); } while (pa != 0xFFFFFFFF); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Moore5865.91%240.00%
Pam Delaney2326.14%120.00%
Linus Torvalds44.55%120.00%
David S. Miller33.41%120.00%
Total88100.00%5100.00%

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptbase_reply - MPT base driver's callback routine * @ioc: Pointer to MPT_ADAPTER structure * @req: Pointer to original MPT request frame * @reply: Pointer to MPT reply frame (NULL if TurboReply) * * MPT base driver's callback routine; all base driver * "internal" request/reply processing is routed here. * Currently used for EventNotification and EventAck handling. * * Returns 1 indicating original alloc'd request frame ptr * should be freed, or 0 if it shouldn't. */
static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { EventNotificationReply_t *pEventReply; u8 event; int evHandlers; int freereq = 1; switch (reply->u.hdr.Function) { case MPI_FUNCTION_EVENT_NOTIFICATION: pEventReply = (EventNotificationReply_t *)reply; evHandlers = 0; ProcessEventNotification(ioc, pEventReply, &evHandlers); event = le32_to_cpu(pEventReply->Event) & 0xFF; if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) freereq = 0; if (event != MPI_EVENT_EVENT_CHANGE) break; case MPI_FUNCTION_CONFIG: case MPI_FUNCTION_SAS_IO_UNIT_CONTROL: ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID; memcpy(ioc->mptbase_cmds.reply, reply, min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength)); if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING; complete(&ioc->mptbase_cmds.done); } else freereq = 0; if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF) freereq = 1; break; case MPI_FUNCTION_EVENT_ACK: devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "EventAck reply received\n", ioc->name)); break; default: printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n", ioc->name, reply->u.hdr.Function); break; } /* * Conditionally tell caller to free the original * EventNotification/EventAck/unexpected request frame! */ return freereq; }

Contributors

PersonTokensPropCommitsCommitProp
Kashyap Desai13154.13%120.00%
Linus Torvalds6627.27%120.00%
Pam Delaney3112.81%120.00%
Sathya Prakash M R104.13%120.00%
Eric Moore41.65%120.00%
Total242100.00%5100.00%

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_register - Register protocol-specific main callback handler. * @cbfunc: callback function pointer * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value) * @func_name: call function's name * * This routine is called by a protocol-specific driver (SCSI host, * LAN, SCSI target) to register its reply callback routine. Each * protocol-specific driver must do this before it will be able to * use any IOC resources, such as obtaining request frames. * * NOTES: The SCSI protocol driver currently calls this routine thrice * in order to register separate callbacks; one for "normal" SCSI IO; * one for MptScsiTaskMgmt requests; one for Scan/DV requests. * * Returns u8 valued "handle" in the range (and S.O.D. order) * {N,...,7,6,5,...,1} if successful. * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be * considered an error by the caller. */
u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name) { u8 cb_idx; last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS; /* * Search for empty callback slot in this order: {N,...,7,6,5,...,1} * (slot/handle 0 is reserved!) */ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { if (MptCallbacks[cb_idx] == NULL) { MptCallbacks[cb_idx] = cbfunc; MptDriverClass[cb_idx] = dclass; MptEvHandlers[cb_idx] = NULL; last_drv_idx = cb_idx; strlcpy(MptCallbacksName[cb_idx], func_name, MPT_MAX_CALLBACKNAME_LEN+1); break; } } return last_drv_idx; }

Contributors

PersonTokensPropCommitsCommitProp
Kashyap Desai5761.96%228.57%
Linus Torvalds1718.48%114.29%
Christoph Hellwig77.61%114.29%
Pam Delaney55.43%114.29%
Wagner Ferenc44.35%114.29%
Sathya Prakash M R22.17%114.29%
Total92100.00%7100.00%

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_deregister - Deregister a protocol drivers resources. * @cb_idx: previously registered callback handle * * Each protocol-specific driver should call this routine when its * module is unloaded. */
void mpt_deregister(u8 cb_idx) { if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) { MptCallbacks[cb_idx] = NULL; MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; MptEvHandlers[cb_idx] = NULL; last_drv_idx++; } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds4090.91%133.33%
Pam Delaney36.82%133.33%
Sathya Prakash M R12.27%133.33%
Total44100.00%3100.00%

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_event_register - Register protocol-specific event callback handler. * @cb_idx: previously registered (via mpt_register) callback handle * @ev_cbfunc: callback function * * This routine can be called by one or more protocol-specific drivers * if/when they choose to be notified of MPT events. * * Returns 0 for success. */
int mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc) { if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return -1; MptEvHandlers[cb_idx] = ev_cbfunc; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds3294.12%150.00%
Sathya Prakash M R25.88%150.00%
Total34100.00%2100.00%

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_event_deregister - Deregister protocol-specific event callback handler * @cb_idx: previously registered callback handle * * Each protocol-specific driver should call this routine * when it does not (or can no longer) handle events, * or when its module is unloaded. */
void mpt_event_deregister(u8 cb_idx) { if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return; MptEvHandlers[cb_idx] = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds2392.00%150.00%
Sathya Prakash M R28.00%150.00%
Total25100.00%2100.00%

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_reset_register - Register protocol-specific IOC reset handler. * @cb_idx: previously registered (via mpt_register) callback handle * @reset_func: reset function * * This routine can be called by one or more protocol-specific drivers * if/when they choose to be notified of IOC resets. * * Returns 0 for success. */
int mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func) { if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return -1; MptResetHandlers[cb_idx] = reset_func; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds3294.12%150.00%
Sathya Prakash M R25.88%150.00%
Total34100.00%2100.00%

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_reset_deregister - Deregister protocol-specific IOC reset handler. * @cb_idx: previously registered callback handle * * Each protocol-specific driver should call this routine * when it does not (or can no longer) handle IOC reset handling, * or when its module is unloaded. */
void mpt_reset_deregister(u8 cb_idx) { if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return; MptResetHandlers[cb_idx] = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds2392.00%150.00%
Sathya Prakash M R28.00%150.00%
Total25100.00%2100.00%

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/