📄 qla_os.c
字号:
/* * 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 + -