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

📄 qla_os.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * QLogic Fibre Channel HBA Driver * Copyright (c)  2003-2005 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing 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 */static kmem_cache_t *srb_cachep;/* * Ioctl related information. */static int num_hosts;int ql2xlogintimeout = 20;module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(ql2xlogintimeout,		"Login timeout value in seconds.");int qlport_down_retry = 30;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 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 ql2xloginretrycount = 0;module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(ql2xloginretrycount,		"Specify an alternate value for the NVRAM login retry count.");int ql2xfwloadbin=1;module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(ql2xfwloadbin,		"Load ISP2xxx firmware image via hotplug.");static void qla2x00_free_device(scsi_qla_host_t *);static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);int ql2xfdmienable;module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(ql2xfdmienable,		"Enables FDMI registratons "		"Default is 0 - no FDMI. 1 - perfom FDMI.");/* * SCSI host template entry points */static int qla2xxx_slave_configure(struct scsi_device * device);static int qla2xxx_slave_alloc(struct scsi_device *);static void qla2xxx_slave_destroy(struct scsi_device *);static int qla2x00_queuecommand(struct scsi_cmnd *cmd,		void (*fn)(struct scsi_cmnd *));static int qla24xx_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_change_queue_depth(struct scsi_device *, int);static int qla2x00_change_queue_type(struct scsi_device *, int);static struct scsi_host_template qla2x00_driver_template = {	.module			= THIS_MODULE,	.name			= "qla2xxx",	.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,	.slave_alloc		= qla2xxx_slave_alloc,	.slave_destroy		= qla2xxx_slave_destroy,	.change_queue_depth	= qla2x00_change_queue_depth,	.change_queue_type	= qla2x00_change_queue_type,	.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,	.shost_attrs		= qla2x00_host_attrs,};static struct scsi_host_template qla24xx_driver_template = {	.module			= THIS_MODULE,	.name			= "qla2xxx",	.queuecommand		= qla24xx_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,	.slave_alloc		= qla2xxx_slave_alloc,	.slave_destroy		= qla2xxx_slave_destroy,	.change_queue_depth	= qla2x00_change_queue_depth,	.change_queue_type	= qla2x00_change_queue_type,	.this_id		= -1,	.cmd_per_lun		= 3,	.use_clustering		= ENABLE_CLUSTERING,	.sg_tablesize		= SG_ALL,	.max_sectors		= 0xFFFF,	.shost_attrs		= qla2x00_host_attrs,};static struct scsi_transport_template *qla2xxx_transport_template = NULL;/* 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;}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 void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);void qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *);/* -------------------------------------------------------------------------- */static char *qla2x00_pci_info_str(struct scsi_qla_host *ha, char *str){	static char *pci_bus_modes[] = {		"33", "66", "100", "133",	};	uint16_t pci_bus;	strcpy(str, "PCI");	pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9;	if (pci_bus) {		strcat(str, "-X (");		strcat(str, pci_bus_modes[pci_bus]);	} else {		pci_bus = (ha->pci_attr & BIT_8) >> 8;		strcat(str, " (");		strcat(str, pci_bus_modes[pci_bus]);	}	strcat(str, " MHz)");	return (str);}static char *qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str){	static char *pci_bus_modes[] = { "33", "66", "100", "133", };	uint32_t pci_bus;	int pcie_reg;	pcie_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);	if (pcie_reg) {		char lwstr[6];		uint16_t pcie_lstat, lspeed, lwidth;		pcie_reg += 0x12;		pci_read_config_word(ha->pdev, pcie_reg, &pcie_lstat);		lspeed = pcie_lstat & (BIT_0 | BIT_1 | BIT_2 | BIT_3);		lwidth = (pcie_lstat &		    (BIT_4 | BIT_5 | BIT_6 | BIT_7 | BIT_8 | BIT_9)) >> 4;		strcpy(str, "PCIe (");		if (lspeed == 1)			strcat(str, "2.5Gb/s ");		else			strcat(str, "<unknown> ");		snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth);		strcat(str, lwstr);		return str;	}	strcpy(str, "PCI");	pci_bus = (ha->pci_attr & CSRX_PCIX_BUS_MODE_MASK) >> 8;	if (pci_bus == 0 || pci_bus == 8) {		strcat(str, " (");		strcat(str, pci_bus_modes[pci_bus >> 3]);	} else {		strcat(str, "-X ");		if (pci_bus & BIT_2)			strcat(str, "Mode 2");		else			strcat(str, "Mode 1");		strcat(str, " (");		strcat(str, pci_bus_modes[pci_bus & ~BIT_2]);	}	strcat(str, " MHz)");	return str;}char *qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str){	char un_str[10];	sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,	    ha->fw_minor_version,	    ha->fw_subminor_version);	if (ha->fw_attributes & BIT_9) {		strcat(str, "FLX");		return (str);	}	switch (ha->fw_attributes & 0xFF) {	case 0x7:		strcat(str, "EF");		break;	case 0x17:		strcat(str, "TP");		break;	case 0x37:		strcat(str, "IP");		break;	case 0x77:		strcat(str, "VI");		break;	default:		sprintf(un_str, "(%x)", ha->fw_attributes);		strcat(str, un_str);		break;	}	if (ha->fw_attributes & 0x100)		strcat(str, "X");	return (str);}char *qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str){	sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,	    ha->fw_minor_version,	    ha->fw_subminor_version);	if (ha->fw_attributes & BIT_0)		strcat(str, "[Class 2] ");	if (ha->fw_attributes & BIT_1)		strcat(str, "[IP] ");	if (ha->fw_attributes & BIT_2)		strcat(str, "[Multi-ID] ");	if (ha->fw_attributes & BIT_13)		strcat(str, "[Experimental]");	return str;}static inline srb_t *qla2x00_get_new_sp(scsi_qla_host_t *ha, fc_port_t *fcport,    struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)){	srb_t *sp;	sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);	if (!sp)		return sp;	atomic_set(&sp->ref_count, 1);	sp->ha = ha;	sp->fcport = fcport;	sp->cmd = cmd;	sp->flags = 0;	CMD_SP(cmd) = (void *)sp;	cmd->scsi_done = done;	return sp;}static intqla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)){	scsi_qla_host_t *ha = to_qla_host(cmd->device->host);	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;	struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));	srb_t *sp;	int rval;	rval = fc_remote_port_chkready(rport);	if (rval) {		cmd->result = rval;		goto qc_fail_command;	}	if (atomic_read(&fcport->state) != FCS_ONLINE) {		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||		    atomic_read(&ha->loop_state) == LOOP_DEAD) {			cmd->result = DID_NO_CONNECT << 16;			goto qc_fail_command;		}		goto qc_host_busy;	}	spin_unlock_irq(ha->host->host_lock);	sp = qla2x00_get_new_sp(ha, fcport, cmd, done);	if (!sp)		goto qc_host_busy_lock;	rval = qla2x00_start_scsi(sp);	if (rval != QLA_SUCCESS)		goto qc_host_busy_free_sp;	spin_lock_irq(ha->host->host_lock);	return 0;qc_host_busy_free_sp:	qla2x00_sp_free_dma(ha, sp);	mempool_free(sp, ha->srb_mempool);qc_host_busy_lock:	spin_lock_irq(ha->host->host_lock);qc_host_busy:	return SCSI_MLQUEUE_HOST_BUSY;qc_fail_command:	done(cmd);	return 0;}static intqla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)){	scsi_qla_host_t *ha = to_qla_host(cmd->device->host);	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;	struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));	srb_t *sp;	int rval;	rval = fc_remote_port_chkready(rport);	if (rval) {		cmd->result = rval;		goto qc24_fail_command;	}	if (atomic_read(&fcport->state) != FCS_ONLINE) {		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||		    atomic_read(&ha->loop_state) == LOOP_DEAD) {			cmd->result = DID_NO_CONNECT << 16;			goto qc24_fail_command;		}		goto qc24_host_busy;	}	spin_unlock_irq(ha->host->host_lock);	sp = qla2x00_get_new_sp(ha, fcport, cmd, done);	if (!sp)		goto qc24_host_busy_lock;	rval = qla24xx_start_scsi(sp);	if (rval != QLA_SUCCESS)		goto qc24_host_busy_free_sp;	spin_lock_irq(ha->host->host_lock);	return 0;qc24_host_busy_free_sp:	qla2x00_sp_free_dma(ha, sp);	mempool_free(sp, ha->srb_mempool);qc24_host_busy_lock:	spin_lock_irq(ha->host->host_lock);qc24_host_busy:	return SCSI_MLQUEUE_HOST_BUSY;qc24_fail_command:	done(cmd);	return 0;}/* * qla2x00_eh_wait_on_command *    Waits for the command to be returned by the Firmware for some *    max time. * * Input: *    ha = actual ha whose done queue will contain the command *	      returned by firmware. *    cmd = Scsi Command to wait on. *    flag = Abort/Reset(Bus or Device Reset) * * Return: *    Not Found : 0 *    Found : 1 */static intqla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd){#define ABORT_POLLING_PERIOD	1000#define ABORT_WAIT_ITER		((10 * 1000) / (ABORT_POLLING_PERIOD))	unsigned long wait_iter = ABORT_WAIT_ITER;	int ret = QLA_SUCCESS;	while (CMD_SP(cmd)) {		msleep(ABORT_POLLING_PERIOD);		if (--wait_iter)			break;	}	if (CMD_SP(cmd))		ret = QLA_FUNCTION_FAILED;	return ret;}/* * qla2x00_wait_for_hba_online *    Wait till the HBA is online after going through *    <= MAX_RETRIES_OF_ISP_ABORT  or *    finally HBA is disabled ie marked offline * * Input: *     ha - pointer to host adapter structure * * Note: *    Does context switching-Release SPIN_LOCK *    (if any) before calling this routine. * * Return: *    Success (Adapter is online) : 0 *    Failed  (Adapter is offline/disabled) : 1 */static intqla2x00_wait_for_hba_online(scsi_qla_host_t *ha){	int		return_status;	unsigned long	wait_online;	wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);	while (((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) ||	    test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||	    test_bit(ISP_ABORT_RETRY, &ha->dpc_flags) ||	    ha->dpc_active) && time_before(jiffies, wait_online)) {

⌨️ 快捷键说明

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