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 + -
显示快捷键?