qla_os.c

来自「linux 内核源代码」· C语言 代码 · 共 2,525 行 · 第 1/5 页

C
2,525
字号
/* * 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/delay.h>#include <linux/kthread.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 struct kmem_cache *srb_cachep;/* * Ioctl related information. */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;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 ql2xallocfwdump = 1;module_param(ql2xallocfwdump, int, S_IRUGO|S_IRUSR);MODULE_PARM_DESC(ql2xallocfwdump,		"Option to enable allocation of memory for a firmware dump "		"during HBA initialization.  Memory allocation requirements "		"vary by ISP type.  Default is 1 - allocate memory.");int ql2xextended_error_logging;module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(ql2xextended_error_logging,		"Option to enable extended error logging, "		"Default is 0 - no logging. 1 - log errors.");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.");#define MAX_Q_DEPTH    32static int ql2xmaxqdepth = MAX_Q_DEPTH;module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(ql2xmaxqdepth,		"Maximum queue depth to report for target devices.");int ql2xqfullrampup = 120;module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(ql2xqfullrampup,		"Number of seconds to wait to begin to ramp-up the queue "		"depth for a device after a queue-full condition has been "		"detected.  Default is 120 seconds.");/* * SCSI host template entry points */static int qla2xxx_slave_configure(struct scsi_device * device);static int qla2xxx_slave_alloc(struct scsi_device *);static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);static void qla2xxx_scan_start(struct Scsi_Host *);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);struct scsi_host_template qla2x00_driver_template = {	.module			= THIS_MODULE,	.name			= QLA2XXX_DRIVER_NAME,	.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,	.scan_finished		= qla2xxx_scan_finished,	.scan_start		= qla2xxx_scan_start,	.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,	.use_sg_chaining	= ENABLE_SG_CHAINING,	.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,};struct scsi_host_template qla24xx_driver_template = {	.module			= THIS_MODULE,	.name			= QLA2XXX_DRIVER_NAME,	.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,	.scan_finished		= qla2xxx_scan_finished,	.scan_start		= qla2xxx_scan_start,	.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,	.use_sg_chaining	= ENABLE_SG_CHAINING,	.sg_tablesize		= SG_ALL,	.max_sectors		= 0xFFFF,	.shost_attrs		= qla2x00_host_attrs,};static struct scsi_transport_template *qla2xxx_transport_template = NULL;struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;/* TODO Convert to inlines * * Timer routines */void qla2x00_timer(scsi_qla_host_t *);__inline__ void qla2x00_start_timer(scsi_qla_host_t *,    void *, unsigned long);static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);__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);}__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 *);uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);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 if (lspeed == 2)			strcat(str, "5.0Gb/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;}static 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);}static 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_3)		strcat(str, "[SB-2] ");	if (ha->fw_attributes & BIT_4)		strcat(str, "[T10 CRC] ");	if (ha->fw_attributes & BIT_5)		strcat(str, "[VI] ");	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;	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 = shost_priv(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;	if (unlikely(pci_channel_offline(ha->pdev))) {		cmd->result = DID_REQUEUE << 16;		goto qc_fail_command;	}	rval = fc_remote_port_chkready(rport);	if (rval) {		cmd->result = rval;		goto qc_fail_command;	}	/* Close window on fcport/rport state-transitioning. */	if (!*(fc_port_t **)rport->dd_data) {		cmd->result = DID_IMM_RETRY << 16;		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 = shost_priv(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;	scsi_qla_host_t *pha = to_qla_parent(ha);	if (unlikely(pci_channel_offline(ha->pdev))) {		cmd->result = DID_REQUEUE << 16;		goto qc24_fail_command;	}	rval = fc_remote_port_chkready(rport);	if (rval) {		cmd->result = rval;		goto qc24_fail_command;	}	/* Close window on fcport/rport state-transitioning. */	if (!*(fc_port_t **)rport->dd_data) {		cmd->result = DID_IMM_RETRY << 16;		goto qc24_fail_command;	}	if (atomic_read(&fcport->state) != FCS_ONLINE) {		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||		    atomic_read(&pha->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(pha, 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(pha, sp);	mempool_free(sp, pha->srb_mempool);qc24_host_busy_lock:	spin_lock_irq(ha->host->host_lock);qc24_host_busy:	return SCSI_MLQUEUE_HOST_BUSY;

⌨️ 快捷键说明

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