/drivers/scsi/qla2xxx/qla_os.c
http://github.com/mirrors/linux · C · 7956 lines · 6323 code · 1033 blank · 600 comment · 1011 complexity · 69290e65b10cef3fe76a68cfae7f6121 MD5 · raw file
Large files are truncated click here to view the full file
- /*
- * QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2014 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 <linux/mutex.h>
- #include <linux/kobject.h>
- #include <linux/slab.h>
- #include <linux/blk-mq-pci.h>
- #include <linux/refcount.h>
- #include <scsi/scsi_tcq.h>
- #include <scsi/scsicam.h>
- #include <scsi/scsi_transport.h>
- #include <scsi/scsi_transport_fc.h>
- #include "qla_target.h"
- /*
- * Driver version
- */
- char qla2x00_version_str[40];
- static int apidev_major;
- /*
- * SRB allocation cache
- */
- struct kmem_cache *srb_cachep;
- /*
- * CT6 CTX allocation cache
- */
- static struct kmem_cache *ctx_cachep;
- /*
- * error level for logging
- */
- uint ql_errlev = 0x8001;
- static int ql2xenableclass2;
- module_param(ql2xenableclass2, int, S_IRUGO|S_IRUSR);
- MODULE_PARM_DESC(ql2xenableclass2,
- "Specify if Class 2 operations are supported from the very "
- "beginning. Default is 0 - class 2 not supported.");
- int ql2xlogintimeout = 20;
- module_param(ql2xlogintimeout, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xlogintimeout,
- "Login timeout value in seconds.");
- int qlport_down_retry;
- module_param(qlport_down_retry, int, S_IRUGO);
- 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 - perform PLOGI.");
- int ql2xloginretrycount;
- module_param(ql2xloginretrycount, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xloginretrycount,
- "Specify an alternate value for the NVRAM login retry count.");
- int ql2xallocfwdump = 1;
- module_param(ql2xallocfwdump, int, S_IRUGO);
- 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_param_named(logging, ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(ql2xextended_error_logging,
- "Option to enable extended error logging,\n"
- "\t\tDefault is 0 - no logging. 0x40000000 - Module Init & Probe.\n"
- "\t\t0x20000000 - Mailbox Cmnds. 0x10000000 - Device Discovery.\n"
- "\t\t0x08000000 - IO tracing. 0x04000000 - DPC Thread.\n"
- "\t\t0x02000000 - Async events. 0x01000000 - Timer routines.\n"
- "\t\t0x00800000 - User space. 0x00400000 - Task Management.\n"
- "\t\t0x00200000 - AER/EEH. 0x00100000 - Multi Q.\n"
- "\t\t0x00080000 - P3P Specific. 0x00040000 - Virtual Port.\n"
- "\t\t0x00020000 - Buffer Dump. 0x00010000 - Misc.\n"
- "\t\t0x00008000 - Verbose. 0x00004000 - Target.\n"
- "\t\t0x00002000 - Target Mgmt. 0x00001000 - Target TMF.\n"
- "\t\t0x7fffffff - For enabling all logs, can be too many logs.\n"
- "\t\t0x1e400000 - Preferred value for capturing essential "
- "debug information (equivalent to old "
- "ql2xextended_error_logging=1).\n"
- "\t\tDo LOGICAL OR of the value to enable more than one level");
- int ql2xshiftctondsd = 6;
- module_param(ql2xshiftctondsd, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xshiftctondsd,
- "Set to control shifting of command type processing "
- "based on total number of SG elements.");
- int ql2xfdmienable = 1;
- module_param(ql2xfdmienable, int, S_IRUGO|S_IWUSR);
- module_param_named(fdmi, ql2xfdmienable, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(ql2xfdmienable,
- "Enables FDMI registrations. "
- "0 - no FDMI registrations. "
- "1 - provide FDMI registrations (default).");
- #define MAX_Q_DEPTH 64
- static int ql2xmaxqdepth = MAX_Q_DEPTH;
- module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(ql2xmaxqdepth,
- "Maximum queue depth to set for each LUN. "
- "Default is 64.");
- int ql2xenabledif = 2;
- module_param(ql2xenabledif, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xenabledif,
- " Enable T10-CRC-DIF:\n"
- " Default is 2.\n"
- " 0 -- No DIF Support\n"
- " 1 -- Enable DIF for all types\n"
- " 2 -- Enable DIF for all types, except Type 0.\n");
- #if (IS_ENABLED(CONFIG_NVME_FC))
- int ql2xnvmeenable = 1;
- #else
- int ql2xnvmeenable;
- #endif
- module_param(ql2xnvmeenable, int, 0644);
- MODULE_PARM_DESC(ql2xnvmeenable,
- "Enables NVME support. "
- "0 - no NVMe. Default is Y");
- int ql2xenablehba_err_chk = 2;
- module_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(ql2xenablehba_err_chk,
- " Enable T10-CRC-DIF Error isolation by HBA:\n"
- " Default is 2.\n"
- " 0 -- Error isolation disabled\n"
- " 1 -- Error isolation enabled only for DIX Type 0\n"
- " 2 -- Error isolation enabled for all Types\n");
- int ql2xiidmaenable = 1;
- module_param(ql2xiidmaenable, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xiidmaenable,
- "Enables iIDMA settings "
- "Default is 1 - perform iIDMA. 0 - no iIDMA.");
- int ql2xmqsupport = 1;
- module_param(ql2xmqsupport, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xmqsupport,
- "Enable on demand multiple queue pairs support "
- "Default is 1 for supported. "
- "Set it to 0 to turn off mq qpair support.");
- int ql2xfwloadbin;
- module_param(ql2xfwloadbin, int, S_IRUGO|S_IWUSR);
- module_param_named(fwload, ql2xfwloadbin, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(ql2xfwloadbin,
- "Option to specify location from which to load ISP firmware:.\n"
- " 2 -- load firmware via the request_firmware() (hotplug).\n"
- " interface.\n"
- " 1 -- load firmware from flash.\n"
- " 0 -- use default semantics.\n");
- int ql2xetsenable;
- module_param(ql2xetsenable, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xetsenable,
- "Enables firmware ETS burst."
- "Default is 0 - skip ETS enablement.");
- int ql2xdbwr = 1;
- module_param(ql2xdbwr, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(ql2xdbwr,
- "Option to specify scheme for request queue posting.\n"
- " 0 -- Regular doorbell.\n"
- " 1 -- CAMRAM doorbell (faster).\n");
- int ql2xtargetreset = 1;
- module_param(ql2xtargetreset, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xtargetreset,
- "Enable target reset."
- "Default is 1 - use hw defaults.");
- int ql2xgffidenable;
- module_param(ql2xgffidenable, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xgffidenable,
- "Enables GFF_ID checks of port type. "
- "Default is 0 - Do not use GFF_ID information.");
- int ql2xasynctmfenable = 1;
- module_param(ql2xasynctmfenable, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xasynctmfenable,
- "Enables issue of TM IOCBs asynchronously via IOCB mechanism"
- "Default is 1 - Issue TM IOCBs via mailbox mechanism.");
- int ql2xdontresethba;
- module_param(ql2xdontresethba, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(ql2xdontresethba,
- "Option to specify reset behaviour.\n"
- " 0 (Default) -- Reset on failure.\n"
- " 1 -- Do not reset on failure.\n");
- uint64_t ql2xmaxlun = MAX_LUNS;
- module_param(ql2xmaxlun, ullong, S_IRUGO);
- MODULE_PARM_DESC(ql2xmaxlun,
- "Defines the maximum LU number to register with the SCSI "
- "midlayer. Default is 65535.");
- int ql2xmdcapmask = 0x1F;
- module_param(ql2xmdcapmask, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xmdcapmask,
- "Set the Minidump driver capture mask level. "
- "Default is 0x1F - Can be set to 0x3, 0x7, 0xF, 0x1F, 0x7F.");
- int ql2xmdenable = 1;
- module_param(ql2xmdenable, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xmdenable,
- "Enable/disable MiniDump. "
- "0 - MiniDump disabled. "
- "1 (Default) - MiniDump enabled.");
- int ql2xexlogins;
- module_param(ql2xexlogins, uint, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(ql2xexlogins,
- "Number of extended Logins. "
- "0 (Default)- Disabled.");
- int ql2xexchoffld = 1024;
- module_param(ql2xexchoffld, uint, 0644);
- MODULE_PARM_DESC(ql2xexchoffld,
- "Number of target exchanges.");
- int ql2xiniexchg = 1024;
- module_param(ql2xiniexchg, uint, 0644);
- MODULE_PARM_DESC(ql2xiniexchg,
- "Number of initiator exchanges.");
- int ql2xfwholdabts;
- module_param(ql2xfwholdabts, int, S_IRUGO);
- MODULE_PARM_DESC(ql2xfwholdabts,
- "Allow FW to hold status IOCB until ABTS rsp received. "
- "0 (Default) Do not set fw option. "
- "1 - Set fw option to hold ABTS.");
- int ql2xmvasynctoatio = 1;
- module_param(ql2xmvasynctoatio, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(ql2xmvasynctoatio,
- "Move PUREX, ABTS RX and RIDA IOCBs to ATIOQ"
- "0 (Default). Do not move IOCBs"
- "1 - Move IOCBs.");
- int ql2xautodetectsfp = 1;
- module_param(ql2xautodetectsfp, int, 0444);
- MODULE_PARM_DESC(ql2xautodetectsfp,
- "Detect SFP range and set appropriate distance.\n"
- "1 (Default): Enable\n");
- int ql2xenablemsix = 1;
- module_param(ql2xenablemsix, int, 0444);
- MODULE_PARM_DESC(ql2xenablemsix,
- "Set to enable MSI or MSI-X interrupt mechanism.\n"
- " Default is 1, enable MSI-X interrupt mechanism.\n"
- " 0 -- enable traditional pin-based mechanism.\n"
- " 1 -- enable MSI-X interrupt mechanism.\n"
- " 2 -- enable MSI interrupt mechanism.\n");
- int qla2xuseresexchforels;
- module_param(qla2xuseresexchforels, int, 0444);
- MODULE_PARM_DESC(qla2xuseresexchforels,
- "Reserve 1/2 of emergency exchanges for ELS.\n"
- " 0 (default): disabled");
- static int ql2xprotmask;
- module_param(ql2xprotmask, int, 0644);
- MODULE_PARM_DESC(ql2xprotmask,
- "Override DIF/DIX protection capabilities mask\n"
- "Default is 0 which sets protection mask based on "
- "capabilities reported by HBA firmware.\n");
- static int ql2xprotguard;
- module_param(ql2xprotguard, int, 0644);
- MODULE_PARM_DESC(ql2xprotguard, "Override choice of DIX checksum\n"
- " 0 -- Let HBA firmware decide\n"
- " 1 -- Force T10 CRC\n"
- " 2 -- Force IP checksum\n");
- int ql2xdifbundlinginternalbuffers;
- module_param(ql2xdifbundlinginternalbuffers, int, 0644);
- MODULE_PARM_DESC(ql2xdifbundlinginternalbuffers,
- "Force using internal buffers for DIF information\n"
- "0 (Default). Based on check.\n"
- "1 Force using internal buffers\n");
- int ql2xsmartsan;
- module_param(ql2xsmartsan, int, 0444);
- module_param_named(smartsan, ql2xsmartsan, int, 0444);
- MODULE_PARM_DESC(ql2xsmartsan,
- "Send SmartSAN Management Attributes for FDMI Registration."
- " Default is 0 - No SmartSAN registration,"
- " 1 - Register SmartSAN Management Attributes.");
- int ql2xrdpenable;
- module_param(ql2xrdpenable, int, 0444);
- module_param_named(rdpenable, ql2xrdpenable, int, 0444);
- MODULE_PARM_DESC(ql2xrdpenable,
- "Enables RDP responses. "
- "0 - no RDP responses (default). "
- "1 - provide RDP responses.");
- static void qla2x00_clear_drv_active(struct qla_hw_data *);
- static void qla2x00_free_device(scsi_qla_host_t *);
- static int qla2xxx_map_queues(struct Scsi_Host *shost);
- static void qla2x00_destroy_deferred_work(struct qla_hw_data *);
- static struct scsi_transport_template *qla2xxx_transport_template = NULL;
- struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
- /* TODO Convert to inlines
- *
- * Timer routines
- */
- __inline__ void
- qla2x00_start_timer(scsi_qla_host_t *vha, unsigned long interval)
- {
- timer_setup(&vha->timer, qla2x00_timer, 0);
- vha->timer.expires = jiffies + interval * HZ;
- add_timer(&vha->timer);
- vha->timer_active = 1;
- }
- static inline void
- qla2x00_restart_timer(scsi_qla_host_t *vha, unsigned long interval)
- {
- /* Currently used for 82XX only. */
- if (vha->device_flags & DFLG_DEV_FAILED) {
- ql_dbg(ql_dbg_timer, vha, 0x600d,
- "Device in a failed state, returning.\n");
- return;
- }
- mod_timer(&vha->timer, jiffies + interval * HZ);
- }
- static __inline__ void
- qla2x00_stop_timer(scsi_qla_host_t *vha)
- {
- del_timer_sync(&vha->timer);
- vha->timer_active = 0;
- }
- static int qla2x00_do_dpc(void *data);
- static void qla2x00_rst_aen(scsi_qla_host_t *);
- static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t,
- struct req_que **, struct rsp_que **);
- static void qla2x00_free_fw_dump(struct qla_hw_data *);
- static void qla2x00_mem_free(struct qla_hw_data *);
- int qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
- struct qla_qpair *qpair);
- /* -------------------------------------------------------------------------- */
- static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req,
- struct rsp_que *rsp)
- {
- struct qla_hw_data *ha = vha->hw;
- rsp->qpair = ha->base_qpair;
- rsp->req = req;
- ha->base_qpair->hw = ha;
- ha->base_qpair->req = req;
- ha->base_qpair->rsp = rsp;
- ha->base_qpair->vha = vha;
- ha->base_qpair->qp_lock_ptr = &ha->hardware_lock;
- ha->base_qpair->use_shadow_reg = IS_SHADOW_REG_CAPABLE(ha) ? 1 : 0;
- ha->base_qpair->msix = &ha->msix_entries[QLA_MSIX_RSP_Q];
- ha->base_qpair->srb_mempool = ha->srb_mempool;
- INIT_LIST_HEAD(&ha->base_qpair->hints_list);
- ha->base_qpair->enable_class_2 = ql2xenableclass2;
- /* init qpair to this cpu. Will adjust at run time. */
- qla_cpu_update(rsp->qpair, raw_smp_processor_id());
- ha->base_qpair->pdev = ha->pdev;
- if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha))
- ha->base_qpair->reqq_start_iocbs = qla_83xx_start_iocbs;
- }
- static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req,
- struct rsp_que *rsp)
- {
- scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
- ha->req_q_map = kcalloc(ha->max_req_queues, sizeof(struct req_que *),
- GFP_KERNEL);
- if (!ha->req_q_map) {
- ql_log(ql_log_fatal, vha, 0x003b,
- "Unable to allocate memory for request queue ptrs.\n");
- goto fail_req_map;
- }
- ha->rsp_q_map = kcalloc(ha->max_rsp_queues, sizeof(struct rsp_que *),
- GFP_KERNEL);
- if (!ha->rsp_q_map) {
- ql_log(ql_log_fatal, vha, 0x003c,
- "Unable to allocate memory for response queue ptrs.\n");
- goto fail_rsp_map;
- }
- ha->base_qpair = kzalloc(sizeof(struct qla_qpair), GFP_KERNEL);
- if (ha->base_qpair == NULL) {
- ql_log(ql_log_warn, vha, 0x00e0,
- "Failed to allocate base queue pair memory.\n");
- goto fail_base_qpair;
- }
- qla_init_base_qpair(vha, req, rsp);
- if ((ql2xmqsupport || ql2xnvmeenable) && ha->max_qpairs) {
- ha->queue_pair_map = kcalloc(ha->max_qpairs, sizeof(struct qla_qpair *),
- GFP_KERNEL);
- if (!ha->queue_pair_map) {
- ql_log(ql_log_fatal, vha, 0x0180,
- "Unable to allocate memory for queue pair ptrs.\n");
- goto fail_qpair_map;
- }
- }
- /*
- * Make sure we record at least the request and response queue zero in
- * case we need to free them if part of the probe fails.
- */
- ha->rsp_q_map[0] = rsp;
- ha->req_q_map[0] = req;
- set_bit(0, ha->rsp_qid_map);
- set_bit(0, ha->req_qid_map);
- return 0;
- fail_qpair_map:
- kfree(ha->base_qpair);
- ha->base_qpair = NULL;
- fail_base_qpair:
- kfree(ha->rsp_q_map);
- ha->rsp_q_map = NULL;
- fail_rsp_map:
- kfree(ha->req_q_map);
- ha->req_q_map = NULL;
- fail_req_map:
- return -ENOMEM;
- }
- static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
- {
- if (IS_QLAFX00(ha)) {
- if (req && req->ring_fx00)
- dma_free_coherent(&ha->pdev->dev,
- (req->length_fx00 + 1) * sizeof(request_t),
- req->ring_fx00, req->dma_fx00);
- } else if (req && req->ring)
- dma_free_coherent(&ha->pdev->dev,
- (req->length + 1) * sizeof(request_t),
- req->ring, req->dma);
- if (req)
- kfree(req->outstanding_cmds);
- kfree(req);
- }
- static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
- {
- if (IS_QLAFX00(ha)) {
- if (rsp && rsp->ring_fx00)
- dma_free_coherent(&ha->pdev->dev,
- (rsp->length_fx00 + 1) * sizeof(request_t),
- rsp->ring_fx00, rsp->dma_fx00);
- } else if (rsp && rsp->ring) {
- dma_free_coherent(&ha->pdev->dev,
- (rsp->length + 1) * sizeof(response_t),
- rsp->ring, rsp->dma);
- }
- kfree(rsp);
- }
- static void qla2x00_free_queues(struct qla_hw_data *ha)
- {
- struct req_que *req;
- struct rsp_que *rsp;
- int cnt;
- unsigned long flags;
- if (ha->queue_pair_map) {
- kfree(ha->queue_pair_map);
- ha->queue_pair_map = NULL;
- }
- if (ha->base_qpair) {
- kfree(ha->base_qpair);
- ha->base_qpair = NULL;
- }
- spin_lock_irqsave(&ha->hardware_lock, flags);
- for (cnt = 0; cnt < ha->max_req_queues; cnt++) {
- if (!test_bit(cnt, ha->req_qid_map))
- continue;
- req = ha->req_q_map[cnt];
- clear_bit(cnt, ha->req_qid_map);
- ha->req_q_map[cnt] = NULL;
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- qla2x00_free_req_que(ha, req);
- spin_lock_irqsave(&ha->hardware_lock, flags);
- }
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- kfree(ha->req_q_map);
- ha->req_q_map = NULL;
- spin_lock_irqsave(&ha->hardware_lock, flags);
- for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) {
- if (!test_bit(cnt, ha->rsp_qid_map))
- continue;
- rsp = ha->rsp_q_map[cnt];
- clear_bit(cnt, ha->rsp_qid_map);
- ha->rsp_q_map[cnt] = NULL;
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- qla2x00_free_rsp_que(ha, rsp);
- spin_lock_irqsave(&ha->hardware_lock, flags);
- }
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- kfree(ha->rsp_q_map);
- ha->rsp_q_map = NULL;
- }
- static char *
- qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len)
- {
- struct qla_hw_data *ha = vha->hw;
- static const char *const pci_bus_modes[] = {
- "33", "66", "100", "133",
- };
- uint16_t pci_bus;
- pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9;
- if (pci_bus) {
- snprintf(str, str_len, "PCI-X (%s MHz)",
- pci_bus_modes[pci_bus]);
- } else {
- pci_bus = (ha->pci_attr & BIT_8) >> 8;
- snprintf(str, str_len, "PCI (%s MHz)", pci_bus_modes[pci_bus]);
- }
- return str;
- }
- static char *
- qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len)
- {
- static const char *const pci_bus_modes[] = {
- "33", "66", "100", "133",
- };
- struct qla_hw_data *ha = vha->hw;
- uint32_t pci_bus;
- if (pci_is_pcie(ha->pdev)) {
- uint32_t lstat, lspeed, lwidth;
- const char *speed_str;
- pcie_capability_read_dword(ha->pdev, PCI_EXP_LNKCAP, &lstat);
- lspeed = lstat & PCI_EXP_LNKCAP_SLS;
- lwidth = (lstat & PCI_EXP_LNKCAP_MLW) >> 4;
- switch (lspeed) {
- case 1:
- speed_str = "2.5GT/s";
- break;
- case 2:
- speed_str = "5.0GT/s";
- break;
- case 3:
- speed_str = "8.0GT/s";
- break;
- case 4:
- speed_str = "16.0GT/s";
- break;
- default:
- speed_str = "<unknown>";
- break;
- }
- snprintf(str, str_len, "PCIe (%s x%d)", speed_str, lwidth);
- return str;
- }
- pci_bus = (ha->pci_attr & CSRX_PCIX_BUS_MODE_MASK) >> 8;
- if (pci_bus == 0 || pci_bus == 8)
- snprintf(str, str_len, "PCI (%s MHz)",
- pci_bus_modes[pci_bus >> 3]);
- else
- snprintf(str, str_len, "PCI-X Mode %d (%s MHz)",
- pci_bus & 4 ? 2 : 1,
- pci_bus_modes[pci_bus & 3]);
- return str;
- }
- static char *
- qla2x00_fw_version_str(struct scsi_qla_host *vha, char *str, size_t size)
- {
- char un_str[10];
- struct qla_hw_data *ha = vha->hw;
- snprintf(str, size, "%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 *vha, char *str, size_t size)
- {
- struct qla_hw_data *ha = vha->hw;
- snprintf(str, size, "%d.%02d.%02d (%x)", ha->fw_major_version,
- ha->fw_minor_version, ha->fw_subminor_version, ha->fw_attributes);
- return str;
- }
- void qla2x00_sp_free_dma(srb_t *sp)
- {
- struct qla_hw_data *ha = sp->vha->hw;
- struct scsi_cmnd *cmd = GET_CMD_SP(sp);
- if (sp->flags & SRB_DMA_VALID) {
- scsi_dma_unmap(cmd);
- sp->flags &= ~SRB_DMA_VALID;
- }
- if (sp->flags & SRB_CRC_PROT_DMA_VALID) {
- dma_unmap_sg(&ha->pdev->dev, scsi_prot_sglist(cmd),
- scsi_prot_sg_count(cmd), cmd->sc_data_direction);
- sp->flags &= ~SRB_CRC_PROT_DMA_VALID;
- }
- if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
- /* List assured to be having elements */
- qla2x00_clean_dsd_pool(ha, sp->u.scmd.crc_ctx);
- sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
- }
- if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
- struct crc_context *ctx0 = sp->u.scmd.crc_ctx;
- dma_pool_free(ha->dl_dma_pool, ctx0, ctx0->crc_ctx_dma);
- sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
- }
- if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
- struct ct6_dsd *ctx1 = sp->u.scmd.ct6_ctx;
- dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
- ctx1->fcp_cmnd_dma);
- list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list);
- ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt;
- ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
- mempool_free(ctx1, ha->ctx_mempool);
- }
- }
- void qla2x00_sp_compl(srb_t *sp, int res)
- {
- struct scsi_cmnd *cmd = GET_CMD_SP(sp);
- struct completion *comp = sp->comp;
- sp->free(sp);
- cmd->result = res;
- CMD_SP(cmd) = NULL;
- cmd->scsi_done(cmd);
- if (comp)
- complete(comp);
- }
- void qla2xxx_qpair_sp_free_dma(srb_t *sp)
- {
- struct scsi_cmnd *cmd = GET_CMD_SP(sp);
- struct qla_hw_data *ha = sp->fcport->vha->hw;
- if (sp->flags & SRB_DMA_VALID) {
- scsi_dma_unmap(cmd);
- sp->flags &= ~SRB_DMA_VALID;
- }
- if (sp->flags & SRB_CRC_PROT_DMA_VALID) {
- dma_unmap_sg(&ha->pdev->dev, scsi_prot_sglist(cmd),
- scsi_prot_sg_count(cmd), cmd->sc_data_direction);
- sp->flags &= ~SRB_CRC_PROT_DMA_VALID;
- }
- if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
- /* List assured to be having elements */
- qla2x00_clean_dsd_pool(ha, sp->u.scmd.crc_ctx);
- sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
- }
- if (sp->flags & SRB_DIF_BUNDL_DMA_VALID) {
- struct crc_context *difctx = sp->u.scmd.crc_ctx;
- struct dsd_dma *dif_dsd, *nxt_dsd;
- list_for_each_entry_safe(dif_dsd, nxt_dsd,
- &difctx->ldif_dma_hndl_list, list) {
- list_del(&dif_dsd->list);
- dma_pool_free(ha->dif_bundl_pool, dif_dsd->dsd_addr,
- dif_dsd->dsd_list_dma);
- kfree(dif_dsd);
- difctx->no_dif_bundl--;
- }
- list_for_each_entry_safe(dif_dsd, nxt_dsd,
- &difctx->ldif_dsd_list, list) {
- list_del(&dif_dsd->list);
- dma_pool_free(ha->dl_dma_pool, dif_dsd->dsd_addr,
- dif_dsd->dsd_list_dma);
- kfree(dif_dsd);
- difctx->no_ldif_dsd--;
- }
- if (difctx->no_ldif_dsd) {
- ql_dbg(ql_dbg_tgt+ql_dbg_verbose, sp->vha, 0xe022,
- "%s: difctx->no_ldif_dsd=%x\n",
- __func__, difctx->no_ldif_dsd);
- }
- if (difctx->no_dif_bundl) {
- ql_dbg(ql_dbg_tgt+ql_dbg_verbose, sp->vha, 0xe022,
- "%s: difctx->no_dif_bundl=%x\n",
- __func__, difctx->no_dif_bundl);
- }
- sp->flags &= ~SRB_DIF_BUNDL_DMA_VALID;
- }
- if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
- struct ct6_dsd *ctx1 = sp->u.scmd.ct6_ctx;
- dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
- ctx1->fcp_cmnd_dma);
- list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list);
- ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt;
- ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
- mempool_free(ctx1, ha->ctx_mempool);
- sp->flags &= ~SRB_FCP_CMND_DMA_VALID;
- }
- if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
- struct crc_context *ctx0 = sp->u.scmd.crc_ctx;
- dma_pool_free(ha->dl_dma_pool, ctx0, ctx0->crc_ctx_dma);
- sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
- }
- }
- void qla2xxx_qpair_sp_compl(srb_t *sp, int res)
- {
- struct scsi_cmnd *cmd = GET_CMD_SP(sp);
- struct completion *comp = sp->comp;
- sp->free(sp);
- cmd->result = res;
- CMD_SP(cmd) = NULL;
- cmd->scsi_done(cmd);
- if (comp)
- complete(comp);
- }
- static int
- qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
- {
- scsi_qla_host_t *vha = shost_priv(host);
- fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
- struct qla_hw_data *ha = vha->hw;
- struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
- srb_t *sp;
- int rval;
- if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags)) ||
- WARN_ON_ONCE(!rport)) {
- cmd->result = DID_NO_CONNECT << 16;
- goto qc24_fail_command;
- }
- if (ha->mqenable) {
- uint32_t tag;
- uint16_t hwq;
- struct qla_qpair *qpair = NULL;
- tag = blk_mq_unique_tag(cmd->request);
- hwq = blk_mq_unique_tag_to_hwq(tag);
- qpair = ha->queue_pair_map[hwq];
- if (qpair)
- return qla2xxx_mqueuecommand(host, cmd, qpair);
- }
- if (ha->flags.eeh_busy) {
- if (ha->flags.pci_channel_io_perm_failure) {
- ql_dbg(ql_dbg_aer, vha, 0x9010,
- "PCI Channel IO permanent failure, exiting "
- "cmd=%p.\n", cmd);
- cmd->result = DID_NO_CONNECT << 16;
- } else {
- ql_dbg(ql_dbg_aer, vha, 0x9011,
- "EEH_Busy, Requeuing the cmd=%p.\n", cmd);
- cmd->result = DID_REQUEUE << 16;
- }
- goto qc24_fail_command;
- }
- rval = fc_remote_port_chkready(rport);
- if (rval) {
- cmd->result = rval;
- ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3003,
- "fc_remote_port_chkready failed for cmd=%p, rval=0x%x.\n",
- cmd, rval);
- goto qc24_fail_command;
- }
- if (!vha->flags.difdix_supported &&
- scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
- ql_dbg(ql_dbg_io, vha, 0x3004,
- "DIF Cap not reg, fail DIF capable cmd's:%p.\n",
- cmd);
- cmd->result = DID_NO_CONNECT << 16;
- goto qc24_fail_command;
- }
- if (!fcport) {
- cmd->result = DID_NO_CONNECT << 16;
- goto qc24_fail_command;
- }
- if (atomic_read(&fcport->state) != FCS_ONLINE || fcport->deleted) {
- if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
- atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
- ql_dbg(ql_dbg_io, vha, 0x3005,
- "Returning DNC, fcport_state=%d loop_state=%d.\n",
- atomic_read(&fcport->state),
- atomic_read(&base_vha->loop_state));
- cmd->result = DID_NO_CONNECT << 16;
- goto qc24_fail_command;
- }
- goto qc24_target_busy;
- }
- /*
- * Return target busy if we've received a non-zero retry_delay_timer
- * in a FCP_RSP.
- */
- if (fcport->retry_delay_timestamp == 0) {
- /* retry delay not set */
- } else if (time_after(jiffies, fcport->retry_delay_timestamp))
- fcport->retry_delay_timestamp = 0;
- else
- goto qc24_target_busy;
- sp = scsi_cmd_priv(cmd);
- qla2xxx_init_sp(sp, vha, vha->hw->base_qpair, fcport);
- sp->u.scmd.cmd = cmd;
- sp->type = SRB_SCSI_CMD;
- CMD_SP(cmd) = (void *)sp;
- sp->free = qla2x00_sp_free_dma;
- sp->done = qla2x00_sp_compl;
- rval = ha->isp_ops->start_scsi(sp);
- if (rval != QLA_SUCCESS) {
- ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3013,
- "Start scsi failed rval=%d for cmd=%p.\n", rval, cmd);
- goto qc24_host_busy_free_sp;
- }
- return 0;
- qc24_host_busy_free_sp:
- sp->free(sp);
- qc24_target_busy:
- return SCSI_MLQUEUE_TARGET_BUSY;
- qc24_fail_command:
- cmd->scsi_done(cmd);
- return 0;
- }
- /* For MQ supported I/O */
- int
- qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
- struct qla_qpair *qpair)
- {
- scsi_qla_host_t *vha = shost_priv(host);
- fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
- struct qla_hw_data *ha = vha->hw;
- struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
- srb_t *sp;
- int rval;
- rval = rport ? fc_remote_port_chkready(rport) : FC_PORTSTATE_OFFLINE;
- if (rval) {
- cmd->result = rval;
- ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3076,
- "fc_remote_port_chkready failed for cmd=%p, rval=0x%x.\n",
- cmd, rval);
- goto qc24_fail_command;
- }
- if (!fcport) {
- cmd->result = DID_NO_CONNECT << 16;
- goto qc24_fail_command;
- }
- if (atomic_read(&fcport->state) != FCS_ONLINE || fcport->deleted) {
- if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
- atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
- ql_dbg(ql_dbg_io, vha, 0x3077,
- "Returning DNC, fcport_state=%d loop_state=%d.\n",
- atomic_read(&fcport->state),
- atomic_read(&base_vha->loop_state));
- cmd->result = DID_NO_CONNECT << 16;
- goto qc24_fail_command;
- }
- goto qc24_target_busy;
- }
- /*
- * Return target busy if we've received a non-zero retry_delay_timer
- * in a FCP_RSP.
- */
- if (fcport->retry_delay_timestamp == 0) {
- /* retry delay not set */
- } else if (time_after(jiffies, fcport->retry_delay_timestamp))
- fcport->retry_delay_timestamp = 0;
- else
- goto qc24_target_busy;
- sp = scsi_cmd_priv(cmd);
- qla2xxx_init_sp(sp, vha, qpair, fcport);
- sp->u.scmd.cmd = cmd;
- sp->type = SRB_SCSI_CMD;
- CMD_SP(cmd) = (void *)sp;
- sp->free = qla2xxx_qpair_sp_free_dma;
- sp->done = qla2xxx_qpair_sp_compl;
- rval = ha->isp_ops->start_scsi_mq(sp);
- if (rval != QLA_SUCCESS) {
- ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3078,
- "Start scsi failed rval=%d for cmd=%p.\n", rval, cmd);
- if (rval == QLA_INTERFACE_ERROR)
- goto qc24_free_sp_fail_command;
- goto qc24_host_busy_free_sp;
- }
- return 0;
- qc24_host_busy_free_sp:
- sp->free(sp);
- qc24_target_busy:
- return SCSI_MLQUEUE_TARGET_BUSY;
- qc24_free_sp_fail_command:
- sp->free(sp);
- CMD_SP(cmd) = NULL;
- qla2xxx_rel_qpair_sp(sp->qpair, sp);
- qc24_fail_command:
- cmd->scsi_done(cmd);
- return 0;
- }
- /*
- * qla2x00_eh_wait_on_command
- * Waits for the command to be returned by the Firmware for some
- * max time.
- *
- * Input:
- * cmd = Scsi Command to wait on.
- *
- * Return:
- * Completed in time : QLA_SUCCESS
- * Did not complete in time : QLA_FUNCTION_FAILED
- */
- static int
- qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd)
- {
- #define ABORT_POLLING_PERIOD 1000
- #define ABORT_WAIT_ITER ((2 * 1000) / (ABORT_POLLING_PERIOD))
- unsigned long wait_iter = ABORT_WAIT_ITER;
- scsi_qla_host_t *vha = shost_priv(cmd->device->host);
- struct qla_hw_data *ha = vha->hw;
- int ret = QLA_SUCCESS;
- if (unlikely(pci_channel_offline(ha->pdev)) || ha->flags.eeh_busy) {
- ql_dbg(ql_dbg_taskm, vha, 0x8005,
- "Return:eh_wait.\n");
- return ret;
- }
- while (CMD_SP(cmd) && wait_iter--) {
- msleep(ABORT_POLLING_PERIOD);
- }
- 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
- */
- int
- qla2x00_wait_for_hba_online(scsi_qla_host_t *vha)
- {
- int return_status;
- unsigned long wait_online;
- struct qla_hw_data *ha = vha->hw;
- scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
- wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);
- while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) ||
- test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) ||
- test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) ||
- ha->dpc_active) && time_before(jiffies, wait_online)) {
- msleep(1000);
- }
- if (base_vha->flags.online)
- return_status = QLA_SUCCESS;
- else
- return_status = QLA_FUNCTION_FAILED;
- return (return_status);
- }
- static inline int test_fcport_count(scsi_qla_host_t *vha)
- {
- struct qla_hw_data *ha = vha->hw;
- unsigned long flags;
- int res;
- spin_lock_irqsave(&ha->tgt.sess_lock, flags);
- ql_dbg(ql_dbg_init, vha, 0x00ec,
- "tgt %p, fcport_count=%d\n",
- vha, vha->fcport_count);
- res = (vha->fcport_count == 0);
- spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
- return res;
- }
- /*
- * qla2x00_wait_for_sess_deletion can only be called from remove_one.
- * it has dependency on UNLOADING flag to stop device discovery
- */
- void
- qla2x00_wait_for_sess_deletion(scsi_qla_host_t *vha)
- {
- u8 i;
- qla2x00_mark_all_devices_lost(vha);
- for (i = 0; i < 10; i++) {
- if (wait_event_timeout(vha->fcport_waitQ,
- test_fcport_count(vha), HZ) > 0)
- break;
- }
- flush_workqueue(vha->hw->wq);
- }
- /*
- * qla2x00_wait_for_hba_ready
- * Wait till the HBA is ready before doing driver unload
- *
- * Input:
- * ha - pointer to host adapter structure
- *
- * Note:
- * Does context switching-Release SPIN_LOCK
- * (if any) before calling this routine.
- *
- */
- static void
- qla2x00_wait_for_hba_ready(scsi_qla_host_t *vha)
- {
- struct qla_hw_data *ha = vha->hw;
- scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
- while ((qla2x00_reset_active(vha) || ha->dpc_active ||
- ha->flags.mbox_busy) ||
- test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) ||
- test_bit(FX00_TARGET_SCAN, &vha->dpc_flags)) {
- if (test_bit(UNLOADING, &base_vha->dpc_flags))
- break;
- msleep(1000);
- }
- }
- int
- qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha)
- {
- int return_status;
- unsigned long wait_reset;
- struct qla_hw_data *ha = vha->hw;
- scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
- wait_reset = jiffies + (MAX_LOOP_TIMEOUT * HZ);
- while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) ||
- test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) ||
- test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) ||
- ha->dpc_active) && time_before(jiffies, wait_reset)) {
- msleep(1000);
- if (!test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags) &&
- ha->flags.chip_reset_done)
- break;
- }
- if (ha->flags.chip_reset_done)
- return_status = QLA_SUCCESS;
- else
- return_status = QLA_FUNCTION_FAILED;
- return return_status;
- }
- #define ISP_REG_DISCONNECT 0xffffffffU
- /**************************************************************************
- * qla2x00_isp_reg_stat
- *
- * Description:
- * Read the host status register of ISP before aborting the command.
- *
- * Input:
- * ha = pointer to host adapter structure.
- *
- *
- * Returns:
- * Either true or false.
- *
- * Note: Return true if there is register disconnect.
- **************************************************************************/
- static inline
- uint32_t qla2x00_isp_reg_stat(struct qla_hw_data *ha)
- {
- struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
- if (IS_P3P_TYPE(ha))
- return ((RD_REG_DWORD(®82->host_int)) == ISP_REG_DISCONNECT);
- else
- return ((RD_REG_DWORD(®->host_status)) ==
- ISP_REG_DISCONNECT);
- }
- /**************************************************************************
- * qla2xxx_eh_abort
- *
- * Description:
- * The abort function will abort the specified command.
- *
- * Input:
- * cmd = Linux SCSI command packet to be aborted.
- *
- * Returns:
- * Either SUCCESS or FAILED.
- *
- * Note:
- * Only return FAILED if command not returned by firmware.
- **************************************************************************/
- static int
- qla2xxx_eh_abort(struct scsi_cmnd *cmd)
- {
- scsi_qla_host_t *vha = shost_priv(cmd->device->host);
- DECLARE_COMPLETION_ONSTACK(comp);
- srb_t *sp;
- int ret;
- unsigned int id;
- uint64_t lun;
- int rval;
- struct qla_hw_data *ha = vha->hw;
- uint32_t ratov_j;
- struct qla_qpair *qpair;
- unsigned long flags;
- if (qla2x00_isp_reg_stat(ha)) {
- ql_log(ql_log_info, vha, 0x8042,
- "PCI/Register disconnect, exiting.\n");
- return FAILED;
- }
- ret = fc_block_scsi_eh(cmd);
- if (ret != 0)
- return ret;
- sp = scsi_cmd_priv(cmd);
- qpair = sp->qpair;
- if ((sp->fcport && sp->fcport->deleted) || !qpair)
- return SUCCESS;
- spin_lock_irqsave(qpair->qp_lock_ptr, flags);
- sp->comp = ∁
- spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
- id = cmd->device->id;
- lun = cmd->device->lun;
- ql_dbg(ql_dbg_taskm, vha, 0x8002,
- "Aborting from RISC nexus=%ld:%d:%llu sp=%p cmd=%p handle=%x\n",
- vha->host_no, id, lun, sp, cmd, sp->handle);
- /*
- * Abort will release the original Command/sp from FW. Let the
- * original command call scsi_done. In return, he will wakeup
- * this sleeping thread.
- */
- rval = ha->isp_ops->abort_command(sp);
- ql_dbg(ql_dbg_taskm, vha, 0x8003,
- "Abort command mbx cmd=%p, rval=%x.\n", cmd, rval);
- /* Wait for the command completion. */
- ratov_j = ha->r_a_tov/10 * 4 * 1000;
- ratov_j = msecs_to_jiffies(ratov_j);
- switch (rval) {
- case QLA_SUCCESS:
- if (!wait_for_completion_timeout(&comp, ratov_j)) {
- ql_dbg(ql_dbg_taskm, vha, 0xffff,
- "%s: Abort wait timer (4 * R_A_TOV[%d]) expired\n",
- __func__, ha->r_a_tov/10);
- ret = FAILED;
- } else {
- ret = SUCCESS;
- }
- break;
- default:
- ret = FAILED;
- break;
- }
- sp->comp = NULL;
- ql_log(ql_log_info, vha, 0x801c,
- "Abort command issued nexus=%ld:%d:%llu -- %x.\n",
- vha->host_no, id, lun, ret);
- return ret;
- }
- /*
- * Returns: QLA_SUCCESS or QLA_FUNCTION_FAILED.
- */
- int
- qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t,
- uint64_t l, enum nexus_wait_type type)
- {
- int cnt, match, status;
- unsigned long flags;
- struct qla_hw_data *ha = vha->hw;
- struct req_que *req;
- srb_t *sp;
- struct scsi_cmnd *cmd;
- status = QLA_SUCCESS;
- spin_lock_irqsave(&ha->hardware_lock, flags);
- req = vha->req;
- for (cnt = 1; status == QLA_SUCCESS &&
- cnt < req->num_outstanding_cmds; cnt++) {
- sp = req->outstanding_cmds[cnt];
- if (!sp)
- continue;
- if (sp->type != SRB_SCSI_CMD)
- continue;
- if (vha->vp_idx != sp->vha->vp_idx)
- continue;
- match = 0;
- cmd = GET_CMD_SP(sp);
- switch (type) {
- case WAIT_HOST:
- match = 1;
- break;
- case WAIT_TARGET:
- match = cmd->device->id == t;
- break;
- case WAIT_LUN:
- match = (cmd->device->id == t &&
- cmd->device->lun == l);
- break;
- }
- if (!match)
- continue;
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- status = qla2x00_eh_wait_on_command(cmd);
- spin_lock_irqsave(&ha->hardware_lock, flags);
- }
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- return status;
- }
- static char *reset_errors[] = {
- "HBA not online",
- "HBA not ready",
- "Task management failed",
- "Waiting for command completions",
- };
- static int
- __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
- struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, uint64_t, int))
- {
- scsi_qla_host_t *vha = shost_priv(cmd->device->host);
- fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int err;
- if (!fcport) {
- return FAILED;
- }
- err = fc_block_scsi_eh(cmd);
- if (err != 0)
- return err;
- if (fcport->deleted)
- return SUCCESS;
- ql_log(ql_log_info, vha, 0x8009,
- "%s RESET ISSUED nexus=%ld:%d:%llu cmd=%p.\n", name, vha->host_no,
- cmd->device->id, cmd->device->lun, cmd);
- err = 0;
- if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
- ql_log(ql_log_warn, vha, 0x800a,
- "Wait for hba online failed for cmd=%p.\n", cmd);
- goto eh_reset_failed;
- }
- err = 2;
- if (do_reset(fcport, cmd->device->lun, 1)
- != QLA_SUCCESS) {
- ql_log(ql_log_warn, vha, 0x800c,
- "do_reset failed for cmd=%p.\n", cmd);
- goto eh_reset_failed;
- }
- err = 3;
- if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id,
- cmd->device->lun, type) != QLA_SUCCESS) {
- ql_log(ql_log_warn, vha, 0x800d,
- "wait for pending cmds failed for cmd=%p.\n", cmd);
- goto eh_reset_failed;
- }
- ql_log(ql_log_info, vha, 0x800e,
- "%s RESET SUCCEEDED nexus:%ld:%d:%llu cmd=%p.\n", name,
- vha->host_no, cmd->device->id, cmd->device->lun, cmd);
- return SUCCESS;
- eh_reset_failed:
- ql_log(ql_log_info, vha, 0x800f,
- "%s RESET FAILED: %s nexus=%ld:%d:%llu cmd=%p.\n", name,
- reset_errors[err], vha->host_no, cmd->device->id, cmd->device->lun,
- cmd);
- return FAILED;
- }
- static int
- qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
- {
- scsi_qla_host_t *vha = shost_priv(cmd->device->host);
- struct qla_hw_data *ha = vha->hw;
- if (qla2x00_isp_reg_stat(ha)) {
- ql_log(ql_log_info, vha, 0x803e,
- "PCI/Register disconnect, exiting.\n");
- return FAILED;
- }
- return __qla2xxx_eh_generic_reset("DEVICE", WAIT_LUN, cmd,
- ha->isp_ops->lun_reset);
- }
- static int
- qla2xxx_eh_target_reset(struct scsi_cmnd *cmd)
- {
- scsi_qla_host_t *vha = shost_priv(cmd->device->host);
- struct qla_hw_data *ha = vha->hw;
- if (qla2x00_isp_reg_stat(ha)) {
- ql_log(ql_log_info, vha, 0x803f,
- "PCI/Register disconnect, exiting.\n");
- return FAILED;
- }
- return __qla2xxx_eh_generic_reset("TARGET", WAIT_TARGET, cmd,
- ha->isp_ops->target_reset);
- }
- /**************************************************************************
- * qla2xxx_eh_bus_reset
- *
- * Description:
- * The bus reset function will reset the bus and abort any executing
- * commands.
- *
- * Input:
- * cmd = Linux SCSI command packet of the command that cause the
- * bus reset.
- *
- * Returns:
- * SUCCESS/FAILURE (defined as macro in scsi.h).
- *
- **************************************************************************/
- static int
- qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
- {
- scsi_qla_host_t *vha = shost_priv(cmd->device->host);
- fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int ret = FAILED;
- unsigned int id;
- uint64_t lun;
- struct qla_hw_data *ha = vha->hw;
- if (qla2x00_isp_reg_stat(ha)) {
- ql_log(ql_log_info, vha, 0x8040,
- "PCI/Register disconnect, exiting.\n");
- return FAILED;
- }
- id = cmd->device->id;
- lun = cmd->device->lun;
- if (!fcport) {
- return ret;
- }
- ret = fc_block_scsi_eh(cmd);
- if (ret != 0)
- return ret;
- ret = FAILED;
- if (qla2x00_chip_is_down(vha))
- return ret;
- ql_log(ql_log_info, vha, 0x8012,
- "BUS RESET ISSUED nexus=%ld:%d:%llu.\n", vha->host_no, id, lun);
- if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
- ql_log(ql_log_fatal, vha, 0x8013,
- "Wait for hba online failed board disabled.\n");
- goto eh_bus_reset_done;
- }
- if (qla2x00_loop_reset(vha) == QLA_SUCCESS)
- ret = SUCCESS;
- if (ret == FAILED)
- goto eh_bus_reset_done;
- /* Flush outstanding commands. */
- if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) !=
- QLA_SUCCESS) {
- ql_log(ql_log_warn, vha, 0x8014,
- "Wait for pending commands failed.\n");
- ret = FAILED;
- }
- eh_bus_reset_done:
- ql_log(ql_log_warn, vha, 0x802b,
- "BUS RESET %s nexus=%ld:%d:%llu.\n",
- (ret == FAILED) ? "FAILED" : "SUCCEEDED", vha->host_no, id, lun);
- return ret;
- }
- /**************************************************************************
- * qla2xxx_eh_host_reset
- *
- * Description:
- * The reset function will reset the Adapter.
- *
- * Input:
- * cmd = Linux SCSI command packet of the command that cause the
- * adapter reset.
- *
- * Returns:
- * Either SUCCESS or FAILED.
- *
- * Note:
- **************************************************************************/
- static int
- qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
- {
- scsi_qla_host_t *vha = shost_priv(cmd->device->host);
- struct qla_hw_data *ha = vha->hw;
- int ret = FAILED;
- unsigned int id;
- uint64_t lun;
- scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
- if (qla2x00_isp_reg_stat(ha)) {
- ql_log(ql_log_info, vha, 0x8041,
- "PCI/Register disconnect, exiting.\n");
- schedule_work(&ha->board_disable);
- return SUCCESS;
- }
- id = cmd->device->id;
- lun = cmd->device->lun;
- ql_log(ql_log_info, vha, 0x8018,
- "ADAPTER RESET ISSUED nexus=%ld:%d:%llu.\n", vha->host_no, id, lun);
- /*
- * No point in issuing another reset if one is active. Also do not
- * attempt a reset if we are updating flash.
- */
- if (qla2x00_reset_active(vha) || ha->optrom_state != QLA_SWAITING)
- goto eh_host_reset_lock;
- if (vha != base_vha) {
- if (qla2x00_vp_abort_isp(vha))
- goto eh_host_reset_lock;
- } else {
- if (IS_P3P_TYPE(vha->hw)) {
- if (!qla82xx_fcoe_ctx_reset(vha)) {
- /* Ctx reset success */
- ret = SUCCESS;
- goto eh_host_reset_lock;
- }
- /* fall thru if ctx reset failed */
- }
- if (ha->wq)
- flush_workqueue(ha->wq);
- set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
- if (ha->isp_ops->abort_isp(base_vha)) {
- clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
- /* failed. schedule dpc to try */
- set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
- if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
- ql_log(ql_log_warn, vha, 0x802a,
- "wait for hba online failed.\n");
- goto eh_host_reset_lock;
- }
- }
- clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
- }
- /* Waiting for command to be returned to OS.*/
- if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) ==
- QLA_SUCCESS)
- ret = SUCCESS;
- eh_host_reset_lock:
- ql_log(ql_log_info, vha, 0x8017,
- "ADAPTER RESET %s nexus=%ld:%d:%llu.\n",
- (ret == FAILED) ? "FAILED" : "SUCCEEDED", vha->host_no, id, lun);
- return ret;
- }
- /*
- * qla2x00_loop_reset
- * Issue loop reset.
- *
- * Input:
- * ha = adapter block pointer.
- *
- * Returns:
- * 0 = success
- */
- int
- qla2x00_loop_reset(scsi_qla_host_t *vha)
- {
- int ret;
- struct fc_port *fcport;
- struct qla_hw_data *ha = vha->hw;
- if (IS_QLAFX00(ha)) {
- return qlafx00_loop_reset(vha);
- }
- if (ql2xtargetreset == 1 && ha->flags.enable_target_reset) {
- list_for_each_entry(fcport, &vha->vp_fcports, list) {
- if (fcport->port_type != FCT_TARGET)
- continue;
- ret = ha->isp_ops->target_reset(fcport, 0, 0);
- if (ret != QLA_SUCCESS) {
- ql_dbg(ql_dbg_taskm, vha, 0x802c,
- "Bus Reset failed: Reset=%d "
- "d_id=%x.\n", ret, fcport->d_id.b24);
- }
- }
- }
- if (ha->flags.enable_lip_full_login && !IS_CNA_CAPABLE(ha)) {
- atomic_set(&vha->loop_state, LOOP_DOWN);
- atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
- qla2x00_mark_all_devices_lost(vha);
- ret = qla2x00_full_login_lip(vha);
- if (ret != QLA_SUCCESS) {
- ql_dbg(ql_dbg_taskm, vha, 0x802d,
- "full_login_lip=%d.\n", ret);
- }
- }
- if (ha->flags.enable_lip_reset) {
- ret = qla2x00_lip_reset(vha);
- if (ret != QLA_SUCCESS)
- ql_dbg(ql_dbg_taskm, vha, 0x802e,
- "lip_reset failed (%d).\n", ret);
- }
- /* Issue marker command only when we are going to start the I/O */
- vha->marker_needed = 1;
- return QLA_SUCCESS;
- }
- /*
- * The caller must ensure that no completion interrupts will happen
- * while this function is in progress.
- */
- static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res,
- unsigned long *flags)
- __releases(qp->qp_lock_ptr)
- __acquires(qp->qp_lock_ptr)
- {
- DECLARE_COMPLETION_ONSTACK(comp);
- scsi_qla_host_t *vha = qp->vha;
- struct qla_hw_data *ha = vha->hw;
- struct scsi_cmnd *cmd = GET_CMD_SP(sp);
- int rval;
- bool ret_cmd;
- uint32_t ratov_j;
- lockdep_assert_held(qp->qp_lock_ptr);
- if (qla2x00_chip_is_down(vha)) {
- sp->done(sp, res);
- return;
- }
- if (sp->type == SRB_NVME_CMD || sp->type == SRB_NVME_LS ||
- (sp->type == SRB_SCSI_CMD && !ha->flags.eeh_busy &&
- !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
- !qla2x00_isp_reg_stat(ha))) {
- if (sp->comp) {
- sp->done(sp, res);
- return;
- }
- sp->comp = ∁
- spin_unlock_irqrestore(qp->qp_lock_ptr, *flags);
- rval = ha->isp_ops->abort_command(sp);
- /* Wait for command completion. */
- ret_cmd = false;
- ratov_j = ha->r_a_tov/10 * 4 * 1000;
- ratov_j = msecs_to_jiffies(ratov_j);
- switch (rval) {
- case QLA_SUCCESS:
- if (wait_for_completion_timeout(&comp, ratov_j)) {
- ql_dbg(ql_dbg_taskm, vha, 0xffff,
- "%s: Abort wait timer (4 * R_A_TOV[%d]) expired\n",
- __func__, ha->r_a_tov/10);
- ret_cmd = true;
- }
- /* else FW return SP to driver */
- break;
- default:
- ret_cmd = true;
- break;
- }
- spin_lock_irqsave(qp->qp_lock_ptr, *flags);
- if (ret_cmd && blk_mq_request_started(cmd->request))
- sp->done(sp, res);
- } else {
- sp->done(sp, res);
- }
- }
- /*
- * The caller must ensure that no completion interrupts will happen
- * while this function is in progress.
- */
- static void
- __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res)
- {
- int cnt;
- unsigned long flags;
- srb_t *sp;
- scsi_qla_host_t *vha = qp->vha;
- struct qla_hw_data *ha = vha->hw;
- struct req_que *req;
- struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
- struct qla_tgt_cmd *cmd;
- if (!ha->req_q_map)
- return;
- spin_lock_irqsave(qp->qp_lock_ptr, flags);
- req = qp->req;
- for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {
- sp = req->outstanding_cmds[cnt];
- if (sp) {
- switch (sp->cmd_type) {
- case TYPE_SRB:
- qla2x00_abort_srb(qp, sp, res, &flags);
- break;
- case TYPE_TGT_CMD:
- if (!vha->hw->tgt.tgt_ops || !tgt ||
- qla_ini_mode_enabled(vha)) {
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf003,
- "HOST-ABORT-HNDLR: dpc_flags=%lx. Target mode disabled\n",
- vha->dpc_flags);
- continue;
- }
- cmd = (struct qla_tgt_cmd *)sp;
- cmd->aborted = 1;
- break;
- case TYPE_TGT_TMCMD:
- /* Skip task management functions. */
- break;
- default:
- break;
- }
- req->outstanding_cmds[cnt] = NULL;
- }
- }
- spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
- }
- /*
- * The caller must ensure that no completion interrupts will happen
- * while this function is in progress.
- */
- void
- qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
- {
- int que;
- struct qla_hw_data *ha = vha->hw;
- /* Continue only if initialization complete. */
- if (!ha->base_qpair)
- return;
- __qla2x00_abort_all_cmds(ha->base_qpair, res);
- if (!ha->queue_pair_map)
- return;
- for (que = 0; que < ha->max_qpairs; que++) {
- if (!ha->queue_pair_map[que])
- continue;
- __qla2x00_abort_all_cmds(ha->queue_pair_map[que], res);
- }
- }
- static int
- qla2xxx_slave_alloc(struct scsi_device *sdev)
- {
- struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
- if (!rport || fc_remote_port_chkready(rport))
- return -ENXIO;
- sdev->hostdata = *(fc_port_t **)rport->dd_data;
- return 0;
- }
- static int
- qla2xxx_slave_configure(struct scsi_device *sdev)
- {
- scsi_qla_host_t *vha = shost_priv(sdev->host);
- struct req_que *req = vha->req;
- if (IS_T10_PI_CAPABLE(vha->hw))
- blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
- scsi_change_queue_depth(sdev, req->max_q_depth);
- return 0;
- }
- static void
- qla2xxx_slave_destroy(struct scsi_device *sdev)
- {
- sdev->hostdata = NULL;
- }
- /**
- * qla2x00_config_dma_addressing() - Configure OS DMA addressing method.
- * @ha: HA context
- *
- * At exit, the @ha's flags.enable_64bit_addressing set to indicated
- * supported addressing method.
- */
- static void
- qla2x00_config_dma_addressing(struct qla_hw_data *ha)
- {
- /* Assume a 32bit DMA mask. */
- ha->flags.enable_64bit_addressing = 0;
- if (!dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(64))) {
- /* Any upper-dword bits set? */
- if (MSD(dma_get_required_mask(&ha->pdev->dev)) &&
- !pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) {
- /* Ok, a 64bit DMA mask is applicable. */
- ha->flags.enable_64bit_addressing = 1;
- ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64;
- ha->isp_ops->build_iocbs = qla2x00_build_scsi_iocbs_64;
- return;
- }
- }
- dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(32));
- pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(32));
- }
- static void
- qla2x00_enable_intrs(struct qla_hw_data *ha)
- {
- unsigned long flags = 0;
- struct device_reg_2xxx _…