⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qla_os.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *                  QLOGIC LINUX SOFTWARE * * QLogic ISP2x00 device driver for Linux 2.6.x * Copyright (C) 2003-2004 QLogic Corporation * (www.qlogic.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; either version 2, 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. * */#include "qla_def.h"#include <linux/moduleparam.h>#include <linux/vmalloc.h>#include <linux/smp_lock.h>#include <linux/delay.h>#include <scsi/scsi_tcq.h>#include <scsi/scsicam.h>#include <scsi/scsi_transport.h>#include <scsi/scsi_transport_fc.h>/* * Driver version */char qla2x00_version_str[40];/* * SRB allocation cache */char srb_cachep_name[16];kmem_cache_t *srb_cachep;/* * Stats for all adpaters. */struct _qla2x00stats qla2x00_stats;/* * Ioctl related information. */int num_hosts;int apiHBAInstance;/* * Module parameter information and variables */int ql2xmaxqdepth;module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(ql2xmaxqdepth,		"Maximum queue depth to report for target devices.");int ql2xlogintimeout = 20;module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(ql2xlogintimeout,		"Login timeout value in seconds.");int qlport_down_retry;module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(qlport_down_retry,		"Maximum number of command retries to a port that returns"		"a PORT-DOWN status.");int ql2xretrycount = 20;module_param(ql2xretrycount, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(ql2xretrycount,		"Maximum number of mid-layer retries allowed for a command.  "		"Default value is 20, ");int displayConfig;module_param(displayConfig, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(displayConfig,		"If 1 then display the configuration used in /etc/modprobe.conf.");int ql2xplogiabsentdevice;module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(ql2xplogiabsentdevice,		"Option to enable PLOGI to devices that are not present after "		"a Fabric scan.  This is needed for several broken switches."		"Default is 0 - no PLOGI. 1 - perfom PLOGI.");int ql2xenablezio = 0;module_param(ql2xenablezio, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(ql2xenablezio,		"Option to enable ZIO:If 1 then enable it otherwise" 		" use the default set in the NVRAM."		" Default is 0 : disabled");int ql2xintrdelaytimer = 10;module_param(ql2xintrdelaytimer, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(ql2xintrdelaytimer,		"ZIO: Waiting time for Firmware before it generates an "		"interrupt to the host to notify completion of request.");int ConfigRequired;module_param(ConfigRequired, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(ConfigRequired,		"If 1, then only configured devices passed in through the"		"ql2xopts parameter will be presented to the OS");int Bind = BIND_BY_PORT_NAME;module_param(Bind, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(Bind,		"Target persistent binding method: "		"0 by Portname (default); 1 by PortID; 2 by Nodename. ");int ql2xsuspendcount = SUSPEND_COUNT;module_param(ql2xsuspendcount, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(ql2xsuspendcount,		"Number of 6-second suspend iterations to perform while a "		"target returns a <NOT READY> status.  Default is 10 "		"iterations.");int ql2xdoinitscan = 1;module_param(ql2xdoinitscan, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(ql2xdoinitscan,		"Signal mid-layer to perform scan after driver load: 0 -- no "		"signal sent to mid-layer.");int ql2xloginretrycount = 0;module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(ql2xloginretrycount,		"Specify an alternate value for the NVRAM login retry count.");/* * Proc structures and functions */struct info_str {	char	*buffer;	int	length;	off_t	offset;	int	pos;};static void copy_mem_info(struct info_str *, char *, int);static int copy_info(struct info_str *, char *, ...);static void qla2x00_free_device(scsi_qla_host_t *);static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);/* * SCSI host template entry points  */static int qla2xxx_slave_configure(struct scsi_device * device);static int qla2x00_queuecommand(struct scsi_cmnd *cmd,		void (*fn)(struct scsi_cmnd *));static int qla2xxx_eh_abort(struct scsi_cmnd *);static int qla2xxx_eh_device_reset(struct scsi_cmnd *);static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);static int qla2xxx_eh_host_reset(struct scsi_cmnd *);static int qla2x00_loop_reset(scsi_qla_host_t *ha);static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);static int qla2x00_proc_info(struct Scsi_Host *, char *, char **,    off_t, int, int);static struct scsi_host_template qla2x00_driver_template = {	.module			= THIS_MODULE,	.name			= "qla2xxx",	.proc_name		= "qla2xxx",	.proc_info		= qla2x00_proc_info,	.queuecommand		= qla2x00_queuecommand,	.eh_abort_handler	= qla2xxx_eh_abort,	.eh_device_reset_handler = qla2xxx_eh_device_reset,	.eh_bus_reset_handler	= qla2xxx_eh_bus_reset,	.eh_host_reset_handler	= qla2xxx_eh_host_reset,	.slave_configure	= qla2xxx_slave_configure,	.this_id		= -1,	.cmd_per_lun		= 3,	.use_clustering		= ENABLE_CLUSTERING,	.sg_tablesize		= SG_ALL,	/*	 * The RISC allows for each command to transfer (2^32-1) bytes of data,	 * which equates to 0x800000 sectors.	 */	.max_sectors		= 0xFFFF,};static struct scsi_transport_template *qla2xxx_transport_template = NULL;static void qla2x00_display_fc_names(scsi_qla_host_t *);/* TODO Convert to inlines * * Timer routines */#define	WATCH_INTERVAL		1       /* number of seconds */static void qla2x00_timer(scsi_qla_host_t *);static __inline__ void qla2x00_start_timer(scsi_qla_host_t *,    void *, unsigned long);static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *);static inline voidqla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval){	init_timer(&ha->timer);	ha->timer.expires = jiffies + interval * HZ;	ha->timer.data = (unsigned long)ha;	ha->timer.function = (void (*)(unsigned long))func;	add_timer(&ha->timer);	ha->timer_active = 1;}static inline voidqla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval){	mod_timer(&ha->timer, jiffies + interval * HZ);}static __inline__ voidqla2x00_stop_timer(scsi_qla_host_t *ha){	del_timer_sync(&ha->timer);	ha->timer_active = 0;}void qla2x00_cmd_timeout(srb_t *);static __inline__ void qla2x00_callback(scsi_qla_host_t *, struct scsi_cmnd *);static __inline__ void sp_put(struct scsi_qla_host * ha, srb_t *sp);static __inline__ void sp_get(struct scsi_qla_host * ha, srb_t *sp);static __inline__ voidqla2x00_delete_from_done_queue(scsi_qla_host_t *, srb_t *); /** qla2x00_callback*      Returns the completed SCSI command to LINUX.** Input:*	ha -- Host adapter structure*	cmd -- SCSI mid-level command structure.* Returns:*      None* Note:From failover point of view we always get the sp*      from vis_ha pool in queuecommand.So when we put it *      back to the pool it has to be the vis_ha.	 *      So rely on struct scsi_cmnd to get the vis_ha and not on sp. 		 	*/static inline voidqla2x00_callback(scsi_qla_host_t *ha, struct scsi_cmnd *cmd){	srb_t *sp = (srb_t *) CMD_SP(cmd);	scsi_qla_host_t *vis_ha;	os_lun_t *lq;	int got_sense;	unsigned long	cpu_flags = 0;	cmd->host_scribble = (unsigned char *) NULL;	vis_ha = (scsi_qla_host_t *) cmd->device->host->hostdata;	if (sp == NULL) {		qla_printk(KERN_INFO, ha,			"%s(): **** CMD derives a NULL SP\n",			__func__);                DEBUG2(BUG();)		return;	}	/*	 * If command status is not DID_BUS_BUSY then go ahead and freed sp.	 */	/*	 * Cancel command timeout	 */	qla2x00_delete_timer_from_cmd(sp);	/*	 * Put SP back in the free queue	 */	sp->cmd   = NULL;	CMD_SP(cmd) = NULL;	lq = sp->lun_queue;	got_sense = (sp->flags & SRB_GOT_SENSE)? 1: 0;	add_to_free_queue(vis_ha, sp);	if (host_byte(cmd->result) == DID_OK) {		/* device ok */		ha->total_bytes += cmd->bufflen;		if (!got_sense) {			/* If lun was suspended then clear retry count */			spin_lock_irqsave(&lq->q_lock, cpu_flags);			if (!test_bit(LUN_EXEC_DELAYED, &lq->q_flag))				lq->q_state = LUN_STATE_READY;			spin_unlock_irqrestore(&lq->q_lock, cpu_flags);		}	} else if (host_byte(cmd->result) == DID_ERROR) {		/* device error */		ha->total_dev_errs++;	}	/* Call the mid-level driver interrupt handler */	(*(cmd)->scsi_done)(cmd);}/*************************************************************************** sp_put** Description:*   Decrement reference count and call the callback if we're the last*   owner of the specified sp. Will get the host_lock before calling*   the callback.** Input:*   ha - pointer to the scsi_qla_host_t where the callback is to occur.*   sp - pointer to srb_t structure to use.** Returns:***************************************************************************/static inline voidsp_put(struct scsi_qla_host * ha, srb_t *sp){        if (atomic_read(&sp->ref_count) == 0) {		qla_printk(KERN_INFO, ha,			"%s(): **** SP->ref_count not zero\n",			__func__);                DEBUG2(BUG();)                return;	}        if (!atomic_dec_and_test(&sp->ref_count)) {                return;        }        qla2x00_callback(ha, sp->cmd);}/*************************************************************************** sp_get** Description:*   Increment reference count of the specified sp.** Input:*   sp - pointer to srb_t structure to use.** Returns:***************************************************************************/static inline voidsp_get(struct scsi_qla_host * ha, srb_t *sp){        atomic_inc(&sp->ref_count);        if (atomic_read(&sp->ref_count) > 2) {		qla_printk(KERN_INFO, ha,			"%s(): **** SP->ref_count greater than two\n",			__func__);                DEBUG2(BUG();)		return;	}}static inline void qla2x00_delete_from_done_queue(scsi_qla_host_t *dest_ha, srb_t *sp) {	/* remove command from done list */	list_del_init(&sp->list);	dest_ha->done_q_cnt--;	sp->state = SRB_NO_QUEUE_STATE;	if (sp->flags & SRB_DMA_VALID) {		sp->flags &= ~SRB_DMA_VALID;		/* Release memory used for this I/O */		if (sp->cmd->use_sg) {			pci_unmap_sg(dest_ha->pdev, sp->cmd->request_buffer,			    sp->cmd->use_sg, sp->cmd->sc_data_direction);		} else if (sp->cmd->request_bufflen) {			pci_unmap_page(dest_ha->pdev, sp->dma_handle,			    sp->cmd->request_bufflen,			    sp->cmd->sc_data_direction);		}	}}static int qla2x00_do_dpc(void *data);static void qla2x00_rst_aen(scsi_qla_host_t *);static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);static void qla2x00_mem_free(scsi_qla_host_t *ha);static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);static srb_t *qla2x00_get_new_sp(scsi_qla_host_t *ha);static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *, char *, loff_t,    size_t);static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *, char *, loff_t,    size_t);static struct bin_attribute sysfs_fw_dump_attr = {	.attr = {		.name = "fw_dump",		.mode = S_IRUSR | S_IWUSR,		.owner = THIS_MODULE,	},	.size = 0,	.read = qla2x00_sysfs_read_fw_dump,	.write = qla2x00_sysfs_write_fw_dump,};static ssize_t qla2x00_sysfs_read_nvram(struct kobject *, char *, loff_t,    size_t);static ssize_t qla2x00_sysfs_write_nvram(struct kobject *, char *, loff_t,    size_t);static struct bin_attribute sysfs_nvram_attr = {	.attr = {		.name = "nvram",		.mode = S_IRUSR | S_IWUSR,		.owner = THIS_MODULE,	},	.size = sizeof(nvram_t),	.read = qla2x00_sysfs_read_nvram,	.write = qla2x00_sysfs_write_nvram,};/* -------------------------------------------------------------------------- *//* SysFS attributes. */static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf,    loff_t off, size_t count){	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,	    struct device, kobj)));	if (ha->fw_dump_reading == 0)		return 0;	if (off > ha->fw_dump_buffer_len)		return 0;	if (off + count > ha->fw_dump_buffer_len)		count = ha->fw_dump_buffer_len - off;	memcpy(buf, &ha->fw_dump_buffer[off], count);	return (count);}static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf,    loff_t off, size_t count){	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,	    struct device, kobj)));	int reading;	uint32_t dump_size;	if (off != 0)		return (0);	reading = simple_strtol(buf, NULL, 10);	switch (reading) {	case 0:		if (ha->fw_dump_reading == 1) {			qla_printk(KERN_INFO, ha,			    "Firmware dump cleared on (%ld).\n",			    ha->host_no);			vfree(ha->fw_dump_buffer);			free_pages((unsigned long)ha->fw_dump,			    ha->fw_dump_order);			ha->fw_dump_reading = 0;			ha->fw_dump_buffer = NULL;			ha->fw_dump = NULL;		}		break;	case 1:		if (ha->fw_dump != NULL && !ha->fw_dump_reading) {			ha->fw_dump_reading = 1;			dump_size = FW_DUMP_SIZE_1M;			if (ha->fw_memory_size < 0x20000) 				dump_size = FW_DUMP_SIZE_128K;			else if (ha->fw_memory_size < 0x80000) 				dump_size = FW_DUMP_SIZE_512K;			ha->fw_dump_buffer = (char *)vmalloc(dump_size);			if (ha->fw_dump_buffer == NULL) {				qla_printk(KERN_WARNING, ha,				    "Unable to allocate memory for firmware "				    "dump buffer (%d).\n", dump_size);				ha->fw_dump_reading = 0;				return (count);			}			qla_printk(KERN_INFO, ha,			    "Firmware dump ready for read on (%ld).\n",			    ha->host_no);			memset(ha->fw_dump_buffer, 0, dump_size);			if (IS_QLA2100(ha) || IS_QLA2200(ha)) 				qla2100_ascii_fw_dump(ha); 			else 				qla2300_ascii_fw_dump(ha);			ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer);		}		break;	}	return (count);}static ssize_t qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -