162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver 462306a36Sopenharmony_ci * Copyright (c) 2003-2014 QLogic Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "qla_def.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/moduleparam.h> 962306a36Sopenharmony_ci#include <linux/vmalloc.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/kthread.h> 1262306a36Sopenharmony_ci#include <linux/mutex.h> 1362306a36Sopenharmony_ci#include <linux/kobject.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/blk-mq-pci.h> 1662306a36Sopenharmony_ci#include <linux/refcount.h> 1762306a36Sopenharmony_ci#include <linux/crash_dump.h> 1862306a36Sopenharmony_ci#include <linux/trace_events.h> 1962306a36Sopenharmony_ci#include <linux/trace.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 2262306a36Sopenharmony_ci#include <scsi/scsicam.h> 2362306a36Sopenharmony_ci#include <scsi/scsi_transport.h> 2462306a36Sopenharmony_ci#include <scsi/scsi_transport_fc.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "qla_target.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * Driver version 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_cichar qla2x00_version_str[40]; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic int apidev_major; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * SRB allocation cache 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_cistruct kmem_cache *srb_cachep; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic struct trace_array *qla_trc_array; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciint ql2xfulldump_on_mpifail; 4362306a36Sopenharmony_cimodule_param(ql2xfulldump_on_mpifail, int, S_IRUGO | S_IWUSR); 4462306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xfulldump_on_mpifail, 4562306a36Sopenharmony_ci "Set this to take full dump on MPI hang."); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciint ql2xenforce_iocb_limit = 2; 4862306a36Sopenharmony_cimodule_param(ql2xenforce_iocb_limit, int, S_IRUGO | S_IWUSR); 4962306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xenforce_iocb_limit, 5062306a36Sopenharmony_ci "Enforce IOCB throttling, to avoid FW congestion. (default: 2) " 5162306a36Sopenharmony_ci "1: track usage per queue, 2: track usage per adapter"); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * CT6 CTX allocation cache 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_cistatic struct kmem_cache *ctx_cachep; 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * error level for logging 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ciuint ql_errlev = 0x8001; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciint ql2xsecenable; 6362306a36Sopenharmony_cimodule_param(ql2xsecenable, int, S_IRUGO); 6462306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xsecenable, 6562306a36Sopenharmony_ci "Enable/disable security. 0(Default) - Security disabled. 1 - Security enabled."); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int ql2xenableclass2; 6862306a36Sopenharmony_cimodule_param(ql2xenableclass2, int, S_IRUGO|S_IRUSR); 6962306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xenableclass2, 7062306a36Sopenharmony_ci "Specify if Class 2 operations are supported from the very " 7162306a36Sopenharmony_ci "beginning. Default is 0 - class 2 not supported."); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ciint ql2xlogintimeout = 20; 7562306a36Sopenharmony_cimodule_param(ql2xlogintimeout, int, S_IRUGO); 7662306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xlogintimeout, 7762306a36Sopenharmony_ci "Login timeout value in seconds."); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciint qlport_down_retry; 8062306a36Sopenharmony_cimodule_param(qlport_down_retry, int, S_IRUGO); 8162306a36Sopenharmony_ciMODULE_PARM_DESC(qlport_down_retry, 8262306a36Sopenharmony_ci "Maximum number of command retries to a port that returns " 8362306a36Sopenharmony_ci "a PORT-DOWN status."); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ciint ql2xplogiabsentdevice; 8662306a36Sopenharmony_cimodule_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR); 8762306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xplogiabsentdevice, 8862306a36Sopenharmony_ci "Option to enable PLOGI to devices that are not present after " 8962306a36Sopenharmony_ci "a Fabric scan. This is needed for several broken switches. " 9062306a36Sopenharmony_ci "Default is 0 - no PLOGI. 1 - perform PLOGI."); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciint ql2xloginretrycount; 9362306a36Sopenharmony_cimodule_param(ql2xloginretrycount, int, S_IRUGO); 9462306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xloginretrycount, 9562306a36Sopenharmony_ci "Specify an alternate value for the NVRAM login retry count."); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciint ql2xallocfwdump = 1; 9862306a36Sopenharmony_cimodule_param(ql2xallocfwdump, int, S_IRUGO); 9962306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xallocfwdump, 10062306a36Sopenharmony_ci "Option to enable allocation of memory for a firmware dump " 10162306a36Sopenharmony_ci "during HBA initialization. Memory allocation requirements " 10262306a36Sopenharmony_ci "vary by ISP type. Default is 1 - allocate memory."); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ciint ql2xextended_error_logging; 10562306a36Sopenharmony_cimodule_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR); 10662306a36Sopenharmony_cimodule_param_named(logging, ql2xextended_error_logging, int, S_IRUGO|S_IWUSR); 10762306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xextended_error_logging, 10862306a36Sopenharmony_ci "Option to enable extended error logging,\n" 10962306a36Sopenharmony_ci "\t\tDefault is 0 - no logging. 0x40000000 - Module Init & Probe.\n" 11062306a36Sopenharmony_ci "\t\t0x20000000 - Mailbox Cmnds. 0x10000000 - Device Discovery.\n" 11162306a36Sopenharmony_ci "\t\t0x08000000 - IO tracing. 0x04000000 - DPC Thread.\n" 11262306a36Sopenharmony_ci "\t\t0x02000000 - Async events. 0x01000000 - Timer routines.\n" 11362306a36Sopenharmony_ci "\t\t0x00800000 - User space. 0x00400000 - Task Management.\n" 11462306a36Sopenharmony_ci "\t\t0x00200000 - AER/EEH. 0x00100000 - Multi Q.\n" 11562306a36Sopenharmony_ci "\t\t0x00080000 - P3P Specific. 0x00040000 - Virtual Port.\n" 11662306a36Sopenharmony_ci "\t\t0x00020000 - Buffer Dump. 0x00010000 - Misc.\n" 11762306a36Sopenharmony_ci "\t\t0x00008000 - Verbose. 0x00004000 - Target.\n" 11862306a36Sopenharmony_ci "\t\t0x00002000 - Target Mgmt. 0x00001000 - Target TMF.\n" 11962306a36Sopenharmony_ci "\t\t0x7fffffff - For enabling all logs, can be too many logs.\n" 12062306a36Sopenharmony_ci "\t\t0x1e400000 - Preferred value for capturing essential " 12162306a36Sopenharmony_ci "debug information (equivalent to old " 12262306a36Sopenharmony_ci "ql2xextended_error_logging=1).\n" 12362306a36Sopenharmony_ci "\t\tDo LOGICAL OR of the value to enable more than one level"); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciint ql2xextended_error_logging_ktrace = 1; 12662306a36Sopenharmony_cimodule_param(ql2xextended_error_logging_ktrace, int, S_IRUGO|S_IWUSR); 12762306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xextended_error_logging_ktrace, 12862306a36Sopenharmony_ci "Same BIT definition as ql2xextended_error_logging, but used to control logging to kernel trace buffer (default=1).\n"); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciint ql2xshiftctondsd = 6; 13162306a36Sopenharmony_cimodule_param(ql2xshiftctondsd, int, S_IRUGO); 13262306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xshiftctondsd, 13362306a36Sopenharmony_ci "Set to control shifting of command type processing " 13462306a36Sopenharmony_ci "based on total number of SG elements."); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ciint ql2xfdmienable = 1; 13762306a36Sopenharmony_cimodule_param(ql2xfdmienable, int, S_IRUGO|S_IWUSR); 13862306a36Sopenharmony_cimodule_param_named(fdmi, ql2xfdmienable, int, S_IRUGO|S_IWUSR); 13962306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xfdmienable, 14062306a36Sopenharmony_ci "Enables FDMI registrations. " 14162306a36Sopenharmony_ci "0 - no FDMI registrations. " 14262306a36Sopenharmony_ci "1 - provide FDMI registrations (default)."); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci#define MAX_Q_DEPTH 64 14562306a36Sopenharmony_cistatic int ql2xmaxqdepth = MAX_Q_DEPTH; 14662306a36Sopenharmony_cimodule_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR); 14762306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xmaxqdepth, 14862306a36Sopenharmony_ci "Maximum queue depth to set for each LUN. " 14962306a36Sopenharmony_ci "Default is 64."); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ciint ql2xenabledif = 2; 15262306a36Sopenharmony_cimodule_param(ql2xenabledif, int, S_IRUGO); 15362306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xenabledif, 15462306a36Sopenharmony_ci " Enable T10-CRC-DIF:\n" 15562306a36Sopenharmony_ci " Default is 2.\n" 15662306a36Sopenharmony_ci " 0 -- No DIF Support\n" 15762306a36Sopenharmony_ci " 1 -- Enable DIF for all types\n" 15862306a36Sopenharmony_ci " 2 -- Enable DIF for all types, except Type 0.\n"); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci#if (IS_ENABLED(CONFIG_NVME_FC)) 16162306a36Sopenharmony_ciint ql2xnvmeenable = 1; 16262306a36Sopenharmony_ci#else 16362306a36Sopenharmony_ciint ql2xnvmeenable; 16462306a36Sopenharmony_ci#endif 16562306a36Sopenharmony_cimodule_param(ql2xnvmeenable, int, 0644); 16662306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xnvmeenable, 16762306a36Sopenharmony_ci "Enables NVME support. " 16862306a36Sopenharmony_ci "0 - no NVMe. Default is Y"); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ciint ql2xenablehba_err_chk = 2; 17162306a36Sopenharmony_cimodule_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR); 17262306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xenablehba_err_chk, 17362306a36Sopenharmony_ci " Enable T10-CRC-DIF Error isolation by HBA:\n" 17462306a36Sopenharmony_ci " Default is 2.\n" 17562306a36Sopenharmony_ci " 0 -- Error isolation disabled\n" 17662306a36Sopenharmony_ci " 1 -- Error isolation enabled only for DIX Type 0\n" 17762306a36Sopenharmony_ci " 2 -- Error isolation enabled for all Types\n"); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ciint ql2xiidmaenable = 1; 18062306a36Sopenharmony_cimodule_param(ql2xiidmaenable, int, S_IRUGO); 18162306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xiidmaenable, 18262306a36Sopenharmony_ci "Enables iIDMA settings " 18362306a36Sopenharmony_ci "Default is 1 - perform iIDMA. 0 - no iIDMA."); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ciint ql2xmqsupport = 1; 18662306a36Sopenharmony_cimodule_param(ql2xmqsupport, int, S_IRUGO); 18762306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xmqsupport, 18862306a36Sopenharmony_ci "Enable on demand multiple queue pairs support " 18962306a36Sopenharmony_ci "Default is 1 for supported. " 19062306a36Sopenharmony_ci "Set it to 0 to turn off mq qpair support."); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciint ql2xfwloadbin; 19362306a36Sopenharmony_cimodule_param(ql2xfwloadbin, int, S_IRUGO|S_IWUSR); 19462306a36Sopenharmony_cimodule_param_named(fwload, ql2xfwloadbin, int, S_IRUGO|S_IWUSR); 19562306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xfwloadbin, 19662306a36Sopenharmony_ci "Option to specify location from which to load ISP firmware:.\n" 19762306a36Sopenharmony_ci " 2 -- load firmware via the request_firmware() (hotplug).\n" 19862306a36Sopenharmony_ci " interface.\n" 19962306a36Sopenharmony_ci " 1 -- load firmware from flash.\n" 20062306a36Sopenharmony_ci " 0 -- use default semantics.\n"); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ciint ql2xetsenable; 20362306a36Sopenharmony_cimodule_param(ql2xetsenable, int, S_IRUGO); 20462306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xetsenable, 20562306a36Sopenharmony_ci "Enables firmware ETS burst." 20662306a36Sopenharmony_ci "Default is 0 - skip ETS enablement."); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ciint ql2xdbwr = 1; 20962306a36Sopenharmony_cimodule_param(ql2xdbwr, int, S_IRUGO|S_IWUSR); 21062306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xdbwr, 21162306a36Sopenharmony_ci "Option to specify scheme for request queue posting.\n" 21262306a36Sopenharmony_ci " 0 -- Regular doorbell.\n" 21362306a36Sopenharmony_ci " 1 -- CAMRAM doorbell (faster).\n"); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ciint ql2xgffidenable; 21662306a36Sopenharmony_cimodule_param(ql2xgffidenable, int, S_IRUGO); 21762306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xgffidenable, 21862306a36Sopenharmony_ci "Enables GFF_ID checks of port type. " 21962306a36Sopenharmony_ci "Default is 0 - Do not use GFF_ID information."); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ciint ql2xasynctmfenable = 1; 22262306a36Sopenharmony_cimodule_param(ql2xasynctmfenable, int, S_IRUGO); 22362306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xasynctmfenable, 22462306a36Sopenharmony_ci "Enables issue of TM IOCBs asynchronously via IOCB mechanism" 22562306a36Sopenharmony_ci "Default is 1 - Issue TM IOCBs via mailbox mechanism."); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ciint ql2xdontresethba; 22862306a36Sopenharmony_cimodule_param(ql2xdontresethba, int, S_IRUGO|S_IWUSR); 22962306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xdontresethba, 23062306a36Sopenharmony_ci "Option to specify reset behaviour.\n" 23162306a36Sopenharmony_ci " 0 (Default) -- Reset on failure.\n" 23262306a36Sopenharmony_ci " 1 -- Do not reset on failure.\n"); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciuint64_t ql2xmaxlun = MAX_LUNS; 23562306a36Sopenharmony_cimodule_param(ql2xmaxlun, ullong, S_IRUGO); 23662306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xmaxlun, 23762306a36Sopenharmony_ci "Defines the maximum LU number to register with the SCSI " 23862306a36Sopenharmony_ci "midlayer. Default is 65535."); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ciint ql2xmdcapmask = 0x1F; 24162306a36Sopenharmony_cimodule_param(ql2xmdcapmask, int, S_IRUGO); 24262306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xmdcapmask, 24362306a36Sopenharmony_ci "Set the Minidump driver capture mask level. " 24462306a36Sopenharmony_ci "Default is 0x1F - Can be set to 0x3, 0x7, 0xF, 0x1F, 0x7F."); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ciint ql2xmdenable = 1; 24762306a36Sopenharmony_cimodule_param(ql2xmdenable, int, S_IRUGO); 24862306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xmdenable, 24962306a36Sopenharmony_ci "Enable/disable MiniDump. " 25062306a36Sopenharmony_ci "0 - MiniDump disabled. " 25162306a36Sopenharmony_ci "1 (Default) - MiniDump enabled."); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ciint ql2xexlogins; 25462306a36Sopenharmony_cimodule_param(ql2xexlogins, uint, S_IRUGO|S_IWUSR); 25562306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xexlogins, 25662306a36Sopenharmony_ci "Number of extended Logins. " 25762306a36Sopenharmony_ci "0 (Default)- Disabled."); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ciint ql2xexchoffld = 1024; 26062306a36Sopenharmony_cimodule_param(ql2xexchoffld, uint, 0644); 26162306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xexchoffld, 26262306a36Sopenharmony_ci "Number of target exchanges."); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ciint ql2xiniexchg = 1024; 26562306a36Sopenharmony_cimodule_param(ql2xiniexchg, uint, 0644); 26662306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xiniexchg, 26762306a36Sopenharmony_ci "Number of initiator exchanges."); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ciint ql2xfwholdabts; 27062306a36Sopenharmony_cimodule_param(ql2xfwholdabts, int, S_IRUGO); 27162306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xfwholdabts, 27262306a36Sopenharmony_ci "Allow FW to hold status IOCB until ABTS rsp received. " 27362306a36Sopenharmony_ci "0 (Default) Do not set fw option. " 27462306a36Sopenharmony_ci "1 - Set fw option to hold ABTS."); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ciint ql2xmvasynctoatio = 1; 27762306a36Sopenharmony_cimodule_param(ql2xmvasynctoatio, int, S_IRUGO|S_IWUSR); 27862306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xmvasynctoatio, 27962306a36Sopenharmony_ci "Move PUREX, ABTS RX and RIDA IOCBs to ATIOQ" 28062306a36Sopenharmony_ci "0 (Default). Do not move IOCBs" 28162306a36Sopenharmony_ci "1 - Move IOCBs."); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ciint ql2xautodetectsfp = 1; 28462306a36Sopenharmony_cimodule_param(ql2xautodetectsfp, int, 0444); 28562306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xautodetectsfp, 28662306a36Sopenharmony_ci "Detect SFP range and set appropriate distance.\n" 28762306a36Sopenharmony_ci "1 (Default): Enable\n"); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ciint ql2xenablemsix = 1; 29062306a36Sopenharmony_cimodule_param(ql2xenablemsix, int, 0444); 29162306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xenablemsix, 29262306a36Sopenharmony_ci "Set to enable MSI or MSI-X interrupt mechanism.\n" 29362306a36Sopenharmony_ci " Default is 1, enable MSI-X interrupt mechanism.\n" 29462306a36Sopenharmony_ci " 0 -- enable traditional pin-based mechanism.\n" 29562306a36Sopenharmony_ci " 1 -- enable MSI-X interrupt mechanism.\n" 29662306a36Sopenharmony_ci " 2 -- enable MSI interrupt mechanism.\n"); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ciint qla2xuseresexchforels; 29962306a36Sopenharmony_cimodule_param(qla2xuseresexchforels, int, 0444); 30062306a36Sopenharmony_ciMODULE_PARM_DESC(qla2xuseresexchforels, 30162306a36Sopenharmony_ci "Reserve 1/2 of emergency exchanges for ELS.\n" 30262306a36Sopenharmony_ci " 0 (default): disabled"); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic int ql2xprotmask; 30562306a36Sopenharmony_cimodule_param(ql2xprotmask, int, 0644); 30662306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xprotmask, 30762306a36Sopenharmony_ci "Override DIF/DIX protection capabilities mask\n" 30862306a36Sopenharmony_ci "Default is 0 which sets protection mask based on " 30962306a36Sopenharmony_ci "capabilities reported by HBA firmware.\n"); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int ql2xprotguard; 31262306a36Sopenharmony_cimodule_param(ql2xprotguard, int, 0644); 31362306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xprotguard, "Override choice of DIX checksum\n" 31462306a36Sopenharmony_ci " 0 -- Let HBA firmware decide\n" 31562306a36Sopenharmony_ci " 1 -- Force T10 CRC\n" 31662306a36Sopenharmony_ci " 2 -- Force IP checksum\n"); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ciint ql2xdifbundlinginternalbuffers; 31962306a36Sopenharmony_cimodule_param(ql2xdifbundlinginternalbuffers, int, 0644); 32062306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xdifbundlinginternalbuffers, 32162306a36Sopenharmony_ci "Force using internal buffers for DIF information\n" 32262306a36Sopenharmony_ci "0 (Default). Based on check.\n" 32362306a36Sopenharmony_ci "1 Force using internal buffers\n"); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ciint ql2xsmartsan; 32662306a36Sopenharmony_cimodule_param(ql2xsmartsan, int, 0444); 32762306a36Sopenharmony_cimodule_param_named(smartsan, ql2xsmartsan, int, 0444); 32862306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xsmartsan, 32962306a36Sopenharmony_ci "Send SmartSAN Management Attributes for FDMI Registration." 33062306a36Sopenharmony_ci " Default is 0 - No SmartSAN registration," 33162306a36Sopenharmony_ci " 1 - Register SmartSAN Management Attributes."); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ciint ql2xrdpenable; 33462306a36Sopenharmony_cimodule_param(ql2xrdpenable, int, 0444); 33562306a36Sopenharmony_cimodule_param_named(rdpenable, ql2xrdpenable, int, 0444); 33662306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xrdpenable, 33762306a36Sopenharmony_ci "Enables RDP responses. " 33862306a36Sopenharmony_ci "0 - no RDP responses (default). " 33962306a36Sopenharmony_ci "1 - provide RDP responses."); 34062306a36Sopenharmony_ciint ql2xabts_wait_nvme = 1; 34162306a36Sopenharmony_cimodule_param(ql2xabts_wait_nvme, int, 0444); 34262306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xabts_wait_nvme, 34362306a36Sopenharmony_ci "To wait for ABTS response on I/O timeouts for NVMe. (default: 1)"); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic u32 ql2xdelay_before_pci_error_handling = 5; 34762306a36Sopenharmony_cimodule_param(ql2xdelay_before_pci_error_handling, uint, 0644); 34862306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xdelay_before_pci_error_handling, 34962306a36Sopenharmony_ci "Number of seconds delayed before qla begin PCI error self-handling (default: 5).\n"); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void qla2x00_clear_drv_active(struct qla_hw_data *); 35262306a36Sopenharmony_cistatic void qla2x00_free_device(scsi_qla_host_t *); 35362306a36Sopenharmony_cistatic void qla2xxx_map_queues(struct Scsi_Host *shost); 35462306a36Sopenharmony_cistatic void qla2x00_destroy_deferred_work(struct qla_hw_data *); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ciu32 ql2xnvme_queues = DEF_NVME_HW_QUEUES; 35762306a36Sopenharmony_cimodule_param(ql2xnvme_queues, uint, S_IRUGO); 35862306a36Sopenharmony_ciMODULE_PARM_DESC(ql2xnvme_queues, 35962306a36Sopenharmony_ci "Number of NVMe Queues that can be configured.\n" 36062306a36Sopenharmony_ci "Final value will be min(ql2xnvme_queues, num_cpus,num_chip_queues)\n" 36162306a36Sopenharmony_ci "1 - Minimum number of queues supported\n" 36262306a36Sopenharmony_ci "8 - Default value"); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ciint ql2xfc2target = 1; 36562306a36Sopenharmony_cimodule_param(ql2xfc2target, int, 0444); 36662306a36Sopenharmony_ciMODULE_PARM_DESC(qla2xfc2target, 36762306a36Sopenharmony_ci "Enables FC2 Target support. " 36862306a36Sopenharmony_ci "0 - FC2 Target support is disabled. " 36962306a36Sopenharmony_ci "1 - FC2 Target support is enabled (default)."); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic struct scsi_transport_template *qla2xxx_transport_template = NULL; 37262306a36Sopenharmony_cistruct scsi_transport_template *qla2xxx_transport_vport_template = NULL; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci/* TODO Convert to inlines 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * Timer routines 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci__inline__ void 38062306a36Sopenharmony_ciqla2x00_start_timer(scsi_qla_host_t *vha, unsigned long interval) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci timer_setup(&vha->timer, qla2x00_timer, 0); 38362306a36Sopenharmony_ci vha->timer.expires = jiffies + interval * HZ; 38462306a36Sopenharmony_ci add_timer(&vha->timer); 38562306a36Sopenharmony_ci vha->timer_active = 1; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic inline void 38962306a36Sopenharmony_ciqla2x00_restart_timer(scsi_qla_host_t *vha, unsigned long interval) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci /* Currently used for 82XX only. */ 39262306a36Sopenharmony_ci if (vha->device_flags & DFLG_DEV_FAILED) { 39362306a36Sopenharmony_ci ql_dbg(ql_dbg_timer, vha, 0x600d, 39462306a36Sopenharmony_ci "Device in a failed state, returning.\n"); 39562306a36Sopenharmony_ci return; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci mod_timer(&vha->timer, jiffies + interval * HZ); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic __inline__ void 40262306a36Sopenharmony_ciqla2x00_stop_timer(scsi_qla_host_t *vha) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci del_timer_sync(&vha->timer); 40562306a36Sopenharmony_ci vha->timer_active = 0; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int qla2x00_do_dpc(void *data); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic void qla2x00_rst_aen(scsi_qla_host_t *); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t, 41362306a36Sopenharmony_ci struct req_que **, struct rsp_que **); 41462306a36Sopenharmony_cistatic void qla2x00_free_fw_dump(struct qla_hw_data *); 41562306a36Sopenharmony_cistatic void qla2x00_mem_free(struct qla_hw_data *); 41662306a36Sopenharmony_ciint qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, 41762306a36Sopenharmony_ci struct qla_qpair *qpair); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */ 42062306a36Sopenharmony_cistatic void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, 42162306a36Sopenharmony_ci struct rsp_que *rsp) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci rsp->qpair = ha->base_qpair; 42662306a36Sopenharmony_ci rsp->req = req; 42762306a36Sopenharmony_ci ha->base_qpair->hw = ha; 42862306a36Sopenharmony_ci ha->base_qpair->req = req; 42962306a36Sopenharmony_ci ha->base_qpair->rsp = rsp; 43062306a36Sopenharmony_ci ha->base_qpair->vha = vha; 43162306a36Sopenharmony_ci ha->base_qpair->qp_lock_ptr = &ha->hardware_lock; 43262306a36Sopenharmony_ci ha->base_qpair->use_shadow_reg = IS_SHADOW_REG_CAPABLE(ha) ? 1 : 0; 43362306a36Sopenharmony_ci ha->base_qpair->msix = &ha->msix_entries[QLA_MSIX_RSP_Q]; 43462306a36Sopenharmony_ci ha->base_qpair->srb_mempool = ha->srb_mempool; 43562306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->base_qpair->hints_list); 43662306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->base_qpair->dsd_list); 43762306a36Sopenharmony_ci ha->base_qpair->enable_class_2 = ql2xenableclass2; 43862306a36Sopenharmony_ci /* init qpair to this cpu. Will adjust at run time. */ 43962306a36Sopenharmony_ci qla_cpu_update(rsp->qpair, raw_smp_processor_id()); 44062306a36Sopenharmony_ci ha->base_qpair->pdev = ha->pdev; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha)) 44362306a36Sopenharmony_ci ha->base_qpair->reqq_start_iocbs = qla_83xx_start_iocbs; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, 44762306a36Sopenharmony_ci struct rsp_que *rsp) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci ha->req_q_map = kcalloc(ha->max_req_queues, sizeof(struct req_que *), 45262306a36Sopenharmony_ci GFP_KERNEL); 45362306a36Sopenharmony_ci if (!ha->req_q_map) { 45462306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x003b, 45562306a36Sopenharmony_ci "Unable to allocate memory for request queue ptrs.\n"); 45662306a36Sopenharmony_ci goto fail_req_map; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci ha->rsp_q_map = kcalloc(ha->max_rsp_queues, sizeof(struct rsp_que *), 46062306a36Sopenharmony_ci GFP_KERNEL); 46162306a36Sopenharmony_ci if (!ha->rsp_q_map) { 46262306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x003c, 46362306a36Sopenharmony_ci "Unable to allocate memory for response queue ptrs.\n"); 46462306a36Sopenharmony_ci goto fail_rsp_map; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci ha->base_qpair = kzalloc(sizeof(struct qla_qpair), GFP_KERNEL); 46862306a36Sopenharmony_ci if (ha->base_qpair == NULL) { 46962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x00e0, 47062306a36Sopenharmony_ci "Failed to allocate base queue pair memory.\n"); 47162306a36Sopenharmony_ci goto fail_base_qpair; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci qla_init_base_qpair(vha, req, rsp); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if ((ql2xmqsupport || ql2xnvmeenable) && ha->max_qpairs) { 47762306a36Sopenharmony_ci ha->queue_pair_map = kcalloc(ha->max_qpairs, sizeof(struct qla_qpair *), 47862306a36Sopenharmony_ci GFP_KERNEL); 47962306a36Sopenharmony_ci if (!ha->queue_pair_map) { 48062306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x0180, 48162306a36Sopenharmony_ci "Unable to allocate memory for queue pair ptrs.\n"); 48262306a36Sopenharmony_ci goto fail_qpair_map; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci if (qla_mapq_alloc_qp_cpu_map(ha) != 0) { 48562306a36Sopenharmony_ci kfree(ha->queue_pair_map); 48662306a36Sopenharmony_ci ha->queue_pair_map = NULL; 48762306a36Sopenharmony_ci goto fail_qpair_map; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* 49262306a36Sopenharmony_ci * Make sure we record at least the request and response queue zero in 49362306a36Sopenharmony_ci * case we need to free them if part of the probe fails. 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ci ha->rsp_q_map[0] = rsp; 49662306a36Sopenharmony_ci ha->req_q_map[0] = req; 49762306a36Sopenharmony_ci set_bit(0, ha->rsp_qid_map); 49862306a36Sopenharmony_ci set_bit(0, ha->req_qid_map); 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cifail_qpair_map: 50262306a36Sopenharmony_ci kfree(ha->base_qpair); 50362306a36Sopenharmony_ci ha->base_qpair = NULL; 50462306a36Sopenharmony_cifail_base_qpair: 50562306a36Sopenharmony_ci kfree(ha->rsp_q_map); 50662306a36Sopenharmony_ci ha->rsp_q_map = NULL; 50762306a36Sopenharmony_cifail_rsp_map: 50862306a36Sopenharmony_ci kfree(ha->req_q_map); 50962306a36Sopenharmony_ci ha->req_q_map = NULL; 51062306a36Sopenharmony_cifail_req_map: 51162306a36Sopenharmony_ci return -ENOMEM; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci if (IS_QLAFX00(ha)) { 51762306a36Sopenharmony_ci if (req && req->ring_fx00) 51862306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, 51962306a36Sopenharmony_ci (req->length_fx00 + 1) * sizeof(request_t), 52062306a36Sopenharmony_ci req->ring_fx00, req->dma_fx00); 52162306a36Sopenharmony_ci } else if (req && req->ring) 52262306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, 52362306a36Sopenharmony_ci (req->length + 1) * sizeof(request_t), 52462306a36Sopenharmony_ci req->ring, req->dma); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (req) 52762306a36Sopenharmony_ci kfree(req->outstanding_cmds); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci kfree(req); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci if (IS_QLAFX00(ha)) { 53562306a36Sopenharmony_ci if (rsp && rsp->ring_fx00) 53662306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, 53762306a36Sopenharmony_ci (rsp->length_fx00 + 1) * sizeof(request_t), 53862306a36Sopenharmony_ci rsp->ring_fx00, rsp->dma_fx00); 53962306a36Sopenharmony_ci } else if (rsp && rsp->ring) { 54062306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, 54162306a36Sopenharmony_ci (rsp->length + 1) * sizeof(response_t), 54262306a36Sopenharmony_ci rsp->ring, rsp->dma); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci kfree(rsp); 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic void qla2x00_free_queues(struct qla_hw_data *ha) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct req_que *req; 55062306a36Sopenharmony_ci struct rsp_que *rsp; 55162306a36Sopenharmony_ci int cnt; 55262306a36Sopenharmony_ci unsigned long flags; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (ha->queue_pair_map) { 55562306a36Sopenharmony_ci kfree(ha->queue_pair_map); 55662306a36Sopenharmony_ci ha->queue_pair_map = NULL; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci if (ha->base_qpair) { 55962306a36Sopenharmony_ci kfree(ha->base_qpair); 56062306a36Sopenharmony_ci ha->base_qpair = NULL; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci qla_mapq_free_qp_cpu_map(ha); 56462306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 56562306a36Sopenharmony_ci for (cnt = 0; cnt < ha->max_req_queues; cnt++) { 56662306a36Sopenharmony_ci if (!test_bit(cnt, ha->req_qid_map)) 56762306a36Sopenharmony_ci continue; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci req = ha->req_q_map[cnt]; 57062306a36Sopenharmony_ci clear_bit(cnt, ha->req_qid_map); 57162306a36Sopenharmony_ci ha->req_q_map[cnt] = NULL; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 57462306a36Sopenharmony_ci qla2x00_free_req_que(ha, req); 57562306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci kfree(ha->req_q_map); 58062306a36Sopenharmony_ci ha->req_q_map = NULL; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 58462306a36Sopenharmony_ci for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) { 58562306a36Sopenharmony_ci if (!test_bit(cnt, ha->rsp_qid_map)) 58662306a36Sopenharmony_ci continue; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci rsp = ha->rsp_q_map[cnt]; 58962306a36Sopenharmony_ci clear_bit(cnt, ha->rsp_qid_map); 59062306a36Sopenharmony_ci ha->rsp_q_map[cnt] = NULL; 59162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 59262306a36Sopenharmony_ci qla2x00_free_rsp_que(ha, rsp); 59362306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci kfree(ha->rsp_q_map); 59862306a36Sopenharmony_ci ha->rsp_q_map = NULL; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic char * 60262306a36Sopenharmony_ciqla2x00_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 60562306a36Sopenharmony_ci static const char *const pci_bus_modes[] = { 60662306a36Sopenharmony_ci "33", "66", "100", "133", 60762306a36Sopenharmony_ci }; 60862306a36Sopenharmony_ci uint16_t pci_bus; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9; 61162306a36Sopenharmony_ci if (pci_bus) { 61262306a36Sopenharmony_ci snprintf(str, str_len, "PCI-X (%s MHz)", 61362306a36Sopenharmony_ci pci_bus_modes[pci_bus]); 61462306a36Sopenharmony_ci } else { 61562306a36Sopenharmony_ci pci_bus = (ha->pci_attr & BIT_8) >> 8; 61662306a36Sopenharmony_ci snprintf(str, str_len, "PCI (%s MHz)", pci_bus_modes[pci_bus]); 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return str; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic char * 62362306a36Sopenharmony_ciqla24xx_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci static const char *const pci_bus_modes[] = { 62662306a36Sopenharmony_ci "33", "66", "100", "133", 62762306a36Sopenharmony_ci }; 62862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 62962306a36Sopenharmony_ci uint32_t pci_bus; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (pci_is_pcie(ha->pdev)) { 63262306a36Sopenharmony_ci uint32_t lstat, lspeed, lwidth; 63362306a36Sopenharmony_ci const char *speed_str; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci pcie_capability_read_dword(ha->pdev, PCI_EXP_LNKCAP, &lstat); 63662306a36Sopenharmony_ci lspeed = lstat & PCI_EXP_LNKCAP_SLS; 63762306a36Sopenharmony_ci lwidth = (lstat & PCI_EXP_LNKCAP_MLW) >> 4; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci switch (lspeed) { 64062306a36Sopenharmony_ci case 1: 64162306a36Sopenharmony_ci speed_str = "2.5GT/s"; 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci case 2: 64462306a36Sopenharmony_ci speed_str = "5.0GT/s"; 64562306a36Sopenharmony_ci break; 64662306a36Sopenharmony_ci case 3: 64762306a36Sopenharmony_ci speed_str = "8.0GT/s"; 64862306a36Sopenharmony_ci break; 64962306a36Sopenharmony_ci case 4: 65062306a36Sopenharmony_ci speed_str = "16.0GT/s"; 65162306a36Sopenharmony_ci break; 65262306a36Sopenharmony_ci default: 65362306a36Sopenharmony_ci speed_str = "<unknown>"; 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci snprintf(str, str_len, "PCIe (%s x%d)", speed_str, lwidth); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci return str; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci pci_bus = (ha->pci_attr & CSRX_PCIX_BUS_MODE_MASK) >> 8; 66262306a36Sopenharmony_ci if (pci_bus == 0 || pci_bus == 8) 66362306a36Sopenharmony_ci snprintf(str, str_len, "PCI (%s MHz)", 66462306a36Sopenharmony_ci pci_bus_modes[pci_bus >> 3]); 66562306a36Sopenharmony_ci else 66662306a36Sopenharmony_ci snprintf(str, str_len, "PCI-X Mode %d (%s MHz)", 66762306a36Sopenharmony_ci pci_bus & 4 ? 2 : 1, 66862306a36Sopenharmony_ci pci_bus_modes[pci_bus & 3]); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return str; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic char * 67462306a36Sopenharmony_ciqla2x00_fw_version_str(struct scsi_qla_host *vha, char *str, size_t size) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci char un_str[10]; 67762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci snprintf(str, size, "%d.%02d.%02d ", ha->fw_major_version, 68062306a36Sopenharmony_ci ha->fw_minor_version, ha->fw_subminor_version); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (ha->fw_attributes & BIT_9) { 68362306a36Sopenharmony_ci strcat(str, "FLX"); 68462306a36Sopenharmony_ci return (str); 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci switch (ha->fw_attributes & 0xFF) { 68862306a36Sopenharmony_ci case 0x7: 68962306a36Sopenharmony_ci strcat(str, "EF"); 69062306a36Sopenharmony_ci break; 69162306a36Sopenharmony_ci case 0x17: 69262306a36Sopenharmony_ci strcat(str, "TP"); 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci case 0x37: 69562306a36Sopenharmony_ci strcat(str, "IP"); 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci case 0x77: 69862306a36Sopenharmony_ci strcat(str, "VI"); 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci default: 70162306a36Sopenharmony_ci sprintf(un_str, "(%x)", ha->fw_attributes); 70262306a36Sopenharmony_ci strcat(str, un_str); 70362306a36Sopenharmony_ci break; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci if (ha->fw_attributes & 0x100) 70662306a36Sopenharmony_ci strcat(str, "X"); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci return (str); 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic char * 71262306a36Sopenharmony_ciqla24xx_fw_version_str(struct scsi_qla_host *vha, char *str, size_t size) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci snprintf(str, size, "%d.%02d.%02d (%x)", ha->fw_major_version, 71762306a36Sopenharmony_ci ha->fw_minor_version, ha->fw_subminor_version, ha->fw_attributes); 71862306a36Sopenharmony_ci return str; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_civoid qla2x00_sp_free_dma(srb_t *sp) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct qla_hw_data *ha = sp->vha->hw; 72462306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (sp->flags & SRB_DMA_VALID) { 72762306a36Sopenharmony_ci scsi_dma_unmap(cmd); 72862306a36Sopenharmony_ci sp->flags &= ~SRB_DMA_VALID; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (sp->flags & SRB_CRC_PROT_DMA_VALID) { 73262306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), 73362306a36Sopenharmony_ci scsi_prot_sg_count(cmd), cmd->sc_data_direction); 73462306a36Sopenharmony_ci sp->flags &= ~SRB_CRC_PROT_DMA_VALID; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (sp->flags & SRB_CRC_CTX_DSD_VALID) { 73862306a36Sopenharmony_ci /* List assured to be having elements */ 73962306a36Sopenharmony_ci qla2x00_clean_dsd_pool(ha, sp->u.scmd.crc_ctx); 74062306a36Sopenharmony_ci sp->flags &= ~SRB_CRC_CTX_DSD_VALID; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (sp->flags & SRB_CRC_CTX_DMA_VALID) { 74462306a36Sopenharmony_ci struct crc_context *ctx0 = sp->u.scmd.crc_ctx; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci dma_pool_free(ha->dl_dma_pool, ctx0, ctx0->crc_ctx_dma); 74762306a36Sopenharmony_ci sp->flags &= ~SRB_CRC_CTX_DMA_VALID; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (sp->flags & SRB_FCP_CMND_DMA_VALID) { 75162306a36Sopenharmony_ci struct ct6_dsd *ctx1 = &sp->u.scmd.ct6_ctx; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd, 75462306a36Sopenharmony_ci ctx1->fcp_cmnd_dma); 75562306a36Sopenharmony_ci list_splice(&ctx1->dsd_list, &sp->qpair->dsd_list); 75662306a36Sopenharmony_ci sp->qpair->dsd_inuse -= ctx1->dsd_use_cnt; 75762306a36Sopenharmony_ci sp->qpair->dsd_avail += ctx1->dsd_use_cnt; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (sp->flags & SRB_GOT_BUF) 76162306a36Sopenharmony_ci qla_put_buf(sp->qpair, &sp->u.scmd.buf_dsc); 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_civoid qla2x00_sp_compl(srb_t *sp, int res) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 76762306a36Sopenharmony_ci struct completion *comp = sp->comp; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* kref: INIT */ 77062306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 77162306a36Sopenharmony_ci cmd->result = res; 77262306a36Sopenharmony_ci sp->type = 0; 77362306a36Sopenharmony_ci scsi_done(cmd); 77462306a36Sopenharmony_ci if (comp) 77562306a36Sopenharmony_ci complete(comp); 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_civoid qla2xxx_qpair_sp_free_dma(srb_t *sp) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 78162306a36Sopenharmony_ci struct qla_hw_data *ha = sp->fcport->vha->hw; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (sp->flags & SRB_DMA_VALID) { 78462306a36Sopenharmony_ci scsi_dma_unmap(cmd); 78562306a36Sopenharmony_ci sp->flags &= ~SRB_DMA_VALID; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (sp->flags & SRB_CRC_PROT_DMA_VALID) { 78962306a36Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), 79062306a36Sopenharmony_ci scsi_prot_sg_count(cmd), cmd->sc_data_direction); 79162306a36Sopenharmony_ci sp->flags &= ~SRB_CRC_PROT_DMA_VALID; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (sp->flags & SRB_CRC_CTX_DSD_VALID) { 79562306a36Sopenharmony_ci /* List assured to be having elements */ 79662306a36Sopenharmony_ci qla2x00_clean_dsd_pool(ha, sp->u.scmd.crc_ctx); 79762306a36Sopenharmony_ci sp->flags &= ~SRB_CRC_CTX_DSD_VALID; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (sp->flags & SRB_DIF_BUNDL_DMA_VALID) { 80162306a36Sopenharmony_ci struct crc_context *difctx = sp->u.scmd.crc_ctx; 80262306a36Sopenharmony_ci struct dsd_dma *dif_dsd, *nxt_dsd; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci list_for_each_entry_safe(dif_dsd, nxt_dsd, 80562306a36Sopenharmony_ci &difctx->ldif_dma_hndl_list, list) { 80662306a36Sopenharmony_ci list_del(&dif_dsd->list); 80762306a36Sopenharmony_ci dma_pool_free(ha->dif_bundl_pool, dif_dsd->dsd_addr, 80862306a36Sopenharmony_ci dif_dsd->dsd_list_dma); 80962306a36Sopenharmony_ci kfree(dif_dsd); 81062306a36Sopenharmony_ci difctx->no_dif_bundl--; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci list_for_each_entry_safe(dif_dsd, nxt_dsd, 81462306a36Sopenharmony_ci &difctx->ldif_dsd_list, list) { 81562306a36Sopenharmony_ci list_del(&dif_dsd->list); 81662306a36Sopenharmony_ci dma_pool_free(ha->dl_dma_pool, dif_dsd->dsd_addr, 81762306a36Sopenharmony_ci dif_dsd->dsd_list_dma); 81862306a36Sopenharmony_ci kfree(dif_dsd); 81962306a36Sopenharmony_ci difctx->no_ldif_dsd--; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci if (difctx->no_ldif_dsd) { 82362306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt+ql_dbg_verbose, sp->vha, 0xe022, 82462306a36Sopenharmony_ci "%s: difctx->no_ldif_dsd=%x\n", 82562306a36Sopenharmony_ci __func__, difctx->no_ldif_dsd); 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (difctx->no_dif_bundl) { 82962306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt+ql_dbg_verbose, sp->vha, 0xe022, 83062306a36Sopenharmony_ci "%s: difctx->no_dif_bundl=%x\n", 83162306a36Sopenharmony_ci __func__, difctx->no_dif_bundl); 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci sp->flags &= ~SRB_DIF_BUNDL_DMA_VALID; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (sp->flags & SRB_FCP_CMND_DMA_VALID) { 83762306a36Sopenharmony_ci struct ct6_dsd *ctx1 = &sp->u.scmd.ct6_ctx; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd, 84062306a36Sopenharmony_ci ctx1->fcp_cmnd_dma); 84162306a36Sopenharmony_ci list_splice(&ctx1->dsd_list, &sp->qpair->dsd_list); 84262306a36Sopenharmony_ci sp->qpair->dsd_inuse -= ctx1->dsd_use_cnt; 84362306a36Sopenharmony_ci sp->qpair->dsd_avail += ctx1->dsd_use_cnt; 84462306a36Sopenharmony_ci sp->flags &= ~SRB_FCP_CMND_DMA_VALID; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (sp->flags & SRB_CRC_CTX_DMA_VALID) { 84862306a36Sopenharmony_ci struct crc_context *ctx0 = sp->u.scmd.crc_ctx; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci dma_pool_free(ha->dl_dma_pool, ctx0, ctx0->crc_ctx_dma); 85162306a36Sopenharmony_ci sp->flags &= ~SRB_CRC_CTX_DMA_VALID; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (sp->flags & SRB_GOT_BUF) 85562306a36Sopenharmony_ci qla_put_buf(sp->qpair, &sp->u.scmd.buf_dsc); 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_civoid qla2xxx_qpair_sp_compl(srb_t *sp, int res) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 86162306a36Sopenharmony_ci struct completion *comp = sp->comp; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* ref: INIT */ 86462306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 86562306a36Sopenharmony_ci cmd->result = res; 86662306a36Sopenharmony_ci sp->type = 0; 86762306a36Sopenharmony_ci scsi_done(cmd); 86862306a36Sopenharmony_ci if (comp) 86962306a36Sopenharmony_ci complete(comp); 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistatic int 87362306a36Sopenharmony_ciqla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 87662306a36Sopenharmony_ci fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; 87762306a36Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); 87862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 87962306a36Sopenharmony_ci struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); 88062306a36Sopenharmony_ci srb_t *sp; 88162306a36Sopenharmony_ci int rval; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags)) || 88462306a36Sopenharmony_ci WARN_ON_ONCE(!rport)) { 88562306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 88662306a36Sopenharmony_ci goto qc24_fail_command; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (ha->mqenable) { 89062306a36Sopenharmony_ci uint32_t tag; 89162306a36Sopenharmony_ci uint16_t hwq; 89262306a36Sopenharmony_ci struct qla_qpair *qpair = NULL; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmd)); 89562306a36Sopenharmony_ci hwq = blk_mq_unique_tag_to_hwq(tag); 89662306a36Sopenharmony_ci qpair = ha->queue_pair_map[hwq]; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci if (qpair) 89962306a36Sopenharmony_ci return qla2xxx_mqueuecommand(host, cmd, qpair); 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (ha->flags.eeh_busy) { 90362306a36Sopenharmony_ci if (ha->flags.pci_channel_io_perm_failure) { 90462306a36Sopenharmony_ci ql_dbg(ql_dbg_aer, vha, 0x9010, 90562306a36Sopenharmony_ci "PCI Channel IO permanent failure, exiting " 90662306a36Sopenharmony_ci "cmd=%p.\n", cmd); 90762306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 90862306a36Sopenharmony_ci } else { 90962306a36Sopenharmony_ci ql_dbg(ql_dbg_aer, vha, 0x9011, 91062306a36Sopenharmony_ci "EEH_Busy, Requeuing the cmd=%p.\n", cmd); 91162306a36Sopenharmony_ci cmd->result = DID_REQUEUE << 16; 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci goto qc24_fail_command; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci rval = fc_remote_port_chkready(rport); 91762306a36Sopenharmony_ci if (rval) { 91862306a36Sopenharmony_ci cmd->result = rval; 91962306a36Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3003, 92062306a36Sopenharmony_ci "fc_remote_port_chkready failed for cmd=%p, rval=0x%x.\n", 92162306a36Sopenharmony_ci cmd, rval); 92262306a36Sopenharmony_ci goto qc24_fail_command; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (!vha->flags.difdix_supported && 92662306a36Sopenharmony_ci scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) { 92762306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3004, 92862306a36Sopenharmony_ci "DIF Cap not reg, fail DIF capable cmd's:%p.\n", 92962306a36Sopenharmony_ci cmd); 93062306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 93162306a36Sopenharmony_ci goto qc24_fail_command; 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (!fcport || fcport->deleted) { 93562306a36Sopenharmony_ci cmd->result = DID_IMM_RETRY << 16; 93662306a36Sopenharmony_ci goto qc24_fail_command; 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (atomic_read(&fcport->state) != FCS_ONLINE || fcport->deleted) { 94062306a36Sopenharmony_ci if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || 94162306a36Sopenharmony_ci atomic_read(&base_vha->loop_state) == LOOP_DEAD) { 94262306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3005, 94362306a36Sopenharmony_ci "Returning DNC, fcport_state=%d loop_state=%d.\n", 94462306a36Sopenharmony_ci atomic_read(&fcport->state), 94562306a36Sopenharmony_ci atomic_read(&base_vha->loop_state)); 94662306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 94762306a36Sopenharmony_ci goto qc24_fail_command; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci goto qc24_target_busy; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci /* 95362306a36Sopenharmony_ci * Return target busy if we've received a non-zero retry_delay_timer 95462306a36Sopenharmony_ci * in a FCP_RSP. 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_ci if (fcport->retry_delay_timestamp == 0) { 95762306a36Sopenharmony_ci /* retry delay not set */ 95862306a36Sopenharmony_ci } else if (time_after(jiffies, fcport->retry_delay_timestamp)) 95962306a36Sopenharmony_ci fcport->retry_delay_timestamp = 0; 96062306a36Sopenharmony_ci else 96162306a36Sopenharmony_ci goto qc24_target_busy; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci sp = scsi_cmd_priv(cmd); 96462306a36Sopenharmony_ci /* ref: INIT */ 96562306a36Sopenharmony_ci qla2xxx_init_sp(sp, vha, vha->hw->base_qpair, fcport); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci sp->u.scmd.cmd = cmd; 96862306a36Sopenharmony_ci sp->type = SRB_SCSI_CMD; 96962306a36Sopenharmony_ci sp->free = qla2x00_sp_free_dma; 97062306a36Sopenharmony_ci sp->done = qla2x00_sp_compl; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci rval = ha->isp_ops->start_scsi(sp); 97362306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 97462306a36Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3013, 97562306a36Sopenharmony_ci "Start scsi failed rval=%d for cmd=%p.\n", rval, cmd); 97662306a36Sopenharmony_ci goto qc24_host_busy_free_sp; 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci return 0; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ciqc24_host_busy_free_sp: 98262306a36Sopenharmony_ci /* ref: INIT */ 98362306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ciqc24_target_busy: 98662306a36Sopenharmony_ci return SCSI_MLQUEUE_TARGET_BUSY; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ciqc24_fail_command: 98962306a36Sopenharmony_ci scsi_done(cmd); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return 0; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci/* For MQ supported I/O */ 99562306a36Sopenharmony_ciint 99662306a36Sopenharmony_ciqla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, 99762306a36Sopenharmony_ci struct qla_qpair *qpair) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(host); 100062306a36Sopenharmony_ci fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; 100162306a36Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); 100262306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 100362306a36Sopenharmony_ci struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); 100462306a36Sopenharmony_ci srb_t *sp; 100562306a36Sopenharmony_ci int rval; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci rval = rport ? fc_remote_port_chkready(rport) : (DID_NO_CONNECT << 16); 100862306a36Sopenharmony_ci if (rval) { 100962306a36Sopenharmony_ci cmd->result = rval; 101062306a36Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3076, 101162306a36Sopenharmony_ci "fc_remote_port_chkready failed for cmd=%p, rval=0x%x.\n", 101262306a36Sopenharmony_ci cmd, rval); 101362306a36Sopenharmony_ci goto qc24_fail_command; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci if (!qpair->online) { 101762306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3077, 101862306a36Sopenharmony_ci "qpair not online. eeh_busy=%d.\n", ha->flags.eeh_busy); 101962306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 102062306a36Sopenharmony_ci goto qc24_fail_command; 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (!fcport || fcport->deleted) { 102462306a36Sopenharmony_ci cmd->result = DID_IMM_RETRY << 16; 102562306a36Sopenharmony_ci goto qc24_fail_command; 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (atomic_read(&fcport->state) != FCS_ONLINE || fcport->deleted) { 102962306a36Sopenharmony_ci if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || 103062306a36Sopenharmony_ci atomic_read(&base_vha->loop_state) == LOOP_DEAD) { 103162306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3077, 103262306a36Sopenharmony_ci "Returning DNC, fcport_state=%d loop_state=%d.\n", 103362306a36Sopenharmony_ci atomic_read(&fcport->state), 103462306a36Sopenharmony_ci atomic_read(&base_vha->loop_state)); 103562306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 103662306a36Sopenharmony_ci goto qc24_fail_command; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci goto qc24_target_busy; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci /* 104262306a36Sopenharmony_ci * Return target busy if we've received a non-zero retry_delay_timer 104362306a36Sopenharmony_ci * in a FCP_RSP. 104462306a36Sopenharmony_ci */ 104562306a36Sopenharmony_ci if (fcport->retry_delay_timestamp == 0) { 104662306a36Sopenharmony_ci /* retry delay not set */ 104762306a36Sopenharmony_ci } else if (time_after(jiffies, fcport->retry_delay_timestamp)) 104862306a36Sopenharmony_ci fcport->retry_delay_timestamp = 0; 104962306a36Sopenharmony_ci else 105062306a36Sopenharmony_ci goto qc24_target_busy; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci sp = scsi_cmd_priv(cmd); 105362306a36Sopenharmony_ci /* ref: INIT */ 105462306a36Sopenharmony_ci qla2xxx_init_sp(sp, vha, qpair, fcport); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci sp->u.scmd.cmd = cmd; 105762306a36Sopenharmony_ci sp->type = SRB_SCSI_CMD; 105862306a36Sopenharmony_ci sp->free = qla2xxx_qpair_sp_free_dma; 105962306a36Sopenharmony_ci sp->done = qla2xxx_qpair_sp_compl; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci rval = ha->isp_ops->start_scsi_mq(sp); 106262306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 106362306a36Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3078, 106462306a36Sopenharmony_ci "Start scsi failed rval=%d for cmd=%p.\n", rval, cmd); 106562306a36Sopenharmony_ci goto qc24_host_busy_free_sp; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci return 0; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ciqc24_host_busy_free_sp: 107162306a36Sopenharmony_ci /* ref: INIT */ 107262306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ciqc24_target_busy: 107562306a36Sopenharmony_ci return SCSI_MLQUEUE_TARGET_BUSY; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ciqc24_fail_command: 107862306a36Sopenharmony_ci scsi_done(cmd); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci return 0; 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci/* 108462306a36Sopenharmony_ci * qla2x00_wait_for_hba_online 108562306a36Sopenharmony_ci * Wait till the HBA is online after going through 108662306a36Sopenharmony_ci * <= MAX_RETRIES_OF_ISP_ABORT or 108762306a36Sopenharmony_ci * finally HBA is disabled ie marked offline 108862306a36Sopenharmony_ci * 108962306a36Sopenharmony_ci * Input: 109062306a36Sopenharmony_ci * ha - pointer to host adapter structure 109162306a36Sopenharmony_ci * 109262306a36Sopenharmony_ci * Note: 109362306a36Sopenharmony_ci * Does context switching-Release SPIN_LOCK 109462306a36Sopenharmony_ci * (if any) before calling this routine. 109562306a36Sopenharmony_ci * 109662306a36Sopenharmony_ci * Return: 109762306a36Sopenharmony_ci * Success (Adapter is online) : 0 109862306a36Sopenharmony_ci * Failed (Adapter is offline/disabled) : 1 109962306a36Sopenharmony_ci */ 110062306a36Sopenharmony_ciint 110162306a36Sopenharmony_ciqla2x00_wait_for_hba_online(scsi_qla_host_t *vha) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci int return_status; 110462306a36Sopenharmony_ci unsigned long wait_online; 110562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 110662306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ); 110962306a36Sopenharmony_ci while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) || 111062306a36Sopenharmony_ci test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || 111162306a36Sopenharmony_ci test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || 111262306a36Sopenharmony_ci ha->dpc_active) && time_before(jiffies, wait_online)) { 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci msleep(1000); 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci if (base_vha->flags.online) 111762306a36Sopenharmony_ci return_status = QLA_SUCCESS; 111862306a36Sopenharmony_ci else 111962306a36Sopenharmony_ci return_status = QLA_FUNCTION_FAILED; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci return (return_status); 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic inline int test_fcport_count(scsi_qla_host_t *vha) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 112762306a36Sopenharmony_ci unsigned long flags; 112862306a36Sopenharmony_ci int res; 112962306a36Sopenharmony_ci /* Return 0 = sleep, x=wake */ 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci spin_lock_irqsave(&ha->tgt.sess_lock, flags); 113262306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x00ec, 113362306a36Sopenharmony_ci "tgt %p, fcport_count=%d\n", 113462306a36Sopenharmony_ci vha, vha->fcport_count); 113562306a36Sopenharmony_ci res = (vha->fcport_count == 0); 113662306a36Sopenharmony_ci if (res) { 113762306a36Sopenharmony_ci struct fc_port *fcport; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 114062306a36Sopenharmony_ci if (fcport->deleted != QLA_SESS_DELETED) { 114162306a36Sopenharmony_ci /* session(s) may not be fully logged in 114262306a36Sopenharmony_ci * (ie fcport_count=0), but session 114362306a36Sopenharmony_ci * deletion thread(s) may be inflight. 114462306a36Sopenharmony_ci */ 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci res = 0; 114762306a36Sopenharmony_ci break; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci return res; 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci/* 115762306a36Sopenharmony_ci * qla2x00_wait_for_sess_deletion can only be called from remove_one. 115862306a36Sopenharmony_ci * it has dependency on UNLOADING flag to stop device discovery 115962306a36Sopenharmony_ci */ 116062306a36Sopenharmony_civoid 116162306a36Sopenharmony_ciqla2x00_wait_for_sess_deletion(scsi_qla_host_t *vha) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci u8 i; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 116862306a36Sopenharmony_ci if (wait_event_timeout(vha->fcport_waitQ, 116962306a36Sopenharmony_ci test_fcport_count(vha), HZ) > 0) 117062306a36Sopenharmony_ci break; 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci flush_workqueue(vha->hw->wq); 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci/* 117762306a36Sopenharmony_ci * qla2x00_wait_for_hba_ready 117862306a36Sopenharmony_ci * Wait till the HBA is ready before doing driver unload 117962306a36Sopenharmony_ci * 118062306a36Sopenharmony_ci * Input: 118162306a36Sopenharmony_ci * ha - pointer to host adapter structure 118262306a36Sopenharmony_ci * 118362306a36Sopenharmony_ci * Note: 118462306a36Sopenharmony_ci * Does context switching-Release SPIN_LOCK 118562306a36Sopenharmony_ci * (if any) before calling this routine. 118662306a36Sopenharmony_ci * 118762306a36Sopenharmony_ci */ 118862306a36Sopenharmony_cistatic void 118962306a36Sopenharmony_ciqla2x00_wait_for_hba_ready(scsi_qla_host_t *vha) 119062306a36Sopenharmony_ci{ 119162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 119262306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci while ((qla2x00_reset_active(vha) || ha->dpc_active || 119562306a36Sopenharmony_ci ha->flags.mbox_busy) || 119662306a36Sopenharmony_ci test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) || 119762306a36Sopenharmony_ci test_bit(FX00_TARGET_SCAN, &vha->dpc_flags)) { 119862306a36Sopenharmony_ci if (test_bit(UNLOADING, &base_vha->dpc_flags)) 119962306a36Sopenharmony_ci break; 120062306a36Sopenharmony_ci msleep(1000); 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci} 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ciint 120562306a36Sopenharmony_ciqla2x00_wait_for_chip_reset(scsi_qla_host_t *vha) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci int return_status; 120862306a36Sopenharmony_ci unsigned long wait_reset; 120962306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 121062306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci wait_reset = jiffies + (MAX_LOOP_TIMEOUT * HZ); 121362306a36Sopenharmony_ci while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) || 121462306a36Sopenharmony_ci test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || 121562306a36Sopenharmony_ci test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || 121662306a36Sopenharmony_ci ha->dpc_active) && time_before(jiffies, wait_reset)) { 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci msleep(1000); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (!test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags) && 122162306a36Sopenharmony_ci ha->flags.chip_reset_done) 122262306a36Sopenharmony_ci break; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci if (ha->flags.chip_reset_done) 122562306a36Sopenharmony_ci return_status = QLA_SUCCESS; 122662306a36Sopenharmony_ci else 122762306a36Sopenharmony_ci return_status = QLA_FUNCTION_FAILED; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci return return_status; 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci/************************************************************************** 123362306a36Sopenharmony_ci* qla2xxx_eh_abort 123462306a36Sopenharmony_ci* 123562306a36Sopenharmony_ci* Description: 123662306a36Sopenharmony_ci* The abort function will abort the specified command. 123762306a36Sopenharmony_ci* 123862306a36Sopenharmony_ci* Input: 123962306a36Sopenharmony_ci* cmd = Linux SCSI command packet to be aborted. 124062306a36Sopenharmony_ci* 124162306a36Sopenharmony_ci* Returns: 124262306a36Sopenharmony_ci* Either SUCCESS or FAILED. 124362306a36Sopenharmony_ci* 124462306a36Sopenharmony_ci* Note: 124562306a36Sopenharmony_ci* Only return FAILED if command not returned by firmware. 124662306a36Sopenharmony_ci**************************************************************************/ 124762306a36Sopenharmony_cistatic int 124862306a36Sopenharmony_ciqla2xxx_eh_abort(struct scsi_cmnd *cmd) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(cmd->device->host); 125162306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(comp); 125262306a36Sopenharmony_ci srb_t *sp; 125362306a36Sopenharmony_ci int ret; 125462306a36Sopenharmony_ci unsigned int id; 125562306a36Sopenharmony_ci uint64_t lun; 125662306a36Sopenharmony_ci int rval; 125762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 125862306a36Sopenharmony_ci uint32_t ratov_j; 125962306a36Sopenharmony_ci struct qla_qpair *qpair; 126062306a36Sopenharmony_ci unsigned long flags; 126162306a36Sopenharmony_ci int fast_fail_status = SUCCESS; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if (qla2x00_isp_reg_stat(ha)) { 126462306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x8042, 126562306a36Sopenharmony_ci "PCI/Register disconnect, exiting.\n"); 126662306a36Sopenharmony_ci qla_pci_set_eeh_busy(vha); 126762306a36Sopenharmony_ci return FAILED; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci /* Save any FAST_IO_FAIL value to return later if abort succeeds */ 127162306a36Sopenharmony_ci ret = fc_block_scsi_eh(cmd); 127262306a36Sopenharmony_ci if (ret != 0) 127362306a36Sopenharmony_ci fast_fail_status = ret; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci sp = scsi_cmd_priv(cmd); 127662306a36Sopenharmony_ci qpair = sp->qpair; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci vha->cmd_timeout_cnt++; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci if ((sp->fcport && sp->fcport->deleted) || !qpair) 128162306a36Sopenharmony_ci return fast_fail_status != SUCCESS ? fast_fail_status : FAILED; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 128462306a36Sopenharmony_ci sp->comp = ∁ 128562306a36Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci id = cmd->device->id; 128962306a36Sopenharmony_ci lun = cmd->device->lun; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci ql_dbg(ql_dbg_taskm, vha, 0x8002, 129262306a36Sopenharmony_ci "Aborting from RISC nexus=%ld:%d:%llu sp=%p cmd=%p handle=%x\n", 129362306a36Sopenharmony_ci vha->host_no, id, lun, sp, cmd, sp->handle); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci /* 129662306a36Sopenharmony_ci * Abort will release the original Command/sp from FW. Let the 129762306a36Sopenharmony_ci * original command call scsi_done. In return, he will wakeup 129862306a36Sopenharmony_ci * this sleeping thread. 129962306a36Sopenharmony_ci */ 130062306a36Sopenharmony_ci rval = ha->isp_ops->abort_command(sp); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci ql_dbg(ql_dbg_taskm, vha, 0x8003, 130362306a36Sopenharmony_ci "Abort command mbx cmd=%p, rval=%x.\n", cmd, rval); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci /* Wait for the command completion. */ 130662306a36Sopenharmony_ci ratov_j = ha->r_a_tov/10 * 4 * 1000; 130762306a36Sopenharmony_ci ratov_j = msecs_to_jiffies(ratov_j); 130862306a36Sopenharmony_ci switch (rval) { 130962306a36Sopenharmony_ci case QLA_SUCCESS: 131062306a36Sopenharmony_ci if (!wait_for_completion_timeout(&comp, ratov_j)) { 131162306a36Sopenharmony_ci ql_dbg(ql_dbg_taskm, vha, 0xffff, 131262306a36Sopenharmony_ci "%s: Abort wait timer (4 * R_A_TOV[%d]) expired\n", 131362306a36Sopenharmony_ci __func__, ha->r_a_tov/10); 131462306a36Sopenharmony_ci ret = FAILED; 131562306a36Sopenharmony_ci } else { 131662306a36Sopenharmony_ci ret = fast_fail_status; 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci break; 131962306a36Sopenharmony_ci default: 132062306a36Sopenharmony_ci ret = FAILED; 132162306a36Sopenharmony_ci break; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci sp->comp = NULL; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x801c, 132762306a36Sopenharmony_ci "Abort command issued nexus=%ld:%d:%llu -- %x.\n", 132862306a36Sopenharmony_ci vha->host_no, id, lun, ret); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci return ret; 133162306a36Sopenharmony_ci} 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci#define ABORT_POLLING_PERIOD 1000 133462306a36Sopenharmony_ci#define ABORT_WAIT_ITER ((2 * 1000) / (ABORT_POLLING_PERIOD)) 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci/* 133762306a36Sopenharmony_ci * Returns: QLA_SUCCESS or QLA_FUNCTION_FAILED. 133862306a36Sopenharmony_ci */ 133962306a36Sopenharmony_cistatic int 134062306a36Sopenharmony_ci__qla2x00_eh_wait_for_pending_commands(struct qla_qpair *qpair, unsigned int t, 134162306a36Sopenharmony_ci uint64_t l, enum nexus_wait_type type) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci int cnt, match, status; 134462306a36Sopenharmony_ci unsigned long flags; 134562306a36Sopenharmony_ci scsi_qla_host_t *vha = qpair->vha; 134662306a36Sopenharmony_ci struct req_que *req = qpair->req; 134762306a36Sopenharmony_ci srb_t *sp; 134862306a36Sopenharmony_ci struct scsi_cmnd *cmd; 134962306a36Sopenharmony_ci unsigned long wait_iter = ABORT_WAIT_ITER; 135062306a36Sopenharmony_ci bool found; 135162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci status = QLA_SUCCESS; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci while (wait_iter--) { 135662306a36Sopenharmony_ci found = false; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 135962306a36Sopenharmony_ci for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) { 136062306a36Sopenharmony_ci sp = req->outstanding_cmds[cnt]; 136162306a36Sopenharmony_ci if (!sp) 136262306a36Sopenharmony_ci continue; 136362306a36Sopenharmony_ci if (sp->type != SRB_SCSI_CMD) 136462306a36Sopenharmony_ci continue; 136562306a36Sopenharmony_ci if (vha->vp_idx != sp->vha->vp_idx) 136662306a36Sopenharmony_ci continue; 136762306a36Sopenharmony_ci match = 0; 136862306a36Sopenharmony_ci cmd = GET_CMD_SP(sp); 136962306a36Sopenharmony_ci switch (type) { 137062306a36Sopenharmony_ci case WAIT_HOST: 137162306a36Sopenharmony_ci match = 1; 137262306a36Sopenharmony_ci break; 137362306a36Sopenharmony_ci case WAIT_TARGET: 137462306a36Sopenharmony_ci if (sp->fcport) 137562306a36Sopenharmony_ci match = sp->fcport->d_id.b24 == t; 137662306a36Sopenharmony_ci else 137762306a36Sopenharmony_ci match = 0; 137862306a36Sopenharmony_ci break; 137962306a36Sopenharmony_ci case WAIT_LUN: 138062306a36Sopenharmony_ci if (sp->fcport) 138162306a36Sopenharmony_ci match = (sp->fcport->d_id.b24 == t && 138262306a36Sopenharmony_ci cmd->device->lun == l); 138362306a36Sopenharmony_ci else 138462306a36Sopenharmony_ci match = 0; 138562306a36Sopenharmony_ci break; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci if (!match) 138862306a36Sopenharmony_ci continue; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev)) || 139362306a36Sopenharmony_ci ha->flags.eeh_busy) { 139462306a36Sopenharmony_ci ql_dbg(ql_dbg_taskm, vha, 0x8005, 139562306a36Sopenharmony_ci "Return:eh_wait.\n"); 139662306a36Sopenharmony_ci return status; 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci /* 140062306a36Sopenharmony_ci * SRB_SCSI_CMD is still in the outstanding_cmds array. 140162306a36Sopenharmony_ci * it means scsi_done has not called. Wait for it to 140262306a36Sopenharmony_ci * clear from outstanding_cmds. 140362306a36Sopenharmony_ci */ 140462306a36Sopenharmony_ci msleep(ABORT_POLLING_PERIOD); 140562306a36Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 140662306a36Sopenharmony_ci found = true; 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci if (!found) 141162306a36Sopenharmony_ci break; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (wait_iter == -1) 141562306a36Sopenharmony_ci status = QLA_FUNCTION_FAILED; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci return status; 141862306a36Sopenharmony_ci} 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ciint 142162306a36Sopenharmony_ciqla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, 142262306a36Sopenharmony_ci uint64_t l, enum nexus_wait_type type) 142362306a36Sopenharmony_ci{ 142462306a36Sopenharmony_ci struct qla_qpair *qpair; 142562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 142662306a36Sopenharmony_ci int i, status = QLA_SUCCESS; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci status = __qla2x00_eh_wait_for_pending_commands(ha->base_qpair, t, l, 142962306a36Sopenharmony_ci type); 143062306a36Sopenharmony_ci for (i = 0; status == QLA_SUCCESS && i < ha->max_qpairs; i++) { 143162306a36Sopenharmony_ci qpair = ha->queue_pair_map[i]; 143262306a36Sopenharmony_ci if (!qpair) 143362306a36Sopenharmony_ci continue; 143462306a36Sopenharmony_ci status = __qla2x00_eh_wait_for_pending_commands(qpair, t, l, 143562306a36Sopenharmony_ci type); 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci return status; 143862306a36Sopenharmony_ci} 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_cistatic char *reset_errors[] = { 144162306a36Sopenharmony_ci "HBA not online", 144262306a36Sopenharmony_ci "HBA not ready", 144362306a36Sopenharmony_ci "Task management failed", 144462306a36Sopenharmony_ci "Waiting for command completions", 144562306a36Sopenharmony_ci}; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_cistatic int 144862306a36Sopenharmony_ciqla2xxx_eh_device_reset(struct scsi_cmnd *cmd) 144962306a36Sopenharmony_ci{ 145062306a36Sopenharmony_ci struct scsi_device *sdev = cmd->device; 145162306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(sdev->host); 145262306a36Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); 145362306a36Sopenharmony_ci fc_port_t *fcport = (struct fc_port *) sdev->hostdata; 145462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 145562306a36Sopenharmony_ci int err; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci if (qla2x00_isp_reg_stat(ha)) { 145862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x803e, 145962306a36Sopenharmony_ci "PCI/Register disconnect, exiting.\n"); 146062306a36Sopenharmony_ci qla_pci_set_eeh_busy(vha); 146162306a36Sopenharmony_ci return FAILED; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci if (!fcport) { 146562306a36Sopenharmony_ci return FAILED; 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci err = fc_block_rport(rport); 146962306a36Sopenharmony_ci if (err != 0) 147062306a36Sopenharmony_ci return err; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (fcport->deleted) 147362306a36Sopenharmony_ci return FAILED; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x8009, 147662306a36Sopenharmony_ci "DEVICE RESET ISSUED nexus=%ld:%d:%llu cmd=%p.\n", vha->host_no, 147762306a36Sopenharmony_ci sdev->id, sdev->lun, cmd); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci err = 0; 148062306a36Sopenharmony_ci if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { 148162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x800a, 148262306a36Sopenharmony_ci "Wait for hba online failed for cmd=%p.\n", cmd); 148362306a36Sopenharmony_ci goto eh_reset_failed; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci err = 2; 148662306a36Sopenharmony_ci if (ha->isp_ops->lun_reset(fcport, sdev->lun, 1) 148762306a36Sopenharmony_ci != QLA_SUCCESS) { 148862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x800c, 148962306a36Sopenharmony_ci "do_reset failed for cmd=%p.\n", cmd); 149062306a36Sopenharmony_ci goto eh_reset_failed; 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci err = 3; 149362306a36Sopenharmony_ci if (qla2x00_eh_wait_for_pending_commands(vha, fcport->d_id.b24, 149462306a36Sopenharmony_ci cmd->device->lun, 149562306a36Sopenharmony_ci WAIT_LUN) != QLA_SUCCESS) { 149662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x800d, 149762306a36Sopenharmony_ci "wait for pending cmds failed for cmd=%p.\n", cmd); 149862306a36Sopenharmony_ci goto eh_reset_failed; 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x800e, 150262306a36Sopenharmony_ci "DEVICE RESET SUCCEEDED nexus:%ld:%d:%llu cmd=%p.\n", 150362306a36Sopenharmony_ci vha->host_no, sdev->id, sdev->lun, cmd); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci return SUCCESS; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_cieh_reset_failed: 150862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x800f, 150962306a36Sopenharmony_ci "DEVICE RESET FAILED: %s nexus=%ld:%d:%llu cmd=%p.\n", 151062306a36Sopenharmony_ci reset_errors[err], vha->host_no, sdev->id, sdev->lun, 151162306a36Sopenharmony_ci cmd); 151262306a36Sopenharmony_ci vha->reset_cmd_err_cnt++; 151362306a36Sopenharmony_ci return FAILED; 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_cistatic int 151762306a36Sopenharmony_ciqla2xxx_eh_target_reset(struct scsi_cmnd *cmd) 151862306a36Sopenharmony_ci{ 151962306a36Sopenharmony_ci struct scsi_device *sdev = cmd->device; 152062306a36Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); 152162306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(rport_to_shost(rport)); 152262306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 152362306a36Sopenharmony_ci fc_port_t *fcport = *(fc_port_t **)rport->dd_data; 152462306a36Sopenharmony_ci int err; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci if (qla2x00_isp_reg_stat(ha)) { 152762306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x803f, 152862306a36Sopenharmony_ci "PCI/Register disconnect, exiting.\n"); 152962306a36Sopenharmony_ci qla_pci_set_eeh_busy(vha); 153062306a36Sopenharmony_ci return FAILED; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci if (!fcport) { 153462306a36Sopenharmony_ci return FAILED; 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci err = fc_block_rport(rport); 153862306a36Sopenharmony_ci if (err != 0) 153962306a36Sopenharmony_ci return err; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci if (fcport->deleted) 154262306a36Sopenharmony_ci return FAILED; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x8009, 154562306a36Sopenharmony_ci "TARGET RESET ISSUED nexus=%ld:%d cmd=%p.\n", vha->host_no, 154662306a36Sopenharmony_ci sdev->id, cmd); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci err = 0; 154962306a36Sopenharmony_ci if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { 155062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x800a, 155162306a36Sopenharmony_ci "Wait for hba online failed for cmd=%p.\n", cmd); 155262306a36Sopenharmony_ci goto eh_reset_failed; 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci err = 2; 155562306a36Sopenharmony_ci if (ha->isp_ops->target_reset(fcport, 0, 0) != QLA_SUCCESS) { 155662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x800c, 155762306a36Sopenharmony_ci "target_reset failed for cmd=%p.\n", cmd); 155862306a36Sopenharmony_ci goto eh_reset_failed; 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci err = 3; 156162306a36Sopenharmony_ci if (qla2x00_eh_wait_for_pending_commands(vha, fcport->d_id.b24, 0, 156262306a36Sopenharmony_ci WAIT_TARGET) != QLA_SUCCESS) { 156362306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x800d, 156462306a36Sopenharmony_ci "wait for pending cmds failed for cmd=%p.\n", cmd); 156562306a36Sopenharmony_ci goto eh_reset_failed; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x800e, 156962306a36Sopenharmony_ci "TARGET RESET SUCCEEDED nexus:%ld:%d cmd=%p.\n", 157062306a36Sopenharmony_ci vha->host_no, sdev->id, cmd); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci return SUCCESS; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_cieh_reset_failed: 157562306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x800f, 157662306a36Sopenharmony_ci "TARGET RESET FAILED: %s nexus=%ld:%d:%llu cmd=%p.\n", 157762306a36Sopenharmony_ci reset_errors[err], vha->host_no, cmd->device->id, cmd->device->lun, 157862306a36Sopenharmony_ci cmd); 157962306a36Sopenharmony_ci vha->reset_cmd_err_cnt++; 158062306a36Sopenharmony_ci return FAILED; 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci/************************************************************************** 158462306a36Sopenharmony_ci* qla2xxx_eh_bus_reset 158562306a36Sopenharmony_ci* 158662306a36Sopenharmony_ci* Description: 158762306a36Sopenharmony_ci* The bus reset function will reset the bus and abort any executing 158862306a36Sopenharmony_ci* commands. 158962306a36Sopenharmony_ci* 159062306a36Sopenharmony_ci* Input: 159162306a36Sopenharmony_ci* cmd = Linux SCSI command packet of the command that cause the 159262306a36Sopenharmony_ci* bus reset. 159362306a36Sopenharmony_ci* 159462306a36Sopenharmony_ci* Returns: 159562306a36Sopenharmony_ci* SUCCESS/FAILURE (defined as macro in scsi.h). 159662306a36Sopenharmony_ci* 159762306a36Sopenharmony_ci**************************************************************************/ 159862306a36Sopenharmony_cistatic int 159962306a36Sopenharmony_ciqla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) 160062306a36Sopenharmony_ci{ 160162306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(cmd->device->host); 160262306a36Sopenharmony_ci int ret = FAILED; 160362306a36Sopenharmony_ci unsigned int id; 160462306a36Sopenharmony_ci uint64_t lun; 160562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci if (qla2x00_isp_reg_stat(ha)) { 160862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x8040, 160962306a36Sopenharmony_ci "PCI/Register disconnect, exiting.\n"); 161062306a36Sopenharmony_ci qla_pci_set_eeh_busy(vha); 161162306a36Sopenharmony_ci return FAILED; 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci id = cmd->device->id; 161562306a36Sopenharmony_ci lun = cmd->device->lun; 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci if (qla2x00_chip_is_down(vha)) 161862306a36Sopenharmony_ci return ret; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x8012, 162162306a36Sopenharmony_ci "BUS RESET ISSUED nexus=%ld:%d:%llu.\n", vha->host_no, id, lun); 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { 162462306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x8013, 162562306a36Sopenharmony_ci "Wait for hba online failed board disabled.\n"); 162662306a36Sopenharmony_ci goto eh_bus_reset_done; 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci if (qla2x00_loop_reset(vha) == QLA_SUCCESS) 163062306a36Sopenharmony_ci ret = SUCCESS; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci if (ret == FAILED) 163362306a36Sopenharmony_ci goto eh_bus_reset_done; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci /* Flush outstanding commands. */ 163662306a36Sopenharmony_ci if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) != 163762306a36Sopenharmony_ci QLA_SUCCESS) { 163862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x8014, 163962306a36Sopenharmony_ci "Wait for pending commands failed.\n"); 164062306a36Sopenharmony_ci ret = FAILED; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_cieh_bus_reset_done: 164462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x802b, 164562306a36Sopenharmony_ci "BUS RESET %s nexus=%ld:%d:%llu.\n", 164662306a36Sopenharmony_ci (ret == FAILED) ? "FAILED" : "SUCCEEDED", vha->host_no, id, lun); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci return ret; 164962306a36Sopenharmony_ci} 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci/************************************************************************** 165262306a36Sopenharmony_ci* qla2xxx_eh_host_reset 165362306a36Sopenharmony_ci* 165462306a36Sopenharmony_ci* Description: 165562306a36Sopenharmony_ci* The reset function will reset the Adapter. 165662306a36Sopenharmony_ci* 165762306a36Sopenharmony_ci* Input: 165862306a36Sopenharmony_ci* cmd = Linux SCSI command packet of the command that cause the 165962306a36Sopenharmony_ci* adapter reset. 166062306a36Sopenharmony_ci* 166162306a36Sopenharmony_ci* Returns: 166262306a36Sopenharmony_ci* Either SUCCESS or FAILED. 166362306a36Sopenharmony_ci* 166462306a36Sopenharmony_ci* Note: 166562306a36Sopenharmony_ci**************************************************************************/ 166662306a36Sopenharmony_cistatic int 166762306a36Sopenharmony_ciqla2xxx_eh_host_reset(struct scsi_cmnd *cmd) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(cmd->device->host); 167062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 167162306a36Sopenharmony_ci int ret = FAILED; 167262306a36Sopenharmony_ci unsigned int id; 167362306a36Sopenharmony_ci uint64_t lun; 167462306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci if (qla2x00_isp_reg_stat(ha)) { 167762306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x8041, 167862306a36Sopenharmony_ci "PCI/Register disconnect, exiting.\n"); 167962306a36Sopenharmony_ci qla_pci_set_eeh_busy(vha); 168062306a36Sopenharmony_ci return SUCCESS; 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci id = cmd->device->id; 168462306a36Sopenharmony_ci lun = cmd->device->lun; 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x8018, 168762306a36Sopenharmony_ci "ADAPTER RESET ISSUED nexus=%ld:%d:%llu.\n", vha->host_no, id, lun); 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci /* 169062306a36Sopenharmony_ci * No point in issuing another reset if one is active. Also do not 169162306a36Sopenharmony_ci * attempt a reset if we are updating flash. 169262306a36Sopenharmony_ci */ 169362306a36Sopenharmony_ci if (qla2x00_reset_active(vha) || ha->optrom_state != QLA_SWAITING) 169462306a36Sopenharmony_ci goto eh_host_reset_lock; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (vha != base_vha) { 169762306a36Sopenharmony_ci if (qla2x00_vp_abort_isp(vha)) 169862306a36Sopenharmony_ci goto eh_host_reset_lock; 169962306a36Sopenharmony_ci } else { 170062306a36Sopenharmony_ci if (IS_P3P_TYPE(vha->hw)) { 170162306a36Sopenharmony_ci if (!qla82xx_fcoe_ctx_reset(vha)) { 170262306a36Sopenharmony_ci /* Ctx reset success */ 170362306a36Sopenharmony_ci ret = SUCCESS; 170462306a36Sopenharmony_ci goto eh_host_reset_lock; 170562306a36Sopenharmony_ci } 170662306a36Sopenharmony_ci /* fall thru if ctx reset failed */ 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci if (ha->wq) 170962306a36Sopenharmony_ci flush_workqueue(ha->wq); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); 171262306a36Sopenharmony_ci if (ha->isp_ops->abort_isp(base_vha)) { 171362306a36Sopenharmony_ci clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); 171462306a36Sopenharmony_ci /* failed. schedule dpc to try */ 171562306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { 171862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x802a, 171962306a36Sopenharmony_ci "wait for hba online failed.\n"); 172062306a36Sopenharmony_ci goto eh_host_reset_lock; 172162306a36Sopenharmony_ci } 172262306a36Sopenharmony_ci } 172362306a36Sopenharmony_ci clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci /* Waiting for command to be returned to OS.*/ 172762306a36Sopenharmony_ci if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) == 172862306a36Sopenharmony_ci QLA_SUCCESS) 172962306a36Sopenharmony_ci ret = SUCCESS; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_cieh_host_reset_lock: 173262306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x8017, 173362306a36Sopenharmony_ci "ADAPTER RESET %s nexus=%ld:%d:%llu.\n", 173462306a36Sopenharmony_ci (ret == FAILED) ? "FAILED" : "SUCCEEDED", vha->host_no, id, lun); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci return ret; 173762306a36Sopenharmony_ci} 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci/* 174062306a36Sopenharmony_ci* qla2x00_loop_reset 174162306a36Sopenharmony_ci* Issue loop reset. 174262306a36Sopenharmony_ci* 174362306a36Sopenharmony_ci* Input: 174462306a36Sopenharmony_ci* ha = adapter block pointer. 174562306a36Sopenharmony_ci* 174662306a36Sopenharmony_ci* Returns: 174762306a36Sopenharmony_ci* 0 = success 174862306a36Sopenharmony_ci*/ 174962306a36Sopenharmony_ciint 175062306a36Sopenharmony_ciqla2x00_loop_reset(scsi_qla_host_t *vha) 175162306a36Sopenharmony_ci{ 175262306a36Sopenharmony_ci int ret; 175362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci if (IS_QLAFX00(ha)) 175662306a36Sopenharmony_ci return QLA_SUCCESS; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci if (ha->flags.enable_lip_full_login && !IS_CNA_CAPABLE(ha)) { 175962306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_DOWN); 176062306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); 176162306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 176262306a36Sopenharmony_ci ret = qla2x00_full_login_lip(vha); 176362306a36Sopenharmony_ci if (ret != QLA_SUCCESS) { 176462306a36Sopenharmony_ci ql_dbg(ql_dbg_taskm, vha, 0x802d, 176562306a36Sopenharmony_ci "full_login_lip=%d.\n", ret); 176662306a36Sopenharmony_ci } 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci if (ha->flags.enable_lip_reset) { 177062306a36Sopenharmony_ci ret = qla2x00_lip_reset(vha); 177162306a36Sopenharmony_ci if (ret != QLA_SUCCESS) 177262306a36Sopenharmony_ci ql_dbg(ql_dbg_taskm, vha, 0x802e, 177362306a36Sopenharmony_ci "lip_reset failed (%d).\n", ret); 177462306a36Sopenharmony_ci } 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci /* Issue marker command only when we are going to start the I/O */ 177762306a36Sopenharmony_ci vha->marker_needed = 1; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci return QLA_SUCCESS; 178062306a36Sopenharmony_ci} 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci/* 178362306a36Sopenharmony_ci * The caller must ensure that no completion interrupts will happen 178462306a36Sopenharmony_ci * while this function is in progress. 178562306a36Sopenharmony_ci */ 178662306a36Sopenharmony_cistatic void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, 178762306a36Sopenharmony_ci unsigned long *flags) 178862306a36Sopenharmony_ci __releases(qp->qp_lock_ptr) 178962306a36Sopenharmony_ci __acquires(qp->qp_lock_ptr) 179062306a36Sopenharmony_ci{ 179162306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(comp); 179262306a36Sopenharmony_ci scsi_qla_host_t *vha = qp->vha; 179362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 179462306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 179562306a36Sopenharmony_ci int rval; 179662306a36Sopenharmony_ci bool ret_cmd; 179762306a36Sopenharmony_ci uint32_t ratov_j; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci lockdep_assert_held(qp->qp_lock_ptr); 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci if (qla2x00_chip_is_down(vha)) { 180262306a36Sopenharmony_ci sp->done(sp, res); 180362306a36Sopenharmony_ci return; 180462306a36Sopenharmony_ci } 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci if (sp->type == SRB_NVME_CMD || sp->type == SRB_NVME_LS || 180762306a36Sopenharmony_ci (sp->type == SRB_SCSI_CMD && !ha->flags.eeh_busy && 180862306a36Sopenharmony_ci !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && 180962306a36Sopenharmony_ci !qla2x00_isp_reg_stat(ha))) { 181062306a36Sopenharmony_ci if (sp->comp) { 181162306a36Sopenharmony_ci sp->done(sp, res); 181262306a36Sopenharmony_ci return; 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci sp->comp = ∁ 181662306a36Sopenharmony_ci spin_unlock_irqrestore(qp->qp_lock_ptr, *flags); 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci rval = ha->isp_ops->abort_command(sp); 181962306a36Sopenharmony_ci /* Wait for command completion. */ 182062306a36Sopenharmony_ci ret_cmd = false; 182162306a36Sopenharmony_ci ratov_j = ha->r_a_tov/10 * 4 * 1000; 182262306a36Sopenharmony_ci ratov_j = msecs_to_jiffies(ratov_j); 182362306a36Sopenharmony_ci switch (rval) { 182462306a36Sopenharmony_ci case QLA_SUCCESS: 182562306a36Sopenharmony_ci if (wait_for_completion_timeout(&comp, ratov_j)) { 182662306a36Sopenharmony_ci ql_dbg(ql_dbg_taskm, vha, 0xffff, 182762306a36Sopenharmony_ci "%s: Abort wait timer (4 * R_A_TOV[%d]) expired\n", 182862306a36Sopenharmony_ci __func__, ha->r_a_tov/10); 182962306a36Sopenharmony_ci ret_cmd = true; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci /* else FW return SP to driver */ 183262306a36Sopenharmony_ci break; 183362306a36Sopenharmony_ci default: 183462306a36Sopenharmony_ci ret_cmd = true; 183562306a36Sopenharmony_ci break; 183662306a36Sopenharmony_ci } 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci spin_lock_irqsave(qp->qp_lock_ptr, *flags); 183962306a36Sopenharmony_ci switch (sp->type) { 184062306a36Sopenharmony_ci case SRB_SCSI_CMD: 184162306a36Sopenharmony_ci if (ret_cmd && blk_mq_request_started(scsi_cmd_to_rq(cmd))) 184262306a36Sopenharmony_ci sp->done(sp, res); 184362306a36Sopenharmony_ci break; 184462306a36Sopenharmony_ci default: 184562306a36Sopenharmony_ci if (ret_cmd) 184662306a36Sopenharmony_ci sp->done(sp, res); 184762306a36Sopenharmony_ci break; 184862306a36Sopenharmony_ci } 184962306a36Sopenharmony_ci } else { 185062306a36Sopenharmony_ci sp->done(sp, res); 185162306a36Sopenharmony_ci } 185262306a36Sopenharmony_ci} 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci/* 185562306a36Sopenharmony_ci * The caller must ensure that no completion interrupts will happen 185662306a36Sopenharmony_ci * while this function is in progress. 185762306a36Sopenharmony_ci */ 185862306a36Sopenharmony_cistatic void 185962306a36Sopenharmony_ci__qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) 186062306a36Sopenharmony_ci{ 186162306a36Sopenharmony_ci int cnt; 186262306a36Sopenharmony_ci unsigned long flags; 186362306a36Sopenharmony_ci srb_t *sp; 186462306a36Sopenharmony_ci scsi_qla_host_t *vha = qp->vha; 186562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 186662306a36Sopenharmony_ci struct req_que *req; 186762306a36Sopenharmony_ci struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; 186862306a36Sopenharmony_ci struct qla_tgt_cmd *cmd; 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci if (!ha->req_q_map) 187162306a36Sopenharmony_ci return; 187262306a36Sopenharmony_ci spin_lock_irqsave(qp->qp_lock_ptr, flags); 187362306a36Sopenharmony_ci req = qp->req; 187462306a36Sopenharmony_ci for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) { 187562306a36Sopenharmony_ci sp = req->outstanding_cmds[cnt]; 187662306a36Sopenharmony_ci if (sp) { 187762306a36Sopenharmony_ci /* 187862306a36Sopenharmony_ci * perform lockless completion during driver unload 187962306a36Sopenharmony_ci */ 188062306a36Sopenharmony_ci if (qla2x00_chip_is_down(vha)) { 188162306a36Sopenharmony_ci req->outstanding_cmds[cnt] = NULL; 188262306a36Sopenharmony_ci spin_unlock_irqrestore(qp->qp_lock_ptr, flags); 188362306a36Sopenharmony_ci sp->done(sp, res); 188462306a36Sopenharmony_ci spin_lock_irqsave(qp->qp_lock_ptr, flags); 188562306a36Sopenharmony_ci continue; 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci switch (sp->cmd_type) { 188962306a36Sopenharmony_ci case TYPE_SRB: 189062306a36Sopenharmony_ci qla2x00_abort_srb(qp, sp, res, &flags); 189162306a36Sopenharmony_ci break; 189262306a36Sopenharmony_ci case TYPE_TGT_CMD: 189362306a36Sopenharmony_ci if (!vha->hw->tgt.tgt_ops || !tgt || 189462306a36Sopenharmony_ci qla_ini_mode_enabled(vha)) { 189562306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt_mgt, vha, 0xf003, 189662306a36Sopenharmony_ci "HOST-ABORT-HNDLR: dpc_flags=%lx. Target mode disabled\n", 189762306a36Sopenharmony_ci vha->dpc_flags); 189862306a36Sopenharmony_ci continue; 189962306a36Sopenharmony_ci } 190062306a36Sopenharmony_ci cmd = (struct qla_tgt_cmd *)sp; 190162306a36Sopenharmony_ci cmd->aborted = 1; 190262306a36Sopenharmony_ci break; 190362306a36Sopenharmony_ci case TYPE_TGT_TMCMD: 190462306a36Sopenharmony_ci /* Skip task management functions. */ 190562306a36Sopenharmony_ci break; 190662306a36Sopenharmony_ci default: 190762306a36Sopenharmony_ci break; 190862306a36Sopenharmony_ci } 190962306a36Sopenharmony_ci req->outstanding_cmds[cnt] = NULL; 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci } 191262306a36Sopenharmony_ci spin_unlock_irqrestore(qp->qp_lock_ptr, flags); 191362306a36Sopenharmony_ci} 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci/* 191662306a36Sopenharmony_ci * The caller must ensure that no completion interrupts will happen 191762306a36Sopenharmony_ci * while this function is in progress. 191862306a36Sopenharmony_ci */ 191962306a36Sopenharmony_civoid 192062306a36Sopenharmony_ciqla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) 192162306a36Sopenharmony_ci{ 192262306a36Sopenharmony_ci int que; 192362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci /* Continue only if initialization complete. */ 192662306a36Sopenharmony_ci if (!ha->base_qpair) 192762306a36Sopenharmony_ci return; 192862306a36Sopenharmony_ci __qla2x00_abort_all_cmds(ha->base_qpair, res); 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci if (!ha->queue_pair_map) 193162306a36Sopenharmony_ci return; 193262306a36Sopenharmony_ci for (que = 0; que < ha->max_qpairs; que++) { 193362306a36Sopenharmony_ci if (!ha->queue_pair_map[que]) 193462306a36Sopenharmony_ci continue; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci __qla2x00_abort_all_cmds(ha->queue_pair_map[que], res); 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci} 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_cistatic int 194162306a36Sopenharmony_ciqla2xxx_slave_alloc(struct scsi_device *sdev) 194262306a36Sopenharmony_ci{ 194362306a36Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci if (!rport || fc_remote_port_chkready(rport)) 194662306a36Sopenharmony_ci return -ENXIO; 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci sdev->hostdata = *(fc_port_t **)rport->dd_data; 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci return 0; 195162306a36Sopenharmony_ci} 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_cistatic int 195462306a36Sopenharmony_ciqla2xxx_slave_configure(struct scsi_device *sdev) 195562306a36Sopenharmony_ci{ 195662306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(sdev->host); 195762306a36Sopenharmony_ci struct req_que *req = vha->req; 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci if (IS_T10_PI_CAPABLE(vha->hw)) 196062306a36Sopenharmony_ci blk_queue_update_dma_alignment(sdev->request_queue, 0x7); 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci scsi_change_queue_depth(sdev, req->max_q_depth); 196362306a36Sopenharmony_ci return 0; 196462306a36Sopenharmony_ci} 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_cistatic void 196762306a36Sopenharmony_ciqla2xxx_slave_destroy(struct scsi_device *sdev) 196862306a36Sopenharmony_ci{ 196962306a36Sopenharmony_ci sdev->hostdata = NULL; 197062306a36Sopenharmony_ci} 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci/** 197362306a36Sopenharmony_ci * qla2x00_config_dma_addressing() - Configure OS DMA addressing method. 197462306a36Sopenharmony_ci * @ha: HA context 197562306a36Sopenharmony_ci * 197662306a36Sopenharmony_ci * At exit, the @ha's flags.enable_64bit_addressing set to indicated 197762306a36Sopenharmony_ci * supported addressing method. 197862306a36Sopenharmony_ci */ 197962306a36Sopenharmony_cistatic void 198062306a36Sopenharmony_ciqla2x00_config_dma_addressing(struct qla_hw_data *ha) 198162306a36Sopenharmony_ci{ 198262306a36Sopenharmony_ci /* Assume a 32bit DMA mask. */ 198362306a36Sopenharmony_ci ha->flags.enable_64bit_addressing = 0; 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci if (!dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(64))) { 198662306a36Sopenharmony_ci /* Any upper-dword bits set? */ 198762306a36Sopenharmony_ci if (MSD(dma_get_required_mask(&ha->pdev->dev)) && 198862306a36Sopenharmony_ci !dma_set_coherent_mask(&ha->pdev->dev, DMA_BIT_MASK(64))) { 198962306a36Sopenharmony_ci /* Ok, a 64bit DMA mask is applicable. */ 199062306a36Sopenharmony_ci ha->flags.enable_64bit_addressing = 1; 199162306a36Sopenharmony_ci ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64; 199262306a36Sopenharmony_ci ha->isp_ops->build_iocbs = qla2x00_build_scsi_iocbs_64; 199362306a36Sopenharmony_ci return; 199462306a36Sopenharmony_ci } 199562306a36Sopenharmony_ci } 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(32)); 199862306a36Sopenharmony_ci dma_set_coherent_mask(&ha->pdev->dev, DMA_BIT_MASK(32)); 199962306a36Sopenharmony_ci} 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_cistatic void 200262306a36Sopenharmony_ciqla2x00_enable_intrs(struct qla_hw_data *ha) 200362306a36Sopenharmony_ci{ 200462306a36Sopenharmony_ci unsigned long flags = 0; 200562306a36Sopenharmony_ci struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 200862306a36Sopenharmony_ci ha->interrupts_on = 1; 200962306a36Sopenharmony_ci /* enable risc and host interrupts */ 201062306a36Sopenharmony_ci wrt_reg_word(®->ictrl, ICR_EN_INT | ICR_EN_RISC); 201162306a36Sopenharmony_ci rd_reg_word(®->ictrl); 201262306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci} 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_cistatic void 201762306a36Sopenharmony_ciqla2x00_disable_intrs(struct qla_hw_data *ha) 201862306a36Sopenharmony_ci{ 201962306a36Sopenharmony_ci unsigned long flags = 0; 202062306a36Sopenharmony_ci struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 202362306a36Sopenharmony_ci ha->interrupts_on = 0; 202462306a36Sopenharmony_ci /* disable risc and host interrupts */ 202562306a36Sopenharmony_ci wrt_reg_word(®->ictrl, 0); 202662306a36Sopenharmony_ci rd_reg_word(®->ictrl); 202762306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 202862306a36Sopenharmony_ci} 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_cistatic void 203162306a36Sopenharmony_ciqla24xx_enable_intrs(struct qla_hw_data *ha) 203262306a36Sopenharmony_ci{ 203362306a36Sopenharmony_ci unsigned long flags = 0; 203462306a36Sopenharmony_ci struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 203762306a36Sopenharmony_ci ha->interrupts_on = 1; 203862306a36Sopenharmony_ci wrt_reg_dword(®->ictrl, ICRX_EN_RISC_INT); 203962306a36Sopenharmony_ci rd_reg_dword(®->ictrl); 204062306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 204162306a36Sopenharmony_ci} 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_cistatic void 204462306a36Sopenharmony_ciqla24xx_disable_intrs(struct qla_hw_data *ha) 204562306a36Sopenharmony_ci{ 204662306a36Sopenharmony_ci unsigned long flags = 0; 204762306a36Sopenharmony_ci struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci if (IS_NOPOLLING_TYPE(ha)) 205062306a36Sopenharmony_ci return; 205162306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 205262306a36Sopenharmony_ci ha->interrupts_on = 0; 205362306a36Sopenharmony_ci wrt_reg_dword(®->ictrl, 0); 205462306a36Sopenharmony_ci rd_reg_dword(®->ictrl); 205562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 205662306a36Sopenharmony_ci} 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_cistatic int 205962306a36Sopenharmony_ciqla2x00_iospace_config(struct qla_hw_data *ha) 206062306a36Sopenharmony_ci{ 206162306a36Sopenharmony_ci resource_size_t pio; 206262306a36Sopenharmony_ci uint16_t msix; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci if (pci_request_selected_regions(ha->pdev, ha->bars, 206562306a36Sopenharmony_ci QLA2XXX_DRIVER_NAME)) { 206662306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x0011, 206762306a36Sopenharmony_ci "Failed to reserve PIO/MMIO regions (%s), aborting.\n", 206862306a36Sopenharmony_ci pci_name(ha->pdev)); 206962306a36Sopenharmony_ci goto iospace_error_exit; 207062306a36Sopenharmony_ci } 207162306a36Sopenharmony_ci if (!(ha->bars & 1)) 207262306a36Sopenharmony_ci goto skip_pio; 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci /* We only need PIO for Flash operations on ISP2312 v2 chips. */ 207562306a36Sopenharmony_ci pio = pci_resource_start(ha->pdev, 0); 207662306a36Sopenharmony_ci if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) { 207762306a36Sopenharmony_ci if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) { 207862306a36Sopenharmony_ci ql_log_pci(ql_log_warn, ha->pdev, 0x0012, 207962306a36Sopenharmony_ci "Invalid pci I/O region size (%s).\n", 208062306a36Sopenharmony_ci pci_name(ha->pdev)); 208162306a36Sopenharmony_ci pio = 0; 208262306a36Sopenharmony_ci } 208362306a36Sopenharmony_ci } else { 208462306a36Sopenharmony_ci ql_log_pci(ql_log_warn, ha->pdev, 0x0013, 208562306a36Sopenharmony_ci "Region #0 no a PIO resource (%s).\n", 208662306a36Sopenharmony_ci pci_name(ha->pdev)); 208762306a36Sopenharmony_ci pio = 0; 208862306a36Sopenharmony_ci } 208962306a36Sopenharmony_ci ha->pio_address = pio; 209062306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0014, 209162306a36Sopenharmony_ci "PIO address=%llu.\n", 209262306a36Sopenharmony_ci (unsigned long long)ha->pio_address); 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ciskip_pio: 209562306a36Sopenharmony_ci /* Use MMIO operations for all accesses. */ 209662306a36Sopenharmony_ci if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) { 209762306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x0015, 209862306a36Sopenharmony_ci "Region #1 not an MMIO resource (%s), aborting.\n", 209962306a36Sopenharmony_ci pci_name(ha->pdev)); 210062306a36Sopenharmony_ci goto iospace_error_exit; 210162306a36Sopenharmony_ci } 210262306a36Sopenharmony_ci if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) { 210362306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x0016, 210462306a36Sopenharmony_ci "Invalid PCI mem region size (%s), aborting.\n", 210562306a36Sopenharmony_ci pci_name(ha->pdev)); 210662306a36Sopenharmony_ci goto iospace_error_exit; 210762306a36Sopenharmony_ci } 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN); 211062306a36Sopenharmony_ci if (!ha->iobase) { 211162306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x0017, 211262306a36Sopenharmony_ci "Cannot remap MMIO (%s), aborting.\n", 211362306a36Sopenharmony_ci pci_name(ha->pdev)); 211462306a36Sopenharmony_ci goto iospace_error_exit; 211562306a36Sopenharmony_ci } 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci /* Determine queue resources */ 211862306a36Sopenharmony_ci ha->max_req_queues = ha->max_rsp_queues = 1; 211962306a36Sopenharmony_ci ha->msix_count = QLA_BASE_VECTORS; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci /* Check if FW supports MQ or not */ 212262306a36Sopenharmony_ci if (!(ha->fw_attributes & BIT_6)) 212362306a36Sopenharmony_ci goto mqiobase_exit; 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci if (!ql2xmqsupport || !ql2xnvmeenable || 212662306a36Sopenharmony_ci (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) 212762306a36Sopenharmony_ci goto mqiobase_exit; 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3), 213062306a36Sopenharmony_ci pci_resource_len(ha->pdev, 3)); 213162306a36Sopenharmony_ci if (ha->mqiobase) { 213262306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0018, 213362306a36Sopenharmony_ci "MQIO Base=%p.\n", ha->mqiobase); 213462306a36Sopenharmony_ci /* Read MSIX vector size of the board */ 213562306a36Sopenharmony_ci pci_read_config_word(ha->pdev, QLA_PCI_MSIX_CONTROL, &msix); 213662306a36Sopenharmony_ci ha->msix_count = msix + 1; 213762306a36Sopenharmony_ci /* Max queues are bounded by available msix vectors */ 213862306a36Sopenharmony_ci /* MB interrupt uses 1 vector */ 213962306a36Sopenharmony_ci ha->max_req_queues = ha->msix_count - 1; 214062306a36Sopenharmony_ci ha->max_rsp_queues = ha->max_req_queues; 214162306a36Sopenharmony_ci /* Queue pairs is the max value minus the base queue pair */ 214262306a36Sopenharmony_ci ha->max_qpairs = ha->max_rsp_queues - 1; 214362306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0188, 214462306a36Sopenharmony_ci "Max no of queues pairs: %d.\n", ha->max_qpairs); 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci ql_log_pci(ql_log_info, ha->pdev, 0x001a, 214762306a36Sopenharmony_ci "MSI-X vector count: %d.\n", ha->msix_count); 214862306a36Sopenharmony_ci } else 214962306a36Sopenharmony_ci ql_log_pci(ql_log_info, ha->pdev, 0x001b, 215062306a36Sopenharmony_ci "BAR 3 not enabled.\n"); 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_cimqiobase_exit: 215362306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x001c, 215462306a36Sopenharmony_ci "MSIX Count: %d.\n", ha->msix_count); 215562306a36Sopenharmony_ci return (0); 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ciiospace_error_exit: 215862306a36Sopenharmony_ci return (-ENOMEM); 215962306a36Sopenharmony_ci} 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_cistatic int 216362306a36Sopenharmony_ciqla83xx_iospace_config(struct qla_hw_data *ha) 216462306a36Sopenharmony_ci{ 216562306a36Sopenharmony_ci uint16_t msix; 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci if (pci_request_selected_regions(ha->pdev, ha->bars, 216862306a36Sopenharmony_ci QLA2XXX_DRIVER_NAME)) { 216962306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x0117, 217062306a36Sopenharmony_ci "Failed to reserve PIO/MMIO regions (%s), aborting.\n", 217162306a36Sopenharmony_ci pci_name(ha->pdev)); 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci goto iospace_error_exit; 217462306a36Sopenharmony_ci } 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci /* Use MMIO operations for all accesses. */ 217762306a36Sopenharmony_ci if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) { 217862306a36Sopenharmony_ci ql_log_pci(ql_log_warn, ha->pdev, 0x0118, 217962306a36Sopenharmony_ci "Invalid pci I/O region size (%s).\n", 218062306a36Sopenharmony_ci pci_name(ha->pdev)); 218162306a36Sopenharmony_ci goto iospace_error_exit; 218262306a36Sopenharmony_ci } 218362306a36Sopenharmony_ci if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) { 218462306a36Sopenharmony_ci ql_log_pci(ql_log_warn, ha->pdev, 0x0119, 218562306a36Sopenharmony_ci "Invalid PCI mem region size (%s), aborting\n", 218662306a36Sopenharmony_ci pci_name(ha->pdev)); 218762306a36Sopenharmony_ci goto iospace_error_exit; 218862306a36Sopenharmony_ci } 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci ha->iobase = ioremap(pci_resource_start(ha->pdev, 0), MIN_IOBASE_LEN); 219162306a36Sopenharmony_ci if (!ha->iobase) { 219262306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x011a, 219362306a36Sopenharmony_ci "Cannot remap MMIO (%s), aborting.\n", 219462306a36Sopenharmony_ci pci_name(ha->pdev)); 219562306a36Sopenharmony_ci goto iospace_error_exit; 219662306a36Sopenharmony_ci } 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci /* 64bit PCI BAR - BAR2 will correspoond to region 4 */ 219962306a36Sopenharmony_ci /* 83XX 26XX always use MQ type access for queues 220062306a36Sopenharmony_ci * - mbar 2, a.k.a region 4 */ 220162306a36Sopenharmony_ci ha->max_req_queues = ha->max_rsp_queues = 1; 220262306a36Sopenharmony_ci ha->msix_count = QLA_BASE_VECTORS; 220362306a36Sopenharmony_ci ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 4), 220462306a36Sopenharmony_ci pci_resource_len(ha->pdev, 4)); 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci if (!ha->mqiobase) { 220762306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x011d, 220862306a36Sopenharmony_ci "BAR2/region4 not enabled\n"); 220962306a36Sopenharmony_ci goto mqiobase_exit; 221062306a36Sopenharmony_ci } 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci ha->msixbase = ioremap(pci_resource_start(ha->pdev, 2), 221362306a36Sopenharmony_ci pci_resource_len(ha->pdev, 2)); 221462306a36Sopenharmony_ci if (ha->msixbase) { 221562306a36Sopenharmony_ci /* Read MSIX vector size of the board */ 221662306a36Sopenharmony_ci pci_read_config_word(ha->pdev, 221762306a36Sopenharmony_ci QLA_83XX_PCI_MSIX_CONTROL, &msix); 221862306a36Sopenharmony_ci ha->msix_count = (msix & PCI_MSIX_FLAGS_QSIZE) + 1; 221962306a36Sopenharmony_ci /* 222062306a36Sopenharmony_ci * By default, driver uses at least two msix vectors 222162306a36Sopenharmony_ci * (default & rspq) 222262306a36Sopenharmony_ci */ 222362306a36Sopenharmony_ci if (ql2xmqsupport || ql2xnvmeenable) { 222462306a36Sopenharmony_ci /* MB interrupt uses 1 vector */ 222562306a36Sopenharmony_ci ha->max_req_queues = ha->msix_count - 1; 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci /* ATIOQ needs 1 vector. That's 1 less QPair */ 222862306a36Sopenharmony_ci if (QLA_TGT_MODE_ENABLED()) 222962306a36Sopenharmony_ci ha->max_req_queues--; 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci ha->max_rsp_queues = ha->max_req_queues; 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci /* Queue pairs is the max value minus 223462306a36Sopenharmony_ci * the base queue pair */ 223562306a36Sopenharmony_ci ha->max_qpairs = ha->max_req_queues - 1; 223662306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x00e3, 223762306a36Sopenharmony_ci "Max no of queues pairs: %d.\n", ha->max_qpairs); 223862306a36Sopenharmony_ci } 223962306a36Sopenharmony_ci ql_log_pci(ql_log_info, ha->pdev, 0x011c, 224062306a36Sopenharmony_ci "MSI-X vector count: %d.\n", ha->msix_count); 224162306a36Sopenharmony_ci } else 224262306a36Sopenharmony_ci ql_log_pci(ql_log_info, ha->pdev, 0x011e, 224362306a36Sopenharmony_ci "BAR 1 not enabled.\n"); 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_cimqiobase_exit: 224662306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011f, 224762306a36Sopenharmony_ci "MSIX Count: %d.\n", ha->msix_count); 224862306a36Sopenharmony_ci return 0; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ciiospace_error_exit: 225162306a36Sopenharmony_ci return -ENOMEM; 225262306a36Sopenharmony_ci} 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_cistatic struct isp_operations qla2100_isp_ops = { 225562306a36Sopenharmony_ci .pci_config = qla2100_pci_config, 225662306a36Sopenharmony_ci .reset_chip = qla2x00_reset_chip, 225762306a36Sopenharmony_ci .chip_diag = qla2x00_chip_diag, 225862306a36Sopenharmony_ci .config_rings = qla2x00_config_rings, 225962306a36Sopenharmony_ci .reset_adapter = qla2x00_reset_adapter, 226062306a36Sopenharmony_ci .nvram_config = qla2x00_nvram_config, 226162306a36Sopenharmony_ci .update_fw_options = qla2x00_update_fw_options, 226262306a36Sopenharmony_ci .load_risc = qla2x00_load_risc, 226362306a36Sopenharmony_ci .pci_info_str = qla2x00_pci_info_str, 226462306a36Sopenharmony_ci .fw_version_str = qla2x00_fw_version_str, 226562306a36Sopenharmony_ci .intr_handler = qla2100_intr_handler, 226662306a36Sopenharmony_ci .enable_intrs = qla2x00_enable_intrs, 226762306a36Sopenharmony_ci .disable_intrs = qla2x00_disable_intrs, 226862306a36Sopenharmony_ci .abort_command = qla2x00_abort_command, 226962306a36Sopenharmony_ci .target_reset = qla2x00_abort_target, 227062306a36Sopenharmony_ci .lun_reset = qla2x00_lun_reset, 227162306a36Sopenharmony_ci .fabric_login = qla2x00_login_fabric, 227262306a36Sopenharmony_ci .fabric_logout = qla2x00_fabric_logout, 227362306a36Sopenharmony_ci .calc_req_entries = qla2x00_calc_iocbs_32, 227462306a36Sopenharmony_ci .build_iocbs = qla2x00_build_scsi_iocbs_32, 227562306a36Sopenharmony_ci .prep_ms_iocb = qla2x00_prep_ms_iocb, 227662306a36Sopenharmony_ci .prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb, 227762306a36Sopenharmony_ci .read_nvram = qla2x00_read_nvram_data, 227862306a36Sopenharmony_ci .write_nvram = qla2x00_write_nvram_data, 227962306a36Sopenharmony_ci .fw_dump = qla2100_fw_dump, 228062306a36Sopenharmony_ci .beacon_on = NULL, 228162306a36Sopenharmony_ci .beacon_off = NULL, 228262306a36Sopenharmony_ci .beacon_blink = NULL, 228362306a36Sopenharmony_ci .read_optrom = qla2x00_read_optrom_data, 228462306a36Sopenharmony_ci .write_optrom = qla2x00_write_optrom_data, 228562306a36Sopenharmony_ci .get_flash_version = qla2x00_get_flash_version, 228662306a36Sopenharmony_ci .start_scsi = qla2x00_start_scsi, 228762306a36Sopenharmony_ci .start_scsi_mq = NULL, 228862306a36Sopenharmony_ci .abort_isp = qla2x00_abort_isp, 228962306a36Sopenharmony_ci .iospace_config = qla2x00_iospace_config, 229062306a36Sopenharmony_ci .initialize_adapter = qla2x00_initialize_adapter, 229162306a36Sopenharmony_ci}; 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_cistatic struct isp_operations qla2300_isp_ops = { 229462306a36Sopenharmony_ci .pci_config = qla2300_pci_config, 229562306a36Sopenharmony_ci .reset_chip = qla2x00_reset_chip, 229662306a36Sopenharmony_ci .chip_diag = qla2x00_chip_diag, 229762306a36Sopenharmony_ci .config_rings = qla2x00_config_rings, 229862306a36Sopenharmony_ci .reset_adapter = qla2x00_reset_adapter, 229962306a36Sopenharmony_ci .nvram_config = qla2x00_nvram_config, 230062306a36Sopenharmony_ci .update_fw_options = qla2x00_update_fw_options, 230162306a36Sopenharmony_ci .load_risc = qla2x00_load_risc, 230262306a36Sopenharmony_ci .pci_info_str = qla2x00_pci_info_str, 230362306a36Sopenharmony_ci .fw_version_str = qla2x00_fw_version_str, 230462306a36Sopenharmony_ci .intr_handler = qla2300_intr_handler, 230562306a36Sopenharmony_ci .enable_intrs = qla2x00_enable_intrs, 230662306a36Sopenharmony_ci .disable_intrs = qla2x00_disable_intrs, 230762306a36Sopenharmony_ci .abort_command = qla2x00_abort_command, 230862306a36Sopenharmony_ci .target_reset = qla2x00_abort_target, 230962306a36Sopenharmony_ci .lun_reset = qla2x00_lun_reset, 231062306a36Sopenharmony_ci .fabric_login = qla2x00_login_fabric, 231162306a36Sopenharmony_ci .fabric_logout = qla2x00_fabric_logout, 231262306a36Sopenharmony_ci .calc_req_entries = qla2x00_calc_iocbs_32, 231362306a36Sopenharmony_ci .build_iocbs = qla2x00_build_scsi_iocbs_32, 231462306a36Sopenharmony_ci .prep_ms_iocb = qla2x00_prep_ms_iocb, 231562306a36Sopenharmony_ci .prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb, 231662306a36Sopenharmony_ci .read_nvram = qla2x00_read_nvram_data, 231762306a36Sopenharmony_ci .write_nvram = qla2x00_write_nvram_data, 231862306a36Sopenharmony_ci .fw_dump = qla2300_fw_dump, 231962306a36Sopenharmony_ci .beacon_on = qla2x00_beacon_on, 232062306a36Sopenharmony_ci .beacon_off = qla2x00_beacon_off, 232162306a36Sopenharmony_ci .beacon_blink = qla2x00_beacon_blink, 232262306a36Sopenharmony_ci .read_optrom = qla2x00_read_optrom_data, 232362306a36Sopenharmony_ci .write_optrom = qla2x00_write_optrom_data, 232462306a36Sopenharmony_ci .get_flash_version = qla2x00_get_flash_version, 232562306a36Sopenharmony_ci .start_scsi = qla2x00_start_scsi, 232662306a36Sopenharmony_ci .start_scsi_mq = NULL, 232762306a36Sopenharmony_ci .abort_isp = qla2x00_abort_isp, 232862306a36Sopenharmony_ci .iospace_config = qla2x00_iospace_config, 232962306a36Sopenharmony_ci .initialize_adapter = qla2x00_initialize_adapter, 233062306a36Sopenharmony_ci}; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_cistatic struct isp_operations qla24xx_isp_ops = { 233362306a36Sopenharmony_ci .pci_config = qla24xx_pci_config, 233462306a36Sopenharmony_ci .reset_chip = qla24xx_reset_chip, 233562306a36Sopenharmony_ci .chip_diag = qla24xx_chip_diag, 233662306a36Sopenharmony_ci .config_rings = qla24xx_config_rings, 233762306a36Sopenharmony_ci .reset_adapter = qla24xx_reset_adapter, 233862306a36Sopenharmony_ci .nvram_config = qla24xx_nvram_config, 233962306a36Sopenharmony_ci .update_fw_options = qla24xx_update_fw_options, 234062306a36Sopenharmony_ci .load_risc = qla24xx_load_risc, 234162306a36Sopenharmony_ci .pci_info_str = qla24xx_pci_info_str, 234262306a36Sopenharmony_ci .fw_version_str = qla24xx_fw_version_str, 234362306a36Sopenharmony_ci .intr_handler = qla24xx_intr_handler, 234462306a36Sopenharmony_ci .enable_intrs = qla24xx_enable_intrs, 234562306a36Sopenharmony_ci .disable_intrs = qla24xx_disable_intrs, 234662306a36Sopenharmony_ci .abort_command = qla24xx_abort_command, 234762306a36Sopenharmony_ci .target_reset = qla24xx_abort_target, 234862306a36Sopenharmony_ci .lun_reset = qla24xx_lun_reset, 234962306a36Sopenharmony_ci .fabric_login = qla24xx_login_fabric, 235062306a36Sopenharmony_ci .fabric_logout = qla24xx_fabric_logout, 235162306a36Sopenharmony_ci .calc_req_entries = NULL, 235262306a36Sopenharmony_ci .build_iocbs = NULL, 235362306a36Sopenharmony_ci .prep_ms_iocb = qla24xx_prep_ms_iocb, 235462306a36Sopenharmony_ci .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, 235562306a36Sopenharmony_ci .read_nvram = qla24xx_read_nvram_data, 235662306a36Sopenharmony_ci .write_nvram = qla24xx_write_nvram_data, 235762306a36Sopenharmony_ci .fw_dump = qla24xx_fw_dump, 235862306a36Sopenharmony_ci .beacon_on = qla24xx_beacon_on, 235962306a36Sopenharmony_ci .beacon_off = qla24xx_beacon_off, 236062306a36Sopenharmony_ci .beacon_blink = qla24xx_beacon_blink, 236162306a36Sopenharmony_ci .read_optrom = qla24xx_read_optrom_data, 236262306a36Sopenharmony_ci .write_optrom = qla24xx_write_optrom_data, 236362306a36Sopenharmony_ci .get_flash_version = qla24xx_get_flash_version, 236462306a36Sopenharmony_ci .start_scsi = qla24xx_start_scsi, 236562306a36Sopenharmony_ci .start_scsi_mq = NULL, 236662306a36Sopenharmony_ci .abort_isp = qla2x00_abort_isp, 236762306a36Sopenharmony_ci .iospace_config = qla2x00_iospace_config, 236862306a36Sopenharmony_ci .initialize_adapter = qla2x00_initialize_adapter, 236962306a36Sopenharmony_ci}; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_cistatic struct isp_operations qla25xx_isp_ops = { 237262306a36Sopenharmony_ci .pci_config = qla25xx_pci_config, 237362306a36Sopenharmony_ci .reset_chip = qla24xx_reset_chip, 237462306a36Sopenharmony_ci .chip_diag = qla24xx_chip_diag, 237562306a36Sopenharmony_ci .config_rings = qla24xx_config_rings, 237662306a36Sopenharmony_ci .reset_adapter = qla24xx_reset_adapter, 237762306a36Sopenharmony_ci .nvram_config = qla24xx_nvram_config, 237862306a36Sopenharmony_ci .update_fw_options = qla24xx_update_fw_options, 237962306a36Sopenharmony_ci .load_risc = qla24xx_load_risc, 238062306a36Sopenharmony_ci .pci_info_str = qla24xx_pci_info_str, 238162306a36Sopenharmony_ci .fw_version_str = qla24xx_fw_version_str, 238262306a36Sopenharmony_ci .intr_handler = qla24xx_intr_handler, 238362306a36Sopenharmony_ci .enable_intrs = qla24xx_enable_intrs, 238462306a36Sopenharmony_ci .disable_intrs = qla24xx_disable_intrs, 238562306a36Sopenharmony_ci .abort_command = qla24xx_abort_command, 238662306a36Sopenharmony_ci .target_reset = qla24xx_abort_target, 238762306a36Sopenharmony_ci .lun_reset = qla24xx_lun_reset, 238862306a36Sopenharmony_ci .fabric_login = qla24xx_login_fabric, 238962306a36Sopenharmony_ci .fabric_logout = qla24xx_fabric_logout, 239062306a36Sopenharmony_ci .calc_req_entries = NULL, 239162306a36Sopenharmony_ci .build_iocbs = NULL, 239262306a36Sopenharmony_ci .prep_ms_iocb = qla24xx_prep_ms_iocb, 239362306a36Sopenharmony_ci .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, 239462306a36Sopenharmony_ci .read_nvram = qla25xx_read_nvram_data, 239562306a36Sopenharmony_ci .write_nvram = qla25xx_write_nvram_data, 239662306a36Sopenharmony_ci .fw_dump = qla25xx_fw_dump, 239762306a36Sopenharmony_ci .beacon_on = qla24xx_beacon_on, 239862306a36Sopenharmony_ci .beacon_off = qla24xx_beacon_off, 239962306a36Sopenharmony_ci .beacon_blink = qla24xx_beacon_blink, 240062306a36Sopenharmony_ci .read_optrom = qla25xx_read_optrom_data, 240162306a36Sopenharmony_ci .write_optrom = qla24xx_write_optrom_data, 240262306a36Sopenharmony_ci .get_flash_version = qla24xx_get_flash_version, 240362306a36Sopenharmony_ci .start_scsi = qla24xx_dif_start_scsi, 240462306a36Sopenharmony_ci .start_scsi_mq = qla2xxx_dif_start_scsi_mq, 240562306a36Sopenharmony_ci .abort_isp = qla2x00_abort_isp, 240662306a36Sopenharmony_ci .iospace_config = qla2x00_iospace_config, 240762306a36Sopenharmony_ci .initialize_adapter = qla2x00_initialize_adapter, 240862306a36Sopenharmony_ci}; 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_cistatic struct isp_operations qla81xx_isp_ops = { 241162306a36Sopenharmony_ci .pci_config = qla25xx_pci_config, 241262306a36Sopenharmony_ci .reset_chip = qla24xx_reset_chip, 241362306a36Sopenharmony_ci .chip_diag = qla24xx_chip_diag, 241462306a36Sopenharmony_ci .config_rings = qla24xx_config_rings, 241562306a36Sopenharmony_ci .reset_adapter = qla24xx_reset_adapter, 241662306a36Sopenharmony_ci .nvram_config = qla81xx_nvram_config, 241762306a36Sopenharmony_ci .update_fw_options = qla24xx_update_fw_options, 241862306a36Sopenharmony_ci .load_risc = qla81xx_load_risc, 241962306a36Sopenharmony_ci .pci_info_str = qla24xx_pci_info_str, 242062306a36Sopenharmony_ci .fw_version_str = qla24xx_fw_version_str, 242162306a36Sopenharmony_ci .intr_handler = qla24xx_intr_handler, 242262306a36Sopenharmony_ci .enable_intrs = qla24xx_enable_intrs, 242362306a36Sopenharmony_ci .disable_intrs = qla24xx_disable_intrs, 242462306a36Sopenharmony_ci .abort_command = qla24xx_abort_command, 242562306a36Sopenharmony_ci .target_reset = qla24xx_abort_target, 242662306a36Sopenharmony_ci .lun_reset = qla24xx_lun_reset, 242762306a36Sopenharmony_ci .fabric_login = qla24xx_login_fabric, 242862306a36Sopenharmony_ci .fabric_logout = qla24xx_fabric_logout, 242962306a36Sopenharmony_ci .calc_req_entries = NULL, 243062306a36Sopenharmony_ci .build_iocbs = NULL, 243162306a36Sopenharmony_ci .prep_ms_iocb = qla24xx_prep_ms_iocb, 243262306a36Sopenharmony_ci .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, 243362306a36Sopenharmony_ci .read_nvram = NULL, 243462306a36Sopenharmony_ci .write_nvram = NULL, 243562306a36Sopenharmony_ci .fw_dump = qla81xx_fw_dump, 243662306a36Sopenharmony_ci .beacon_on = qla24xx_beacon_on, 243762306a36Sopenharmony_ci .beacon_off = qla24xx_beacon_off, 243862306a36Sopenharmony_ci .beacon_blink = qla83xx_beacon_blink, 243962306a36Sopenharmony_ci .read_optrom = qla25xx_read_optrom_data, 244062306a36Sopenharmony_ci .write_optrom = qla24xx_write_optrom_data, 244162306a36Sopenharmony_ci .get_flash_version = qla24xx_get_flash_version, 244262306a36Sopenharmony_ci .start_scsi = qla24xx_dif_start_scsi, 244362306a36Sopenharmony_ci .start_scsi_mq = qla2xxx_dif_start_scsi_mq, 244462306a36Sopenharmony_ci .abort_isp = qla2x00_abort_isp, 244562306a36Sopenharmony_ci .iospace_config = qla2x00_iospace_config, 244662306a36Sopenharmony_ci .initialize_adapter = qla2x00_initialize_adapter, 244762306a36Sopenharmony_ci}; 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_cistatic struct isp_operations qla82xx_isp_ops = { 245062306a36Sopenharmony_ci .pci_config = qla82xx_pci_config, 245162306a36Sopenharmony_ci .reset_chip = qla82xx_reset_chip, 245262306a36Sopenharmony_ci .chip_diag = qla24xx_chip_diag, 245362306a36Sopenharmony_ci .config_rings = qla82xx_config_rings, 245462306a36Sopenharmony_ci .reset_adapter = qla24xx_reset_adapter, 245562306a36Sopenharmony_ci .nvram_config = qla81xx_nvram_config, 245662306a36Sopenharmony_ci .update_fw_options = qla24xx_update_fw_options, 245762306a36Sopenharmony_ci .load_risc = qla82xx_load_risc, 245862306a36Sopenharmony_ci .pci_info_str = qla24xx_pci_info_str, 245962306a36Sopenharmony_ci .fw_version_str = qla24xx_fw_version_str, 246062306a36Sopenharmony_ci .intr_handler = qla82xx_intr_handler, 246162306a36Sopenharmony_ci .enable_intrs = qla82xx_enable_intrs, 246262306a36Sopenharmony_ci .disable_intrs = qla82xx_disable_intrs, 246362306a36Sopenharmony_ci .abort_command = qla24xx_abort_command, 246462306a36Sopenharmony_ci .target_reset = qla24xx_abort_target, 246562306a36Sopenharmony_ci .lun_reset = qla24xx_lun_reset, 246662306a36Sopenharmony_ci .fabric_login = qla24xx_login_fabric, 246762306a36Sopenharmony_ci .fabric_logout = qla24xx_fabric_logout, 246862306a36Sopenharmony_ci .calc_req_entries = NULL, 246962306a36Sopenharmony_ci .build_iocbs = NULL, 247062306a36Sopenharmony_ci .prep_ms_iocb = qla24xx_prep_ms_iocb, 247162306a36Sopenharmony_ci .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, 247262306a36Sopenharmony_ci .read_nvram = qla24xx_read_nvram_data, 247362306a36Sopenharmony_ci .write_nvram = qla24xx_write_nvram_data, 247462306a36Sopenharmony_ci .fw_dump = qla82xx_fw_dump, 247562306a36Sopenharmony_ci .beacon_on = qla82xx_beacon_on, 247662306a36Sopenharmony_ci .beacon_off = qla82xx_beacon_off, 247762306a36Sopenharmony_ci .beacon_blink = NULL, 247862306a36Sopenharmony_ci .read_optrom = qla82xx_read_optrom_data, 247962306a36Sopenharmony_ci .write_optrom = qla82xx_write_optrom_data, 248062306a36Sopenharmony_ci .get_flash_version = qla82xx_get_flash_version, 248162306a36Sopenharmony_ci .start_scsi = qla82xx_start_scsi, 248262306a36Sopenharmony_ci .start_scsi_mq = NULL, 248362306a36Sopenharmony_ci .abort_isp = qla82xx_abort_isp, 248462306a36Sopenharmony_ci .iospace_config = qla82xx_iospace_config, 248562306a36Sopenharmony_ci .initialize_adapter = qla2x00_initialize_adapter, 248662306a36Sopenharmony_ci}; 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_cistatic struct isp_operations qla8044_isp_ops = { 248962306a36Sopenharmony_ci .pci_config = qla82xx_pci_config, 249062306a36Sopenharmony_ci .reset_chip = qla82xx_reset_chip, 249162306a36Sopenharmony_ci .chip_diag = qla24xx_chip_diag, 249262306a36Sopenharmony_ci .config_rings = qla82xx_config_rings, 249362306a36Sopenharmony_ci .reset_adapter = qla24xx_reset_adapter, 249462306a36Sopenharmony_ci .nvram_config = qla81xx_nvram_config, 249562306a36Sopenharmony_ci .update_fw_options = qla24xx_update_fw_options, 249662306a36Sopenharmony_ci .load_risc = qla82xx_load_risc, 249762306a36Sopenharmony_ci .pci_info_str = qla24xx_pci_info_str, 249862306a36Sopenharmony_ci .fw_version_str = qla24xx_fw_version_str, 249962306a36Sopenharmony_ci .intr_handler = qla8044_intr_handler, 250062306a36Sopenharmony_ci .enable_intrs = qla82xx_enable_intrs, 250162306a36Sopenharmony_ci .disable_intrs = qla82xx_disable_intrs, 250262306a36Sopenharmony_ci .abort_command = qla24xx_abort_command, 250362306a36Sopenharmony_ci .target_reset = qla24xx_abort_target, 250462306a36Sopenharmony_ci .lun_reset = qla24xx_lun_reset, 250562306a36Sopenharmony_ci .fabric_login = qla24xx_login_fabric, 250662306a36Sopenharmony_ci .fabric_logout = qla24xx_fabric_logout, 250762306a36Sopenharmony_ci .calc_req_entries = NULL, 250862306a36Sopenharmony_ci .build_iocbs = NULL, 250962306a36Sopenharmony_ci .prep_ms_iocb = qla24xx_prep_ms_iocb, 251062306a36Sopenharmony_ci .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, 251162306a36Sopenharmony_ci .read_nvram = NULL, 251262306a36Sopenharmony_ci .write_nvram = NULL, 251362306a36Sopenharmony_ci .fw_dump = qla8044_fw_dump, 251462306a36Sopenharmony_ci .beacon_on = qla82xx_beacon_on, 251562306a36Sopenharmony_ci .beacon_off = qla82xx_beacon_off, 251662306a36Sopenharmony_ci .beacon_blink = NULL, 251762306a36Sopenharmony_ci .read_optrom = qla8044_read_optrom_data, 251862306a36Sopenharmony_ci .write_optrom = qla8044_write_optrom_data, 251962306a36Sopenharmony_ci .get_flash_version = qla82xx_get_flash_version, 252062306a36Sopenharmony_ci .start_scsi = qla82xx_start_scsi, 252162306a36Sopenharmony_ci .start_scsi_mq = NULL, 252262306a36Sopenharmony_ci .abort_isp = qla8044_abort_isp, 252362306a36Sopenharmony_ci .iospace_config = qla82xx_iospace_config, 252462306a36Sopenharmony_ci .initialize_adapter = qla2x00_initialize_adapter, 252562306a36Sopenharmony_ci}; 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_cistatic struct isp_operations qla83xx_isp_ops = { 252862306a36Sopenharmony_ci .pci_config = qla25xx_pci_config, 252962306a36Sopenharmony_ci .reset_chip = qla24xx_reset_chip, 253062306a36Sopenharmony_ci .chip_diag = qla24xx_chip_diag, 253162306a36Sopenharmony_ci .config_rings = qla24xx_config_rings, 253262306a36Sopenharmony_ci .reset_adapter = qla24xx_reset_adapter, 253362306a36Sopenharmony_ci .nvram_config = qla81xx_nvram_config, 253462306a36Sopenharmony_ci .update_fw_options = qla24xx_update_fw_options, 253562306a36Sopenharmony_ci .load_risc = qla81xx_load_risc, 253662306a36Sopenharmony_ci .pci_info_str = qla24xx_pci_info_str, 253762306a36Sopenharmony_ci .fw_version_str = qla24xx_fw_version_str, 253862306a36Sopenharmony_ci .intr_handler = qla24xx_intr_handler, 253962306a36Sopenharmony_ci .enable_intrs = qla24xx_enable_intrs, 254062306a36Sopenharmony_ci .disable_intrs = qla24xx_disable_intrs, 254162306a36Sopenharmony_ci .abort_command = qla24xx_abort_command, 254262306a36Sopenharmony_ci .target_reset = qla24xx_abort_target, 254362306a36Sopenharmony_ci .lun_reset = qla24xx_lun_reset, 254462306a36Sopenharmony_ci .fabric_login = qla24xx_login_fabric, 254562306a36Sopenharmony_ci .fabric_logout = qla24xx_fabric_logout, 254662306a36Sopenharmony_ci .calc_req_entries = NULL, 254762306a36Sopenharmony_ci .build_iocbs = NULL, 254862306a36Sopenharmony_ci .prep_ms_iocb = qla24xx_prep_ms_iocb, 254962306a36Sopenharmony_ci .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, 255062306a36Sopenharmony_ci .read_nvram = NULL, 255162306a36Sopenharmony_ci .write_nvram = NULL, 255262306a36Sopenharmony_ci .fw_dump = qla83xx_fw_dump, 255362306a36Sopenharmony_ci .beacon_on = qla24xx_beacon_on, 255462306a36Sopenharmony_ci .beacon_off = qla24xx_beacon_off, 255562306a36Sopenharmony_ci .beacon_blink = qla83xx_beacon_blink, 255662306a36Sopenharmony_ci .read_optrom = qla25xx_read_optrom_data, 255762306a36Sopenharmony_ci .write_optrom = qla24xx_write_optrom_data, 255862306a36Sopenharmony_ci .get_flash_version = qla24xx_get_flash_version, 255962306a36Sopenharmony_ci .start_scsi = qla24xx_dif_start_scsi, 256062306a36Sopenharmony_ci .start_scsi_mq = qla2xxx_dif_start_scsi_mq, 256162306a36Sopenharmony_ci .abort_isp = qla2x00_abort_isp, 256262306a36Sopenharmony_ci .iospace_config = qla83xx_iospace_config, 256362306a36Sopenharmony_ci .initialize_adapter = qla2x00_initialize_adapter, 256462306a36Sopenharmony_ci}; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_cistatic struct isp_operations qlafx00_isp_ops = { 256762306a36Sopenharmony_ci .pci_config = qlafx00_pci_config, 256862306a36Sopenharmony_ci .reset_chip = qlafx00_soft_reset, 256962306a36Sopenharmony_ci .chip_diag = qlafx00_chip_diag, 257062306a36Sopenharmony_ci .config_rings = qlafx00_config_rings, 257162306a36Sopenharmony_ci .reset_adapter = qlafx00_soft_reset, 257262306a36Sopenharmony_ci .nvram_config = NULL, 257362306a36Sopenharmony_ci .update_fw_options = NULL, 257462306a36Sopenharmony_ci .load_risc = NULL, 257562306a36Sopenharmony_ci .pci_info_str = qlafx00_pci_info_str, 257662306a36Sopenharmony_ci .fw_version_str = qlafx00_fw_version_str, 257762306a36Sopenharmony_ci .intr_handler = qlafx00_intr_handler, 257862306a36Sopenharmony_ci .enable_intrs = qlafx00_enable_intrs, 257962306a36Sopenharmony_ci .disable_intrs = qlafx00_disable_intrs, 258062306a36Sopenharmony_ci .abort_command = qla24xx_async_abort_command, 258162306a36Sopenharmony_ci .target_reset = qlafx00_abort_target, 258262306a36Sopenharmony_ci .lun_reset = qlafx00_lun_reset, 258362306a36Sopenharmony_ci .fabric_login = NULL, 258462306a36Sopenharmony_ci .fabric_logout = NULL, 258562306a36Sopenharmony_ci .calc_req_entries = NULL, 258662306a36Sopenharmony_ci .build_iocbs = NULL, 258762306a36Sopenharmony_ci .prep_ms_iocb = qla24xx_prep_ms_iocb, 258862306a36Sopenharmony_ci .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, 258962306a36Sopenharmony_ci .read_nvram = qla24xx_read_nvram_data, 259062306a36Sopenharmony_ci .write_nvram = qla24xx_write_nvram_data, 259162306a36Sopenharmony_ci .fw_dump = NULL, 259262306a36Sopenharmony_ci .beacon_on = qla24xx_beacon_on, 259362306a36Sopenharmony_ci .beacon_off = qla24xx_beacon_off, 259462306a36Sopenharmony_ci .beacon_blink = NULL, 259562306a36Sopenharmony_ci .read_optrom = qla24xx_read_optrom_data, 259662306a36Sopenharmony_ci .write_optrom = qla24xx_write_optrom_data, 259762306a36Sopenharmony_ci .get_flash_version = qla24xx_get_flash_version, 259862306a36Sopenharmony_ci .start_scsi = qlafx00_start_scsi, 259962306a36Sopenharmony_ci .start_scsi_mq = NULL, 260062306a36Sopenharmony_ci .abort_isp = qlafx00_abort_isp, 260162306a36Sopenharmony_ci .iospace_config = qlafx00_iospace_config, 260262306a36Sopenharmony_ci .initialize_adapter = qlafx00_initialize_adapter, 260362306a36Sopenharmony_ci}; 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_cistatic struct isp_operations qla27xx_isp_ops = { 260662306a36Sopenharmony_ci .pci_config = qla25xx_pci_config, 260762306a36Sopenharmony_ci .reset_chip = qla24xx_reset_chip, 260862306a36Sopenharmony_ci .chip_diag = qla24xx_chip_diag, 260962306a36Sopenharmony_ci .config_rings = qla24xx_config_rings, 261062306a36Sopenharmony_ci .reset_adapter = qla24xx_reset_adapter, 261162306a36Sopenharmony_ci .nvram_config = qla81xx_nvram_config, 261262306a36Sopenharmony_ci .update_fw_options = qla24xx_update_fw_options, 261362306a36Sopenharmony_ci .load_risc = qla81xx_load_risc, 261462306a36Sopenharmony_ci .pci_info_str = qla24xx_pci_info_str, 261562306a36Sopenharmony_ci .fw_version_str = qla24xx_fw_version_str, 261662306a36Sopenharmony_ci .intr_handler = qla24xx_intr_handler, 261762306a36Sopenharmony_ci .enable_intrs = qla24xx_enable_intrs, 261862306a36Sopenharmony_ci .disable_intrs = qla24xx_disable_intrs, 261962306a36Sopenharmony_ci .abort_command = qla24xx_abort_command, 262062306a36Sopenharmony_ci .target_reset = qla24xx_abort_target, 262162306a36Sopenharmony_ci .lun_reset = qla24xx_lun_reset, 262262306a36Sopenharmony_ci .fabric_login = qla24xx_login_fabric, 262362306a36Sopenharmony_ci .fabric_logout = qla24xx_fabric_logout, 262462306a36Sopenharmony_ci .calc_req_entries = NULL, 262562306a36Sopenharmony_ci .build_iocbs = NULL, 262662306a36Sopenharmony_ci .prep_ms_iocb = qla24xx_prep_ms_iocb, 262762306a36Sopenharmony_ci .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, 262862306a36Sopenharmony_ci .read_nvram = NULL, 262962306a36Sopenharmony_ci .write_nvram = NULL, 263062306a36Sopenharmony_ci .fw_dump = qla27xx_fwdump, 263162306a36Sopenharmony_ci .mpi_fw_dump = qla27xx_mpi_fwdump, 263262306a36Sopenharmony_ci .beacon_on = qla24xx_beacon_on, 263362306a36Sopenharmony_ci .beacon_off = qla24xx_beacon_off, 263462306a36Sopenharmony_ci .beacon_blink = qla83xx_beacon_blink, 263562306a36Sopenharmony_ci .read_optrom = qla25xx_read_optrom_data, 263662306a36Sopenharmony_ci .write_optrom = qla24xx_write_optrom_data, 263762306a36Sopenharmony_ci .get_flash_version = qla24xx_get_flash_version, 263862306a36Sopenharmony_ci .start_scsi = qla24xx_dif_start_scsi, 263962306a36Sopenharmony_ci .start_scsi_mq = qla2xxx_dif_start_scsi_mq, 264062306a36Sopenharmony_ci .abort_isp = qla2x00_abort_isp, 264162306a36Sopenharmony_ci .iospace_config = qla83xx_iospace_config, 264262306a36Sopenharmony_ci .initialize_adapter = qla2x00_initialize_adapter, 264362306a36Sopenharmony_ci}; 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_cistatic inline void 264662306a36Sopenharmony_ciqla2x00_set_isp_flags(struct qla_hw_data *ha) 264762306a36Sopenharmony_ci{ 264862306a36Sopenharmony_ci ha->device_type = DT_EXTENDED_IDS; 264962306a36Sopenharmony_ci switch (ha->pdev->device) { 265062306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2100: 265162306a36Sopenharmony_ci ha->isp_type |= DT_ISP2100; 265262306a36Sopenharmony_ci ha->device_type &= ~DT_EXTENDED_IDS; 265362306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2100; 265462306a36Sopenharmony_ci break; 265562306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2200: 265662306a36Sopenharmony_ci ha->isp_type |= DT_ISP2200; 265762306a36Sopenharmony_ci ha->device_type &= ~DT_EXTENDED_IDS; 265862306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2100; 265962306a36Sopenharmony_ci break; 266062306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2300: 266162306a36Sopenharmony_ci ha->isp_type |= DT_ISP2300; 266262306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 266362306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2300; 266462306a36Sopenharmony_ci break; 266562306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2312: 266662306a36Sopenharmony_ci ha->isp_type |= DT_ISP2312; 266762306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 266862306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2300; 266962306a36Sopenharmony_ci break; 267062306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2322: 267162306a36Sopenharmony_ci ha->isp_type |= DT_ISP2322; 267262306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 267362306a36Sopenharmony_ci if (ha->pdev->subsystem_vendor == 0x1028 && 267462306a36Sopenharmony_ci ha->pdev->subsystem_device == 0x0170) 267562306a36Sopenharmony_ci ha->device_type |= DT_OEM_001; 267662306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2300; 267762306a36Sopenharmony_ci break; 267862306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP6312: 267962306a36Sopenharmony_ci ha->isp_type |= DT_ISP6312; 268062306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2300; 268162306a36Sopenharmony_ci break; 268262306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP6322: 268362306a36Sopenharmony_ci ha->isp_type |= DT_ISP6322; 268462306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2300; 268562306a36Sopenharmony_ci break; 268662306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2422: 268762306a36Sopenharmony_ci ha->isp_type |= DT_ISP2422; 268862306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 268962306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 269062306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 269162306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 269262306a36Sopenharmony_ci break; 269362306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2432: 269462306a36Sopenharmony_ci ha->isp_type |= DT_ISP2432; 269562306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 269662306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 269762306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 269862306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 269962306a36Sopenharmony_ci break; 270062306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP8432: 270162306a36Sopenharmony_ci ha->isp_type |= DT_ISP8432; 270262306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 270362306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 270462306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 270562306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 270662306a36Sopenharmony_ci break; 270762306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP5422: 270862306a36Sopenharmony_ci ha->isp_type |= DT_ISP5422; 270962306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 271062306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 271162306a36Sopenharmony_ci break; 271262306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP5432: 271362306a36Sopenharmony_ci ha->isp_type |= DT_ISP5432; 271462306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 271562306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 271662306a36Sopenharmony_ci break; 271762306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2532: 271862306a36Sopenharmony_ci ha->isp_type |= DT_ISP2532; 271962306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 272062306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 272162306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 272262306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 272362306a36Sopenharmony_ci break; 272462306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP8001: 272562306a36Sopenharmony_ci ha->isp_type |= DT_ISP8001; 272662306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 272762306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 272862306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 272962306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 273062306a36Sopenharmony_ci break; 273162306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP8021: 273262306a36Sopenharmony_ci ha->isp_type |= DT_ISP8021; 273362306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 273462306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 273562306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 273662306a36Sopenharmony_ci /* Initialize 82XX ISP flags */ 273762306a36Sopenharmony_ci qla82xx_init_flags(ha); 273862306a36Sopenharmony_ci break; 273962306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP8044: 274062306a36Sopenharmony_ci ha->isp_type |= DT_ISP8044; 274162306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 274262306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 274362306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 274462306a36Sopenharmony_ci /* Initialize 82XX ISP flags */ 274562306a36Sopenharmony_ci qla82xx_init_flags(ha); 274662306a36Sopenharmony_ci break; 274762306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2031: 274862306a36Sopenharmony_ci ha->isp_type |= DT_ISP2031; 274962306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 275062306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 275162306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 275262306a36Sopenharmony_ci ha->device_type |= DT_T10_PI; 275362306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 275462306a36Sopenharmony_ci break; 275562306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP8031: 275662306a36Sopenharmony_ci ha->isp_type |= DT_ISP8031; 275762306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 275862306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 275962306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 276062306a36Sopenharmony_ci ha->device_type |= DT_T10_PI; 276162306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 276262306a36Sopenharmony_ci break; 276362306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISPF001: 276462306a36Sopenharmony_ci ha->isp_type |= DT_ISPFX00; 276562306a36Sopenharmony_ci break; 276662306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2071: 276762306a36Sopenharmony_ci ha->isp_type |= DT_ISP2071; 276862306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 276962306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 277062306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 277162306a36Sopenharmony_ci ha->device_type |= DT_T10_PI; 277262306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 277362306a36Sopenharmony_ci break; 277462306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2271: 277562306a36Sopenharmony_ci ha->isp_type |= DT_ISP2271; 277662306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 277762306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 277862306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 277962306a36Sopenharmony_ci ha->device_type |= DT_T10_PI; 278062306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 278162306a36Sopenharmony_ci break; 278262306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2261: 278362306a36Sopenharmony_ci ha->isp_type |= DT_ISP2261; 278462306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 278562306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 278662306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 278762306a36Sopenharmony_ci ha->device_type |= DT_T10_PI; 278862306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 278962306a36Sopenharmony_ci break; 279062306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2081: 279162306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2089: 279262306a36Sopenharmony_ci ha->isp_type |= DT_ISP2081; 279362306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 279462306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 279562306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 279662306a36Sopenharmony_ci ha->device_type |= DT_T10_PI; 279762306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 279862306a36Sopenharmony_ci break; 279962306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2281: 280062306a36Sopenharmony_ci case PCI_DEVICE_ID_QLOGIC_ISP2289: 280162306a36Sopenharmony_ci ha->isp_type |= DT_ISP2281; 280262306a36Sopenharmony_ci ha->device_type |= DT_ZIO_SUPPORTED; 280362306a36Sopenharmony_ci ha->device_type |= DT_FWI2; 280462306a36Sopenharmony_ci ha->device_type |= DT_IIDMA; 280562306a36Sopenharmony_ci ha->device_type |= DT_T10_PI; 280662306a36Sopenharmony_ci ha->fw_srisc_address = RISC_START_ADDRESS_2400; 280762306a36Sopenharmony_ci break; 280862306a36Sopenharmony_ci } 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_ci if (IS_QLA82XX(ha)) 281162306a36Sopenharmony_ci ha->port_no = ha->portnum & 1; 281262306a36Sopenharmony_ci else { 281362306a36Sopenharmony_ci /* Get adapter physical port no from interrupt pin register. */ 281462306a36Sopenharmony_ci pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no); 281562306a36Sopenharmony_ci if (IS_QLA25XX(ha) || IS_QLA2031(ha) || 281662306a36Sopenharmony_ci IS_QLA27XX(ha) || IS_QLA28XX(ha)) 281762306a36Sopenharmony_ci ha->port_no--; 281862306a36Sopenharmony_ci else 281962306a36Sopenharmony_ci ha->port_no = !(ha->port_no & 1); 282062306a36Sopenharmony_ci } 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x000b, 282362306a36Sopenharmony_ci "device_type=0x%x port=%d fw_srisc_address=0x%x.\n", 282462306a36Sopenharmony_ci ha->device_type, ha->port_no, ha->fw_srisc_address); 282562306a36Sopenharmony_ci} 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_cistatic void 282862306a36Sopenharmony_ciqla2xxx_scan_start(struct Scsi_Host *shost) 282962306a36Sopenharmony_ci{ 283062306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(shost); 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci if (vha->hw->flags.running_gold_fw) 283362306a36Sopenharmony_ci return; 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 283662306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 283762306a36Sopenharmony_ci set_bit(RSCN_UPDATE, &vha->dpc_flags); 283862306a36Sopenharmony_ci set_bit(NPIV_CONFIG_NEEDED, &vha->dpc_flags); 283962306a36Sopenharmony_ci} 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_cistatic int 284262306a36Sopenharmony_ciqla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time) 284362306a36Sopenharmony_ci{ 284462306a36Sopenharmony_ci scsi_qla_host_t *vha = shost_priv(shost); 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci if (test_bit(UNLOADING, &vha->dpc_flags)) 284762306a36Sopenharmony_ci return 1; 284862306a36Sopenharmony_ci if (!vha->host) 284962306a36Sopenharmony_ci return 1; 285062306a36Sopenharmony_ci if (time > vha->hw->loop_reset_delay * HZ) 285162306a36Sopenharmony_ci return 1; 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci return atomic_read(&vha->loop_state) == LOOP_READY; 285462306a36Sopenharmony_ci} 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_cistatic void qla_heartbeat_work_fn(struct work_struct *work) 285762306a36Sopenharmony_ci{ 285862306a36Sopenharmony_ci struct qla_hw_data *ha = container_of(work, 285962306a36Sopenharmony_ci struct qla_hw_data, heartbeat_work); 286062306a36Sopenharmony_ci struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_ci if (!ha->flags.mbox_busy && base_vha->flags.init_done) 286362306a36Sopenharmony_ci qla_no_op_mb(base_vha); 286462306a36Sopenharmony_ci} 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_cistatic void qla2x00_iocb_work_fn(struct work_struct *work) 286762306a36Sopenharmony_ci{ 286862306a36Sopenharmony_ci struct scsi_qla_host *vha = container_of(work, 286962306a36Sopenharmony_ci struct scsi_qla_host, iocb_work); 287062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 287162306a36Sopenharmony_ci struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); 287262306a36Sopenharmony_ci int i = 2; 287362306a36Sopenharmony_ci unsigned long flags; 287462306a36Sopenharmony_ci 287562306a36Sopenharmony_ci if (test_bit(UNLOADING, &base_vha->dpc_flags)) 287662306a36Sopenharmony_ci return; 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci while (!list_empty(&vha->work_list) && i > 0) { 287962306a36Sopenharmony_ci qla2x00_do_work(vha); 288062306a36Sopenharmony_ci i--; 288162306a36Sopenharmony_ci } 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 288462306a36Sopenharmony_ci clear_bit(IOCB_WORK_ACTIVE, &vha->dpc_flags); 288562306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 288662306a36Sopenharmony_ci} 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_cistatic void 288962306a36Sopenharmony_ciqla_trace_init(void) 289062306a36Sopenharmony_ci{ 289162306a36Sopenharmony_ci qla_trc_array = trace_array_get_by_name("qla2xxx"); 289262306a36Sopenharmony_ci if (!qla_trc_array) { 289362306a36Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0x0001, 289462306a36Sopenharmony_ci "Unable to create qla2xxx trace instance, instance logging will be disabled.\n"); 289562306a36Sopenharmony_ci return; 289662306a36Sopenharmony_ci } 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci QLA_TRACE_ENABLE(qla_trc_array); 289962306a36Sopenharmony_ci} 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_cistatic void 290262306a36Sopenharmony_ciqla_trace_uninit(void) 290362306a36Sopenharmony_ci{ 290462306a36Sopenharmony_ci if (!qla_trc_array) 290562306a36Sopenharmony_ci return; 290662306a36Sopenharmony_ci trace_array_put(qla_trc_array); 290762306a36Sopenharmony_ci} 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_ci/* 291062306a36Sopenharmony_ci * PCI driver interface 291162306a36Sopenharmony_ci */ 291262306a36Sopenharmony_cistatic int 291362306a36Sopenharmony_ciqla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) 291462306a36Sopenharmony_ci{ 291562306a36Sopenharmony_ci int ret = -ENODEV; 291662306a36Sopenharmony_ci struct Scsi_Host *host; 291762306a36Sopenharmony_ci scsi_qla_host_t *base_vha = NULL; 291862306a36Sopenharmony_ci struct qla_hw_data *ha; 291962306a36Sopenharmony_ci char pci_info[30]; 292062306a36Sopenharmony_ci char fw_str[30], wq_name[30]; 292162306a36Sopenharmony_ci struct scsi_host_template *sht; 292262306a36Sopenharmony_ci int bars, mem_only = 0; 292362306a36Sopenharmony_ci uint16_t req_length = 0, rsp_length = 0; 292462306a36Sopenharmony_ci struct req_que *req = NULL; 292562306a36Sopenharmony_ci struct rsp_que *rsp = NULL; 292662306a36Sopenharmony_ci int i; 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); 292962306a36Sopenharmony_ci sht = &qla2xxx_driver_template; 293062306a36Sopenharmony_ci if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || 293162306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 || 293262306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 || 293362306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 || 293462306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 || 293562306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532 || 293662306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001 || 293762306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021 || 293862306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2031 || 293962306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8031 || 294062306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISPF001 || 294162306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8044 || 294262306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2071 || 294362306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2271 || 294462306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2261 || 294562306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2081 || 294662306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2281 || 294762306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2089 || 294862306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2289) { 294962306a36Sopenharmony_ci bars = pci_select_bars(pdev, IORESOURCE_MEM); 295062306a36Sopenharmony_ci mem_only = 1; 295162306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, pdev, 0x0007, 295262306a36Sopenharmony_ci "Mem only adapter.\n"); 295362306a36Sopenharmony_ci } 295462306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, pdev, 0x0008, 295562306a36Sopenharmony_ci "Bars=%d.\n", bars); 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci if (mem_only) { 295862306a36Sopenharmony_ci if (pci_enable_device_mem(pdev)) 295962306a36Sopenharmony_ci return ret; 296062306a36Sopenharmony_ci } else { 296162306a36Sopenharmony_ci if (pci_enable_device(pdev)) 296262306a36Sopenharmony_ci return ret; 296362306a36Sopenharmony_ci } 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci if (is_kdump_kernel()) { 296662306a36Sopenharmony_ci ql2xmqsupport = 0; 296762306a36Sopenharmony_ci ql2xallocfwdump = 0; 296862306a36Sopenharmony_ci } 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL); 297162306a36Sopenharmony_ci if (!ha) { 297262306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, pdev, 0x0009, 297362306a36Sopenharmony_ci "Unable to allocate memory for ha.\n"); 297462306a36Sopenharmony_ci goto disable_device; 297562306a36Sopenharmony_ci } 297662306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, pdev, 0x000a, 297762306a36Sopenharmony_ci "Memory allocated for ha=%p.\n", ha); 297862306a36Sopenharmony_ci ha->pdev = pdev; 297962306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->tgt.q_full_list); 298062306a36Sopenharmony_ci spin_lock_init(&ha->tgt.q_full_lock); 298162306a36Sopenharmony_ci spin_lock_init(&ha->tgt.sess_lock); 298262306a36Sopenharmony_ci spin_lock_init(&ha->tgt.atio_lock); 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci spin_lock_init(&ha->sadb_lock); 298562306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->sadb_tx_index_list); 298662306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->sadb_rx_index_list); 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci spin_lock_init(&ha->sadb_fp_lock); 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci if (qla_edif_sadb_build_free_pool(ha)) { 299162306a36Sopenharmony_ci kfree(ha); 299262306a36Sopenharmony_ci goto disable_device; 299362306a36Sopenharmony_ci } 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci atomic_set(&ha->nvme_active_aen_cnt, 0); 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci /* Clear our data area */ 299862306a36Sopenharmony_ci ha->bars = bars; 299962306a36Sopenharmony_ci ha->mem_only = mem_only; 300062306a36Sopenharmony_ci spin_lock_init(&ha->hardware_lock); 300162306a36Sopenharmony_ci spin_lock_init(&ha->vport_slock); 300262306a36Sopenharmony_ci mutex_init(&ha->selflogin_lock); 300362306a36Sopenharmony_ci mutex_init(&ha->optrom_mutex); 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci /* Set ISP-type information. */ 300662306a36Sopenharmony_ci qla2x00_set_isp_flags(ha); 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci /* Set EEH reset type to fundamental if required by hba */ 300962306a36Sopenharmony_ci if (IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha) || 301062306a36Sopenharmony_ci IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) 301162306a36Sopenharmony_ci pdev->needs_freset = 1; 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci ha->prev_topology = 0; 301462306a36Sopenharmony_ci ha->init_cb_size = sizeof(init_cb_t); 301562306a36Sopenharmony_ci ha->link_data_rate = PORT_SPEED_UNKNOWN; 301662306a36Sopenharmony_ci ha->optrom_size = OPTROM_SIZE_2300; 301762306a36Sopenharmony_ci ha->max_exchg = FW_MAX_EXCHANGES_CNT; 301862306a36Sopenharmony_ci atomic_set(&ha->num_pend_mbx_stage1, 0); 301962306a36Sopenharmony_ci atomic_set(&ha->num_pend_mbx_stage2, 0); 302062306a36Sopenharmony_ci atomic_set(&ha->zio_threshold, DEFAULT_ZIO_THRESHOLD); 302162306a36Sopenharmony_ci ha->last_zio_threshold = DEFAULT_ZIO_THRESHOLD; 302262306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->tmf_pending); 302362306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->tmf_active); 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_ci /* Assign ISP specific operations. */ 302662306a36Sopenharmony_ci if (IS_QLA2100(ha)) { 302762306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_2100; 302862306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT_2100; 302962306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_2100; 303062306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_2100; 303162306a36Sopenharmony_ci ha->max_loop_id = SNS_LAST_LOOP_ID_2100; 303262306a36Sopenharmony_ci ha->gid_list_info_size = 4; 303362306a36Sopenharmony_ci ha->flash_conf_off = ~0; 303462306a36Sopenharmony_ci ha->flash_data_off = ~0; 303562306a36Sopenharmony_ci ha->nvram_conf_off = ~0; 303662306a36Sopenharmony_ci ha->nvram_data_off = ~0; 303762306a36Sopenharmony_ci ha->isp_ops = &qla2100_isp_ops; 303862306a36Sopenharmony_ci } else if (IS_QLA2200(ha)) { 303962306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_2100; 304062306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT_2200; 304162306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_2200; 304262306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_2100; 304362306a36Sopenharmony_ci ha->max_loop_id = SNS_LAST_LOOP_ID_2100; 304462306a36Sopenharmony_ci ha->gid_list_info_size = 4; 304562306a36Sopenharmony_ci ha->flash_conf_off = ~0; 304662306a36Sopenharmony_ci ha->flash_data_off = ~0; 304762306a36Sopenharmony_ci ha->nvram_conf_off = ~0; 304862306a36Sopenharmony_ci ha->nvram_data_off = ~0; 304962306a36Sopenharmony_ci ha->isp_ops = &qla2100_isp_ops; 305062306a36Sopenharmony_ci } else if (IS_QLA23XX(ha)) { 305162306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_2100; 305262306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT; 305362306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_2200; 305462306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_2300; 305562306a36Sopenharmony_ci ha->max_loop_id = SNS_LAST_LOOP_ID_2300; 305662306a36Sopenharmony_ci ha->gid_list_info_size = 6; 305762306a36Sopenharmony_ci if (IS_QLA2322(ha) || IS_QLA6322(ha)) 305862306a36Sopenharmony_ci ha->optrom_size = OPTROM_SIZE_2322; 305962306a36Sopenharmony_ci ha->flash_conf_off = ~0; 306062306a36Sopenharmony_ci ha->flash_data_off = ~0; 306162306a36Sopenharmony_ci ha->nvram_conf_off = ~0; 306262306a36Sopenharmony_ci ha->nvram_data_off = ~0; 306362306a36Sopenharmony_ci ha->isp_ops = &qla2300_isp_ops; 306462306a36Sopenharmony_ci } else if (IS_QLA24XX_TYPE(ha)) { 306562306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; 306662306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT; 306762306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_24XX; 306862306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_2300; 306962306a36Sopenharmony_ci ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; 307062306a36Sopenharmony_ci ha->max_loop_id = SNS_LAST_LOOP_ID_2300; 307162306a36Sopenharmony_ci ha->init_cb_size = sizeof(struct mid_init_cb_24xx); 307262306a36Sopenharmony_ci ha->gid_list_info_size = 8; 307362306a36Sopenharmony_ci ha->optrom_size = OPTROM_SIZE_24XX; 307462306a36Sopenharmony_ci ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA24XX; 307562306a36Sopenharmony_ci ha->isp_ops = &qla24xx_isp_ops; 307662306a36Sopenharmony_ci ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; 307762306a36Sopenharmony_ci ha->flash_data_off = FARX_ACCESS_FLASH_DATA; 307862306a36Sopenharmony_ci ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; 307962306a36Sopenharmony_ci ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA; 308062306a36Sopenharmony_ci } else if (IS_QLA25XX(ha)) { 308162306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; 308262306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT; 308362306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_24XX; 308462306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_2300; 308562306a36Sopenharmony_ci ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; 308662306a36Sopenharmony_ci ha->max_loop_id = SNS_LAST_LOOP_ID_2300; 308762306a36Sopenharmony_ci ha->init_cb_size = sizeof(struct mid_init_cb_24xx); 308862306a36Sopenharmony_ci ha->gid_list_info_size = 8; 308962306a36Sopenharmony_ci ha->optrom_size = OPTROM_SIZE_25XX; 309062306a36Sopenharmony_ci ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; 309162306a36Sopenharmony_ci ha->isp_ops = &qla25xx_isp_ops; 309262306a36Sopenharmony_ci ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; 309362306a36Sopenharmony_ci ha->flash_data_off = FARX_ACCESS_FLASH_DATA; 309462306a36Sopenharmony_ci ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; 309562306a36Sopenharmony_ci ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA; 309662306a36Sopenharmony_ci } else if (IS_QLA81XX(ha)) { 309762306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; 309862306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT; 309962306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_24XX; 310062306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_2300; 310162306a36Sopenharmony_ci ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; 310262306a36Sopenharmony_ci ha->max_loop_id = SNS_LAST_LOOP_ID_2300; 310362306a36Sopenharmony_ci ha->init_cb_size = sizeof(struct mid_init_cb_81xx); 310462306a36Sopenharmony_ci ha->gid_list_info_size = 8; 310562306a36Sopenharmony_ci ha->optrom_size = OPTROM_SIZE_81XX; 310662306a36Sopenharmony_ci ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; 310762306a36Sopenharmony_ci ha->isp_ops = &qla81xx_isp_ops; 310862306a36Sopenharmony_ci ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX; 310962306a36Sopenharmony_ci ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX; 311062306a36Sopenharmony_ci ha->nvram_conf_off = ~0; 311162306a36Sopenharmony_ci ha->nvram_data_off = ~0; 311262306a36Sopenharmony_ci } else if (IS_QLA82XX(ha)) { 311362306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; 311462306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT; 311562306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_82XX; 311662306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_82XX; 311762306a36Sopenharmony_ci ha->max_loop_id = SNS_LAST_LOOP_ID_2300; 311862306a36Sopenharmony_ci ha->init_cb_size = sizeof(struct mid_init_cb_81xx); 311962306a36Sopenharmony_ci ha->gid_list_info_size = 8; 312062306a36Sopenharmony_ci ha->optrom_size = OPTROM_SIZE_82XX; 312162306a36Sopenharmony_ci ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; 312262306a36Sopenharmony_ci ha->isp_ops = &qla82xx_isp_ops; 312362306a36Sopenharmony_ci ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; 312462306a36Sopenharmony_ci ha->flash_data_off = FARX_ACCESS_FLASH_DATA; 312562306a36Sopenharmony_ci ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; 312662306a36Sopenharmony_ci ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA; 312762306a36Sopenharmony_ci } else if (IS_QLA8044(ha)) { 312862306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; 312962306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT; 313062306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_82XX; 313162306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_82XX; 313262306a36Sopenharmony_ci ha->max_loop_id = SNS_LAST_LOOP_ID_2300; 313362306a36Sopenharmony_ci ha->init_cb_size = sizeof(struct mid_init_cb_81xx); 313462306a36Sopenharmony_ci ha->gid_list_info_size = 8; 313562306a36Sopenharmony_ci ha->optrom_size = OPTROM_SIZE_83XX; 313662306a36Sopenharmony_ci ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; 313762306a36Sopenharmony_ci ha->isp_ops = &qla8044_isp_ops; 313862306a36Sopenharmony_ci ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; 313962306a36Sopenharmony_ci ha->flash_data_off = FARX_ACCESS_FLASH_DATA; 314062306a36Sopenharmony_ci ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; 314162306a36Sopenharmony_ci ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA; 314262306a36Sopenharmony_ci } else if (IS_QLA83XX(ha)) { 314362306a36Sopenharmony_ci ha->portnum = PCI_FUNC(ha->pdev->devfn); 314462306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; 314562306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT; 314662306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_83XX; 314762306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_83XX; 314862306a36Sopenharmony_ci ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; 314962306a36Sopenharmony_ci ha->max_loop_id = SNS_LAST_LOOP_ID_2300; 315062306a36Sopenharmony_ci ha->init_cb_size = sizeof(struct mid_init_cb_81xx); 315162306a36Sopenharmony_ci ha->gid_list_info_size = 8; 315262306a36Sopenharmony_ci ha->optrom_size = OPTROM_SIZE_83XX; 315362306a36Sopenharmony_ci ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; 315462306a36Sopenharmony_ci ha->isp_ops = &qla83xx_isp_ops; 315562306a36Sopenharmony_ci ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX; 315662306a36Sopenharmony_ci ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX; 315762306a36Sopenharmony_ci ha->nvram_conf_off = ~0; 315862306a36Sopenharmony_ci ha->nvram_data_off = ~0; 315962306a36Sopenharmony_ci } else if (IS_QLAFX00(ha)) { 316062306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_FX00; 316162306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT_FX00; 316262306a36Sopenharmony_ci ha->aen_mbx_count = AEN_MAILBOX_REGISTER_COUNT_FX00; 316362306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_FX00; 316462306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_FX00; 316562306a36Sopenharmony_ci ha->isp_ops = &qlafx00_isp_ops; 316662306a36Sopenharmony_ci ha->port_down_retry_count = 30; /* default value */ 316762306a36Sopenharmony_ci ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL; 316862306a36Sopenharmony_ci ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL; 316962306a36Sopenharmony_ci ha->mr.fw_critemp_timer_tick = QLAFX00_CRITEMP_INTERVAL; 317062306a36Sopenharmony_ci ha->mr.fw_hbt_en = 1; 317162306a36Sopenharmony_ci ha->mr.host_info_resend = false; 317262306a36Sopenharmony_ci ha->mr.hinfo_resend_timer_tick = QLAFX00_HINFO_RESEND_INTERVAL; 317362306a36Sopenharmony_ci } else if (IS_QLA27XX(ha)) { 317462306a36Sopenharmony_ci ha->portnum = PCI_FUNC(ha->pdev->devfn); 317562306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; 317662306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT; 317762306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_83XX; 317862306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_83XX; 317962306a36Sopenharmony_ci ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; 318062306a36Sopenharmony_ci ha->max_loop_id = SNS_LAST_LOOP_ID_2300; 318162306a36Sopenharmony_ci ha->init_cb_size = sizeof(struct mid_init_cb_81xx); 318262306a36Sopenharmony_ci ha->gid_list_info_size = 8; 318362306a36Sopenharmony_ci ha->optrom_size = OPTROM_SIZE_83XX; 318462306a36Sopenharmony_ci ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; 318562306a36Sopenharmony_ci ha->isp_ops = &qla27xx_isp_ops; 318662306a36Sopenharmony_ci ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX; 318762306a36Sopenharmony_ci ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX; 318862306a36Sopenharmony_ci ha->nvram_conf_off = ~0; 318962306a36Sopenharmony_ci ha->nvram_data_off = ~0; 319062306a36Sopenharmony_ci } else if (IS_QLA28XX(ha)) { 319162306a36Sopenharmony_ci ha->portnum = PCI_FUNC(ha->pdev->devfn); 319262306a36Sopenharmony_ci ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; 319362306a36Sopenharmony_ci ha->mbx_count = MAILBOX_REGISTER_COUNT; 319462306a36Sopenharmony_ci req_length = REQUEST_ENTRY_CNT_83XX; 319562306a36Sopenharmony_ci rsp_length = RESPONSE_ENTRY_CNT_83XX; 319662306a36Sopenharmony_ci ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; 319762306a36Sopenharmony_ci ha->max_loop_id = SNS_LAST_LOOP_ID_2300; 319862306a36Sopenharmony_ci ha->init_cb_size = sizeof(struct mid_init_cb_81xx); 319962306a36Sopenharmony_ci ha->gid_list_info_size = 8; 320062306a36Sopenharmony_ci ha->optrom_size = OPTROM_SIZE_28XX; 320162306a36Sopenharmony_ci ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; 320262306a36Sopenharmony_ci ha->isp_ops = &qla27xx_isp_ops; 320362306a36Sopenharmony_ci ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_28XX; 320462306a36Sopenharmony_ci ha->flash_data_off = FARX_ACCESS_FLASH_DATA_28XX; 320562306a36Sopenharmony_ci ha->nvram_conf_off = ~0; 320662306a36Sopenharmony_ci ha->nvram_data_off = ~0; 320762306a36Sopenharmony_ci } 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, pdev, 0x001e, 321062306a36Sopenharmony_ci "mbx_count=%d, req_length=%d, " 321162306a36Sopenharmony_ci "rsp_length=%d, max_loop_id=%d, init_cb_size=%d, " 321262306a36Sopenharmony_ci "gid_list_info_size=%d, optrom_size=%d, nvram_npiv_size=%d, " 321362306a36Sopenharmony_ci "max_fibre_devices=%d.\n", 321462306a36Sopenharmony_ci ha->mbx_count, req_length, rsp_length, ha->max_loop_id, 321562306a36Sopenharmony_ci ha->init_cb_size, ha->gid_list_info_size, ha->optrom_size, 321662306a36Sopenharmony_ci ha->nvram_npiv_size, ha->max_fibre_devices); 321762306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, pdev, 0x001f, 321862306a36Sopenharmony_ci "isp_ops=%p, flash_conf_off=%d, " 321962306a36Sopenharmony_ci "flash_data_off=%d, nvram_conf_off=%d, nvram_data_off=%d.\n", 322062306a36Sopenharmony_ci ha->isp_ops, ha->flash_conf_off, ha->flash_data_off, 322162306a36Sopenharmony_ci ha->nvram_conf_off, ha->nvram_data_off); 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci /* Configure PCI I/O space */ 322462306a36Sopenharmony_ci ret = ha->isp_ops->iospace_config(ha); 322562306a36Sopenharmony_ci if (ret) 322662306a36Sopenharmony_ci goto iospace_config_failed; 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci ql_log_pci(ql_log_info, pdev, 0x001d, 322962306a36Sopenharmony_ci "Found an ISP%04X irq %d iobase 0x%p.\n", 323062306a36Sopenharmony_ci pdev->device, pdev->irq, ha->iobase); 323162306a36Sopenharmony_ci mutex_init(&ha->vport_lock); 323262306a36Sopenharmony_ci mutex_init(&ha->mq_lock); 323362306a36Sopenharmony_ci init_completion(&ha->mbx_cmd_comp); 323462306a36Sopenharmony_ci complete(&ha->mbx_cmd_comp); 323562306a36Sopenharmony_ci init_completion(&ha->mbx_intr_comp); 323662306a36Sopenharmony_ci init_completion(&ha->dcbx_comp); 323762306a36Sopenharmony_ci init_completion(&ha->lb_portup_comp); 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci set_bit(0, (unsigned long *) ha->vp_idx_map); 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci qla2x00_config_dma_addressing(ha); 324262306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, pdev, 0x0020, 324362306a36Sopenharmony_ci "64 Bit addressing is %s.\n", 324462306a36Sopenharmony_ci ha->flags.enable_64bit_addressing ? "enable" : 324562306a36Sopenharmony_ci "disable"); 324662306a36Sopenharmony_ci ret = qla2x00_mem_alloc(ha, req_length, rsp_length, &req, &rsp); 324762306a36Sopenharmony_ci if (ret) { 324862306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, pdev, 0x0031, 324962306a36Sopenharmony_ci "Failed to allocate memory for adapter, aborting.\n"); 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci goto probe_hw_failed; 325262306a36Sopenharmony_ci } 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci req->max_q_depth = MAX_Q_DEPTH; 325562306a36Sopenharmony_ci if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU) 325662306a36Sopenharmony_ci req->max_q_depth = ql2xmaxqdepth; 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_ci base_vha = qla2x00_create_host(sht, ha); 326062306a36Sopenharmony_ci if (!base_vha) { 326162306a36Sopenharmony_ci ret = -ENOMEM; 326262306a36Sopenharmony_ci goto probe_hw_failed; 326362306a36Sopenharmony_ci } 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci pci_set_drvdata(pdev, base_vha); 326662306a36Sopenharmony_ci set_bit(PFLG_DRIVER_PROBING, &base_vha->pci_flags); 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci host = base_vha->host; 326962306a36Sopenharmony_ci base_vha->req = req; 327062306a36Sopenharmony_ci if (IS_QLA2XXX_MIDTYPE(ha)) 327162306a36Sopenharmony_ci base_vha->mgmt_svr_loop_id = 327262306a36Sopenharmony_ci qla2x00_reserve_mgmt_server_loop_id(base_vha); 327362306a36Sopenharmony_ci else 327462306a36Sopenharmony_ci base_vha->mgmt_svr_loop_id = MANAGEMENT_SERVER + 327562306a36Sopenharmony_ci base_vha->vp_idx; 327662306a36Sopenharmony_ci 327762306a36Sopenharmony_ci /* Setup fcport template structure. */ 327862306a36Sopenharmony_ci ha->mr.fcport.vha = base_vha; 327962306a36Sopenharmony_ci ha->mr.fcport.port_type = FCT_UNKNOWN; 328062306a36Sopenharmony_ci ha->mr.fcport.loop_id = FC_NO_LOOP_ID; 328162306a36Sopenharmony_ci qla2x00_set_fcport_state(&ha->mr.fcport, FCS_UNCONFIGURED); 328262306a36Sopenharmony_ci ha->mr.fcport.supported_classes = FC_COS_UNSPECIFIED; 328362306a36Sopenharmony_ci ha->mr.fcport.scan_state = 1; 328462306a36Sopenharmony_ci 328562306a36Sopenharmony_ci qla2xxx_reset_stats(host, QLA2XX_HW_ERROR | QLA2XX_SHT_LNK_DWN | 328662306a36Sopenharmony_ci QLA2XX_INT_ERR | QLA2XX_CMD_TIMEOUT | 328762306a36Sopenharmony_ci QLA2XX_RESET_CMD_ERR | QLA2XX_TGT_SHT_LNK_DOWN); 328862306a36Sopenharmony_ci 328962306a36Sopenharmony_ci /* Set the SG table size based on ISP type */ 329062306a36Sopenharmony_ci if (!IS_FWI2_CAPABLE(ha)) { 329162306a36Sopenharmony_ci if (IS_QLA2100(ha)) 329262306a36Sopenharmony_ci host->sg_tablesize = 32; 329362306a36Sopenharmony_ci } else { 329462306a36Sopenharmony_ci if (!IS_QLA82XX(ha)) 329562306a36Sopenharmony_ci host->sg_tablesize = QLA_SG_ALL; 329662306a36Sopenharmony_ci } 329762306a36Sopenharmony_ci host->max_id = ha->max_fibre_devices; 329862306a36Sopenharmony_ci host->cmd_per_lun = 3; 329962306a36Sopenharmony_ci host->unique_id = host->host_no; 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_ci if (ql2xenabledif && ql2xenabledif != 2) { 330262306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0x302d, 330362306a36Sopenharmony_ci "Invalid value for ql2xenabledif, resetting it to default (2)\n"); 330462306a36Sopenharmony_ci ql2xenabledif = 2; 330562306a36Sopenharmony_ci } 330662306a36Sopenharmony_ci 330762306a36Sopenharmony_ci if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) 330862306a36Sopenharmony_ci host->max_cmd_len = 32; 330962306a36Sopenharmony_ci else 331062306a36Sopenharmony_ci host->max_cmd_len = MAX_CMDSZ; 331162306a36Sopenharmony_ci host->max_channel = MAX_BUSES - 1; 331262306a36Sopenharmony_ci /* Older HBAs support only 16-bit LUNs */ 331362306a36Sopenharmony_ci if (!IS_QLAFX00(ha) && !IS_FWI2_CAPABLE(ha) && 331462306a36Sopenharmony_ci ql2xmaxlun > 0xffff) 331562306a36Sopenharmony_ci host->max_lun = 0xffff; 331662306a36Sopenharmony_ci else 331762306a36Sopenharmony_ci host->max_lun = ql2xmaxlun; 331862306a36Sopenharmony_ci host->transportt = qla2xxx_transport_template; 331962306a36Sopenharmony_ci sht->vendor_id = (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC); 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x0033, 332262306a36Sopenharmony_ci "max_id=%d this_id=%d " 332362306a36Sopenharmony_ci "cmd_per_len=%d unique_id=%d max_cmd_len=%d max_channel=%d " 332462306a36Sopenharmony_ci "max_lun=%llu transportt=%p, vendor_id=%llu.\n", host->max_id, 332562306a36Sopenharmony_ci host->this_id, host->cmd_per_lun, host->unique_id, 332662306a36Sopenharmony_ci host->max_cmd_len, host->max_channel, host->max_lun, 332762306a36Sopenharmony_ci host->transportt, sht->vendor_id); 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_ci INIT_WORK(&ha->heartbeat_work, qla_heartbeat_work_fn); 333062306a36Sopenharmony_ci 333162306a36Sopenharmony_ci /* Set up the irqs */ 333262306a36Sopenharmony_ci ret = qla2x00_request_irqs(ha, rsp); 333362306a36Sopenharmony_ci if (ret) 333462306a36Sopenharmony_ci goto probe_failed; 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_ci /* Alloc arrays of request and response ring ptrs */ 333762306a36Sopenharmony_ci ret = qla2x00_alloc_queues(ha, req, rsp); 333862306a36Sopenharmony_ci if (ret) { 333962306a36Sopenharmony_ci ql_log(ql_log_fatal, base_vha, 0x003d, 334062306a36Sopenharmony_ci "Failed to allocate memory for queue pointers..." 334162306a36Sopenharmony_ci "aborting.\n"); 334262306a36Sopenharmony_ci ret = -ENODEV; 334362306a36Sopenharmony_ci goto probe_failed; 334462306a36Sopenharmony_ci } 334562306a36Sopenharmony_ci 334662306a36Sopenharmony_ci if (ha->mqenable) { 334762306a36Sopenharmony_ci /* number of hardware queues supported by blk/scsi-mq*/ 334862306a36Sopenharmony_ci host->nr_hw_queues = ha->max_qpairs; 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x0192, 335162306a36Sopenharmony_ci "blk/scsi-mq enabled, HW queues = %d.\n", host->nr_hw_queues); 335262306a36Sopenharmony_ci } else { 335362306a36Sopenharmony_ci if (ql2xnvmeenable) { 335462306a36Sopenharmony_ci host->nr_hw_queues = ha->max_qpairs; 335562306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x0194, 335662306a36Sopenharmony_ci "FC-NVMe support is enabled, HW queues=%d\n", 335762306a36Sopenharmony_ci host->nr_hw_queues); 335862306a36Sopenharmony_ci } else { 335962306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x0193, 336062306a36Sopenharmony_ci "blk/scsi-mq disabled.\n"); 336162306a36Sopenharmony_ci } 336262306a36Sopenharmony_ci } 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci qlt_probe_one_stage1(base_vha, ha); 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci pci_save_state(pdev); 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_ci /* Assign back pointers */ 336962306a36Sopenharmony_ci rsp->req = req; 337062306a36Sopenharmony_ci req->rsp = rsp; 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci if (IS_QLAFX00(ha)) { 337362306a36Sopenharmony_ci ha->rsp_q_map[0] = rsp; 337462306a36Sopenharmony_ci ha->req_q_map[0] = req; 337562306a36Sopenharmony_ci set_bit(0, ha->req_qid_map); 337662306a36Sopenharmony_ci set_bit(0, ha->rsp_qid_map); 337762306a36Sopenharmony_ci } 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_ci /* FWI2-capable only. */ 338062306a36Sopenharmony_ci req->req_q_in = &ha->iobase->isp24.req_q_in; 338162306a36Sopenharmony_ci req->req_q_out = &ha->iobase->isp24.req_q_out; 338262306a36Sopenharmony_ci rsp->rsp_q_in = &ha->iobase->isp24.rsp_q_in; 338362306a36Sopenharmony_ci rsp->rsp_q_out = &ha->iobase->isp24.rsp_q_out; 338462306a36Sopenharmony_ci if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) || 338562306a36Sopenharmony_ci IS_QLA28XX(ha)) { 338662306a36Sopenharmony_ci req->req_q_in = &ha->mqiobase->isp25mq.req_q_in; 338762306a36Sopenharmony_ci req->req_q_out = &ha->mqiobase->isp25mq.req_q_out; 338862306a36Sopenharmony_ci rsp->rsp_q_in = &ha->mqiobase->isp25mq.rsp_q_in; 338962306a36Sopenharmony_ci rsp->rsp_q_out = &ha->mqiobase->isp25mq.rsp_q_out; 339062306a36Sopenharmony_ci } 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci if (IS_QLAFX00(ha)) { 339362306a36Sopenharmony_ci req->req_q_in = &ha->iobase->ispfx00.req_q_in; 339462306a36Sopenharmony_ci req->req_q_out = &ha->iobase->ispfx00.req_q_out; 339562306a36Sopenharmony_ci rsp->rsp_q_in = &ha->iobase->ispfx00.rsp_q_in; 339662306a36Sopenharmony_ci rsp->rsp_q_out = &ha->iobase->ispfx00.rsp_q_out; 339762306a36Sopenharmony_ci } 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) { 340062306a36Sopenharmony_ci req->req_q_out = &ha->iobase->isp82.req_q_out[0]; 340162306a36Sopenharmony_ci rsp->rsp_q_in = &ha->iobase->isp82.rsp_q_in[0]; 340262306a36Sopenharmony_ci rsp->rsp_q_out = &ha->iobase->isp82.rsp_q_out[0]; 340362306a36Sopenharmony_ci } 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci ql_dbg(ql_dbg_multiq, base_vha, 0xc009, 340662306a36Sopenharmony_ci "rsp_q_map=%p req_q_map=%p rsp->req=%p req->rsp=%p.\n", 340762306a36Sopenharmony_ci ha->rsp_q_map, ha->req_q_map, rsp->req, req->rsp); 340862306a36Sopenharmony_ci ql_dbg(ql_dbg_multiq, base_vha, 0xc00a, 340962306a36Sopenharmony_ci "req->req_q_in=%p req->req_q_out=%p " 341062306a36Sopenharmony_ci "rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n", 341162306a36Sopenharmony_ci req->req_q_in, req->req_q_out, 341262306a36Sopenharmony_ci rsp->rsp_q_in, rsp->rsp_q_out); 341362306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x003e, 341462306a36Sopenharmony_ci "rsp_q_map=%p req_q_map=%p rsp->req=%p req->rsp=%p.\n", 341562306a36Sopenharmony_ci ha->rsp_q_map, ha->req_q_map, rsp->req, req->rsp); 341662306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x003f, 341762306a36Sopenharmony_ci "req->req_q_in=%p req->req_q_out=%p rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n", 341862306a36Sopenharmony_ci req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out); 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 0); 342162306a36Sopenharmony_ci if (unlikely(!ha->wq)) { 342262306a36Sopenharmony_ci ret = -ENOMEM; 342362306a36Sopenharmony_ci goto probe_failed; 342462306a36Sopenharmony_ci } 342562306a36Sopenharmony_ci 342662306a36Sopenharmony_ci if (ha->isp_ops->initialize_adapter(base_vha)) { 342762306a36Sopenharmony_ci ql_log(ql_log_fatal, base_vha, 0x00d6, 342862306a36Sopenharmony_ci "Failed to initialize adapter - Adapter flags %x.\n", 342962306a36Sopenharmony_ci base_vha->device_flags); 343062306a36Sopenharmony_ci 343162306a36Sopenharmony_ci if (IS_QLA82XX(ha)) { 343262306a36Sopenharmony_ci qla82xx_idc_lock(ha); 343362306a36Sopenharmony_ci qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 343462306a36Sopenharmony_ci QLA8XXX_DEV_FAILED); 343562306a36Sopenharmony_ci qla82xx_idc_unlock(ha); 343662306a36Sopenharmony_ci ql_log(ql_log_fatal, base_vha, 0x00d7, 343762306a36Sopenharmony_ci "HW State: FAILED.\n"); 343862306a36Sopenharmony_ci } else if (IS_QLA8044(ha)) { 343962306a36Sopenharmony_ci qla8044_idc_lock(ha); 344062306a36Sopenharmony_ci qla8044_wr_direct(base_vha, 344162306a36Sopenharmony_ci QLA8044_CRB_DEV_STATE_INDEX, 344262306a36Sopenharmony_ci QLA8XXX_DEV_FAILED); 344362306a36Sopenharmony_ci qla8044_idc_unlock(ha); 344462306a36Sopenharmony_ci ql_log(ql_log_fatal, base_vha, 0x0150, 344562306a36Sopenharmony_ci "HW State: FAILED.\n"); 344662306a36Sopenharmony_ci } 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci ret = -ENODEV; 344962306a36Sopenharmony_ci goto probe_failed; 345062306a36Sopenharmony_ci } 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci if (IS_QLAFX00(ha)) 345362306a36Sopenharmony_ci host->can_queue = QLAFX00_MAX_CANQUEUE; 345462306a36Sopenharmony_ci else 345562306a36Sopenharmony_ci host->can_queue = req->num_outstanding_cmds - 10; 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x0032, 345862306a36Sopenharmony_ci "can_queue=%d, req=%p, mgmt_svr_loop_id=%d, sg_tablesize=%d.\n", 345962306a36Sopenharmony_ci host->can_queue, base_vha->req, 346062306a36Sopenharmony_ci base_vha->mgmt_svr_loop_id, host->sg_tablesize); 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci /* Check if FW supports MQ or not for ISP25xx */ 346362306a36Sopenharmony_ci if (IS_QLA25XX(ha) && !(ha->fw_attributes & BIT_6)) 346462306a36Sopenharmony_ci ha->mqenable = 0; 346562306a36Sopenharmony_ci 346662306a36Sopenharmony_ci if (ha->mqenable) { 346762306a36Sopenharmony_ci bool startit = false; 346862306a36Sopenharmony_ci 346962306a36Sopenharmony_ci if (QLA_TGT_MODE_ENABLED()) 347062306a36Sopenharmony_ci startit = false; 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ci if (ql2x_ini_mode == QLA2XXX_INI_MODE_ENABLED) 347362306a36Sopenharmony_ci startit = true; 347462306a36Sopenharmony_ci 347562306a36Sopenharmony_ci /* Create start of day qpairs for Block MQ */ 347662306a36Sopenharmony_ci for (i = 0; i < ha->max_qpairs; i++) 347762306a36Sopenharmony_ci qla2xxx_create_qpair(base_vha, 5, 0, startit); 347862306a36Sopenharmony_ci } 347962306a36Sopenharmony_ci qla_init_iocb_limit(base_vha); 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_ci if (ha->flags.running_gold_fw) 348262306a36Sopenharmony_ci goto skip_dpc; 348362306a36Sopenharmony_ci 348462306a36Sopenharmony_ci /* 348562306a36Sopenharmony_ci * Startup the kernel thread for this host adapter 348662306a36Sopenharmony_ci */ 348762306a36Sopenharmony_ci ha->dpc_thread = kthread_create(qla2x00_do_dpc, ha, 348862306a36Sopenharmony_ci "%s_dpc", base_vha->host_str); 348962306a36Sopenharmony_ci if (IS_ERR(ha->dpc_thread)) { 349062306a36Sopenharmony_ci ql_log(ql_log_fatal, base_vha, 0x00ed, 349162306a36Sopenharmony_ci "Failed to start DPC thread.\n"); 349262306a36Sopenharmony_ci ret = PTR_ERR(ha->dpc_thread); 349362306a36Sopenharmony_ci ha->dpc_thread = NULL; 349462306a36Sopenharmony_ci goto probe_failed; 349562306a36Sopenharmony_ci } 349662306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x00ee, 349762306a36Sopenharmony_ci "DPC thread started successfully.\n"); 349862306a36Sopenharmony_ci 349962306a36Sopenharmony_ci /* 350062306a36Sopenharmony_ci * If we're not coming up in initiator mode, we might sit for 350162306a36Sopenharmony_ci * a while without waking up the dpc thread, which leads to a 350262306a36Sopenharmony_ci * stuck process warning. So just kick the dpc once here and 350362306a36Sopenharmony_ci * let the kthread start (and go back to sleep in qla2x00_do_dpc). 350462306a36Sopenharmony_ci */ 350562306a36Sopenharmony_ci qla2xxx_wake_dpc(base_vha); 350662306a36Sopenharmony_ci 350762306a36Sopenharmony_ci INIT_WORK(&ha->board_disable, qla2x00_disable_board_on_pci_error); 350862306a36Sopenharmony_ci 350962306a36Sopenharmony_ci if (IS_QLA8031(ha) || IS_MCTP_CAPABLE(ha)) { 351062306a36Sopenharmony_ci sprintf(wq_name, "qla2xxx_%lu_dpc_lp_wq", base_vha->host_no); 351162306a36Sopenharmony_ci ha->dpc_lp_wq = create_singlethread_workqueue(wq_name); 351262306a36Sopenharmony_ci INIT_WORK(&ha->idc_aen, qla83xx_service_idc_aen); 351362306a36Sopenharmony_ci 351462306a36Sopenharmony_ci sprintf(wq_name, "qla2xxx_%lu_dpc_hp_wq", base_vha->host_no); 351562306a36Sopenharmony_ci ha->dpc_hp_wq = create_singlethread_workqueue(wq_name); 351662306a36Sopenharmony_ci INIT_WORK(&ha->nic_core_reset, qla83xx_nic_core_reset_work); 351762306a36Sopenharmony_ci INIT_WORK(&ha->idc_state_handler, 351862306a36Sopenharmony_ci qla83xx_idc_state_handler_work); 351962306a36Sopenharmony_ci INIT_WORK(&ha->nic_core_unrecoverable, 352062306a36Sopenharmony_ci qla83xx_nic_core_unrecoverable_work); 352162306a36Sopenharmony_ci } 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_ciskip_dpc: 352462306a36Sopenharmony_ci list_add_tail(&base_vha->list, &ha->vp_list); 352562306a36Sopenharmony_ci base_vha->host->irq = ha->pdev->irq; 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci /* Initialized the timer */ 352862306a36Sopenharmony_ci qla2x00_start_timer(base_vha, WATCH_INTERVAL); 352962306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x00ef, 353062306a36Sopenharmony_ci "Started qla2x00_timer with " 353162306a36Sopenharmony_ci "interval=%d.\n", WATCH_INTERVAL); 353262306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x00f0, 353362306a36Sopenharmony_ci "Detected hba at address=%p.\n", 353462306a36Sopenharmony_ci ha); 353562306a36Sopenharmony_ci 353662306a36Sopenharmony_ci if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { 353762306a36Sopenharmony_ci if (ha->fw_attributes & BIT_4) { 353862306a36Sopenharmony_ci int prot = 0, guard; 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci base_vha->flags.difdix_supported = 1; 354162306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x00f1, 354262306a36Sopenharmony_ci "Registering for DIF/DIX type 1 and 3 protection.\n"); 354362306a36Sopenharmony_ci if (ql2xprotmask) 354462306a36Sopenharmony_ci scsi_host_set_prot(host, ql2xprotmask); 354562306a36Sopenharmony_ci else 354662306a36Sopenharmony_ci scsi_host_set_prot(host, 354762306a36Sopenharmony_ci prot | SHOST_DIF_TYPE1_PROTECTION 354862306a36Sopenharmony_ci | SHOST_DIF_TYPE2_PROTECTION 354962306a36Sopenharmony_ci | SHOST_DIF_TYPE3_PROTECTION 355062306a36Sopenharmony_ci | SHOST_DIX_TYPE1_PROTECTION 355162306a36Sopenharmony_ci | SHOST_DIX_TYPE2_PROTECTION 355262306a36Sopenharmony_ci | SHOST_DIX_TYPE3_PROTECTION); 355362306a36Sopenharmony_ci 355462306a36Sopenharmony_ci guard = SHOST_DIX_GUARD_CRC; 355562306a36Sopenharmony_ci 355662306a36Sopenharmony_ci if (IS_PI_IPGUARD_CAPABLE(ha) && 355762306a36Sopenharmony_ci (ql2xenabledif > 1 || IS_PI_DIFB_DIX0_CAPABLE(ha))) 355862306a36Sopenharmony_ci guard |= SHOST_DIX_GUARD_IP; 355962306a36Sopenharmony_ci 356062306a36Sopenharmony_ci if (ql2xprotguard) 356162306a36Sopenharmony_ci scsi_host_set_guard(host, ql2xprotguard); 356262306a36Sopenharmony_ci else 356362306a36Sopenharmony_ci scsi_host_set_guard(host, guard); 356462306a36Sopenharmony_ci } else 356562306a36Sopenharmony_ci base_vha->flags.difdix_supported = 0; 356662306a36Sopenharmony_ci } 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci ha->isp_ops->enable_intrs(ha); 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_ci if (IS_QLAFX00(ha)) { 357162306a36Sopenharmony_ci ret = qlafx00_fx_disc(base_vha, 357262306a36Sopenharmony_ci &base_vha->hw->mr.fcport, FXDISC_GET_CONFIG_INFO); 357362306a36Sopenharmony_ci host->sg_tablesize = (ha->mr.extended_io_enabled) ? 357462306a36Sopenharmony_ci QLA_SG_ALL : 128; 357562306a36Sopenharmony_ci } 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_ci ret = scsi_add_host(host, &pdev->dev); 357862306a36Sopenharmony_ci if (ret) 357962306a36Sopenharmony_ci goto probe_failed; 358062306a36Sopenharmony_ci 358162306a36Sopenharmony_ci base_vha->flags.init_done = 1; 358262306a36Sopenharmony_ci base_vha->flags.online = 1; 358362306a36Sopenharmony_ci ha->prev_minidump_failed = 0; 358462306a36Sopenharmony_ci 358562306a36Sopenharmony_ci ql_dbg(ql_dbg_init, base_vha, 0x00f2, 358662306a36Sopenharmony_ci "Init done and hba is online.\n"); 358762306a36Sopenharmony_ci 358862306a36Sopenharmony_ci if (qla_ini_mode_enabled(base_vha) || 358962306a36Sopenharmony_ci qla_dual_mode_enabled(base_vha)) 359062306a36Sopenharmony_ci scsi_scan_host(host); 359162306a36Sopenharmony_ci else 359262306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0x0122, 359362306a36Sopenharmony_ci "skipping scsi_scan_host() for non-initiator port\n"); 359462306a36Sopenharmony_ci 359562306a36Sopenharmony_ci qla2x00_alloc_sysfs_attr(base_vha); 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_ci if (IS_QLAFX00(ha)) { 359862306a36Sopenharmony_ci ret = qlafx00_fx_disc(base_vha, 359962306a36Sopenharmony_ci &base_vha->hw->mr.fcport, FXDISC_GET_PORT_INFO); 360062306a36Sopenharmony_ci 360162306a36Sopenharmony_ci /* Register system information */ 360262306a36Sopenharmony_ci ret = qlafx00_fx_disc(base_vha, 360362306a36Sopenharmony_ci &base_vha->hw->mr.fcport, FXDISC_REG_HOST_INFO); 360462306a36Sopenharmony_ci } 360562306a36Sopenharmony_ci 360662306a36Sopenharmony_ci qla2x00_init_host_attr(base_vha); 360762306a36Sopenharmony_ci 360862306a36Sopenharmony_ci qla2x00_dfs_setup(base_vha); 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0x00fb, 361162306a36Sopenharmony_ci "QLogic %s - %s.\n", ha->model_number, ha->model_desc); 361262306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0x00fc, 361362306a36Sopenharmony_ci "ISP%04X: %s @ %s hdma%c host#=%ld fw=%s.\n", 361462306a36Sopenharmony_ci pdev->device, ha->isp_ops->pci_info_str(base_vha, pci_info, 361562306a36Sopenharmony_ci sizeof(pci_info)), 361662306a36Sopenharmony_ci pci_name(pdev), ha->flags.enable_64bit_addressing ? '+' : '-', 361762306a36Sopenharmony_ci base_vha->host_no, 361862306a36Sopenharmony_ci ha->isp_ops->fw_version_str(base_vha, fw_str, sizeof(fw_str))); 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_ci qlt_add_target(ha, base_vha); 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci clear_bit(PFLG_DRIVER_PROBING, &base_vha->pci_flags); 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci if (test_bit(UNLOADING, &base_vha->dpc_flags)) 362562306a36Sopenharmony_ci return -ENODEV; 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci return 0; 362862306a36Sopenharmony_ci 362962306a36Sopenharmony_ciprobe_failed: 363062306a36Sopenharmony_ci qla_enode_stop(base_vha); 363162306a36Sopenharmony_ci qla_edb_stop(base_vha); 363262306a36Sopenharmony_ci vfree(base_vha->scan.l); 363362306a36Sopenharmony_ci if (base_vha->gnl.l) { 363462306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size, 363562306a36Sopenharmony_ci base_vha->gnl.l, base_vha->gnl.ldma); 363662306a36Sopenharmony_ci base_vha->gnl.l = NULL; 363762306a36Sopenharmony_ci } 363862306a36Sopenharmony_ci 363962306a36Sopenharmony_ci if (base_vha->timer_active) 364062306a36Sopenharmony_ci qla2x00_stop_timer(base_vha); 364162306a36Sopenharmony_ci base_vha->flags.online = 0; 364262306a36Sopenharmony_ci if (ha->dpc_thread) { 364362306a36Sopenharmony_ci struct task_struct *t = ha->dpc_thread; 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci ha->dpc_thread = NULL; 364662306a36Sopenharmony_ci kthread_stop(t); 364762306a36Sopenharmony_ci } 364862306a36Sopenharmony_ci 364962306a36Sopenharmony_ci qla2x00_free_device(base_vha); 365062306a36Sopenharmony_ci scsi_host_put(base_vha->host); 365162306a36Sopenharmony_ci /* 365262306a36Sopenharmony_ci * Need to NULL out local req/rsp after 365362306a36Sopenharmony_ci * qla2x00_free_device => qla2x00_free_queues frees 365462306a36Sopenharmony_ci * what these are pointing to. Or else we'll 365562306a36Sopenharmony_ci * fall over below in qla2x00_free_req/rsp_que. 365662306a36Sopenharmony_ci */ 365762306a36Sopenharmony_ci req = NULL; 365862306a36Sopenharmony_ci rsp = NULL; 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_ciprobe_hw_failed: 366162306a36Sopenharmony_ci qla2x00_mem_free(ha); 366262306a36Sopenharmony_ci qla2x00_free_req_que(ha, req); 366362306a36Sopenharmony_ci qla2x00_free_rsp_que(ha, rsp); 366462306a36Sopenharmony_ci qla2x00_clear_drv_active(ha); 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ciiospace_config_failed: 366762306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) { 366862306a36Sopenharmony_ci if (!ha->nx_pcibase) 366962306a36Sopenharmony_ci iounmap((device_reg_t *)ha->nx_pcibase); 367062306a36Sopenharmony_ci if (!ql2xdbwr) 367162306a36Sopenharmony_ci iounmap((device_reg_t *)ha->nxdb_wr_ptr); 367262306a36Sopenharmony_ci } else { 367362306a36Sopenharmony_ci if (ha->iobase) 367462306a36Sopenharmony_ci iounmap(ha->iobase); 367562306a36Sopenharmony_ci if (ha->cregbase) 367662306a36Sopenharmony_ci iounmap(ha->cregbase); 367762306a36Sopenharmony_ci } 367862306a36Sopenharmony_ci pci_release_selected_regions(ha->pdev, ha->bars); 367962306a36Sopenharmony_ci kfree(ha); 368062306a36Sopenharmony_ci 368162306a36Sopenharmony_cidisable_device: 368262306a36Sopenharmony_ci pci_disable_device(pdev); 368362306a36Sopenharmony_ci return ret; 368462306a36Sopenharmony_ci} 368562306a36Sopenharmony_ci 368662306a36Sopenharmony_cistatic void __qla_set_remove_flag(scsi_qla_host_t *base_vha) 368762306a36Sopenharmony_ci{ 368862306a36Sopenharmony_ci scsi_qla_host_t *vp; 368962306a36Sopenharmony_ci unsigned long flags; 369062306a36Sopenharmony_ci struct qla_hw_data *ha; 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci if (!base_vha) 369362306a36Sopenharmony_ci return; 369462306a36Sopenharmony_ci 369562306a36Sopenharmony_ci ha = base_vha->hw; 369662306a36Sopenharmony_ci 369762306a36Sopenharmony_ci spin_lock_irqsave(&ha->vport_slock, flags); 369862306a36Sopenharmony_ci list_for_each_entry(vp, &ha->vp_list, list) 369962306a36Sopenharmony_ci set_bit(PFLG_DRIVER_REMOVING, &vp->pci_flags); 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_ci /* 370262306a36Sopenharmony_ci * Indicate device removal to prevent future board_disable 370362306a36Sopenharmony_ci * and wait until any pending board_disable has completed. 370462306a36Sopenharmony_ci */ 370562306a36Sopenharmony_ci set_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags); 370662306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->vport_slock, flags); 370762306a36Sopenharmony_ci} 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_cistatic void 371062306a36Sopenharmony_ciqla2x00_shutdown(struct pci_dev *pdev) 371162306a36Sopenharmony_ci{ 371262306a36Sopenharmony_ci scsi_qla_host_t *vha; 371362306a36Sopenharmony_ci struct qla_hw_data *ha; 371462306a36Sopenharmony_ci 371562306a36Sopenharmony_ci vha = pci_get_drvdata(pdev); 371662306a36Sopenharmony_ci ha = vha->hw; 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xfffa, 371962306a36Sopenharmony_ci "Adapter shutdown\n"); 372062306a36Sopenharmony_ci 372162306a36Sopenharmony_ci /* 372262306a36Sopenharmony_ci * Prevent future board_disable and wait 372362306a36Sopenharmony_ci * until any pending board_disable has completed. 372462306a36Sopenharmony_ci */ 372562306a36Sopenharmony_ci __qla_set_remove_flag(vha); 372662306a36Sopenharmony_ci cancel_work_sync(&ha->board_disable); 372762306a36Sopenharmony_ci 372862306a36Sopenharmony_ci if (!atomic_read(&pdev->enable_cnt)) 372962306a36Sopenharmony_ci return; 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci /* Notify ISPFX00 firmware */ 373262306a36Sopenharmony_ci if (IS_QLAFX00(ha)) 373362306a36Sopenharmony_ci qlafx00_driver_shutdown(vha, 20); 373462306a36Sopenharmony_ci 373562306a36Sopenharmony_ci /* Turn-off FCE trace */ 373662306a36Sopenharmony_ci if (ha->flags.fce_enabled) { 373762306a36Sopenharmony_ci qla2x00_disable_fce_trace(vha, NULL, NULL); 373862306a36Sopenharmony_ci ha->flags.fce_enabled = 0; 373962306a36Sopenharmony_ci } 374062306a36Sopenharmony_ci 374162306a36Sopenharmony_ci /* Turn-off EFT trace */ 374262306a36Sopenharmony_ci if (ha->eft) 374362306a36Sopenharmony_ci qla2x00_disable_eft_trace(vha); 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || 374662306a36Sopenharmony_ci IS_QLA28XX(ha)) { 374762306a36Sopenharmony_ci if (ha->flags.fw_started) 374862306a36Sopenharmony_ci qla2x00_abort_isp_cleanup(vha); 374962306a36Sopenharmony_ci } else { 375062306a36Sopenharmony_ci /* Stop currently executing firmware. */ 375162306a36Sopenharmony_ci qla2x00_try_to_stop_firmware(vha); 375262306a36Sopenharmony_ci } 375362306a36Sopenharmony_ci 375462306a36Sopenharmony_ci /* Disable timer */ 375562306a36Sopenharmony_ci if (vha->timer_active) 375662306a36Sopenharmony_ci qla2x00_stop_timer(vha); 375762306a36Sopenharmony_ci 375862306a36Sopenharmony_ci /* Turn adapter off line */ 375962306a36Sopenharmony_ci vha->flags.online = 0; 376062306a36Sopenharmony_ci 376162306a36Sopenharmony_ci /* turn-off interrupts on the card */ 376262306a36Sopenharmony_ci if (ha->interrupts_on) { 376362306a36Sopenharmony_ci vha->flags.init_done = 0; 376462306a36Sopenharmony_ci ha->isp_ops->disable_intrs(ha); 376562306a36Sopenharmony_ci } 376662306a36Sopenharmony_ci 376762306a36Sopenharmony_ci qla2x00_free_irqs(vha); 376862306a36Sopenharmony_ci 376962306a36Sopenharmony_ci qla2x00_free_fw_dump(ha); 377062306a36Sopenharmony_ci 377162306a36Sopenharmony_ci pci_disable_device(pdev); 377262306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xfffe, 377362306a36Sopenharmony_ci "Adapter shutdown successfully.\n"); 377462306a36Sopenharmony_ci} 377562306a36Sopenharmony_ci 377662306a36Sopenharmony_ci/* Deletes all the virtual ports for a given ha */ 377762306a36Sopenharmony_cistatic void 377862306a36Sopenharmony_ciqla2x00_delete_all_vps(struct qla_hw_data *ha, scsi_qla_host_t *base_vha) 377962306a36Sopenharmony_ci{ 378062306a36Sopenharmony_ci scsi_qla_host_t *vha; 378162306a36Sopenharmony_ci unsigned long flags; 378262306a36Sopenharmony_ci 378362306a36Sopenharmony_ci mutex_lock(&ha->vport_lock); 378462306a36Sopenharmony_ci while (ha->cur_vport_count) { 378562306a36Sopenharmony_ci spin_lock_irqsave(&ha->vport_slock, flags); 378662306a36Sopenharmony_ci 378762306a36Sopenharmony_ci BUG_ON(base_vha->list.next == &ha->vp_list); 378862306a36Sopenharmony_ci /* This assumes first entry in ha->vp_list is always base vha */ 378962306a36Sopenharmony_ci vha = list_first_entry(&base_vha->list, scsi_qla_host_t, list); 379062306a36Sopenharmony_ci scsi_host_get(vha->host); 379162306a36Sopenharmony_ci 379262306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->vport_slock, flags); 379362306a36Sopenharmony_ci mutex_unlock(&ha->vport_lock); 379462306a36Sopenharmony_ci 379562306a36Sopenharmony_ci qla_nvme_delete(vha); 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_ci fc_vport_terminate(vha->fc_vport); 379862306a36Sopenharmony_ci scsi_host_put(vha->host); 379962306a36Sopenharmony_ci 380062306a36Sopenharmony_ci mutex_lock(&ha->vport_lock); 380162306a36Sopenharmony_ci } 380262306a36Sopenharmony_ci mutex_unlock(&ha->vport_lock); 380362306a36Sopenharmony_ci} 380462306a36Sopenharmony_ci 380562306a36Sopenharmony_ci/* Stops all deferred work threads */ 380662306a36Sopenharmony_cistatic void 380762306a36Sopenharmony_ciqla2x00_destroy_deferred_work(struct qla_hw_data *ha) 380862306a36Sopenharmony_ci{ 380962306a36Sopenharmony_ci /* Cancel all work and destroy DPC workqueues */ 381062306a36Sopenharmony_ci if (ha->dpc_lp_wq) { 381162306a36Sopenharmony_ci cancel_work_sync(&ha->idc_aen); 381262306a36Sopenharmony_ci destroy_workqueue(ha->dpc_lp_wq); 381362306a36Sopenharmony_ci ha->dpc_lp_wq = NULL; 381462306a36Sopenharmony_ci } 381562306a36Sopenharmony_ci 381662306a36Sopenharmony_ci if (ha->dpc_hp_wq) { 381762306a36Sopenharmony_ci cancel_work_sync(&ha->nic_core_reset); 381862306a36Sopenharmony_ci cancel_work_sync(&ha->idc_state_handler); 381962306a36Sopenharmony_ci cancel_work_sync(&ha->nic_core_unrecoverable); 382062306a36Sopenharmony_ci destroy_workqueue(ha->dpc_hp_wq); 382162306a36Sopenharmony_ci ha->dpc_hp_wq = NULL; 382262306a36Sopenharmony_ci } 382362306a36Sopenharmony_ci 382462306a36Sopenharmony_ci /* Kill the kernel thread for this host */ 382562306a36Sopenharmony_ci if (ha->dpc_thread) { 382662306a36Sopenharmony_ci struct task_struct *t = ha->dpc_thread; 382762306a36Sopenharmony_ci 382862306a36Sopenharmony_ci /* 382962306a36Sopenharmony_ci * qla2xxx_wake_dpc checks for ->dpc_thread 383062306a36Sopenharmony_ci * so we need to zero it out. 383162306a36Sopenharmony_ci */ 383262306a36Sopenharmony_ci ha->dpc_thread = NULL; 383362306a36Sopenharmony_ci kthread_stop(t); 383462306a36Sopenharmony_ci } 383562306a36Sopenharmony_ci} 383662306a36Sopenharmony_ci 383762306a36Sopenharmony_cistatic void 383862306a36Sopenharmony_ciqla2x00_unmap_iobases(struct qla_hw_data *ha) 383962306a36Sopenharmony_ci{ 384062306a36Sopenharmony_ci if (IS_QLA82XX(ha)) { 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci iounmap((device_reg_t *)ha->nx_pcibase); 384362306a36Sopenharmony_ci if (!ql2xdbwr) 384462306a36Sopenharmony_ci iounmap((device_reg_t *)ha->nxdb_wr_ptr); 384562306a36Sopenharmony_ci } else { 384662306a36Sopenharmony_ci if (ha->iobase) 384762306a36Sopenharmony_ci iounmap(ha->iobase); 384862306a36Sopenharmony_ci 384962306a36Sopenharmony_ci if (ha->cregbase) 385062306a36Sopenharmony_ci iounmap(ha->cregbase); 385162306a36Sopenharmony_ci 385262306a36Sopenharmony_ci if (ha->mqiobase) 385362306a36Sopenharmony_ci iounmap(ha->mqiobase); 385462306a36Sopenharmony_ci 385562306a36Sopenharmony_ci if (ha->msixbase) 385662306a36Sopenharmony_ci iounmap(ha->msixbase); 385762306a36Sopenharmony_ci } 385862306a36Sopenharmony_ci} 385962306a36Sopenharmony_ci 386062306a36Sopenharmony_cistatic void 386162306a36Sopenharmony_ciqla2x00_clear_drv_active(struct qla_hw_data *ha) 386262306a36Sopenharmony_ci{ 386362306a36Sopenharmony_ci if (IS_QLA8044(ha)) { 386462306a36Sopenharmony_ci qla8044_idc_lock(ha); 386562306a36Sopenharmony_ci qla8044_clear_drv_active(ha); 386662306a36Sopenharmony_ci qla8044_idc_unlock(ha); 386762306a36Sopenharmony_ci } else if (IS_QLA82XX(ha)) { 386862306a36Sopenharmony_ci qla82xx_idc_lock(ha); 386962306a36Sopenharmony_ci qla82xx_clear_drv_active(ha); 387062306a36Sopenharmony_ci qla82xx_idc_unlock(ha); 387162306a36Sopenharmony_ci } 387262306a36Sopenharmony_ci} 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_cistatic void 387562306a36Sopenharmony_ciqla2x00_remove_one(struct pci_dev *pdev) 387662306a36Sopenharmony_ci{ 387762306a36Sopenharmony_ci scsi_qla_host_t *base_vha; 387862306a36Sopenharmony_ci struct qla_hw_data *ha; 387962306a36Sopenharmony_ci 388062306a36Sopenharmony_ci base_vha = pci_get_drvdata(pdev); 388162306a36Sopenharmony_ci ha = base_vha->hw; 388262306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0xb079, 388362306a36Sopenharmony_ci "Removing driver\n"); 388462306a36Sopenharmony_ci __qla_set_remove_flag(base_vha); 388562306a36Sopenharmony_ci cancel_work_sync(&ha->board_disable); 388662306a36Sopenharmony_ci 388762306a36Sopenharmony_ci /* 388862306a36Sopenharmony_ci * If the PCI device is disabled then there was a PCI-disconnect and 388962306a36Sopenharmony_ci * qla2x00_disable_board_on_pci_error has taken care of most of the 389062306a36Sopenharmony_ci * resources. 389162306a36Sopenharmony_ci */ 389262306a36Sopenharmony_ci if (!atomic_read(&pdev->enable_cnt)) { 389362306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size, 389462306a36Sopenharmony_ci base_vha->gnl.l, base_vha->gnl.ldma); 389562306a36Sopenharmony_ci base_vha->gnl.l = NULL; 389662306a36Sopenharmony_ci scsi_host_put(base_vha->host); 389762306a36Sopenharmony_ci kfree(ha); 389862306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 389962306a36Sopenharmony_ci return; 390062306a36Sopenharmony_ci } 390162306a36Sopenharmony_ci qla2x00_wait_for_hba_ready(base_vha); 390262306a36Sopenharmony_ci 390362306a36Sopenharmony_ci /* 390462306a36Sopenharmony_ci * if UNLOADING flag is already set, then continue unload, 390562306a36Sopenharmony_ci * where it was set first. 390662306a36Sopenharmony_ci */ 390762306a36Sopenharmony_ci if (test_and_set_bit(UNLOADING, &base_vha->dpc_flags)) 390862306a36Sopenharmony_ci return; 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_ci if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || 391162306a36Sopenharmony_ci IS_QLA28XX(ha)) { 391262306a36Sopenharmony_ci if (ha->flags.fw_started) 391362306a36Sopenharmony_ci qla2x00_abort_isp_cleanup(base_vha); 391462306a36Sopenharmony_ci } else if (!IS_QLAFX00(ha)) { 391562306a36Sopenharmony_ci if (IS_QLA8031(ha)) { 391662306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb07e, 391762306a36Sopenharmony_ci "Clearing fcoe driver presence.\n"); 391862306a36Sopenharmony_ci if (qla83xx_clear_drv_presence(base_vha) != QLA_SUCCESS) 391962306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb079, 392062306a36Sopenharmony_ci "Error while clearing DRV-Presence.\n"); 392162306a36Sopenharmony_ci } 392262306a36Sopenharmony_ci 392362306a36Sopenharmony_ci qla2x00_try_to_stop_firmware(base_vha); 392462306a36Sopenharmony_ci } 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_ci qla2x00_wait_for_sess_deletion(base_vha); 392762306a36Sopenharmony_ci 392862306a36Sopenharmony_ci qla_nvme_delete(base_vha); 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, 393162306a36Sopenharmony_ci base_vha->gnl.size, base_vha->gnl.l, base_vha->gnl.ldma); 393262306a36Sopenharmony_ci 393362306a36Sopenharmony_ci base_vha->gnl.l = NULL; 393462306a36Sopenharmony_ci qla_enode_stop(base_vha); 393562306a36Sopenharmony_ci qla_edb_stop(base_vha); 393662306a36Sopenharmony_ci 393762306a36Sopenharmony_ci vfree(base_vha->scan.l); 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ci if (IS_QLAFX00(ha)) 394062306a36Sopenharmony_ci qlafx00_driver_shutdown(base_vha, 20); 394162306a36Sopenharmony_ci 394262306a36Sopenharmony_ci qla2x00_delete_all_vps(ha, base_vha); 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ci qla2x00_dfs_remove(base_vha); 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_ci qla84xx_put_chip(base_vha); 394762306a36Sopenharmony_ci 394862306a36Sopenharmony_ci /* Disable timer */ 394962306a36Sopenharmony_ci if (base_vha->timer_active) 395062306a36Sopenharmony_ci qla2x00_stop_timer(base_vha); 395162306a36Sopenharmony_ci 395262306a36Sopenharmony_ci base_vha->flags.online = 0; 395362306a36Sopenharmony_ci 395462306a36Sopenharmony_ci /* free DMA memory */ 395562306a36Sopenharmony_ci if (ha->exlogin_buf) 395662306a36Sopenharmony_ci qla2x00_free_exlogin_buffer(ha); 395762306a36Sopenharmony_ci 395862306a36Sopenharmony_ci /* free DMA memory */ 395962306a36Sopenharmony_ci if (ha->exchoffld_buf) 396062306a36Sopenharmony_ci qla2x00_free_exchoffld_buffer(ha); 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci qla2x00_destroy_deferred_work(ha); 396362306a36Sopenharmony_ci 396462306a36Sopenharmony_ci qlt_remove_target(ha, base_vha); 396562306a36Sopenharmony_ci 396662306a36Sopenharmony_ci qla2x00_free_sysfs_attr(base_vha, true); 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci fc_remove_host(base_vha->host); 396962306a36Sopenharmony_ci 397062306a36Sopenharmony_ci scsi_remove_host(base_vha->host); 397162306a36Sopenharmony_ci 397262306a36Sopenharmony_ci qla2x00_free_device(base_vha); 397362306a36Sopenharmony_ci 397462306a36Sopenharmony_ci qla2x00_clear_drv_active(ha); 397562306a36Sopenharmony_ci 397662306a36Sopenharmony_ci scsi_host_put(base_vha->host); 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_ci qla2x00_unmap_iobases(ha); 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci pci_release_selected_regions(ha->pdev, ha->bars); 398162306a36Sopenharmony_ci kfree(ha); 398262306a36Sopenharmony_ci 398362306a36Sopenharmony_ci pci_disable_device(pdev); 398462306a36Sopenharmony_ci} 398562306a36Sopenharmony_ci 398662306a36Sopenharmony_cistatic inline void 398762306a36Sopenharmony_ciqla24xx_free_purex_list(struct purex_list *list) 398862306a36Sopenharmony_ci{ 398962306a36Sopenharmony_ci struct purex_item *item, *next; 399062306a36Sopenharmony_ci ulong flags; 399162306a36Sopenharmony_ci 399262306a36Sopenharmony_ci spin_lock_irqsave(&list->lock, flags); 399362306a36Sopenharmony_ci list_for_each_entry_safe(item, next, &list->head, list) { 399462306a36Sopenharmony_ci list_del(&item->list); 399562306a36Sopenharmony_ci if (item == &item->vha->default_item) 399662306a36Sopenharmony_ci continue; 399762306a36Sopenharmony_ci kfree(item); 399862306a36Sopenharmony_ci } 399962306a36Sopenharmony_ci spin_unlock_irqrestore(&list->lock, flags); 400062306a36Sopenharmony_ci} 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_cistatic void 400362306a36Sopenharmony_ciqla2x00_free_device(scsi_qla_host_t *vha) 400462306a36Sopenharmony_ci{ 400562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 400662306a36Sopenharmony_ci 400762306a36Sopenharmony_ci qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); 400862306a36Sopenharmony_ci 400962306a36Sopenharmony_ci /* Disable timer */ 401062306a36Sopenharmony_ci if (vha->timer_active) 401162306a36Sopenharmony_ci qla2x00_stop_timer(vha); 401262306a36Sopenharmony_ci 401362306a36Sopenharmony_ci qla25xx_delete_queues(vha); 401462306a36Sopenharmony_ci vha->flags.online = 0; 401562306a36Sopenharmony_ci 401662306a36Sopenharmony_ci /* turn-off interrupts on the card */ 401762306a36Sopenharmony_ci if (ha->interrupts_on) { 401862306a36Sopenharmony_ci vha->flags.init_done = 0; 401962306a36Sopenharmony_ci ha->isp_ops->disable_intrs(ha); 402062306a36Sopenharmony_ci } 402162306a36Sopenharmony_ci 402262306a36Sopenharmony_ci qla2x00_free_fcports(vha); 402362306a36Sopenharmony_ci 402462306a36Sopenharmony_ci qla2x00_free_irqs(vha); 402562306a36Sopenharmony_ci 402662306a36Sopenharmony_ci /* Flush the work queue and remove it */ 402762306a36Sopenharmony_ci if (ha->wq) { 402862306a36Sopenharmony_ci destroy_workqueue(ha->wq); 402962306a36Sopenharmony_ci ha->wq = NULL; 403062306a36Sopenharmony_ci } 403162306a36Sopenharmony_ci 403262306a36Sopenharmony_ci 403362306a36Sopenharmony_ci qla24xx_free_purex_list(&vha->purex_list); 403462306a36Sopenharmony_ci 403562306a36Sopenharmony_ci qla2x00_mem_free(ha); 403662306a36Sopenharmony_ci 403762306a36Sopenharmony_ci qla82xx_md_free(vha); 403862306a36Sopenharmony_ci 403962306a36Sopenharmony_ci qla_edif_sadb_release_free_pool(ha); 404062306a36Sopenharmony_ci qla_edif_sadb_release(ha); 404162306a36Sopenharmony_ci 404262306a36Sopenharmony_ci qla2x00_free_queues(ha); 404362306a36Sopenharmony_ci} 404462306a36Sopenharmony_ci 404562306a36Sopenharmony_civoid qla2x00_free_fcports(struct scsi_qla_host *vha) 404662306a36Sopenharmony_ci{ 404762306a36Sopenharmony_ci fc_port_t *fcport, *tfcport; 404862306a36Sopenharmony_ci 404962306a36Sopenharmony_ci list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) 405062306a36Sopenharmony_ci qla2x00_free_fcport(fcport); 405162306a36Sopenharmony_ci} 405262306a36Sopenharmony_ci 405362306a36Sopenharmony_cistatic inline void 405462306a36Sopenharmony_ciqla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport) 405562306a36Sopenharmony_ci{ 405662306a36Sopenharmony_ci int now; 405762306a36Sopenharmony_ci 405862306a36Sopenharmony_ci if (!fcport->rport) 405962306a36Sopenharmony_ci return; 406062306a36Sopenharmony_ci 406162306a36Sopenharmony_ci if (fcport->rport) { 406262306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, fcport->vha, 0x2109, 406362306a36Sopenharmony_ci "%s %8phN. rport %p roles %x\n", 406462306a36Sopenharmony_ci __func__, fcport->port_name, fcport->rport, 406562306a36Sopenharmony_ci fcport->rport->roles); 406662306a36Sopenharmony_ci fc_remote_port_delete(fcport->rport); 406762306a36Sopenharmony_ci } 406862306a36Sopenharmony_ci qlt_do_generation_tick(vha, &now); 406962306a36Sopenharmony_ci} 407062306a36Sopenharmony_ci 407162306a36Sopenharmony_ci/* 407262306a36Sopenharmony_ci * qla2x00_mark_device_lost Updates fcport state when device goes offline. 407362306a36Sopenharmony_ci * 407462306a36Sopenharmony_ci * Input: ha = adapter block pointer. fcport = port structure pointer. 407562306a36Sopenharmony_ci * 407662306a36Sopenharmony_ci * Return: None. 407762306a36Sopenharmony_ci * 407862306a36Sopenharmony_ci * Context: 407962306a36Sopenharmony_ci */ 408062306a36Sopenharmony_civoid qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, 408162306a36Sopenharmony_ci int do_login) 408262306a36Sopenharmony_ci{ 408362306a36Sopenharmony_ci if (IS_QLAFX00(vha->hw)) { 408462306a36Sopenharmony_ci qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); 408562306a36Sopenharmony_ci qla2x00_schedule_rport_del(vha, fcport); 408662306a36Sopenharmony_ci return; 408762306a36Sopenharmony_ci } 408862306a36Sopenharmony_ci 408962306a36Sopenharmony_ci if (atomic_read(&fcport->state) == FCS_ONLINE && 409062306a36Sopenharmony_ci vha->vp_idx == fcport->vha->vp_idx) { 409162306a36Sopenharmony_ci qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); 409262306a36Sopenharmony_ci qla2x00_schedule_rport_del(vha, fcport); 409362306a36Sopenharmony_ci } 409462306a36Sopenharmony_ci 409562306a36Sopenharmony_ci /* 409662306a36Sopenharmony_ci * We may need to retry the login, so don't change the state of the 409762306a36Sopenharmony_ci * port but do the retries. 409862306a36Sopenharmony_ci */ 409962306a36Sopenharmony_ci if (atomic_read(&fcport->state) != FCS_DEVICE_DEAD) 410062306a36Sopenharmony_ci qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); 410162306a36Sopenharmony_ci 410262306a36Sopenharmony_ci if (!do_login) 410362306a36Sopenharmony_ci return; 410462306a36Sopenharmony_ci 410562306a36Sopenharmony_ci set_bit(RELOGIN_NEEDED, &vha->dpc_flags); 410662306a36Sopenharmony_ci} 410762306a36Sopenharmony_ci 410862306a36Sopenharmony_civoid 410962306a36Sopenharmony_ciqla2x00_mark_all_devices_lost(scsi_qla_host_t *vha) 411062306a36Sopenharmony_ci{ 411162306a36Sopenharmony_ci fc_port_t *fcport; 411262306a36Sopenharmony_ci 411362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f1, 411462306a36Sopenharmony_ci "Mark all dev lost\n"); 411562306a36Sopenharmony_ci 411662306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 411762306a36Sopenharmony_ci if (ql2xfc2target && 411862306a36Sopenharmony_ci fcport->loop_id != FC_NO_LOOP_ID && 411962306a36Sopenharmony_ci (fcport->flags & FCF_FCP2_DEVICE) && 412062306a36Sopenharmony_ci fcport->port_type == FCT_TARGET && 412162306a36Sopenharmony_ci !qla2x00_reset_active(vha)) { 412262306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x211a, 412362306a36Sopenharmony_ci "Delaying session delete for FCP2 flags 0x%x port_type = 0x%x port_id=%06x %phC", 412462306a36Sopenharmony_ci fcport->flags, fcport->port_type, 412562306a36Sopenharmony_ci fcport->d_id.b24, fcport->port_name); 412662306a36Sopenharmony_ci continue; 412762306a36Sopenharmony_ci } 412862306a36Sopenharmony_ci fcport->scan_state = 0; 412962306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 413062306a36Sopenharmony_ci } 413162306a36Sopenharmony_ci} 413262306a36Sopenharmony_ci 413362306a36Sopenharmony_cistatic void qla2x00_set_reserved_loop_ids(struct qla_hw_data *ha) 413462306a36Sopenharmony_ci{ 413562306a36Sopenharmony_ci int i; 413662306a36Sopenharmony_ci 413762306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) 413862306a36Sopenharmony_ci return; 413962306a36Sopenharmony_ci 414062306a36Sopenharmony_ci for (i = 0; i < SNS_FIRST_LOOP_ID; i++) 414162306a36Sopenharmony_ci set_bit(i, ha->loop_id_map); 414262306a36Sopenharmony_ci set_bit(MANAGEMENT_SERVER, ha->loop_id_map); 414362306a36Sopenharmony_ci set_bit(BROADCAST, ha->loop_id_map); 414462306a36Sopenharmony_ci} 414562306a36Sopenharmony_ci 414662306a36Sopenharmony_ci/* 414762306a36Sopenharmony_ci* qla2x00_mem_alloc 414862306a36Sopenharmony_ci* Allocates adapter memory. 414962306a36Sopenharmony_ci* 415062306a36Sopenharmony_ci* Returns: 415162306a36Sopenharmony_ci* 0 = success. 415262306a36Sopenharmony_ci* !0 = failure. 415362306a36Sopenharmony_ci*/ 415462306a36Sopenharmony_cistatic int 415562306a36Sopenharmony_ciqla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, 415662306a36Sopenharmony_ci struct req_que **req, struct rsp_que **rsp) 415762306a36Sopenharmony_ci{ 415862306a36Sopenharmony_ci char name[16]; 415962306a36Sopenharmony_ci int rc; 416062306a36Sopenharmony_ci 416162306a36Sopenharmony_ci if (QLA_TGT_MODE_ENABLED() || EDIF_CAP(ha)) { 416262306a36Sopenharmony_ci ha->vp_map = kcalloc(MAX_MULTI_ID_FABRIC, sizeof(struct qla_vp_map), GFP_KERNEL); 416362306a36Sopenharmony_ci if (!ha->vp_map) 416462306a36Sopenharmony_ci goto fail; 416562306a36Sopenharmony_ci } 416662306a36Sopenharmony_ci 416762306a36Sopenharmony_ci ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, ha->init_cb_size, 416862306a36Sopenharmony_ci &ha->init_cb_dma, GFP_KERNEL); 416962306a36Sopenharmony_ci if (!ha->init_cb) 417062306a36Sopenharmony_ci goto fail_free_vp_map; 417162306a36Sopenharmony_ci 417262306a36Sopenharmony_ci rc = btree_init32(&ha->host_map); 417362306a36Sopenharmony_ci if (rc) 417462306a36Sopenharmony_ci goto fail_free_init_cb; 417562306a36Sopenharmony_ci 417662306a36Sopenharmony_ci if (qlt_mem_alloc(ha) < 0) 417762306a36Sopenharmony_ci goto fail_free_btree; 417862306a36Sopenharmony_ci 417962306a36Sopenharmony_ci ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, 418062306a36Sopenharmony_ci qla2x00_gid_list_size(ha), &ha->gid_list_dma, GFP_KERNEL); 418162306a36Sopenharmony_ci if (!ha->gid_list) 418262306a36Sopenharmony_ci goto fail_free_tgt_mem; 418362306a36Sopenharmony_ci 418462306a36Sopenharmony_ci ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); 418562306a36Sopenharmony_ci if (!ha->srb_mempool) 418662306a36Sopenharmony_ci goto fail_free_gid_list; 418762306a36Sopenharmony_ci 418862306a36Sopenharmony_ci if (IS_P3P_TYPE(ha) || IS_QLA27XX(ha) || (ql2xsecenable && IS_QLA28XX(ha))) { 418962306a36Sopenharmony_ci /* Allocate cache for CT6 Ctx. */ 419062306a36Sopenharmony_ci if (!ctx_cachep) { 419162306a36Sopenharmony_ci ctx_cachep = kmem_cache_create("qla2xxx_ctx", 419262306a36Sopenharmony_ci sizeof(struct ct6_dsd), 0, 419362306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN, NULL); 419462306a36Sopenharmony_ci if (!ctx_cachep) 419562306a36Sopenharmony_ci goto fail_free_srb_mempool; 419662306a36Sopenharmony_ci } 419762306a36Sopenharmony_ci ha->ctx_mempool = mempool_create_slab_pool(SRB_MIN_REQ, 419862306a36Sopenharmony_ci ctx_cachep); 419962306a36Sopenharmony_ci if (!ha->ctx_mempool) 420062306a36Sopenharmony_ci goto fail_free_srb_mempool; 420162306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0021, 420262306a36Sopenharmony_ci "ctx_cachep=%p ctx_mempool=%p.\n", 420362306a36Sopenharmony_ci ctx_cachep, ha->ctx_mempool); 420462306a36Sopenharmony_ci } 420562306a36Sopenharmony_ci 420662306a36Sopenharmony_ci /* Get memory for cached NVRAM */ 420762306a36Sopenharmony_ci ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL); 420862306a36Sopenharmony_ci if (!ha->nvram) 420962306a36Sopenharmony_ci goto fail_free_ctx_mempool; 421062306a36Sopenharmony_ci 421162306a36Sopenharmony_ci snprintf(name, sizeof(name), "%s_%d", QLA2XXX_DRIVER_NAME, 421262306a36Sopenharmony_ci ha->pdev->device); 421362306a36Sopenharmony_ci ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev, 421462306a36Sopenharmony_ci DMA_POOL_SIZE, 8, 0); 421562306a36Sopenharmony_ci if (!ha->s_dma_pool) 421662306a36Sopenharmony_ci goto fail_free_nvram; 421762306a36Sopenharmony_ci 421862306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0022, 421962306a36Sopenharmony_ci "init_cb=%p gid_list=%p, srb_mempool=%p s_dma_pool=%p.\n", 422062306a36Sopenharmony_ci ha->init_cb, ha->gid_list, ha->srb_mempool, ha->s_dma_pool); 422162306a36Sopenharmony_ci 422262306a36Sopenharmony_ci if (IS_P3P_TYPE(ha) || ql2xenabledif || (IS_QLA28XX(ha) && ql2xsecenable)) { 422362306a36Sopenharmony_ci ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev, 422462306a36Sopenharmony_ci DSD_LIST_DMA_POOL_SIZE, 8, 0); 422562306a36Sopenharmony_ci if (!ha->dl_dma_pool) { 422662306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x0023, 422762306a36Sopenharmony_ci "Failed to allocate memory for dl_dma_pool.\n"); 422862306a36Sopenharmony_ci goto fail_s_dma_pool; 422962306a36Sopenharmony_ci } 423062306a36Sopenharmony_ci 423162306a36Sopenharmony_ci ha->fcp_cmnd_dma_pool = dma_pool_create(name, &ha->pdev->dev, 423262306a36Sopenharmony_ci FCP_CMND_DMA_POOL_SIZE, 8, 0); 423362306a36Sopenharmony_ci if (!ha->fcp_cmnd_dma_pool) { 423462306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x0024, 423562306a36Sopenharmony_ci "Failed to allocate memory for fcp_cmnd_dma_pool.\n"); 423662306a36Sopenharmony_ci goto fail_dl_dma_pool; 423762306a36Sopenharmony_ci } 423862306a36Sopenharmony_ci 423962306a36Sopenharmony_ci if (ql2xenabledif) { 424062306a36Sopenharmony_ci u64 bufsize = DIF_BUNDLING_DMA_POOL_SIZE; 424162306a36Sopenharmony_ci struct dsd_dma *dsd, *nxt; 424262306a36Sopenharmony_ci uint i; 424362306a36Sopenharmony_ci /* Creata a DMA pool of buffers for DIF bundling */ 424462306a36Sopenharmony_ci ha->dif_bundl_pool = dma_pool_create(name, 424562306a36Sopenharmony_ci &ha->pdev->dev, DIF_BUNDLING_DMA_POOL_SIZE, 8, 0); 424662306a36Sopenharmony_ci if (!ha->dif_bundl_pool) { 424762306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0024, 424862306a36Sopenharmony_ci "%s: failed create dif_bundl_pool\n", 424962306a36Sopenharmony_ci __func__); 425062306a36Sopenharmony_ci goto fail_dif_bundl_dma_pool; 425162306a36Sopenharmony_ci } 425262306a36Sopenharmony_ci 425362306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->pool.good.head); 425462306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->pool.unusable.head); 425562306a36Sopenharmony_ci ha->pool.good.count = 0; 425662306a36Sopenharmony_ci ha->pool.unusable.count = 0; 425762306a36Sopenharmony_ci for (i = 0; i < 128; i++) { 425862306a36Sopenharmony_ci dsd = kzalloc(sizeof(*dsd), GFP_ATOMIC); 425962306a36Sopenharmony_ci if (!dsd) { 426062306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 426162306a36Sopenharmony_ci 0xe0ee, "%s: failed alloc dsd\n", 426262306a36Sopenharmony_ci __func__); 426362306a36Sopenharmony_ci return -ENOMEM; 426462306a36Sopenharmony_ci } 426562306a36Sopenharmony_ci ha->dif_bundle_kallocs++; 426662306a36Sopenharmony_ci 426762306a36Sopenharmony_ci dsd->dsd_addr = dma_pool_alloc( 426862306a36Sopenharmony_ci ha->dif_bundl_pool, GFP_ATOMIC, 426962306a36Sopenharmony_ci &dsd->dsd_list_dma); 427062306a36Sopenharmony_ci if (!dsd->dsd_addr) { 427162306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 427262306a36Sopenharmony_ci 0xe0ee, 427362306a36Sopenharmony_ci "%s: failed alloc ->dsd_addr\n", 427462306a36Sopenharmony_ci __func__); 427562306a36Sopenharmony_ci kfree(dsd); 427662306a36Sopenharmony_ci ha->dif_bundle_kallocs--; 427762306a36Sopenharmony_ci continue; 427862306a36Sopenharmony_ci } 427962306a36Sopenharmony_ci ha->dif_bundle_dma_allocs++; 428062306a36Sopenharmony_ci 428162306a36Sopenharmony_ci /* 428262306a36Sopenharmony_ci * if DMA buffer crosses 4G boundary, 428362306a36Sopenharmony_ci * put it on bad list 428462306a36Sopenharmony_ci */ 428562306a36Sopenharmony_ci if (MSD(dsd->dsd_list_dma) ^ 428662306a36Sopenharmony_ci MSD(dsd->dsd_list_dma + bufsize)) { 428762306a36Sopenharmony_ci list_add_tail(&dsd->list, 428862306a36Sopenharmony_ci &ha->pool.unusable.head); 428962306a36Sopenharmony_ci ha->pool.unusable.count++; 429062306a36Sopenharmony_ci } else { 429162306a36Sopenharmony_ci list_add_tail(&dsd->list, 429262306a36Sopenharmony_ci &ha->pool.good.head); 429362306a36Sopenharmony_ci ha->pool.good.count++; 429462306a36Sopenharmony_ci } 429562306a36Sopenharmony_ci } 429662306a36Sopenharmony_ci 429762306a36Sopenharmony_ci /* return the good ones back to the pool */ 429862306a36Sopenharmony_ci list_for_each_entry_safe(dsd, nxt, 429962306a36Sopenharmony_ci &ha->pool.good.head, list) { 430062306a36Sopenharmony_ci list_del(&dsd->list); 430162306a36Sopenharmony_ci dma_pool_free(ha->dif_bundl_pool, 430262306a36Sopenharmony_ci dsd->dsd_addr, dsd->dsd_list_dma); 430362306a36Sopenharmony_ci ha->dif_bundle_dma_allocs--; 430462306a36Sopenharmony_ci kfree(dsd); 430562306a36Sopenharmony_ci ha->dif_bundle_kallocs--; 430662306a36Sopenharmony_ci } 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0024, 430962306a36Sopenharmony_ci "%s: dif dma pool (good=%u unusable=%u)\n", 431062306a36Sopenharmony_ci __func__, ha->pool.good.count, 431162306a36Sopenharmony_ci ha->pool.unusable.count); 431262306a36Sopenharmony_ci } 431362306a36Sopenharmony_ci 431462306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0025, 431562306a36Sopenharmony_ci "dl_dma_pool=%p fcp_cmnd_dma_pool=%p dif_bundl_pool=%p.\n", 431662306a36Sopenharmony_ci ha->dl_dma_pool, ha->fcp_cmnd_dma_pool, 431762306a36Sopenharmony_ci ha->dif_bundl_pool); 431862306a36Sopenharmony_ci } 431962306a36Sopenharmony_ci 432062306a36Sopenharmony_ci /* Allocate memory for SNS commands */ 432162306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)) { 432262306a36Sopenharmony_ci /* Get consistent memory allocated for SNS commands */ 432362306a36Sopenharmony_ci ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev, 432462306a36Sopenharmony_ci sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL); 432562306a36Sopenharmony_ci if (!ha->sns_cmd) 432662306a36Sopenharmony_ci goto fail_dma_pool; 432762306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0026, 432862306a36Sopenharmony_ci "sns_cmd: %p.\n", ha->sns_cmd); 432962306a36Sopenharmony_ci } else { 433062306a36Sopenharmony_ci /* Get consistent memory allocated for MS IOCB */ 433162306a36Sopenharmony_ci ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, 433262306a36Sopenharmony_ci &ha->ms_iocb_dma); 433362306a36Sopenharmony_ci if (!ha->ms_iocb) 433462306a36Sopenharmony_ci goto fail_dma_pool; 433562306a36Sopenharmony_ci /* Get consistent memory allocated for CT SNS commands */ 433662306a36Sopenharmony_ci ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev, 433762306a36Sopenharmony_ci sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL); 433862306a36Sopenharmony_ci if (!ha->ct_sns) 433962306a36Sopenharmony_ci goto fail_free_ms_iocb; 434062306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0027, 434162306a36Sopenharmony_ci "ms_iocb=%p ct_sns=%p.\n", 434262306a36Sopenharmony_ci ha->ms_iocb, ha->ct_sns); 434362306a36Sopenharmony_ci } 434462306a36Sopenharmony_ci 434562306a36Sopenharmony_ci /* Allocate memory for request ring */ 434662306a36Sopenharmony_ci *req = kzalloc(sizeof(struct req_que), GFP_KERNEL); 434762306a36Sopenharmony_ci if (!*req) { 434862306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x0028, 434962306a36Sopenharmony_ci "Failed to allocate memory for req.\n"); 435062306a36Sopenharmony_ci goto fail_req; 435162306a36Sopenharmony_ci } 435262306a36Sopenharmony_ci (*req)->length = req_len; 435362306a36Sopenharmony_ci (*req)->ring = dma_alloc_coherent(&ha->pdev->dev, 435462306a36Sopenharmony_ci ((*req)->length + 1) * sizeof(request_t), 435562306a36Sopenharmony_ci &(*req)->dma, GFP_KERNEL); 435662306a36Sopenharmony_ci if (!(*req)->ring) { 435762306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x0029, 435862306a36Sopenharmony_ci "Failed to allocate memory for req_ring.\n"); 435962306a36Sopenharmony_ci goto fail_req_ring; 436062306a36Sopenharmony_ci } 436162306a36Sopenharmony_ci /* Allocate memory for response ring */ 436262306a36Sopenharmony_ci *rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL); 436362306a36Sopenharmony_ci if (!*rsp) { 436462306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x002a, 436562306a36Sopenharmony_ci "Failed to allocate memory for rsp.\n"); 436662306a36Sopenharmony_ci goto fail_rsp; 436762306a36Sopenharmony_ci } 436862306a36Sopenharmony_ci (*rsp)->hw = ha; 436962306a36Sopenharmony_ci (*rsp)->length = rsp_len; 437062306a36Sopenharmony_ci (*rsp)->ring = dma_alloc_coherent(&ha->pdev->dev, 437162306a36Sopenharmony_ci ((*rsp)->length + 1) * sizeof(response_t), 437262306a36Sopenharmony_ci &(*rsp)->dma, GFP_KERNEL); 437362306a36Sopenharmony_ci if (!(*rsp)->ring) { 437462306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x002b, 437562306a36Sopenharmony_ci "Failed to allocate memory for rsp_ring.\n"); 437662306a36Sopenharmony_ci goto fail_rsp_ring; 437762306a36Sopenharmony_ci } 437862306a36Sopenharmony_ci (*req)->rsp = *rsp; 437962306a36Sopenharmony_ci (*rsp)->req = *req; 438062306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002c, 438162306a36Sopenharmony_ci "req=%p req->length=%d req->ring=%p rsp=%p " 438262306a36Sopenharmony_ci "rsp->length=%d rsp->ring=%p.\n", 438362306a36Sopenharmony_ci *req, (*req)->length, (*req)->ring, *rsp, (*rsp)->length, 438462306a36Sopenharmony_ci (*rsp)->ring); 438562306a36Sopenharmony_ci /* Allocate memory for NVRAM data for vports */ 438662306a36Sopenharmony_ci if (ha->nvram_npiv_size) { 438762306a36Sopenharmony_ci ha->npiv_info = kcalloc(ha->nvram_npiv_size, 438862306a36Sopenharmony_ci sizeof(struct qla_npiv_entry), 438962306a36Sopenharmony_ci GFP_KERNEL); 439062306a36Sopenharmony_ci if (!ha->npiv_info) { 439162306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x002d, 439262306a36Sopenharmony_ci "Failed to allocate memory for npiv_info.\n"); 439362306a36Sopenharmony_ci goto fail_npiv_info; 439462306a36Sopenharmony_ci } 439562306a36Sopenharmony_ci } else 439662306a36Sopenharmony_ci ha->npiv_info = NULL; 439762306a36Sopenharmony_ci 439862306a36Sopenharmony_ci /* Get consistent memory allocated for EX-INIT-CB. */ 439962306a36Sopenharmony_ci if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || 440062306a36Sopenharmony_ci IS_QLA28XX(ha)) { 440162306a36Sopenharmony_ci ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, 440262306a36Sopenharmony_ci &ha->ex_init_cb_dma); 440362306a36Sopenharmony_ci if (!ha->ex_init_cb) 440462306a36Sopenharmony_ci goto fail_ex_init_cb; 440562306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002e, 440662306a36Sopenharmony_ci "ex_init_cb=%p.\n", ha->ex_init_cb); 440762306a36Sopenharmony_ci } 440862306a36Sopenharmony_ci 440962306a36Sopenharmony_ci /* Get consistent memory allocated for Special Features-CB. */ 441062306a36Sopenharmony_ci if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { 441162306a36Sopenharmony_ci ha->sf_init_cb = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, 441262306a36Sopenharmony_ci &ha->sf_init_cb_dma); 441362306a36Sopenharmony_ci if (!ha->sf_init_cb) 441462306a36Sopenharmony_ci goto fail_sf_init_cb; 441562306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0199, 441662306a36Sopenharmony_ci "sf_init_cb=%p.\n", ha->sf_init_cb); 441762306a36Sopenharmony_ci } 441862306a36Sopenharmony_ci 441962306a36Sopenharmony_ci 442062306a36Sopenharmony_ci /* Get consistent memory allocated for Async Port-Database. */ 442162306a36Sopenharmony_ci if (!IS_FWI2_CAPABLE(ha)) { 442262306a36Sopenharmony_ci ha->async_pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, 442362306a36Sopenharmony_ci &ha->async_pd_dma); 442462306a36Sopenharmony_ci if (!ha->async_pd) 442562306a36Sopenharmony_ci goto fail_async_pd; 442662306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002f, 442762306a36Sopenharmony_ci "async_pd=%p.\n", ha->async_pd); 442862306a36Sopenharmony_ci } 442962306a36Sopenharmony_ci 443062306a36Sopenharmony_ci INIT_LIST_HEAD(&ha->vp_list); 443162306a36Sopenharmony_ci 443262306a36Sopenharmony_ci /* Allocate memory for our loop_id bitmap */ 443362306a36Sopenharmony_ci ha->loop_id_map = kcalloc(BITS_TO_LONGS(LOOPID_MAP_SIZE), 443462306a36Sopenharmony_ci sizeof(long), 443562306a36Sopenharmony_ci GFP_KERNEL); 443662306a36Sopenharmony_ci if (!ha->loop_id_map) 443762306a36Sopenharmony_ci goto fail_loop_id_map; 443862306a36Sopenharmony_ci else { 443962306a36Sopenharmony_ci qla2x00_set_reserved_loop_ids(ha); 444062306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0123, 444162306a36Sopenharmony_ci "loop_id_map=%p.\n", ha->loop_id_map); 444262306a36Sopenharmony_ci } 444362306a36Sopenharmony_ci 444462306a36Sopenharmony_ci ha->sfp_data = dma_alloc_coherent(&ha->pdev->dev, 444562306a36Sopenharmony_ci SFP_DEV_SIZE, &ha->sfp_data_dma, GFP_KERNEL); 444662306a36Sopenharmony_ci if (!ha->sfp_data) { 444762306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b, 444862306a36Sopenharmony_ci "Unable to allocate memory for SFP read-data.\n"); 444962306a36Sopenharmony_ci goto fail_sfp_data; 445062306a36Sopenharmony_ci } 445162306a36Sopenharmony_ci 445262306a36Sopenharmony_ci ha->flt = dma_alloc_coherent(&ha->pdev->dev, 445362306a36Sopenharmony_ci sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE, &ha->flt_dma, 445462306a36Sopenharmony_ci GFP_KERNEL); 445562306a36Sopenharmony_ci if (!ha->flt) { 445662306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b, 445762306a36Sopenharmony_ci "Unable to allocate memory for FLT.\n"); 445862306a36Sopenharmony_ci goto fail_flt_buffer; 445962306a36Sopenharmony_ci } 446062306a36Sopenharmony_ci 446162306a36Sopenharmony_ci /* allocate the purex dma pool */ 446262306a36Sopenharmony_ci ha->purex_dma_pool = dma_pool_create(name, &ha->pdev->dev, 446362306a36Sopenharmony_ci ELS_MAX_PAYLOAD, 8, 0); 446462306a36Sopenharmony_ci 446562306a36Sopenharmony_ci if (!ha->purex_dma_pool) { 446662306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b, 446762306a36Sopenharmony_ci "Unable to allocate purex_dma_pool.\n"); 446862306a36Sopenharmony_ci goto fail_flt; 446962306a36Sopenharmony_ci } 447062306a36Sopenharmony_ci 447162306a36Sopenharmony_ci ha->elsrej.size = sizeof(struct fc_els_ls_rjt) + 16; 447262306a36Sopenharmony_ci ha->elsrej.c = dma_alloc_coherent(&ha->pdev->dev, 447362306a36Sopenharmony_ci ha->elsrej.size, 447462306a36Sopenharmony_ci &ha->elsrej.cdma, 447562306a36Sopenharmony_ci GFP_KERNEL); 447662306a36Sopenharmony_ci if (!ha->elsrej.c) { 447762306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0xffff, 447862306a36Sopenharmony_ci "Alloc failed for els reject cmd.\n"); 447962306a36Sopenharmony_ci goto fail_elsrej; 448062306a36Sopenharmony_ci } 448162306a36Sopenharmony_ci ha->elsrej.c->er_cmd = ELS_LS_RJT; 448262306a36Sopenharmony_ci ha->elsrej.c->er_reason = ELS_RJT_LOGIC; 448362306a36Sopenharmony_ci ha->elsrej.c->er_explan = ELS_EXPL_UNAB_DATA; 448462306a36Sopenharmony_ci 448562306a36Sopenharmony_ci ha->lsrjt.size = sizeof(struct fcnvme_ls_rjt); 448662306a36Sopenharmony_ci ha->lsrjt.c = dma_alloc_coherent(&ha->pdev->dev, ha->lsrjt.size, 448762306a36Sopenharmony_ci &ha->lsrjt.cdma, GFP_KERNEL); 448862306a36Sopenharmony_ci if (!ha->lsrjt.c) { 448962306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0xffff, 449062306a36Sopenharmony_ci "Alloc failed for nvme fc reject cmd.\n"); 449162306a36Sopenharmony_ci goto fail_lsrjt; 449262306a36Sopenharmony_ci } 449362306a36Sopenharmony_ci 449462306a36Sopenharmony_ci return 0; 449562306a36Sopenharmony_ci 449662306a36Sopenharmony_cifail_lsrjt: 449762306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ha->elsrej.size, 449862306a36Sopenharmony_ci ha->elsrej.c, ha->elsrej.cdma); 449962306a36Sopenharmony_cifail_elsrej: 450062306a36Sopenharmony_ci dma_pool_destroy(ha->purex_dma_pool); 450162306a36Sopenharmony_cifail_flt: 450262306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, 450362306a36Sopenharmony_ci ha->flt, ha->flt_dma); 450462306a36Sopenharmony_ci 450562306a36Sopenharmony_cifail_flt_buffer: 450662306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, 450762306a36Sopenharmony_ci ha->sfp_data, ha->sfp_data_dma); 450862306a36Sopenharmony_cifail_sfp_data: 450962306a36Sopenharmony_ci kfree(ha->loop_id_map); 451062306a36Sopenharmony_cifail_loop_id_map: 451162306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma); 451262306a36Sopenharmony_cifail_async_pd: 451362306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, ha->sf_init_cb, ha->sf_init_cb_dma); 451462306a36Sopenharmony_cifail_sf_init_cb: 451562306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma); 451662306a36Sopenharmony_cifail_ex_init_cb: 451762306a36Sopenharmony_ci kfree(ha->npiv_info); 451862306a36Sopenharmony_cifail_npiv_info: 451962306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ((*rsp)->length + 1) * 452062306a36Sopenharmony_ci sizeof(response_t), (*rsp)->ring, (*rsp)->dma); 452162306a36Sopenharmony_ci (*rsp)->ring = NULL; 452262306a36Sopenharmony_ci (*rsp)->dma = 0; 452362306a36Sopenharmony_cifail_rsp_ring: 452462306a36Sopenharmony_ci kfree(*rsp); 452562306a36Sopenharmony_ci *rsp = NULL; 452662306a36Sopenharmony_cifail_rsp: 452762306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ((*req)->length + 1) * 452862306a36Sopenharmony_ci sizeof(request_t), (*req)->ring, (*req)->dma); 452962306a36Sopenharmony_ci (*req)->ring = NULL; 453062306a36Sopenharmony_ci (*req)->dma = 0; 453162306a36Sopenharmony_cifail_req_ring: 453262306a36Sopenharmony_ci kfree(*req); 453362306a36Sopenharmony_ci *req = NULL; 453462306a36Sopenharmony_cifail_req: 453562306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), 453662306a36Sopenharmony_ci ha->ct_sns, ha->ct_sns_dma); 453762306a36Sopenharmony_ci ha->ct_sns = NULL; 453862306a36Sopenharmony_ci ha->ct_sns_dma = 0; 453962306a36Sopenharmony_cifail_free_ms_iocb: 454062306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); 454162306a36Sopenharmony_ci ha->ms_iocb = NULL; 454262306a36Sopenharmony_ci ha->ms_iocb_dma = 0; 454362306a36Sopenharmony_ci 454462306a36Sopenharmony_ci if (ha->sns_cmd) 454562306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), 454662306a36Sopenharmony_ci ha->sns_cmd, ha->sns_cmd_dma); 454762306a36Sopenharmony_cifail_dma_pool: 454862306a36Sopenharmony_ci if (ql2xenabledif) { 454962306a36Sopenharmony_ci struct dsd_dma *dsd, *nxt; 455062306a36Sopenharmony_ci 455162306a36Sopenharmony_ci list_for_each_entry_safe(dsd, nxt, &ha->pool.unusable.head, 455262306a36Sopenharmony_ci list) { 455362306a36Sopenharmony_ci list_del(&dsd->list); 455462306a36Sopenharmony_ci dma_pool_free(ha->dif_bundl_pool, dsd->dsd_addr, 455562306a36Sopenharmony_ci dsd->dsd_list_dma); 455662306a36Sopenharmony_ci ha->dif_bundle_dma_allocs--; 455762306a36Sopenharmony_ci kfree(dsd); 455862306a36Sopenharmony_ci ha->dif_bundle_kallocs--; 455962306a36Sopenharmony_ci ha->pool.unusable.count--; 456062306a36Sopenharmony_ci } 456162306a36Sopenharmony_ci dma_pool_destroy(ha->dif_bundl_pool); 456262306a36Sopenharmony_ci ha->dif_bundl_pool = NULL; 456362306a36Sopenharmony_ci } 456462306a36Sopenharmony_ci 456562306a36Sopenharmony_cifail_dif_bundl_dma_pool: 456662306a36Sopenharmony_ci if (IS_QLA82XX(ha) || ql2xenabledif) { 456762306a36Sopenharmony_ci dma_pool_destroy(ha->fcp_cmnd_dma_pool); 456862306a36Sopenharmony_ci ha->fcp_cmnd_dma_pool = NULL; 456962306a36Sopenharmony_ci } 457062306a36Sopenharmony_cifail_dl_dma_pool: 457162306a36Sopenharmony_ci if (IS_QLA82XX(ha) || ql2xenabledif) { 457262306a36Sopenharmony_ci dma_pool_destroy(ha->dl_dma_pool); 457362306a36Sopenharmony_ci ha->dl_dma_pool = NULL; 457462306a36Sopenharmony_ci } 457562306a36Sopenharmony_cifail_s_dma_pool: 457662306a36Sopenharmony_ci dma_pool_destroy(ha->s_dma_pool); 457762306a36Sopenharmony_ci ha->s_dma_pool = NULL; 457862306a36Sopenharmony_cifail_free_nvram: 457962306a36Sopenharmony_ci kfree(ha->nvram); 458062306a36Sopenharmony_ci ha->nvram = NULL; 458162306a36Sopenharmony_cifail_free_ctx_mempool: 458262306a36Sopenharmony_ci mempool_destroy(ha->ctx_mempool); 458362306a36Sopenharmony_ci ha->ctx_mempool = NULL; 458462306a36Sopenharmony_cifail_free_srb_mempool: 458562306a36Sopenharmony_ci mempool_destroy(ha->srb_mempool); 458662306a36Sopenharmony_ci ha->srb_mempool = NULL; 458762306a36Sopenharmony_cifail_free_gid_list: 458862306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), 458962306a36Sopenharmony_ci ha->gid_list, 459062306a36Sopenharmony_ci ha->gid_list_dma); 459162306a36Sopenharmony_ci ha->gid_list = NULL; 459262306a36Sopenharmony_ci ha->gid_list_dma = 0; 459362306a36Sopenharmony_cifail_free_tgt_mem: 459462306a36Sopenharmony_ci qlt_mem_free(ha); 459562306a36Sopenharmony_cifail_free_btree: 459662306a36Sopenharmony_ci btree_destroy32(&ha->host_map); 459762306a36Sopenharmony_cifail_free_init_cb: 459862306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, 459962306a36Sopenharmony_ci ha->init_cb_dma); 460062306a36Sopenharmony_ci ha->init_cb = NULL; 460162306a36Sopenharmony_ci ha->init_cb_dma = 0; 460262306a36Sopenharmony_cifail_free_vp_map: 460362306a36Sopenharmony_ci kfree(ha->vp_map); 460462306a36Sopenharmony_cifail: 460562306a36Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0x0030, 460662306a36Sopenharmony_ci "Memory allocation failure.\n"); 460762306a36Sopenharmony_ci return -ENOMEM; 460862306a36Sopenharmony_ci} 460962306a36Sopenharmony_ci 461062306a36Sopenharmony_ciint 461162306a36Sopenharmony_ciqla2x00_set_exlogins_buffer(scsi_qla_host_t *vha) 461262306a36Sopenharmony_ci{ 461362306a36Sopenharmony_ci int rval; 461462306a36Sopenharmony_ci uint16_t size, max_cnt; 461562306a36Sopenharmony_ci uint32_t temp; 461662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 461762306a36Sopenharmony_ci 461862306a36Sopenharmony_ci /* Return if we don't need to alloacate any extended logins */ 461962306a36Sopenharmony_ci if (ql2xexlogins <= MAX_FIBRE_DEVICES_2400) 462062306a36Sopenharmony_ci return QLA_SUCCESS; 462162306a36Sopenharmony_ci 462262306a36Sopenharmony_ci if (!IS_EXLOGIN_OFFLD_CAPABLE(ha)) 462362306a36Sopenharmony_ci return QLA_SUCCESS; 462462306a36Sopenharmony_ci 462562306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xd021, "EXLOGIN count: %d.\n", ql2xexlogins); 462662306a36Sopenharmony_ci max_cnt = 0; 462762306a36Sopenharmony_ci rval = qla_get_exlogin_status(vha, &size, &max_cnt); 462862306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 462962306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0xd029, 463062306a36Sopenharmony_ci "Failed to get exlogin status.\n"); 463162306a36Sopenharmony_ci return rval; 463262306a36Sopenharmony_ci } 463362306a36Sopenharmony_ci 463462306a36Sopenharmony_ci temp = (ql2xexlogins > max_cnt) ? max_cnt : ql2xexlogins; 463562306a36Sopenharmony_ci temp *= size; 463662306a36Sopenharmony_ci 463762306a36Sopenharmony_ci if (temp != ha->exlogin_size) { 463862306a36Sopenharmony_ci qla2x00_free_exlogin_buffer(ha); 463962306a36Sopenharmony_ci ha->exlogin_size = temp; 464062306a36Sopenharmony_ci 464162306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xd024, 464262306a36Sopenharmony_ci "EXLOGIN: max_logins=%d, portdb=0x%x, total=%d.\n", 464362306a36Sopenharmony_ci max_cnt, size, temp); 464462306a36Sopenharmony_ci 464562306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xd025, 464662306a36Sopenharmony_ci "EXLOGIN: requested size=0x%x\n", ha->exlogin_size); 464762306a36Sopenharmony_ci 464862306a36Sopenharmony_ci /* Get consistent memory for extended logins */ 464962306a36Sopenharmony_ci ha->exlogin_buf = dma_alloc_coherent(&ha->pdev->dev, 465062306a36Sopenharmony_ci ha->exlogin_size, &ha->exlogin_buf_dma, GFP_KERNEL); 465162306a36Sopenharmony_ci if (!ha->exlogin_buf) { 465262306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0xd02a, 465362306a36Sopenharmony_ci "Failed to allocate memory for exlogin_buf_dma.\n"); 465462306a36Sopenharmony_ci return -ENOMEM; 465562306a36Sopenharmony_ci } 465662306a36Sopenharmony_ci } 465762306a36Sopenharmony_ci 465862306a36Sopenharmony_ci /* Now configure the dma buffer */ 465962306a36Sopenharmony_ci rval = qla_set_exlogin_mem_cfg(vha, ha->exlogin_buf_dma); 466062306a36Sopenharmony_ci if (rval) { 466162306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xd033, 466262306a36Sopenharmony_ci "Setup extended login buffer ****FAILED****.\n"); 466362306a36Sopenharmony_ci qla2x00_free_exlogin_buffer(ha); 466462306a36Sopenharmony_ci } 466562306a36Sopenharmony_ci 466662306a36Sopenharmony_ci return rval; 466762306a36Sopenharmony_ci} 466862306a36Sopenharmony_ci 466962306a36Sopenharmony_ci/* 467062306a36Sopenharmony_ci* qla2x00_free_exlogin_buffer 467162306a36Sopenharmony_ci* 467262306a36Sopenharmony_ci* Input: 467362306a36Sopenharmony_ci* ha = adapter block pointer 467462306a36Sopenharmony_ci*/ 467562306a36Sopenharmony_civoid 467662306a36Sopenharmony_ciqla2x00_free_exlogin_buffer(struct qla_hw_data *ha) 467762306a36Sopenharmony_ci{ 467862306a36Sopenharmony_ci if (ha->exlogin_buf) { 467962306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ha->exlogin_size, 468062306a36Sopenharmony_ci ha->exlogin_buf, ha->exlogin_buf_dma); 468162306a36Sopenharmony_ci ha->exlogin_buf = NULL; 468262306a36Sopenharmony_ci ha->exlogin_size = 0; 468362306a36Sopenharmony_ci } 468462306a36Sopenharmony_ci} 468562306a36Sopenharmony_ci 468662306a36Sopenharmony_cistatic void 468762306a36Sopenharmony_ciqla2x00_number_of_exch(scsi_qla_host_t *vha, u32 *ret_cnt, u16 max_cnt) 468862306a36Sopenharmony_ci{ 468962306a36Sopenharmony_ci u32 temp; 469062306a36Sopenharmony_ci struct init_cb_81xx *icb = (struct init_cb_81xx *)&vha->hw->init_cb; 469162306a36Sopenharmony_ci *ret_cnt = FW_DEF_EXCHANGES_CNT; 469262306a36Sopenharmony_ci 469362306a36Sopenharmony_ci if (max_cnt > vha->hw->max_exchg) 469462306a36Sopenharmony_ci max_cnt = vha->hw->max_exchg; 469562306a36Sopenharmony_ci 469662306a36Sopenharmony_ci if (qla_ini_mode_enabled(vha)) { 469762306a36Sopenharmony_ci if (vha->ql2xiniexchg > max_cnt) 469862306a36Sopenharmony_ci vha->ql2xiniexchg = max_cnt; 469962306a36Sopenharmony_ci 470062306a36Sopenharmony_ci if (vha->ql2xiniexchg > FW_DEF_EXCHANGES_CNT) 470162306a36Sopenharmony_ci *ret_cnt = vha->ql2xiniexchg; 470262306a36Sopenharmony_ci 470362306a36Sopenharmony_ci } else if (qla_tgt_mode_enabled(vha)) { 470462306a36Sopenharmony_ci if (vha->ql2xexchoffld > max_cnt) { 470562306a36Sopenharmony_ci vha->ql2xexchoffld = max_cnt; 470662306a36Sopenharmony_ci icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld); 470762306a36Sopenharmony_ci } 470862306a36Sopenharmony_ci 470962306a36Sopenharmony_ci if (vha->ql2xexchoffld > FW_DEF_EXCHANGES_CNT) 471062306a36Sopenharmony_ci *ret_cnt = vha->ql2xexchoffld; 471162306a36Sopenharmony_ci } else if (qla_dual_mode_enabled(vha)) { 471262306a36Sopenharmony_ci temp = vha->ql2xiniexchg + vha->ql2xexchoffld; 471362306a36Sopenharmony_ci if (temp > max_cnt) { 471462306a36Sopenharmony_ci vha->ql2xiniexchg -= (temp - max_cnt)/2; 471562306a36Sopenharmony_ci vha->ql2xexchoffld -= (((temp - max_cnt)/2) + 1); 471662306a36Sopenharmony_ci temp = max_cnt; 471762306a36Sopenharmony_ci icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld); 471862306a36Sopenharmony_ci } 471962306a36Sopenharmony_ci 472062306a36Sopenharmony_ci if (temp > FW_DEF_EXCHANGES_CNT) 472162306a36Sopenharmony_ci *ret_cnt = temp; 472262306a36Sopenharmony_ci } 472362306a36Sopenharmony_ci} 472462306a36Sopenharmony_ci 472562306a36Sopenharmony_ciint 472662306a36Sopenharmony_ciqla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha) 472762306a36Sopenharmony_ci{ 472862306a36Sopenharmony_ci int rval; 472962306a36Sopenharmony_ci u16 size, max_cnt; 473062306a36Sopenharmony_ci u32 actual_cnt, totsz; 473162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 473262306a36Sopenharmony_ci 473362306a36Sopenharmony_ci if (!ha->flags.exchoffld_enabled) 473462306a36Sopenharmony_ci return QLA_SUCCESS; 473562306a36Sopenharmony_ci 473662306a36Sopenharmony_ci if (!IS_EXCHG_OFFLD_CAPABLE(ha)) 473762306a36Sopenharmony_ci return QLA_SUCCESS; 473862306a36Sopenharmony_ci 473962306a36Sopenharmony_ci max_cnt = 0; 474062306a36Sopenharmony_ci rval = qla_get_exchoffld_status(vha, &size, &max_cnt); 474162306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 474262306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0xd012, 474362306a36Sopenharmony_ci "Failed to get exlogin status.\n"); 474462306a36Sopenharmony_ci return rval; 474562306a36Sopenharmony_ci } 474662306a36Sopenharmony_ci 474762306a36Sopenharmony_ci qla2x00_number_of_exch(vha, &actual_cnt, max_cnt); 474862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xd014, 474962306a36Sopenharmony_ci "Actual exchange offload count: %d.\n", actual_cnt); 475062306a36Sopenharmony_ci 475162306a36Sopenharmony_ci totsz = actual_cnt * size; 475262306a36Sopenharmony_ci 475362306a36Sopenharmony_ci if (totsz != ha->exchoffld_size) { 475462306a36Sopenharmony_ci qla2x00_free_exchoffld_buffer(ha); 475562306a36Sopenharmony_ci if (actual_cnt <= FW_DEF_EXCHANGES_CNT) { 475662306a36Sopenharmony_ci ha->exchoffld_size = 0; 475762306a36Sopenharmony_ci ha->flags.exchoffld_enabled = 0; 475862306a36Sopenharmony_ci return QLA_SUCCESS; 475962306a36Sopenharmony_ci } 476062306a36Sopenharmony_ci 476162306a36Sopenharmony_ci ha->exchoffld_size = totsz; 476262306a36Sopenharmony_ci 476362306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xd016, 476462306a36Sopenharmony_ci "Exchange offload: max_count=%d, actual count=%d entry sz=0x%x, total sz=0x%x\n", 476562306a36Sopenharmony_ci max_cnt, actual_cnt, size, totsz); 476662306a36Sopenharmony_ci 476762306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xd017, 476862306a36Sopenharmony_ci "Exchange Buffers requested size = 0x%x\n", 476962306a36Sopenharmony_ci ha->exchoffld_size); 477062306a36Sopenharmony_ci 477162306a36Sopenharmony_ci /* Get consistent memory for extended logins */ 477262306a36Sopenharmony_ci ha->exchoffld_buf = dma_alloc_coherent(&ha->pdev->dev, 477362306a36Sopenharmony_ci ha->exchoffld_size, &ha->exchoffld_buf_dma, GFP_KERNEL); 477462306a36Sopenharmony_ci if (!ha->exchoffld_buf) { 477562306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0xd013, 477662306a36Sopenharmony_ci "Failed to allocate memory for Exchange Offload.\n"); 477762306a36Sopenharmony_ci 477862306a36Sopenharmony_ci if (ha->max_exchg > 477962306a36Sopenharmony_ci (FW_DEF_EXCHANGES_CNT + REDUCE_EXCHANGES_CNT)) { 478062306a36Sopenharmony_ci ha->max_exchg -= REDUCE_EXCHANGES_CNT; 478162306a36Sopenharmony_ci } else if (ha->max_exchg > 478262306a36Sopenharmony_ci (FW_DEF_EXCHANGES_CNT + 512)) { 478362306a36Sopenharmony_ci ha->max_exchg -= 512; 478462306a36Sopenharmony_ci } else { 478562306a36Sopenharmony_ci ha->flags.exchoffld_enabled = 0; 478662306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0xd013, 478762306a36Sopenharmony_ci "Disabling Exchange offload due to lack of memory\n"); 478862306a36Sopenharmony_ci } 478962306a36Sopenharmony_ci ha->exchoffld_size = 0; 479062306a36Sopenharmony_ci 479162306a36Sopenharmony_ci return -ENOMEM; 479262306a36Sopenharmony_ci } 479362306a36Sopenharmony_ci } else if (!ha->exchoffld_buf || (actual_cnt <= FW_DEF_EXCHANGES_CNT)) { 479462306a36Sopenharmony_ci /* pathological case */ 479562306a36Sopenharmony_ci qla2x00_free_exchoffld_buffer(ha); 479662306a36Sopenharmony_ci ha->exchoffld_size = 0; 479762306a36Sopenharmony_ci ha->flags.exchoffld_enabled = 0; 479862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xd016, 479962306a36Sopenharmony_ci "Exchange offload not enable: offld size=%d, actual count=%d entry sz=0x%x, total sz=0x%x.\n", 480062306a36Sopenharmony_ci ha->exchoffld_size, actual_cnt, size, totsz); 480162306a36Sopenharmony_ci return 0; 480262306a36Sopenharmony_ci } 480362306a36Sopenharmony_ci 480462306a36Sopenharmony_ci /* Now configure the dma buffer */ 480562306a36Sopenharmony_ci rval = qla_set_exchoffld_mem_cfg(vha); 480662306a36Sopenharmony_ci if (rval) { 480762306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xd02e, 480862306a36Sopenharmony_ci "Setup exchange offload buffer ****FAILED****.\n"); 480962306a36Sopenharmony_ci qla2x00_free_exchoffld_buffer(ha); 481062306a36Sopenharmony_ci } else { 481162306a36Sopenharmony_ci /* re-adjust number of target exchange */ 481262306a36Sopenharmony_ci struct init_cb_81xx *icb = (struct init_cb_81xx *)ha->init_cb; 481362306a36Sopenharmony_ci 481462306a36Sopenharmony_ci if (qla_ini_mode_enabled(vha)) 481562306a36Sopenharmony_ci icb->exchange_count = 0; 481662306a36Sopenharmony_ci else 481762306a36Sopenharmony_ci icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld); 481862306a36Sopenharmony_ci } 481962306a36Sopenharmony_ci 482062306a36Sopenharmony_ci return rval; 482162306a36Sopenharmony_ci} 482262306a36Sopenharmony_ci 482362306a36Sopenharmony_ci/* 482462306a36Sopenharmony_ci* qla2x00_free_exchoffld_buffer 482562306a36Sopenharmony_ci* 482662306a36Sopenharmony_ci* Input: 482762306a36Sopenharmony_ci* ha = adapter block pointer 482862306a36Sopenharmony_ci*/ 482962306a36Sopenharmony_civoid 483062306a36Sopenharmony_ciqla2x00_free_exchoffld_buffer(struct qla_hw_data *ha) 483162306a36Sopenharmony_ci{ 483262306a36Sopenharmony_ci if (ha->exchoffld_buf) { 483362306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ha->exchoffld_size, 483462306a36Sopenharmony_ci ha->exchoffld_buf, ha->exchoffld_buf_dma); 483562306a36Sopenharmony_ci ha->exchoffld_buf = NULL; 483662306a36Sopenharmony_ci ha->exchoffld_size = 0; 483762306a36Sopenharmony_ci } 483862306a36Sopenharmony_ci} 483962306a36Sopenharmony_ci 484062306a36Sopenharmony_ci/* 484162306a36Sopenharmony_ci* qla2x00_free_fw_dump 484262306a36Sopenharmony_ci* Frees fw dump stuff. 484362306a36Sopenharmony_ci* 484462306a36Sopenharmony_ci* Input: 484562306a36Sopenharmony_ci* ha = adapter block pointer 484662306a36Sopenharmony_ci*/ 484762306a36Sopenharmony_cistatic void 484862306a36Sopenharmony_ciqla2x00_free_fw_dump(struct qla_hw_data *ha) 484962306a36Sopenharmony_ci{ 485062306a36Sopenharmony_ci struct fwdt *fwdt = ha->fwdt; 485162306a36Sopenharmony_ci uint j; 485262306a36Sopenharmony_ci 485362306a36Sopenharmony_ci if (ha->fce) 485462306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, 485562306a36Sopenharmony_ci FCE_SIZE, ha->fce, ha->fce_dma); 485662306a36Sopenharmony_ci 485762306a36Sopenharmony_ci if (ha->eft) 485862306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, 485962306a36Sopenharmony_ci EFT_SIZE, ha->eft, ha->eft_dma); 486062306a36Sopenharmony_ci 486162306a36Sopenharmony_ci vfree(ha->fw_dump); 486262306a36Sopenharmony_ci 486362306a36Sopenharmony_ci ha->fce = NULL; 486462306a36Sopenharmony_ci ha->fce_dma = 0; 486562306a36Sopenharmony_ci ha->flags.fce_enabled = 0; 486662306a36Sopenharmony_ci ha->eft = NULL; 486762306a36Sopenharmony_ci ha->eft_dma = 0; 486862306a36Sopenharmony_ci ha->fw_dumped = false; 486962306a36Sopenharmony_ci ha->fw_dump_cap_flags = 0; 487062306a36Sopenharmony_ci ha->fw_dump_reading = 0; 487162306a36Sopenharmony_ci ha->fw_dump = NULL; 487262306a36Sopenharmony_ci ha->fw_dump_len = 0; 487362306a36Sopenharmony_ci 487462306a36Sopenharmony_ci for (j = 0; j < 2; j++, fwdt++) { 487562306a36Sopenharmony_ci vfree(fwdt->template); 487662306a36Sopenharmony_ci fwdt->template = NULL; 487762306a36Sopenharmony_ci fwdt->length = 0; 487862306a36Sopenharmony_ci } 487962306a36Sopenharmony_ci} 488062306a36Sopenharmony_ci 488162306a36Sopenharmony_ci/* 488262306a36Sopenharmony_ci* qla2x00_mem_free 488362306a36Sopenharmony_ci* Frees all adapter allocated memory. 488462306a36Sopenharmony_ci* 488562306a36Sopenharmony_ci* Input: 488662306a36Sopenharmony_ci* ha = adapter block pointer. 488762306a36Sopenharmony_ci*/ 488862306a36Sopenharmony_cistatic void 488962306a36Sopenharmony_ciqla2x00_mem_free(struct qla_hw_data *ha) 489062306a36Sopenharmony_ci{ 489162306a36Sopenharmony_ci qla2x00_free_fw_dump(ha); 489262306a36Sopenharmony_ci 489362306a36Sopenharmony_ci if (ha->mctp_dump) 489462306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, MCTP_DUMP_SIZE, ha->mctp_dump, 489562306a36Sopenharmony_ci ha->mctp_dump_dma); 489662306a36Sopenharmony_ci ha->mctp_dump = NULL; 489762306a36Sopenharmony_ci 489862306a36Sopenharmony_ci mempool_destroy(ha->srb_mempool); 489962306a36Sopenharmony_ci ha->srb_mempool = NULL; 490062306a36Sopenharmony_ci 490162306a36Sopenharmony_ci if (ha->dcbx_tlv) 490262306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE, 490362306a36Sopenharmony_ci ha->dcbx_tlv, ha->dcbx_tlv_dma); 490462306a36Sopenharmony_ci ha->dcbx_tlv = NULL; 490562306a36Sopenharmony_ci 490662306a36Sopenharmony_ci if (ha->xgmac_data) 490762306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE, 490862306a36Sopenharmony_ci ha->xgmac_data, ha->xgmac_data_dma); 490962306a36Sopenharmony_ci ha->xgmac_data = NULL; 491062306a36Sopenharmony_ci 491162306a36Sopenharmony_ci if (ha->sns_cmd) 491262306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), 491362306a36Sopenharmony_ci ha->sns_cmd, ha->sns_cmd_dma); 491462306a36Sopenharmony_ci ha->sns_cmd = NULL; 491562306a36Sopenharmony_ci ha->sns_cmd_dma = 0; 491662306a36Sopenharmony_ci 491762306a36Sopenharmony_ci if (ha->ct_sns) 491862306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), 491962306a36Sopenharmony_ci ha->ct_sns, ha->ct_sns_dma); 492062306a36Sopenharmony_ci ha->ct_sns = NULL; 492162306a36Sopenharmony_ci ha->ct_sns_dma = 0; 492262306a36Sopenharmony_ci 492362306a36Sopenharmony_ci if (ha->sfp_data) 492462306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, ha->sfp_data, 492562306a36Sopenharmony_ci ha->sfp_data_dma); 492662306a36Sopenharmony_ci ha->sfp_data = NULL; 492762306a36Sopenharmony_ci 492862306a36Sopenharmony_ci if (ha->flt) 492962306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, 493062306a36Sopenharmony_ci sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE, 493162306a36Sopenharmony_ci ha->flt, ha->flt_dma); 493262306a36Sopenharmony_ci ha->flt = NULL; 493362306a36Sopenharmony_ci ha->flt_dma = 0; 493462306a36Sopenharmony_ci 493562306a36Sopenharmony_ci if (ha->ms_iocb) 493662306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); 493762306a36Sopenharmony_ci ha->ms_iocb = NULL; 493862306a36Sopenharmony_ci ha->ms_iocb_dma = 0; 493962306a36Sopenharmony_ci 494062306a36Sopenharmony_ci if (ha->sf_init_cb) 494162306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, 494262306a36Sopenharmony_ci ha->sf_init_cb, ha->sf_init_cb_dma); 494362306a36Sopenharmony_ci 494462306a36Sopenharmony_ci if (ha->ex_init_cb) 494562306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, 494662306a36Sopenharmony_ci ha->ex_init_cb, ha->ex_init_cb_dma); 494762306a36Sopenharmony_ci ha->ex_init_cb = NULL; 494862306a36Sopenharmony_ci ha->ex_init_cb_dma = 0; 494962306a36Sopenharmony_ci 495062306a36Sopenharmony_ci if (ha->async_pd) 495162306a36Sopenharmony_ci dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma); 495262306a36Sopenharmony_ci ha->async_pd = NULL; 495362306a36Sopenharmony_ci ha->async_pd_dma = 0; 495462306a36Sopenharmony_ci 495562306a36Sopenharmony_ci dma_pool_destroy(ha->s_dma_pool); 495662306a36Sopenharmony_ci ha->s_dma_pool = NULL; 495762306a36Sopenharmony_ci 495862306a36Sopenharmony_ci if (ha->gid_list) 495962306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), 496062306a36Sopenharmony_ci ha->gid_list, ha->gid_list_dma); 496162306a36Sopenharmony_ci ha->gid_list = NULL; 496262306a36Sopenharmony_ci ha->gid_list_dma = 0; 496362306a36Sopenharmony_ci 496462306a36Sopenharmony_ci if (ha->base_qpair && !list_empty(&ha->base_qpair->dsd_list)) { 496562306a36Sopenharmony_ci struct dsd_dma *dsd_ptr, *tdsd_ptr; 496662306a36Sopenharmony_ci 496762306a36Sopenharmony_ci /* clean up allocated prev pool */ 496862306a36Sopenharmony_ci list_for_each_entry_safe(dsd_ptr, tdsd_ptr, 496962306a36Sopenharmony_ci &ha->base_qpair->dsd_list, list) { 497062306a36Sopenharmony_ci dma_pool_free(ha->dl_dma_pool, dsd_ptr->dsd_addr, 497162306a36Sopenharmony_ci dsd_ptr->dsd_list_dma); 497262306a36Sopenharmony_ci list_del(&dsd_ptr->list); 497362306a36Sopenharmony_ci kfree(dsd_ptr); 497462306a36Sopenharmony_ci } 497562306a36Sopenharmony_ci } 497662306a36Sopenharmony_ci 497762306a36Sopenharmony_ci dma_pool_destroy(ha->dl_dma_pool); 497862306a36Sopenharmony_ci ha->dl_dma_pool = NULL; 497962306a36Sopenharmony_ci 498062306a36Sopenharmony_ci dma_pool_destroy(ha->fcp_cmnd_dma_pool); 498162306a36Sopenharmony_ci ha->fcp_cmnd_dma_pool = NULL; 498262306a36Sopenharmony_ci 498362306a36Sopenharmony_ci mempool_destroy(ha->ctx_mempool); 498462306a36Sopenharmony_ci ha->ctx_mempool = NULL; 498562306a36Sopenharmony_ci 498662306a36Sopenharmony_ci if (ql2xenabledif && ha->dif_bundl_pool) { 498762306a36Sopenharmony_ci struct dsd_dma *dsd, *nxt; 498862306a36Sopenharmony_ci 498962306a36Sopenharmony_ci list_for_each_entry_safe(dsd, nxt, &ha->pool.unusable.head, 499062306a36Sopenharmony_ci list) { 499162306a36Sopenharmony_ci list_del(&dsd->list); 499262306a36Sopenharmony_ci dma_pool_free(ha->dif_bundl_pool, dsd->dsd_addr, 499362306a36Sopenharmony_ci dsd->dsd_list_dma); 499462306a36Sopenharmony_ci ha->dif_bundle_dma_allocs--; 499562306a36Sopenharmony_ci kfree(dsd); 499662306a36Sopenharmony_ci ha->dif_bundle_kallocs--; 499762306a36Sopenharmony_ci ha->pool.unusable.count--; 499862306a36Sopenharmony_ci } 499962306a36Sopenharmony_ci list_for_each_entry_safe(dsd, nxt, &ha->pool.good.head, list) { 500062306a36Sopenharmony_ci list_del(&dsd->list); 500162306a36Sopenharmony_ci dma_pool_free(ha->dif_bundl_pool, dsd->dsd_addr, 500262306a36Sopenharmony_ci dsd->dsd_list_dma); 500362306a36Sopenharmony_ci ha->dif_bundle_dma_allocs--; 500462306a36Sopenharmony_ci kfree(dsd); 500562306a36Sopenharmony_ci ha->dif_bundle_kallocs--; 500662306a36Sopenharmony_ci } 500762306a36Sopenharmony_ci } 500862306a36Sopenharmony_ci 500962306a36Sopenharmony_ci dma_pool_destroy(ha->dif_bundl_pool); 501062306a36Sopenharmony_ci ha->dif_bundl_pool = NULL; 501162306a36Sopenharmony_ci 501262306a36Sopenharmony_ci qlt_mem_free(ha); 501362306a36Sopenharmony_ci qla_remove_hostmap(ha); 501462306a36Sopenharmony_ci 501562306a36Sopenharmony_ci if (ha->init_cb) 501662306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, 501762306a36Sopenharmony_ci ha->init_cb, ha->init_cb_dma); 501862306a36Sopenharmony_ci 501962306a36Sopenharmony_ci dma_pool_destroy(ha->purex_dma_pool); 502062306a36Sopenharmony_ci ha->purex_dma_pool = NULL; 502162306a36Sopenharmony_ci 502262306a36Sopenharmony_ci if (ha->elsrej.c) { 502362306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ha->elsrej.size, 502462306a36Sopenharmony_ci ha->elsrej.c, ha->elsrej.cdma); 502562306a36Sopenharmony_ci ha->elsrej.c = NULL; 502662306a36Sopenharmony_ci } 502762306a36Sopenharmony_ci 502862306a36Sopenharmony_ci if (ha->lsrjt.c) { 502962306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ha->lsrjt.size, ha->lsrjt.c, 503062306a36Sopenharmony_ci ha->lsrjt.cdma); 503162306a36Sopenharmony_ci ha->lsrjt.c = NULL; 503262306a36Sopenharmony_ci } 503362306a36Sopenharmony_ci 503462306a36Sopenharmony_ci ha->init_cb = NULL; 503562306a36Sopenharmony_ci ha->init_cb_dma = 0; 503662306a36Sopenharmony_ci 503762306a36Sopenharmony_ci vfree(ha->optrom_buffer); 503862306a36Sopenharmony_ci ha->optrom_buffer = NULL; 503962306a36Sopenharmony_ci kfree(ha->nvram); 504062306a36Sopenharmony_ci ha->nvram = NULL; 504162306a36Sopenharmony_ci kfree(ha->npiv_info); 504262306a36Sopenharmony_ci ha->npiv_info = NULL; 504362306a36Sopenharmony_ci kfree(ha->swl); 504462306a36Sopenharmony_ci ha->swl = NULL; 504562306a36Sopenharmony_ci kfree(ha->loop_id_map); 504662306a36Sopenharmony_ci ha->sf_init_cb = NULL; 504762306a36Sopenharmony_ci ha->sf_init_cb_dma = 0; 504862306a36Sopenharmony_ci ha->loop_id_map = NULL; 504962306a36Sopenharmony_ci 505062306a36Sopenharmony_ci kfree(ha->vp_map); 505162306a36Sopenharmony_ci ha->vp_map = NULL; 505262306a36Sopenharmony_ci} 505362306a36Sopenharmony_ci 505462306a36Sopenharmony_cistruct scsi_qla_host *qla2x00_create_host(const struct scsi_host_template *sht, 505562306a36Sopenharmony_ci struct qla_hw_data *ha) 505662306a36Sopenharmony_ci{ 505762306a36Sopenharmony_ci struct Scsi_Host *host; 505862306a36Sopenharmony_ci struct scsi_qla_host *vha = NULL; 505962306a36Sopenharmony_ci 506062306a36Sopenharmony_ci host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t)); 506162306a36Sopenharmony_ci if (!host) { 506262306a36Sopenharmony_ci ql_log_pci(ql_log_fatal, ha->pdev, 0x0107, 506362306a36Sopenharmony_ci "Failed to allocate host from the scsi layer, aborting.\n"); 506462306a36Sopenharmony_ci return NULL; 506562306a36Sopenharmony_ci } 506662306a36Sopenharmony_ci 506762306a36Sopenharmony_ci /* Clear our data area */ 506862306a36Sopenharmony_ci vha = shost_priv(host); 506962306a36Sopenharmony_ci memset(vha, 0, sizeof(scsi_qla_host_t)); 507062306a36Sopenharmony_ci 507162306a36Sopenharmony_ci vha->host = host; 507262306a36Sopenharmony_ci vha->host_no = host->host_no; 507362306a36Sopenharmony_ci vha->hw = ha; 507462306a36Sopenharmony_ci 507562306a36Sopenharmony_ci vha->qlini_mode = ql2x_ini_mode; 507662306a36Sopenharmony_ci vha->ql2xexchoffld = ql2xexchoffld; 507762306a36Sopenharmony_ci vha->ql2xiniexchg = ql2xiniexchg; 507862306a36Sopenharmony_ci 507962306a36Sopenharmony_ci INIT_LIST_HEAD(&vha->vp_fcports); 508062306a36Sopenharmony_ci INIT_LIST_HEAD(&vha->work_list); 508162306a36Sopenharmony_ci INIT_LIST_HEAD(&vha->list); 508262306a36Sopenharmony_ci INIT_LIST_HEAD(&vha->qla_cmd_list); 508362306a36Sopenharmony_ci INIT_LIST_HEAD(&vha->logo_list); 508462306a36Sopenharmony_ci INIT_LIST_HEAD(&vha->plogi_ack_list); 508562306a36Sopenharmony_ci INIT_LIST_HEAD(&vha->qp_list); 508662306a36Sopenharmony_ci INIT_LIST_HEAD(&vha->gnl.fcports); 508762306a36Sopenharmony_ci INIT_WORK(&vha->iocb_work, qla2x00_iocb_work_fn); 508862306a36Sopenharmony_ci 508962306a36Sopenharmony_ci INIT_LIST_HEAD(&vha->purex_list.head); 509062306a36Sopenharmony_ci spin_lock_init(&vha->purex_list.lock); 509162306a36Sopenharmony_ci 509262306a36Sopenharmony_ci spin_lock_init(&vha->work_lock); 509362306a36Sopenharmony_ci spin_lock_init(&vha->cmd_list_lock); 509462306a36Sopenharmony_ci init_waitqueue_head(&vha->fcport_waitQ); 509562306a36Sopenharmony_ci init_waitqueue_head(&vha->vref_waitq); 509662306a36Sopenharmony_ci qla_enode_init(vha); 509762306a36Sopenharmony_ci qla_edb_init(vha); 509862306a36Sopenharmony_ci 509962306a36Sopenharmony_ci 510062306a36Sopenharmony_ci vha->gnl.size = sizeof(struct get_name_list_extended) * 510162306a36Sopenharmony_ci (ha->max_loop_id + 1); 510262306a36Sopenharmony_ci vha->gnl.l = dma_alloc_coherent(&ha->pdev->dev, 510362306a36Sopenharmony_ci vha->gnl.size, &vha->gnl.ldma, GFP_KERNEL); 510462306a36Sopenharmony_ci if (!vha->gnl.l) { 510562306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xd04a, 510662306a36Sopenharmony_ci "Alloc failed for name list.\n"); 510762306a36Sopenharmony_ci scsi_host_put(vha->host); 510862306a36Sopenharmony_ci return NULL; 510962306a36Sopenharmony_ci } 511062306a36Sopenharmony_ci 511162306a36Sopenharmony_ci /* todo: what about ext login? */ 511262306a36Sopenharmony_ci vha->scan.size = ha->max_fibre_devices * sizeof(struct fab_scan_rp); 511362306a36Sopenharmony_ci vha->scan.l = vmalloc(vha->scan.size); 511462306a36Sopenharmony_ci if (!vha->scan.l) { 511562306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xd04a, 511662306a36Sopenharmony_ci "Alloc failed for scan database.\n"); 511762306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, vha->gnl.size, 511862306a36Sopenharmony_ci vha->gnl.l, vha->gnl.ldma); 511962306a36Sopenharmony_ci vha->gnl.l = NULL; 512062306a36Sopenharmony_ci scsi_host_put(vha->host); 512162306a36Sopenharmony_ci return NULL; 512262306a36Sopenharmony_ci } 512362306a36Sopenharmony_ci INIT_DELAYED_WORK(&vha->scan.scan_work, qla_scan_work_fn); 512462306a36Sopenharmony_ci 512562306a36Sopenharmony_ci snprintf(vha->host_str, sizeof(vha->host_str), "%s_%lu", 512662306a36Sopenharmony_ci QLA2XXX_DRIVER_NAME, vha->host_no); 512762306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0041, 512862306a36Sopenharmony_ci "Allocated the host=%p hw=%p vha=%p dev_name=%s", 512962306a36Sopenharmony_ci vha->host, vha->hw, vha, 513062306a36Sopenharmony_ci dev_name(&(ha->pdev->dev))); 513162306a36Sopenharmony_ci 513262306a36Sopenharmony_ci return vha; 513362306a36Sopenharmony_ci} 513462306a36Sopenharmony_ci 513562306a36Sopenharmony_cistruct qla_work_evt * 513662306a36Sopenharmony_ciqla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type) 513762306a36Sopenharmony_ci{ 513862306a36Sopenharmony_ci struct qla_work_evt *e; 513962306a36Sopenharmony_ci 514062306a36Sopenharmony_ci if (test_bit(UNLOADING, &vha->dpc_flags)) 514162306a36Sopenharmony_ci return NULL; 514262306a36Sopenharmony_ci 514362306a36Sopenharmony_ci if (qla_vha_mark_busy(vha)) 514462306a36Sopenharmony_ci return NULL; 514562306a36Sopenharmony_ci 514662306a36Sopenharmony_ci e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC); 514762306a36Sopenharmony_ci if (!e) { 514862306a36Sopenharmony_ci QLA_VHA_MARK_NOT_BUSY(vha); 514962306a36Sopenharmony_ci return NULL; 515062306a36Sopenharmony_ci } 515162306a36Sopenharmony_ci 515262306a36Sopenharmony_ci INIT_LIST_HEAD(&e->list); 515362306a36Sopenharmony_ci e->type = type; 515462306a36Sopenharmony_ci e->flags = QLA_EVT_FLAG_FREE; 515562306a36Sopenharmony_ci return e; 515662306a36Sopenharmony_ci} 515762306a36Sopenharmony_ci 515862306a36Sopenharmony_ciint 515962306a36Sopenharmony_ciqla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e) 516062306a36Sopenharmony_ci{ 516162306a36Sopenharmony_ci unsigned long flags; 516262306a36Sopenharmony_ci bool q = false; 516362306a36Sopenharmony_ci 516462306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 516562306a36Sopenharmony_ci list_add_tail(&e->list, &vha->work_list); 516662306a36Sopenharmony_ci 516762306a36Sopenharmony_ci if (!test_and_set_bit(IOCB_WORK_ACTIVE, &vha->dpc_flags)) 516862306a36Sopenharmony_ci q = true; 516962306a36Sopenharmony_ci 517062306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 517162306a36Sopenharmony_ci 517262306a36Sopenharmony_ci if (q) 517362306a36Sopenharmony_ci queue_work(vha->hw->wq, &vha->iocb_work); 517462306a36Sopenharmony_ci 517562306a36Sopenharmony_ci return QLA_SUCCESS; 517662306a36Sopenharmony_ci} 517762306a36Sopenharmony_ci 517862306a36Sopenharmony_ciint 517962306a36Sopenharmony_ciqla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code, 518062306a36Sopenharmony_ci u32 data) 518162306a36Sopenharmony_ci{ 518262306a36Sopenharmony_ci struct qla_work_evt *e; 518362306a36Sopenharmony_ci 518462306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_AEN); 518562306a36Sopenharmony_ci if (!e) 518662306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 518762306a36Sopenharmony_ci 518862306a36Sopenharmony_ci e->u.aen.code = code; 518962306a36Sopenharmony_ci e->u.aen.data = data; 519062306a36Sopenharmony_ci return qla2x00_post_work(vha, e); 519162306a36Sopenharmony_ci} 519262306a36Sopenharmony_ci 519362306a36Sopenharmony_ciint 519462306a36Sopenharmony_ciqla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb) 519562306a36Sopenharmony_ci{ 519662306a36Sopenharmony_ci struct qla_work_evt *e; 519762306a36Sopenharmony_ci 519862306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK); 519962306a36Sopenharmony_ci if (!e) 520062306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 520162306a36Sopenharmony_ci 520262306a36Sopenharmony_ci memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t)); 520362306a36Sopenharmony_ci return qla2x00_post_work(vha, e); 520462306a36Sopenharmony_ci} 520562306a36Sopenharmony_ci 520662306a36Sopenharmony_ci#define qla2x00_post_async_work(name, type) \ 520762306a36Sopenharmony_ciint qla2x00_post_async_##name##_work( \ 520862306a36Sopenharmony_ci struct scsi_qla_host *vha, \ 520962306a36Sopenharmony_ci fc_port_t *fcport, uint16_t *data) \ 521062306a36Sopenharmony_ci{ \ 521162306a36Sopenharmony_ci struct qla_work_evt *e; \ 521262306a36Sopenharmony_ci \ 521362306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, type); \ 521462306a36Sopenharmony_ci if (!e) \ 521562306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; \ 521662306a36Sopenharmony_ci \ 521762306a36Sopenharmony_ci e->u.logio.fcport = fcport; \ 521862306a36Sopenharmony_ci if (data) { \ 521962306a36Sopenharmony_ci e->u.logio.data[0] = data[0]; \ 522062306a36Sopenharmony_ci e->u.logio.data[1] = data[1]; \ 522162306a36Sopenharmony_ci } \ 522262306a36Sopenharmony_ci fcport->flags |= FCF_ASYNC_ACTIVE; \ 522362306a36Sopenharmony_ci return qla2x00_post_work(vha, e); \ 522462306a36Sopenharmony_ci} 522562306a36Sopenharmony_ci 522662306a36Sopenharmony_ciqla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN); 522762306a36Sopenharmony_ciqla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT); 522862306a36Sopenharmony_ciqla2x00_post_async_work(adisc, QLA_EVT_ASYNC_ADISC); 522962306a36Sopenharmony_ciqla2x00_post_async_work(prlo, QLA_EVT_ASYNC_PRLO); 523062306a36Sopenharmony_ciqla2x00_post_async_work(prlo_done, QLA_EVT_ASYNC_PRLO_DONE); 523162306a36Sopenharmony_ci 523262306a36Sopenharmony_ciint 523362306a36Sopenharmony_ciqla2x00_post_uevent_work(struct scsi_qla_host *vha, u32 code) 523462306a36Sopenharmony_ci{ 523562306a36Sopenharmony_ci struct qla_work_evt *e; 523662306a36Sopenharmony_ci 523762306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_UEVENT); 523862306a36Sopenharmony_ci if (!e) 523962306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 524062306a36Sopenharmony_ci 524162306a36Sopenharmony_ci e->u.uevent.code = code; 524262306a36Sopenharmony_ci return qla2x00_post_work(vha, e); 524362306a36Sopenharmony_ci} 524462306a36Sopenharmony_ci 524562306a36Sopenharmony_cistatic void 524662306a36Sopenharmony_ciqla2x00_uevent_emit(struct scsi_qla_host *vha, u32 code) 524762306a36Sopenharmony_ci{ 524862306a36Sopenharmony_ci char event_string[40]; 524962306a36Sopenharmony_ci char *envp[] = { event_string, NULL }; 525062306a36Sopenharmony_ci 525162306a36Sopenharmony_ci switch (code) { 525262306a36Sopenharmony_ci case QLA_UEVENT_CODE_FW_DUMP: 525362306a36Sopenharmony_ci snprintf(event_string, sizeof(event_string), "FW_DUMP=%lu", 525462306a36Sopenharmony_ci vha->host_no); 525562306a36Sopenharmony_ci break; 525662306a36Sopenharmony_ci default: 525762306a36Sopenharmony_ci /* do nothing */ 525862306a36Sopenharmony_ci break; 525962306a36Sopenharmony_ci } 526062306a36Sopenharmony_ci kobject_uevent_env(&vha->hw->pdev->dev.kobj, KOBJ_CHANGE, envp); 526162306a36Sopenharmony_ci} 526262306a36Sopenharmony_ci 526362306a36Sopenharmony_ciint 526462306a36Sopenharmony_ciqlafx00_post_aenfx_work(struct scsi_qla_host *vha, uint32_t evtcode, 526562306a36Sopenharmony_ci uint32_t *data, int cnt) 526662306a36Sopenharmony_ci{ 526762306a36Sopenharmony_ci struct qla_work_evt *e; 526862306a36Sopenharmony_ci 526962306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_AENFX); 527062306a36Sopenharmony_ci if (!e) 527162306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 527262306a36Sopenharmony_ci 527362306a36Sopenharmony_ci e->u.aenfx.evtcode = evtcode; 527462306a36Sopenharmony_ci e->u.aenfx.count = cnt; 527562306a36Sopenharmony_ci memcpy(e->u.aenfx.mbx, data, sizeof(*data) * cnt); 527662306a36Sopenharmony_ci return qla2x00_post_work(vha, e); 527762306a36Sopenharmony_ci} 527862306a36Sopenharmony_ci 527962306a36Sopenharmony_civoid qla24xx_sched_upd_fcport(fc_port_t *fcport) 528062306a36Sopenharmony_ci{ 528162306a36Sopenharmony_ci unsigned long flags; 528262306a36Sopenharmony_ci 528362306a36Sopenharmony_ci if (IS_SW_RESV_ADDR(fcport->d_id)) 528462306a36Sopenharmony_ci return; 528562306a36Sopenharmony_ci 528662306a36Sopenharmony_ci spin_lock_irqsave(&fcport->vha->work_lock, flags); 528762306a36Sopenharmony_ci if (fcport->disc_state == DSC_UPD_FCPORT) { 528862306a36Sopenharmony_ci spin_unlock_irqrestore(&fcport->vha->work_lock, flags); 528962306a36Sopenharmony_ci return; 529062306a36Sopenharmony_ci } 529162306a36Sopenharmony_ci fcport->jiffies_at_registration = jiffies; 529262306a36Sopenharmony_ci fcport->sec_since_registration = 0; 529362306a36Sopenharmony_ci fcport->next_disc_state = DSC_DELETED; 529462306a36Sopenharmony_ci qla2x00_set_fcport_disc_state(fcport, DSC_UPD_FCPORT); 529562306a36Sopenharmony_ci spin_unlock_irqrestore(&fcport->vha->work_lock, flags); 529662306a36Sopenharmony_ci 529762306a36Sopenharmony_ci queue_work(system_unbound_wq, &fcport->reg_work); 529862306a36Sopenharmony_ci} 529962306a36Sopenharmony_ci 530062306a36Sopenharmony_cistatic 530162306a36Sopenharmony_civoid qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) 530262306a36Sopenharmony_ci{ 530362306a36Sopenharmony_ci unsigned long flags; 530462306a36Sopenharmony_ci fc_port_t *fcport = NULL, *tfcp; 530562306a36Sopenharmony_ci struct qlt_plogi_ack_t *pla = 530662306a36Sopenharmony_ci (struct qlt_plogi_ack_t *)e->u.new_sess.pla; 530762306a36Sopenharmony_ci uint8_t free_fcport = 0; 530862306a36Sopenharmony_ci 530962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 531062306a36Sopenharmony_ci "%s %d %8phC enter\n", 531162306a36Sopenharmony_ci __func__, __LINE__, e->u.new_sess.port_name); 531262306a36Sopenharmony_ci 531362306a36Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 531462306a36Sopenharmony_ci fcport = qla2x00_find_fcport_by_wwpn(vha, e->u.new_sess.port_name, 1); 531562306a36Sopenharmony_ci if (fcport) { 531662306a36Sopenharmony_ci fcport->d_id = e->u.new_sess.id; 531762306a36Sopenharmony_ci if (pla) { 531862306a36Sopenharmony_ci fcport->fw_login_state = DSC_LS_PLOGI_PEND; 531962306a36Sopenharmony_ci memcpy(fcport->node_name, 532062306a36Sopenharmony_ci pla->iocb.u.isp24.u.plogi.node_name, 532162306a36Sopenharmony_ci WWN_SIZE); 532262306a36Sopenharmony_ci qlt_plogi_ack_link(vha, pla, fcport, QLT_PLOGI_LINK_SAME_WWN); 532362306a36Sopenharmony_ci /* we took an extra ref_count to prevent PLOGI ACK when 532462306a36Sopenharmony_ci * fcport/sess has not been created. 532562306a36Sopenharmony_ci */ 532662306a36Sopenharmony_ci pla->ref_count--; 532762306a36Sopenharmony_ci } 532862306a36Sopenharmony_ci } else { 532962306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 533062306a36Sopenharmony_ci fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); 533162306a36Sopenharmony_ci if (fcport) { 533262306a36Sopenharmony_ci fcport->d_id = e->u.new_sess.id; 533362306a36Sopenharmony_ci fcport->flags |= FCF_FABRIC_DEVICE; 533462306a36Sopenharmony_ci fcport->fw_login_state = DSC_LS_PLOGI_PEND; 533562306a36Sopenharmony_ci fcport->tgt_short_link_down_cnt = 0; 533662306a36Sopenharmony_ci 533762306a36Sopenharmony_ci memcpy(fcport->port_name, e->u.new_sess.port_name, 533862306a36Sopenharmony_ci WWN_SIZE); 533962306a36Sopenharmony_ci 534062306a36Sopenharmony_ci fcport->fc4_type = e->u.new_sess.fc4_type; 534162306a36Sopenharmony_ci if (NVME_PRIORITY(vha->hw, fcport)) 534262306a36Sopenharmony_ci fcport->do_prli_nvme = 1; 534362306a36Sopenharmony_ci else 534462306a36Sopenharmony_ci fcport->do_prli_nvme = 0; 534562306a36Sopenharmony_ci 534662306a36Sopenharmony_ci if (e->u.new_sess.fc4_type & FS_FCP_IS_N2N) { 534762306a36Sopenharmony_ci fcport->dm_login_expire = jiffies + 534862306a36Sopenharmony_ci QLA_N2N_WAIT_TIME * HZ; 534962306a36Sopenharmony_ci fcport->fc4_type = FS_FC4TYPE_FCP; 535062306a36Sopenharmony_ci fcport->n2n_flag = 1; 535162306a36Sopenharmony_ci if (vha->flags.nvme_enabled) 535262306a36Sopenharmony_ci fcport->fc4_type |= FS_FC4TYPE_NVME; 535362306a36Sopenharmony_ci } 535462306a36Sopenharmony_ci 535562306a36Sopenharmony_ci } else { 535662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 535762306a36Sopenharmony_ci "%s %8phC mem alloc fail.\n", 535862306a36Sopenharmony_ci __func__, e->u.new_sess.port_name); 535962306a36Sopenharmony_ci 536062306a36Sopenharmony_ci if (pla) { 536162306a36Sopenharmony_ci list_del(&pla->list); 536262306a36Sopenharmony_ci kmem_cache_free(qla_tgt_plogi_cachep, pla); 536362306a36Sopenharmony_ci } 536462306a36Sopenharmony_ci return; 536562306a36Sopenharmony_ci } 536662306a36Sopenharmony_ci 536762306a36Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 536862306a36Sopenharmony_ci /* search again to make sure no one else got ahead */ 536962306a36Sopenharmony_ci tfcp = qla2x00_find_fcport_by_wwpn(vha, 537062306a36Sopenharmony_ci e->u.new_sess.port_name, 1); 537162306a36Sopenharmony_ci if (tfcp) { 537262306a36Sopenharmony_ci /* should rarily happen */ 537362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 537462306a36Sopenharmony_ci "%s %8phC found existing fcport b4 add. DS %d LS %d\n", 537562306a36Sopenharmony_ci __func__, tfcp->port_name, tfcp->disc_state, 537662306a36Sopenharmony_ci tfcp->fw_login_state); 537762306a36Sopenharmony_ci 537862306a36Sopenharmony_ci free_fcport = 1; 537962306a36Sopenharmony_ci } else { 538062306a36Sopenharmony_ci list_add_tail(&fcport->list, &vha->vp_fcports); 538162306a36Sopenharmony_ci 538262306a36Sopenharmony_ci } 538362306a36Sopenharmony_ci if (pla) { 538462306a36Sopenharmony_ci qlt_plogi_ack_link(vha, pla, fcport, 538562306a36Sopenharmony_ci QLT_PLOGI_LINK_SAME_WWN); 538662306a36Sopenharmony_ci pla->ref_count--; 538762306a36Sopenharmony_ci } 538862306a36Sopenharmony_ci } 538962306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 539062306a36Sopenharmony_ci 539162306a36Sopenharmony_ci if (fcport) { 539262306a36Sopenharmony_ci fcport->id_changed = 1; 539362306a36Sopenharmony_ci fcport->scan_state = QLA_FCPORT_FOUND; 539462306a36Sopenharmony_ci fcport->chip_reset = vha->hw->base_qpair->chip_reset; 539562306a36Sopenharmony_ci memcpy(fcport->node_name, e->u.new_sess.node_name, WWN_SIZE); 539662306a36Sopenharmony_ci 539762306a36Sopenharmony_ci if (pla) { 539862306a36Sopenharmony_ci if (pla->iocb.u.isp24.status_subcode == ELS_PRLI) { 539962306a36Sopenharmony_ci u16 wd3_lo; 540062306a36Sopenharmony_ci 540162306a36Sopenharmony_ci fcport->fw_login_state = DSC_LS_PRLI_PEND; 540262306a36Sopenharmony_ci fcport->local = 0; 540362306a36Sopenharmony_ci fcport->loop_id = 540462306a36Sopenharmony_ci le16_to_cpu( 540562306a36Sopenharmony_ci pla->iocb.u.isp24.nport_handle); 540662306a36Sopenharmony_ci fcport->fw_login_state = DSC_LS_PRLI_PEND; 540762306a36Sopenharmony_ci wd3_lo = 540862306a36Sopenharmony_ci le16_to_cpu( 540962306a36Sopenharmony_ci pla->iocb.u.isp24.u.prli.wd3_lo); 541062306a36Sopenharmony_ci 541162306a36Sopenharmony_ci if (wd3_lo & BIT_7) 541262306a36Sopenharmony_ci fcport->conf_compl_supported = 1; 541362306a36Sopenharmony_ci 541462306a36Sopenharmony_ci if ((wd3_lo & BIT_4) == 0) 541562306a36Sopenharmony_ci fcport->port_type = FCT_INITIATOR; 541662306a36Sopenharmony_ci else 541762306a36Sopenharmony_ci fcport->port_type = FCT_TARGET; 541862306a36Sopenharmony_ci } 541962306a36Sopenharmony_ci qlt_plogi_ack_unref(vha, pla); 542062306a36Sopenharmony_ci } else { 542162306a36Sopenharmony_ci fc_port_t *dfcp = NULL; 542262306a36Sopenharmony_ci 542362306a36Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 542462306a36Sopenharmony_ci tfcp = qla2x00_find_fcport_by_nportid(vha, 542562306a36Sopenharmony_ci &e->u.new_sess.id, 1); 542662306a36Sopenharmony_ci if (tfcp && (tfcp != fcport)) { 542762306a36Sopenharmony_ci /* 542862306a36Sopenharmony_ci * We have a conflict fcport with same NportID. 542962306a36Sopenharmony_ci */ 543062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 543162306a36Sopenharmony_ci "%s %8phC found conflict b4 add. DS %d LS %d\n", 543262306a36Sopenharmony_ci __func__, tfcp->port_name, tfcp->disc_state, 543362306a36Sopenharmony_ci tfcp->fw_login_state); 543462306a36Sopenharmony_ci 543562306a36Sopenharmony_ci switch (tfcp->disc_state) { 543662306a36Sopenharmony_ci case DSC_DELETED: 543762306a36Sopenharmony_ci break; 543862306a36Sopenharmony_ci case DSC_DELETE_PEND: 543962306a36Sopenharmony_ci fcport->login_pause = 1; 544062306a36Sopenharmony_ci tfcp->conflict = fcport; 544162306a36Sopenharmony_ci break; 544262306a36Sopenharmony_ci default: 544362306a36Sopenharmony_ci fcport->login_pause = 1; 544462306a36Sopenharmony_ci tfcp->conflict = fcport; 544562306a36Sopenharmony_ci dfcp = tfcp; 544662306a36Sopenharmony_ci break; 544762306a36Sopenharmony_ci } 544862306a36Sopenharmony_ci } 544962306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 545062306a36Sopenharmony_ci if (dfcp) 545162306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(tfcp); 545262306a36Sopenharmony_ci 545362306a36Sopenharmony_ci if (N2N_TOPO(vha->hw)) { 545462306a36Sopenharmony_ci fcport->flags &= ~FCF_FABRIC_DEVICE; 545562306a36Sopenharmony_ci fcport->keep_nport_handle = 1; 545662306a36Sopenharmony_ci if (vha->flags.nvme_enabled) { 545762306a36Sopenharmony_ci fcport->fc4_type = 545862306a36Sopenharmony_ci (FS_FC4TYPE_NVME | FS_FC4TYPE_FCP); 545962306a36Sopenharmony_ci fcport->n2n_flag = 1; 546062306a36Sopenharmony_ci } 546162306a36Sopenharmony_ci fcport->fw_login_state = 0; 546262306a36Sopenharmony_ci 546362306a36Sopenharmony_ci schedule_delayed_work(&vha->scan.scan_work, 5); 546462306a36Sopenharmony_ci } else { 546562306a36Sopenharmony_ci qla24xx_fcport_handle_login(vha, fcport); 546662306a36Sopenharmony_ci } 546762306a36Sopenharmony_ci } 546862306a36Sopenharmony_ci } 546962306a36Sopenharmony_ci 547062306a36Sopenharmony_ci if (free_fcport) { 547162306a36Sopenharmony_ci qla2x00_free_fcport(fcport); 547262306a36Sopenharmony_ci if (pla) { 547362306a36Sopenharmony_ci list_del(&pla->list); 547462306a36Sopenharmony_ci kmem_cache_free(qla_tgt_plogi_cachep, pla); 547562306a36Sopenharmony_ci } 547662306a36Sopenharmony_ci } 547762306a36Sopenharmony_ci} 547862306a36Sopenharmony_ci 547962306a36Sopenharmony_cistatic void qla_sp_retry(struct scsi_qla_host *vha, struct qla_work_evt *e) 548062306a36Sopenharmony_ci{ 548162306a36Sopenharmony_ci struct srb *sp = e->u.iosb.sp; 548262306a36Sopenharmony_ci int rval; 548362306a36Sopenharmony_ci 548462306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 548562306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 548662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2043, 548762306a36Sopenharmony_ci "%s: %s: Re-issue IOCB failed (%d).\n", 548862306a36Sopenharmony_ci __func__, sp->name, rval); 548962306a36Sopenharmony_ci qla24xx_sp_unmap(vha, sp); 549062306a36Sopenharmony_ci } 549162306a36Sopenharmony_ci} 549262306a36Sopenharmony_ci 549362306a36Sopenharmony_civoid 549462306a36Sopenharmony_ciqla2x00_do_work(struct scsi_qla_host *vha) 549562306a36Sopenharmony_ci{ 549662306a36Sopenharmony_ci struct qla_work_evt *e, *tmp; 549762306a36Sopenharmony_ci unsigned long flags; 549862306a36Sopenharmony_ci LIST_HEAD(work); 549962306a36Sopenharmony_ci int rc; 550062306a36Sopenharmony_ci 550162306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 550262306a36Sopenharmony_ci list_splice_init(&vha->work_list, &work); 550362306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 550462306a36Sopenharmony_ci 550562306a36Sopenharmony_ci list_for_each_entry_safe(e, tmp, &work, list) { 550662306a36Sopenharmony_ci rc = QLA_SUCCESS; 550762306a36Sopenharmony_ci switch (e->type) { 550862306a36Sopenharmony_ci case QLA_EVT_AEN: 550962306a36Sopenharmony_ci fc_host_post_event(vha->host, fc_get_event_number(), 551062306a36Sopenharmony_ci e->u.aen.code, e->u.aen.data); 551162306a36Sopenharmony_ci break; 551262306a36Sopenharmony_ci case QLA_EVT_IDC_ACK: 551362306a36Sopenharmony_ci qla81xx_idc_ack(vha, e->u.idc_ack.mb); 551462306a36Sopenharmony_ci break; 551562306a36Sopenharmony_ci case QLA_EVT_ASYNC_LOGIN: 551662306a36Sopenharmony_ci qla2x00_async_login(vha, e->u.logio.fcport, 551762306a36Sopenharmony_ci e->u.logio.data); 551862306a36Sopenharmony_ci break; 551962306a36Sopenharmony_ci case QLA_EVT_ASYNC_LOGOUT: 552062306a36Sopenharmony_ci rc = qla2x00_async_logout(vha, e->u.logio.fcport); 552162306a36Sopenharmony_ci break; 552262306a36Sopenharmony_ci case QLA_EVT_ASYNC_ADISC: 552362306a36Sopenharmony_ci qla2x00_async_adisc(vha, e->u.logio.fcport, 552462306a36Sopenharmony_ci e->u.logio.data); 552562306a36Sopenharmony_ci break; 552662306a36Sopenharmony_ci case QLA_EVT_UEVENT: 552762306a36Sopenharmony_ci qla2x00_uevent_emit(vha, e->u.uevent.code); 552862306a36Sopenharmony_ci break; 552962306a36Sopenharmony_ci case QLA_EVT_AENFX: 553062306a36Sopenharmony_ci qlafx00_process_aen(vha, e); 553162306a36Sopenharmony_ci break; 553262306a36Sopenharmony_ci case QLA_EVT_UNMAP: 553362306a36Sopenharmony_ci qla24xx_sp_unmap(vha, e->u.iosb.sp); 553462306a36Sopenharmony_ci break; 553562306a36Sopenharmony_ci case QLA_EVT_RELOGIN: 553662306a36Sopenharmony_ci qla2x00_relogin(vha); 553762306a36Sopenharmony_ci break; 553862306a36Sopenharmony_ci case QLA_EVT_NEW_SESS: 553962306a36Sopenharmony_ci qla24xx_create_new_sess(vha, e); 554062306a36Sopenharmony_ci break; 554162306a36Sopenharmony_ci case QLA_EVT_GPDB: 554262306a36Sopenharmony_ci qla24xx_async_gpdb(vha, e->u.fcport.fcport, 554362306a36Sopenharmony_ci e->u.fcport.opt); 554462306a36Sopenharmony_ci break; 554562306a36Sopenharmony_ci case QLA_EVT_PRLI: 554662306a36Sopenharmony_ci qla24xx_async_prli(vha, e->u.fcport.fcport); 554762306a36Sopenharmony_ci break; 554862306a36Sopenharmony_ci case QLA_EVT_GPSC: 554962306a36Sopenharmony_ci qla24xx_async_gpsc(vha, e->u.fcport.fcport); 555062306a36Sopenharmony_ci break; 555162306a36Sopenharmony_ci case QLA_EVT_GNL: 555262306a36Sopenharmony_ci qla24xx_async_gnl(vha, e->u.fcport.fcport); 555362306a36Sopenharmony_ci break; 555462306a36Sopenharmony_ci case QLA_EVT_NACK: 555562306a36Sopenharmony_ci qla24xx_do_nack_work(vha, e); 555662306a36Sopenharmony_ci break; 555762306a36Sopenharmony_ci case QLA_EVT_ASYNC_PRLO: 555862306a36Sopenharmony_ci rc = qla2x00_async_prlo(vha, e->u.logio.fcport); 555962306a36Sopenharmony_ci break; 556062306a36Sopenharmony_ci case QLA_EVT_ASYNC_PRLO_DONE: 556162306a36Sopenharmony_ci qla2x00_async_prlo_done(vha, e->u.logio.fcport, 556262306a36Sopenharmony_ci e->u.logio.data); 556362306a36Sopenharmony_ci break; 556462306a36Sopenharmony_ci case QLA_EVT_GPNFT: 556562306a36Sopenharmony_ci qla24xx_async_gpnft(vha, e->u.gpnft.fc4_type, 556662306a36Sopenharmony_ci e->u.gpnft.sp); 556762306a36Sopenharmony_ci break; 556862306a36Sopenharmony_ci case QLA_EVT_GPNFT_DONE: 556962306a36Sopenharmony_ci qla24xx_async_gpnft_done(vha, e->u.iosb.sp); 557062306a36Sopenharmony_ci break; 557162306a36Sopenharmony_ci case QLA_EVT_GNNFT_DONE: 557262306a36Sopenharmony_ci qla24xx_async_gnnft_done(vha, e->u.iosb.sp); 557362306a36Sopenharmony_ci break; 557462306a36Sopenharmony_ci case QLA_EVT_GFPNID: 557562306a36Sopenharmony_ci qla24xx_async_gfpnid(vha, e->u.fcport.fcport); 557662306a36Sopenharmony_ci break; 557762306a36Sopenharmony_ci case QLA_EVT_SP_RETRY: 557862306a36Sopenharmony_ci qla_sp_retry(vha, e); 557962306a36Sopenharmony_ci break; 558062306a36Sopenharmony_ci case QLA_EVT_IIDMA: 558162306a36Sopenharmony_ci qla_do_iidma_work(vha, e->u.fcport.fcport); 558262306a36Sopenharmony_ci break; 558362306a36Sopenharmony_ci case QLA_EVT_ELS_PLOGI: 558462306a36Sopenharmony_ci qla24xx_els_dcmd2_iocb(vha, ELS_DCMD_PLOGI, 558562306a36Sopenharmony_ci e->u.fcport.fcport, false); 558662306a36Sopenharmony_ci break; 558762306a36Sopenharmony_ci case QLA_EVT_SA_REPLACE: 558862306a36Sopenharmony_ci rc = qla24xx_issue_sa_replace_iocb(vha, e); 558962306a36Sopenharmony_ci break; 559062306a36Sopenharmony_ci } 559162306a36Sopenharmony_ci 559262306a36Sopenharmony_ci if (rc == EAGAIN) { 559362306a36Sopenharmony_ci /* put 'work' at head of 'vha->work_list' */ 559462306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 559562306a36Sopenharmony_ci list_splice(&work, &vha->work_list); 559662306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 559762306a36Sopenharmony_ci break; 559862306a36Sopenharmony_ci } 559962306a36Sopenharmony_ci list_del_init(&e->list); 560062306a36Sopenharmony_ci if (e->flags & QLA_EVT_FLAG_FREE) 560162306a36Sopenharmony_ci kfree(e); 560262306a36Sopenharmony_ci 560362306a36Sopenharmony_ci /* For each work completed decrement vha ref count */ 560462306a36Sopenharmony_ci QLA_VHA_MARK_NOT_BUSY(vha); 560562306a36Sopenharmony_ci } 560662306a36Sopenharmony_ci} 560762306a36Sopenharmony_ci 560862306a36Sopenharmony_ciint qla24xx_post_relogin_work(struct scsi_qla_host *vha) 560962306a36Sopenharmony_ci{ 561062306a36Sopenharmony_ci struct qla_work_evt *e; 561162306a36Sopenharmony_ci 561262306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_RELOGIN); 561362306a36Sopenharmony_ci 561462306a36Sopenharmony_ci if (!e) { 561562306a36Sopenharmony_ci set_bit(RELOGIN_NEEDED, &vha->dpc_flags); 561662306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 561762306a36Sopenharmony_ci } 561862306a36Sopenharmony_ci 561962306a36Sopenharmony_ci return qla2x00_post_work(vha, e); 562062306a36Sopenharmony_ci} 562162306a36Sopenharmony_ci 562262306a36Sopenharmony_ci/* Relogins all the fcports of a vport 562362306a36Sopenharmony_ci * Context: dpc thread 562462306a36Sopenharmony_ci */ 562562306a36Sopenharmony_civoid qla2x00_relogin(struct scsi_qla_host *vha) 562662306a36Sopenharmony_ci{ 562762306a36Sopenharmony_ci fc_port_t *fcport; 562862306a36Sopenharmony_ci int status, relogin_needed = 0; 562962306a36Sopenharmony_ci struct event_arg ea; 563062306a36Sopenharmony_ci 563162306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 563262306a36Sopenharmony_ci /* 563362306a36Sopenharmony_ci * If the port is not ONLINE then try to login 563462306a36Sopenharmony_ci * to it if we haven't run out of retries. 563562306a36Sopenharmony_ci */ 563662306a36Sopenharmony_ci if (atomic_read(&fcport->state) != FCS_ONLINE && 563762306a36Sopenharmony_ci fcport->login_retry) { 563862306a36Sopenharmony_ci if (fcport->scan_state != QLA_FCPORT_FOUND || 563962306a36Sopenharmony_ci fcport->disc_state == DSC_LOGIN_AUTH_PEND || 564062306a36Sopenharmony_ci fcport->disc_state == DSC_LOGIN_COMPLETE) 564162306a36Sopenharmony_ci continue; 564262306a36Sopenharmony_ci 564362306a36Sopenharmony_ci if (fcport->flags & (FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE) || 564462306a36Sopenharmony_ci fcport->disc_state == DSC_DELETE_PEND) { 564562306a36Sopenharmony_ci relogin_needed = 1; 564662306a36Sopenharmony_ci } else { 564762306a36Sopenharmony_ci if (vha->hw->current_topology != ISP_CFG_NL) { 564862306a36Sopenharmony_ci memset(&ea, 0, sizeof(ea)); 564962306a36Sopenharmony_ci ea.fcport = fcport; 565062306a36Sopenharmony_ci qla24xx_handle_relogin_event(vha, &ea); 565162306a36Sopenharmony_ci } else if (vha->hw->current_topology == 565262306a36Sopenharmony_ci ISP_CFG_NL && 565362306a36Sopenharmony_ci IS_QLA2XXX_MIDTYPE(vha->hw)) { 565462306a36Sopenharmony_ci (void)qla24xx_fcport_handle_login(vha, 565562306a36Sopenharmony_ci fcport); 565662306a36Sopenharmony_ci } else if (vha->hw->current_topology == 565762306a36Sopenharmony_ci ISP_CFG_NL) { 565862306a36Sopenharmony_ci fcport->login_retry--; 565962306a36Sopenharmony_ci status = 566062306a36Sopenharmony_ci qla2x00_local_device_login(vha, 566162306a36Sopenharmony_ci fcport); 566262306a36Sopenharmony_ci if (status == QLA_SUCCESS) { 566362306a36Sopenharmony_ci fcport->old_loop_id = 566462306a36Sopenharmony_ci fcport->loop_id; 566562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2003, 566662306a36Sopenharmony_ci "Port login OK: logged in ID 0x%x.\n", 566762306a36Sopenharmony_ci fcport->loop_id); 566862306a36Sopenharmony_ci qla2x00_update_fcport 566962306a36Sopenharmony_ci (vha, fcport); 567062306a36Sopenharmony_ci } else if (status == 1) { 567162306a36Sopenharmony_ci set_bit(RELOGIN_NEEDED, 567262306a36Sopenharmony_ci &vha->dpc_flags); 567362306a36Sopenharmony_ci /* retry the login again */ 567462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2007, 567562306a36Sopenharmony_ci "Retrying %d login again loop_id 0x%x.\n", 567662306a36Sopenharmony_ci fcport->login_retry, 567762306a36Sopenharmony_ci fcport->loop_id); 567862306a36Sopenharmony_ci } else { 567962306a36Sopenharmony_ci fcport->login_retry = 0; 568062306a36Sopenharmony_ci } 568162306a36Sopenharmony_ci 568262306a36Sopenharmony_ci if (fcport->login_retry == 0 && 568362306a36Sopenharmony_ci status != QLA_SUCCESS) 568462306a36Sopenharmony_ci qla2x00_clear_loop_id(fcport); 568562306a36Sopenharmony_ci } 568662306a36Sopenharmony_ci } 568762306a36Sopenharmony_ci } 568862306a36Sopenharmony_ci if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) 568962306a36Sopenharmony_ci break; 569062306a36Sopenharmony_ci } 569162306a36Sopenharmony_ci 569262306a36Sopenharmony_ci if (relogin_needed) 569362306a36Sopenharmony_ci set_bit(RELOGIN_NEEDED, &vha->dpc_flags); 569462306a36Sopenharmony_ci 569562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x400e, 569662306a36Sopenharmony_ci "Relogin end.\n"); 569762306a36Sopenharmony_ci} 569862306a36Sopenharmony_ci 569962306a36Sopenharmony_ci/* Schedule work on any of the dpc-workqueues */ 570062306a36Sopenharmony_civoid 570162306a36Sopenharmony_ciqla83xx_schedule_work(scsi_qla_host_t *base_vha, int work_code) 570262306a36Sopenharmony_ci{ 570362306a36Sopenharmony_ci struct qla_hw_data *ha = base_vha->hw; 570462306a36Sopenharmony_ci 570562306a36Sopenharmony_ci switch (work_code) { 570662306a36Sopenharmony_ci case MBA_IDC_AEN: /* 0x8200 */ 570762306a36Sopenharmony_ci if (ha->dpc_lp_wq) 570862306a36Sopenharmony_ci queue_work(ha->dpc_lp_wq, &ha->idc_aen); 570962306a36Sopenharmony_ci break; 571062306a36Sopenharmony_ci 571162306a36Sopenharmony_ci case QLA83XX_NIC_CORE_RESET: /* 0x1 */ 571262306a36Sopenharmony_ci if (!ha->flags.nic_core_reset_hdlr_active) { 571362306a36Sopenharmony_ci if (ha->dpc_hp_wq) 571462306a36Sopenharmony_ci queue_work(ha->dpc_hp_wq, &ha->nic_core_reset); 571562306a36Sopenharmony_ci } else 571662306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb05e, 571762306a36Sopenharmony_ci "NIC Core reset is already active. Skip " 571862306a36Sopenharmony_ci "scheduling it again.\n"); 571962306a36Sopenharmony_ci break; 572062306a36Sopenharmony_ci case QLA83XX_IDC_STATE_HANDLER: /* 0x2 */ 572162306a36Sopenharmony_ci if (ha->dpc_hp_wq) 572262306a36Sopenharmony_ci queue_work(ha->dpc_hp_wq, &ha->idc_state_handler); 572362306a36Sopenharmony_ci break; 572462306a36Sopenharmony_ci case QLA83XX_NIC_CORE_UNRECOVERABLE: /* 0x3 */ 572562306a36Sopenharmony_ci if (ha->dpc_hp_wq) 572662306a36Sopenharmony_ci queue_work(ha->dpc_hp_wq, &ha->nic_core_unrecoverable); 572762306a36Sopenharmony_ci break; 572862306a36Sopenharmony_ci default: 572962306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0xb05f, 573062306a36Sopenharmony_ci "Unknown work-code=0x%x.\n", work_code); 573162306a36Sopenharmony_ci } 573262306a36Sopenharmony_ci 573362306a36Sopenharmony_ci return; 573462306a36Sopenharmony_ci} 573562306a36Sopenharmony_ci 573662306a36Sopenharmony_ci/* Work: Perform NIC Core Unrecoverable state handling */ 573762306a36Sopenharmony_civoid 573862306a36Sopenharmony_ciqla83xx_nic_core_unrecoverable_work(struct work_struct *work) 573962306a36Sopenharmony_ci{ 574062306a36Sopenharmony_ci struct qla_hw_data *ha = 574162306a36Sopenharmony_ci container_of(work, struct qla_hw_data, nic_core_unrecoverable); 574262306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 574362306a36Sopenharmony_ci uint32_t dev_state = 0; 574462306a36Sopenharmony_ci 574562306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 574662306a36Sopenharmony_ci qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state); 574762306a36Sopenharmony_ci qla83xx_reset_ownership(base_vha); 574862306a36Sopenharmony_ci if (ha->flags.nic_core_reset_owner) { 574962306a36Sopenharmony_ci ha->flags.nic_core_reset_owner = 0; 575062306a36Sopenharmony_ci qla83xx_wr_reg(base_vha, QLA83XX_IDC_DEV_STATE, 575162306a36Sopenharmony_ci QLA8XXX_DEV_FAILED); 575262306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0xb060, "HW State: FAILED.\n"); 575362306a36Sopenharmony_ci qla83xx_schedule_work(base_vha, QLA83XX_IDC_STATE_HANDLER); 575462306a36Sopenharmony_ci } 575562306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 575662306a36Sopenharmony_ci} 575762306a36Sopenharmony_ci 575862306a36Sopenharmony_ci/* Work: Execute IDC state handler */ 575962306a36Sopenharmony_civoid 576062306a36Sopenharmony_ciqla83xx_idc_state_handler_work(struct work_struct *work) 576162306a36Sopenharmony_ci{ 576262306a36Sopenharmony_ci struct qla_hw_data *ha = 576362306a36Sopenharmony_ci container_of(work, struct qla_hw_data, idc_state_handler); 576462306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 576562306a36Sopenharmony_ci uint32_t dev_state = 0; 576662306a36Sopenharmony_ci 576762306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 576862306a36Sopenharmony_ci qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state); 576962306a36Sopenharmony_ci if (dev_state == QLA8XXX_DEV_FAILED || 577062306a36Sopenharmony_ci dev_state == QLA8XXX_DEV_NEED_QUIESCENT) 577162306a36Sopenharmony_ci qla83xx_idc_state_handler(base_vha); 577262306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 577362306a36Sopenharmony_ci} 577462306a36Sopenharmony_ci 577562306a36Sopenharmony_cistatic int 577662306a36Sopenharmony_ciqla83xx_check_nic_core_fw_alive(scsi_qla_host_t *base_vha) 577762306a36Sopenharmony_ci{ 577862306a36Sopenharmony_ci int rval = QLA_SUCCESS; 577962306a36Sopenharmony_ci unsigned long heart_beat_wait = jiffies + (1 * HZ); 578062306a36Sopenharmony_ci uint32_t heart_beat_counter1, heart_beat_counter2; 578162306a36Sopenharmony_ci 578262306a36Sopenharmony_ci do { 578362306a36Sopenharmony_ci if (time_after(jiffies, heart_beat_wait)) { 578462306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb07c, 578562306a36Sopenharmony_ci "Nic Core f/w is not alive.\n"); 578662306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 578762306a36Sopenharmony_ci break; 578862306a36Sopenharmony_ci } 578962306a36Sopenharmony_ci 579062306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 579162306a36Sopenharmony_ci qla83xx_rd_reg(base_vha, QLA83XX_FW_HEARTBEAT, 579262306a36Sopenharmony_ci &heart_beat_counter1); 579362306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 579462306a36Sopenharmony_ci msleep(100); 579562306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 579662306a36Sopenharmony_ci qla83xx_rd_reg(base_vha, QLA83XX_FW_HEARTBEAT, 579762306a36Sopenharmony_ci &heart_beat_counter2); 579862306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 579962306a36Sopenharmony_ci } while (heart_beat_counter1 == heart_beat_counter2); 580062306a36Sopenharmony_ci 580162306a36Sopenharmony_ci return rval; 580262306a36Sopenharmony_ci} 580362306a36Sopenharmony_ci 580462306a36Sopenharmony_ci/* Work: Perform NIC Core Reset handling */ 580562306a36Sopenharmony_civoid 580662306a36Sopenharmony_ciqla83xx_nic_core_reset_work(struct work_struct *work) 580762306a36Sopenharmony_ci{ 580862306a36Sopenharmony_ci struct qla_hw_data *ha = 580962306a36Sopenharmony_ci container_of(work, struct qla_hw_data, nic_core_reset); 581062306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 581162306a36Sopenharmony_ci uint32_t dev_state = 0; 581262306a36Sopenharmony_ci 581362306a36Sopenharmony_ci if (IS_QLA2031(ha)) { 581462306a36Sopenharmony_ci if (qla2xxx_mctp_dump(base_vha) != QLA_SUCCESS) 581562306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0xb081, 581662306a36Sopenharmony_ci "Failed to dump mctp\n"); 581762306a36Sopenharmony_ci return; 581862306a36Sopenharmony_ci } 581962306a36Sopenharmony_ci 582062306a36Sopenharmony_ci if (!ha->flags.nic_core_reset_hdlr_active) { 582162306a36Sopenharmony_ci if (qla83xx_check_nic_core_fw_alive(base_vha) == QLA_SUCCESS) { 582262306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 582362306a36Sopenharmony_ci qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, 582462306a36Sopenharmony_ci &dev_state); 582562306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 582662306a36Sopenharmony_ci if (dev_state != QLA8XXX_DEV_NEED_RESET) { 582762306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb07a, 582862306a36Sopenharmony_ci "Nic Core f/w is alive.\n"); 582962306a36Sopenharmony_ci return; 583062306a36Sopenharmony_ci } 583162306a36Sopenharmony_ci } 583262306a36Sopenharmony_ci 583362306a36Sopenharmony_ci ha->flags.nic_core_reset_hdlr_active = 1; 583462306a36Sopenharmony_ci if (qla83xx_nic_core_reset(base_vha)) { 583562306a36Sopenharmony_ci /* NIC Core reset failed. */ 583662306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb061, 583762306a36Sopenharmony_ci "NIC Core reset failed.\n"); 583862306a36Sopenharmony_ci } 583962306a36Sopenharmony_ci ha->flags.nic_core_reset_hdlr_active = 0; 584062306a36Sopenharmony_ci } 584162306a36Sopenharmony_ci} 584262306a36Sopenharmony_ci 584362306a36Sopenharmony_ci/* Work: Handle 8200 IDC aens */ 584462306a36Sopenharmony_civoid 584562306a36Sopenharmony_ciqla83xx_service_idc_aen(struct work_struct *work) 584662306a36Sopenharmony_ci{ 584762306a36Sopenharmony_ci struct qla_hw_data *ha = 584862306a36Sopenharmony_ci container_of(work, struct qla_hw_data, idc_aen); 584962306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 585062306a36Sopenharmony_ci uint32_t dev_state, idc_control; 585162306a36Sopenharmony_ci 585262306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 585362306a36Sopenharmony_ci qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state); 585462306a36Sopenharmony_ci qla83xx_rd_reg(base_vha, QLA83XX_IDC_CONTROL, &idc_control); 585562306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 585662306a36Sopenharmony_ci if (dev_state == QLA8XXX_DEV_NEED_RESET) { 585762306a36Sopenharmony_ci if (idc_control & QLA83XX_IDC_GRACEFUL_RESET) { 585862306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb062, 585962306a36Sopenharmony_ci "Application requested NIC Core Reset.\n"); 586062306a36Sopenharmony_ci qla83xx_schedule_work(base_vha, QLA83XX_NIC_CORE_RESET); 586162306a36Sopenharmony_ci } else if (qla83xx_check_nic_core_fw_alive(base_vha) == 586262306a36Sopenharmony_ci QLA_SUCCESS) { 586362306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb07b, 586462306a36Sopenharmony_ci "Other protocol driver requested NIC Core Reset.\n"); 586562306a36Sopenharmony_ci qla83xx_schedule_work(base_vha, QLA83XX_NIC_CORE_RESET); 586662306a36Sopenharmony_ci } 586762306a36Sopenharmony_ci } else if (dev_state == QLA8XXX_DEV_FAILED || 586862306a36Sopenharmony_ci dev_state == QLA8XXX_DEV_NEED_QUIESCENT) { 586962306a36Sopenharmony_ci qla83xx_schedule_work(base_vha, QLA83XX_IDC_STATE_HANDLER); 587062306a36Sopenharmony_ci } 587162306a36Sopenharmony_ci} 587262306a36Sopenharmony_ci 587362306a36Sopenharmony_ci/* 587462306a36Sopenharmony_ci * Control the frequency of IDC lock retries 587562306a36Sopenharmony_ci */ 587662306a36Sopenharmony_ci#define QLA83XX_WAIT_LOGIC_MS 100 587762306a36Sopenharmony_ci 587862306a36Sopenharmony_cistatic int 587962306a36Sopenharmony_ciqla83xx_force_lock_recovery(scsi_qla_host_t *base_vha) 588062306a36Sopenharmony_ci{ 588162306a36Sopenharmony_ci int rval; 588262306a36Sopenharmony_ci uint32_t data; 588362306a36Sopenharmony_ci uint32_t idc_lck_rcvry_stage_mask = 0x3; 588462306a36Sopenharmony_ci uint32_t idc_lck_rcvry_owner_mask = 0x3c; 588562306a36Sopenharmony_ci struct qla_hw_data *ha = base_vha->hw; 588662306a36Sopenharmony_ci 588762306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb086, 588862306a36Sopenharmony_ci "Trying force recovery of the IDC lock.\n"); 588962306a36Sopenharmony_ci 589062306a36Sopenharmony_ci rval = qla83xx_rd_reg(base_vha, QLA83XX_IDC_LOCK_RECOVERY, &data); 589162306a36Sopenharmony_ci if (rval) 589262306a36Sopenharmony_ci return rval; 589362306a36Sopenharmony_ci 589462306a36Sopenharmony_ci if ((data & idc_lck_rcvry_stage_mask) > 0) { 589562306a36Sopenharmony_ci return QLA_SUCCESS; 589662306a36Sopenharmony_ci } else { 589762306a36Sopenharmony_ci data = (IDC_LOCK_RECOVERY_STAGE1) | (ha->portnum << 2); 589862306a36Sopenharmony_ci rval = qla83xx_wr_reg(base_vha, QLA83XX_IDC_LOCK_RECOVERY, 589962306a36Sopenharmony_ci data); 590062306a36Sopenharmony_ci if (rval) 590162306a36Sopenharmony_ci return rval; 590262306a36Sopenharmony_ci 590362306a36Sopenharmony_ci msleep(200); 590462306a36Sopenharmony_ci 590562306a36Sopenharmony_ci rval = qla83xx_rd_reg(base_vha, QLA83XX_IDC_LOCK_RECOVERY, 590662306a36Sopenharmony_ci &data); 590762306a36Sopenharmony_ci if (rval) 590862306a36Sopenharmony_ci return rval; 590962306a36Sopenharmony_ci 591062306a36Sopenharmony_ci if (((data & idc_lck_rcvry_owner_mask) >> 2) == ha->portnum) { 591162306a36Sopenharmony_ci data &= (IDC_LOCK_RECOVERY_STAGE2 | 591262306a36Sopenharmony_ci ~(idc_lck_rcvry_stage_mask)); 591362306a36Sopenharmony_ci rval = qla83xx_wr_reg(base_vha, 591462306a36Sopenharmony_ci QLA83XX_IDC_LOCK_RECOVERY, data); 591562306a36Sopenharmony_ci if (rval) 591662306a36Sopenharmony_ci return rval; 591762306a36Sopenharmony_ci 591862306a36Sopenharmony_ci /* Forcefully perform IDC UnLock */ 591962306a36Sopenharmony_ci rval = qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_UNLOCK, 592062306a36Sopenharmony_ci &data); 592162306a36Sopenharmony_ci if (rval) 592262306a36Sopenharmony_ci return rval; 592362306a36Sopenharmony_ci /* Clear lock-id by setting 0xff */ 592462306a36Sopenharmony_ci rval = qla83xx_wr_reg(base_vha, QLA83XX_DRIVER_LOCKID, 592562306a36Sopenharmony_ci 0xff); 592662306a36Sopenharmony_ci if (rval) 592762306a36Sopenharmony_ci return rval; 592862306a36Sopenharmony_ci /* Clear lock-recovery by setting 0x0 */ 592962306a36Sopenharmony_ci rval = qla83xx_wr_reg(base_vha, 593062306a36Sopenharmony_ci QLA83XX_IDC_LOCK_RECOVERY, 0x0); 593162306a36Sopenharmony_ci if (rval) 593262306a36Sopenharmony_ci return rval; 593362306a36Sopenharmony_ci } else 593462306a36Sopenharmony_ci return QLA_SUCCESS; 593562306a36Sopenharmony_ci } 593662306a36Sopenharmony_ci 593762306a36Sopenharmony_ci return rval; 593862306a36Sopenharmony_ci} 593962306a36Sopenharmony_ci 594062306a36Sopenharmony_cistatic int 594162306a36Sopenharmony_ciqla83xx_idc_lock_recovery(scsi_qla_host_t *base_vha) 594262306a36Sopenharmony_ci{ 594362306a36Sopenharmony_ci int rval = QLA_SUCCESS; 594462306a36Sopenharmony_ci uint32_t o_drv_lockid, n_drv_lockid; 594562306a36Sopenharmony_ci unsigned long lock_recovery_timeout; 594662306a36Sopenharmony_ci 594762306a36Sopenharmony_ci lock_recovery_timeout = jiffies + QLA83XX_MAX_LOCK_RECOVERY_WAIT; 594862306a36Sopenharmony_ciretry_lockid: 594962306a36Sopenharmony_ci rval = qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCKID, &o_drv_lockid); 595062306a36Sopenharmony_ci if (rval) 595162306a36Sopenharmony_ci goto exit; 595262306a36Sopenharmony_ci 595362306a36Sopenharmony_ci /* MAX wait time before forcing IDC Lock recovery = 2 secs */ 595462306a36Sopenharmony_ci if (time_after_eq(jiffies, lock_recovery_timeout)) { 595562306a36Sopenharmony_ci if (qla83xx_force_lock_recovery(base_vha) == QLA_SUCCESS) 595662306a36Sopenharmony_ci return QLA_SUCCESS; 595762306a36Sopenharmony_ci else 595862306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 595962306a36Sopenharmony_ci } 596062306a36Sopenharmony_ci 596162306a36Sopenharmony_ci rval = qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCKID, &n_drv_lockid); 596262306a36Sopenharmony_ci if (rval) 596362306a36Sopenharmony_ci goto exit; 596462306a36Sopenharmony_ci 596562306a36Sopenharmony_ci if (o_drv_lockid == n_drv_lockid) { 596662306a36Sopenharmony_ci msleep(QLA83XX_WAIT_LOGIC_MS); 596762306a36Sopenharmony_ci goto retry_lockid; 596862306a36Sopenharmony_ci } else 596962306a36Sopenharmony_ci return QLA_SUCCESS; 597062306a36Sopenharmony_ci 597162306a36Sopenharmony_ciexit: 597262306a36Sopenharmony_ci return rval; 597362306a36Sopenharmony_ci} 597462306a36Sopenharmony_ci 597562306a36Sopenharmony_ci/* 597662306a36Sopenharmony_ci * Context: task, can sleep 597762306a36Sopenharmony_ci */ 597862306a36Sopenharmony_civoid 597962306a36Sopenharmony_ciqla83xx_idc_lock(scsi_qla_host_t *base_vha, uint16_t requester_id) 598062306a36Sopenharmony_ci{ 598162306a36Sopenharmony_ci uint32_t data; 598262306a36Sopenharmony_ci uint32_t lock_owner; 598362306a36Sopenharmony_ci struct qla_hw_data *ha = base_vha->hw; 598462306a36Sopenharmony_ci 598562306a36Sopenharmony_ci might_sleep(); 598662306a36Sopenharmony_ci 598762306a36Sopenharmony_ci /* IDC-lock implementation using driver-lock/lock-id remote registers */ 598862306a36Sopenharmony_ciretry_lock: 598962306a36Sopenharmony_ci if (qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCK, &data) 599062306a36Sopenharmony_ci == QLA_SUCCESS) { 599162306a36Sopenharmony_ci if (data) { 599262306a36Sopenharmony_ci /* Setting lock-id to our function-number */ 599362306a36Sopenharmony_ci qla83xx_wr_reg(base_vha, QLA83XX_DRIVER_LOCKID, 599462306a36Sopenharmony_ci ha->portnum); 599562306a36Sopenharmony_ci } else { 599662306a36Sopenharmony_ci qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCKID, 599762306a36Sopenharmony_ci &lock_owner); 599862306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb063, 599962306a36Sopenharmony_ci "Failed to acquire IDC lock, acquired by %d, " 600062306a36Sopenharmony_ci "retrying...\n", lock_owner); 600162306a36Sopenharmony_ci 600262306a36Sopenharmony_ci /* Retry/Perform IDC-Lock recovery */ 600362306a36Sopenharmony_ci if (qla83xx_idc_lock_recovery(base_vha) 600462306a36Sopenharmony_ci == QLA_SUCCESS) { 600562306a36Sopenharmony_ci msleep(QLA83XX_WAIT_LOGIC_MS); 600662306a36Sopenharmony_ci goto retry_lock; 600762306a36Sopenharmony_ci } else 600862306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0xb075, 600962306a36Sopenharmony_ci "IDC Lock recovery FAILED.\n"); 601062306a36Sopenharmony_ci } 601162306a36Sopenharmony_ci 601262306a36Sopenharmony_ci } 601362306a36Sopenharmony_ci 601462306a36Sopenharmony_ci return; 601562306a36Sopenharmony_ci} 601662306a36Sopenharmony_ci 601762306a36Sopenharmony_cistatic bool 601862306a36Sopenharmony_ciqla25xx_rdp_rsp_reduce_size(struct scsi_qla_host *vha, 601962306a36Sopenharmony_ci struct purex_entry_24xx *purex) 602062306a36Sopenharmony_ci{ 602162306a36Sopenharmony_ci char fwstr[16]; 602262306a36Sopenharmony_ci u32 sid = purex->s_id[2] << 16 | purex->s_id[1] << 8 | purex->s_id[0]; 602362306a36Sopenharmony_ci struct port_database_24xx *pdb; 602462306a36Sopenharmony_ci 602562306a36Sopenharmony_ci /* Domain Controller is always logged-out. */ 602662306a36Sopenharmony_ci /* if RDP request is not from Domain Controller: */ 602762306a36Sopenharmony_ci if (sid != 0xfffc01) 602862306a36Sopenharmony_ci return false; 602962306a36Sopenharmony_ci 603062306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0181, "%s: s_id=%#x\n", __func__, sid); 603162306a36Sopenharmony_ci 603262306a36Sopenharmony_ci pdb = kzalloc(sizeof(*pdb), GFP_KERNEL); 603362306a36Sopenharmony_ci if (!pdb) { 603462306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0181, 603562306a36Sopenharmony_ci "%s: Failed allocate pdb\n", __func__); 603662306a36Sopenharmony_ci } else if (qla24xx_get_port_database(vha, 603762306a36Sopenharmony_ci le16_to_cpu(purex->nport_handle), pdb)) { 603862306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0181, 603962306a36Sopenharmony_ci "%s: Failed get pdb sid=%x\n", __func__, sid); 604062306a36Sopenharmony_ci } else if (pdb->current_login_state != PDS_PLOGI_COMPLETE && 604162306a36Sopenharmony_ci pdb->current_login_state != PDS_PRLI_COMPLETE) { 604262306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0181, 604362306a36Sopenharmony_ci "%s: Port not logged in sid=%#x\n", __func__, sid); 604462306a36Sopenharmony_ci } else { 604562306a36Sopenharmony_ci /* RDP request is from logged in port */ 604662306a36Sopenharmony_ci kfree(pdb); 604762306a36Sopenharmony_ci return false; 604862306a36Sopenharmony_ci } 604962306a36Sopenharmony_ci kfree(pdb); 605062306a36Sopenharmony_ci 605162306a36Sopenharmony_ci vha->hw->isp_ops->fw_version_str(vha, fwstr, sizeof(fwstr)); 605262306a36Sopenharmony_ci fwstr[strcspn(fwstr, " ")] = 0; 605362306a36Sopenharmony_ci /* if FW version allows RDP response length upto 2048 bytes: */ 605462306a36Sopenharmony_ci if (strcmp(fwstr, "8.09.00") > 0 || strcmp(fwstr, "8.05.65") == 0) 605562306a36Sopenharmony_ci return false; 605662306a36Sopenharmony_ci 605762306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0181, "%s: fw=%s\n", __func__, fwstr); 605862306a36Sopenharmony_ci 605962306a36Sopenharmony_ci /* RDP response length is to be reduced to maximum 256 bytes */ 606062306a36Sopenharmony_ci return true; 606162306a36Sopenharmony_ci} 606262306a36Sopenharmony_ci 606362306a36Sopenharmony_ci/* 606462306a36Sopenharmony_ci * Function Name: qla24xx_process_purex_iocb 606562306a36Sopenharmony_ci * 606662306a36Sopenharmony_ci * Description: 606762306a36Sopenharmony_ci * Prepare a RDP response and send to Fabric switch 606862306a36Sopenharmony_ci * 606962306a36Sopenharmony_ci * PARAMETERS: 607062306a36Sopenharmony_ci * vha: SCSI qla host 607162306a36Sopenharmony_ci * purex: RDP request received by HBA 607262306a36Sopenharmony_ci */ 607362306a36Sopenharmony_civoid qla24xx_process_purex_rdp(struct scsi_qla_host *vha, 607462306a36Sopenharmony_ci struct purex_item *item) 607562306a36Sopenharmony_ci{ 607662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 607762306a36Sopenharmony_ci struct purex_entry_24xx *purex = 607862306a36Sopenharmony_ci (struct purex_entry_24xx *)&item->iocb; 607962306a36Sopenharmony_ci dma_addr_t rsp_els_dma; 608062306a36Sopenharmony_ci dma_addr_t rsp_payload_dma; 608162306a36Sopenharmony_ci dma_addr_t stat_dma; 608262306a36Sopenharmony_ci dma_addr_t sfp_dma; 608362306a36Sopenharmony_ci struct els_entry_24xx *rsp_els = NULL; 608462306a36Sopenharmony_ci struct rdp_rsp_payload *rsp_payload = NULL; 608562306a36Sopenharmony_ci struct link_statistics *stat = NULL; 608662306a36Sopenharmony_ci uint8_t *sfp = NULL; 608762306a36Sopenharmony_ci uint16_t sfp_flags = 0; 608862306a36Sopenharmony_ci uint rsp_payload_length = sizeof(*rsp_payload); 608962306a36Sopenharmony_ci int rval; 609062306a36Sopenharmony_ci 609162306a36Sopenharmony_ci ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0180, 609262306a36Sopenharmony_ci "%s: Enter\n", __func__); 609362306a36Sopenharmony_ci 609462306a36Sopenharmony_ci ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0181, 609562306a36Sopenharmony_ci "-------- ELS REQ -------\n"); 609662306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0182, 609762306a36Sopenharmony_ci purex, sizeof(*purex)); 609862306a36Sopenharmony_ci 609962306a36Sopenharmony_ci if (qla25xx_rdp_rsp_reduce_size(vha, purex)) { 610062306a36Sopenharmony_ci rsp_payload_length = 610162306a36Sopenharmony_ci offsetof(typeof(*rsp_payload), optical_elmt_desc); 610262306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0181, 610362306a36Sopenharmony_ci "Reducing RSP payload length to %u bytes...\n", 610462306a36Sopenharmony_ci rsp_payload_length); 610562306a36Sopenharmony_ci } 610662306a36Sopenharmony_ci 610762306a36Sopenharmony_ci rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els), 610862306a36Sopenharmony_ci &rsp_els_dma, GFP_KERNEL); 610962306a36Sopenharmony_ci if (!rsp_els) { 611062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0183, 611162306a36Sopenharmony_ci "Failed allocate dma buffer ELS RSP.\n"); 611262306a36Sopenharmony_ci goto dealloc; 611362306a36Sopenharmony_ci } 611462306a36Sopenharmony_ci 611562306a36Sopenharmony_ci rsp_payload = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_payload), 611662306a36Sopenharmony_ci &rsp_payload_dma, GFP_KERNEL); 611762306a36Sopenharmony_ci if (!rsp_payload) { 611862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0184, 611962306a36Sopenharmony_ci "Failed allocate dma buffer ELS RSP payload.\n"); 612062306a36Sopenharmony_ci goto dealloc; 612162306a36Sopenharmony_ci } 612262306a36Sopenharmony_ci 612362306a36Sopenharmony_ci sfp = dma_alloc_coherent(&ha->pdev->dev, SFP_RTDI_LEN, 612462306a36Sopenharmony_ci &sfp_dma, GFP_KERNEL); 612562306a36Sopenharmony_ci 612662306a36Sopenharmony_ci stat = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stat), 612762306a36Sopenharmony_ci &stat_dma, GFP_KERNEL); 612862306a36Sopenharmony_ci 612962306a36Sopenharmony_ci /* Prepare Response IOCB */ 613062306a36Sopenharmony_ci rsp_els->entry_type = ELS_IOCB_TYPE; 613162306a36Sopenharmony_ci rsp_els->entry_count = 1; 613262306a36Sopenharmony_ci rsp_els->sys_define = 0; 613362306a36Sopenharmony_ci rsp_els->entry_status = 0; 613462306a36Sopenharmony_ci rsp_els->handle = 0; 613562306a36Sopenharmony_ci rsp_els->nport_handle = purex->nport_handle; 613662306a36Sopenharmony_ci rsp_els->tx_dsd_count = cpu_to_le16(1); 613762306a36Sopenharmony_ci rsp_els->vp_index = purex->vp_idx; 613862306a36Sopenharmony_ci rsp_els->sof_type = EST_SOFI3; 613962306a36Sopenharmony_ci rsp_els->rx_xchg_address = purex->rx_xchg_addr; 614062306a36Sopenharmony_ci rsp_els->rx_dsd_count = 0; 614162306a36Sopenharmony_ci rsp_els->opcode = purex->els_frame_payload[0]; 614262306a36Sopenharmony_ci 614362306a36Sopenharmony_ci rsp_els->d_id[0] = purex->s_id[0]; 614462306a36Sopenharmony_ci rsp_els->d_id[1] = purex->s_id[1]; 614562306a36Sopenharmony_ci rsp_els->d_id[2] = purex->s_id[2]; 614662306a36Sopenharmony_ci 614762306a36Sopenharmony_ci rsp_els->control_flags = cpu_to_le16(EPD_ELS_ACC); 614862306a36Sopenharmony_ci rsp_els->rx_byte_count = 0; 614962306a36Sopenharmony_ci rsp_els->tx_byte_count = cpu_to_le32(rsp_payload_length); 615062306a36Sopenharmony_ci 615162306a36Sopenharmony_ci put_unaligned_le64(rsp_payload_dma, &rsp_els->tx_address); 615262306a36Sopenharmony_ci rsp_els->tx_len = rsp_els->tx_byte_count; 615362306a36Sopenharmony_ci 615462306a36Sopenharmony_ci rsp_els->rx_address = 0; 615562306a36Sopenharmony_ci rsp_els->rx_len = 0; 615662306a36Sopenharmony_ci 615762306a36Sopenharmony_ci /* Prepare Response Payload */ 615862306a36Sopenharmony_ci rsp_payload->hdr.cmd = cpu_to_be32(0x2 << 24); /* LS_ACC */ 615962306a36Sopenharmony_ci rsp_payload->hdr.len = cpu_to_be32(le32_to_cpu(rsp_els->tx_byte_count) - 616062306a36Sopenharmony_ci sizeof(rsp_payload->hdr)); 616162306a36Sopenharmony_ci 616262306a36Sopenharmony_ci /* Link service Request Info Descriptor */ 616362306a36Sopenharmony_ci rsp_payload->ls_req_info_desc.desc_tag = cpu_to_be32(0x1); 616462306a36Sopenharmony_ci rsp_payload->ls_req_info_desc.desc_len = 616562306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_req_info_desc)); 616662306a36Sopenharmony_ci rsp_payload->ls_req_info_desc.req_payload_word_0 = 616762306a36Sopenharmony_ci cpu_to_be32p((uint32_t *)purex->els_frame_payload); 616862306a36Sopenharmony_ci 616962306a36Sopenharmony_ci /* Link service Request Info Descriptor 2 */ 617062306a36Sopenharmony_ci rsp_payload->ls_req_info_desc2.desc_tag = cpu_to_be32(0x1); 617162306a36Sopenharmony_ci rsp_payload->ls_req_info_desc2.desc_len = 617262306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_req_info_desc2)); 617362306a36Sopenharmony_ci rsp_payload->ls_req_info_desc2.req_payload_word_0 = 617462306a36Sopenharmony_ci cpu_to_be32p((uint32_t *)purex->els_frame_payload); 617562306a36Sopenharmony_ci 617662306a36Sopenharmony_ci 617762306a36Sopenharmony_ci rsp_payload->sfp_diag_desc.desc_tag = cpu_to_be32(0x10000); 617862306a36Sopenharmony_ci rsp_payload->sfp_diag_desc.desc_len = 617962306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(rsp_payload->sfp_diag_desc)); 618062306a36Sopenharmony_ci 618162306a36Sopenharmony_ci if (sfp) { 618262306a36Sopenharmony_ci /* SFP Flags */ 618362306a36Sopenharmony_ci memset(sfp, 0, SFP_RTDI_LEN); 618462306a36Sopenharmony_ci rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 0x7, 2, 0); 618562306a36Sopenharmony_ci if (!rval) { 618662306a36Sopenharmony_ci /* SFP Flags bits 3-0: Port Tx Laser Type */ 618762306a36Sopenharmony_ci if (sfp[0] & BIT_2 || sfp[1] & (BIT_6|BIT_5)) 618862306a36Sopenharmony_ci sfp_flags |= BIT_0; /* short wave */ 618962306a36Sopenharmony_ci else if (sfp[0] & BIT_1) 619062306a36Sopenharmony_ci sfp_flags |= BIT_1; /* long wave 1310nm */ 619162306a36Sopenharmony_ci else if (sfp[1] & BIT_4) 619262306a36Sopenharmony_ci sfp_flags |= BIT_1|BIT_0; /* long wave 1550nm */ 619362306a36Sopenharmony_ci } 619462306a36Sopenharmony_ci 619562306a36Sopenharmony_ci /* SFP Type */ 619662306a36Sopenharmony_ci memset(sfp, 0, SFP_RTDI_LEN); 619762306a36Sopenharmony_ci rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 0x0, 1, 0); 619862306a36Sopenharmony_ci if (!rval) { 619962306a36Sopenharmony_ci sfp_flags |= BIT_4; /* optical */ 620062306a36Sopenharmony_ci if (sfp[0] == 0x3) 620162306a36Sopenharmony_ci sfp_flags |= BIT_6; /* sfp+ */ 620262306a36Sopenharmony_ci } 620362306a36Sopenharmony_ci 620462306a36Sopenharmony_ci rsp_payload->sfp_diag_desc.sfp_flags = cpu_to_be16(sfp_flags); 620562306a36Sopenharmony_ci 620662306a36Sopenharmony_ci /* SFP Diagnostics */ 620762306a36Sopenharmony_ci memset(sfp, 0, SFP_RTDI_LEN); 620862306a36Sopenharmony_ci rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 0x60, 10, 0); 620962306a36Sopenharmony_ci if (!rval) { 621062306a36Sopenharmony_ci __be16 *trx = (__force __be16 *)sfp; /* already be16 */ 621162306a36Sopenharmony_ci rsp_payload->sfp_diag_desc.temperature = trx[0]; 621262306a36Sopenharmony_ci rsp_payload->sfp_diag_desc.vcc = trx[1]; 621362306a36Sopenharmony_ci rsp_payload->sfp_diag_desc.tx_bias = trx[2]; 621462306a36Sopenharmony_ci rsp_payload->sfp_diag_desc.tx_power = trx[3]; 621562306a36Sopenharmony_ci rsp_payload->sfp_diag_desc.rx_power = trx[4]; 621662306a36Sopenharmony_ci } 621762306a36Sopenharmony_ci } 621862306a36Sopenharmony_ci 621962306a36Sopenharmony_ci /* Port Speed Descriptor */ 622062306a36Sopenharmony_ci rsp_payload->port_speed_desc.desc_tag = cpu_to_be32(0x10001); 622162306a36Sopenharmony_ci rsp_payload->port_speed_desc.desc_len = 622262306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_speed_desc)); 622362306a36Sopenharmony_ci rsp_payload->port_speed_desc.speed_capab = cpu_to_be16( 622462306a36Sopenharmony_ci qla25xx_fdmi_port_speed_capability(ha)); 622562306a36Sopenharmony_ci rsp_payload->port_speed_desc.operating_speed = cpu_to_be16( 622662306a36Sopenharmony_ci qla25xx_fdmi_port_speed_currently(ha)); 622762306a36Sopenharmony_ci 622862306a36Sopenharmony_ci /* Link Error Status Descriptor */ 622962306a36Sopenharmony_ci rsp_payload->ls_err_desc.desc_tag = cpu_to_be32(0x10002); 623062306a36Sopenharmony_ci rsp_payload->ls_err_desc.desc_len = 623162306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_err_desc)); 623262306a36Sopenharmony_ci 623362306a36Sopenharmony_ci if (stat) { 623462306a36Sopenharmony_ci rval = qla24xx_get_isp_stats(vha, stat, stat_dma, 0); 623562306a36Sopenharmony_ci if (!rval) { 623662306a36Sopenharmony_ci rsp_payload->ls_err_desc.link_fail_cnt = 623762306a36Sopenharmony_ci cpu_to_be32(le32_to_cpu(stat->link_fail_cnt)); 623862306a36Sopenharmony_ci rsp_payload->ls_err_desc.loss_sync_cnt = 623962306a36Sopenharmony_ci cpu_to_be32(le32_to_cpu(stat->loss_sync_cnt)); 624062306a36Sopenharmony_ci rsp_payload->ls_err_desc.loss_sig_cnt = 624162306a36Sopenharmony_ci cpu_to_be32(le32_to_cpu(stat->loss_sig_cnt)); 624262306a36Sopenharmony_ci rsp_payload->ls_err_desc.prim_seq_err_cnt = 624362306a36Sopenharmony_ci cpu_to_be32(le32_to_cpu(stat->prim_seq_err_cnt)); 624462306a36Sopenharmony_ci rsp_payload->ls_err_desc.inval_xmit_word_cnt = 624562306a36Sopenharmony_ci cpu_to_be32(le32_to_cpu(stat->inval_xmit_word_cnt)); 624662306a36Sopenharmony_ci rsp_payload->ls_err_desc.inval_crc_cnt = 624762306a36Sopenharmony_ci cpu_to_be32(le32_to_cpu(stat->inval_crc_cnt)); 624862306a36Sopenharmony_ci rsp_payload->ls_err_desc.pn_port_phy_type |= BIT_6; 624962306a36Sopenharmony_ci } 625062306a36Sopenharmony_ci } 625162306a36Sopenharmony_ci 625262306a36Sopenharmony_ci /* Portname Descriptor */ 625362306a36Sopenharmony_ci rsp_payload->port_name_diag_desc.desc_tag = cpu_to_be32(0x10003); 625462306a36Sopenharmony_ci rsp_payload->port_name_diag_desc.desc_len = 625562306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_name_diag_desc)); 625662306a36Sopenharmony_ci memcpy(rsp_payload->port_name_diag_desc.WWNN, 625762306a36Sopenharmony_ci vha->node_name, 625862306a36Sopenharmony_ci sizeof(rsp_payload->port_name_diag_desc.WWNN)); 625962306a36Sopenharmony_ci memcpy(rsp_payload->port_name_diag_desc.WWPN, 626062306a36Sopenharmony_ci vha->port_name, 626162306a36Sopenharmony_ci sizeof(rsp_payload->port_name_diag_desc.WWPN)); 626262306a36Sopenharmony_ci 626362306a36Sopenharmony_ci /* F-Port Portname Descriptor */ 626462306a36Sopenharmony_ci rsp_payload->port_name_direct_desc.desc_tag = cpu_to_be32(0x10003); 626562306a36Sopenharmony_ci rsp_payload->port_name_direct_desc.desc_len = 626662306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_name_direct_desc)); 626762306a36Sopenharmony_ci memcpy(rsp_payload->port_name_direct_desc.WWNN, 626862306a36Sopenharmony_ci vha->fabric_node_name, 626962306a36Sopenharmony_ci sizeof(rsp_payload->port_name_direct_desc.WWNN)); 627062306a36Sopenharmony_ci memcpy(rsp_payload->port_name_direct_desc.WWPN, 627162306a36Sopenharmony_ci vha->fabric_port_name, 627262306a36Sopenharmony_ci sizeof(rsp_payload->port_name_direct_desc.WWPN)); 627362306a36Sopenharmony_ci 627462306a36Sopenharmony_ci /* Bufer Credit Descriptor */ 627562306a36Sopenharmony_ci rsp_payload->buffer_credit_desc.desc_tag = cpu_to_be32(0x10006); 627662306a36Sopenharmony_ci rsp_payload->buffer_credit_desc.desc_len = 627762306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(rsp_payload->buffer_credit_desc)); 627862306a36Sopenharmony_ci rsp_payload->buffer_credit_desc.fcport_b2b = 0; 627962306a36Sopenharmony_ci rsp_payload->buffer_credit_desc.attached_fcport_b2b = cpu_to_be32(0); 628062306a36Sopenharmony_ci rsp_payload->buffer_credit_desc.fcport_rtt = cpu_to_be32(0); 628162306a36Sopenharmony_ci 628262306a36Sopenharmony_ci if (ha->flags.plogi_template_valid) { 628362306a36Sopenharmony_ci uint32_t tmp = 628462306a36Sopenharmony_ci be16_to_cpu(ha->plogi_els_payld.fl_csp.sp_bb_cred); 628562306a36Sopenharmony_ci rsp_payload->buffer_credit_desc.fcport_b2b = cpu_to_be32(tmp); 628662306a36Sopenharmony_ci } 628762306a36Sopenharmony_ci 628862306a36Sopenharmony_ci if (rsp_payload_length < sizeof(*rsp_payload)) 628962306a36Sopenharmony_ci goto send; 629062306a36Sopenharmony_ci 629162306a36Sopenharmony_ci /* Optical Element Descriptor, Temperature */ 629262306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[0].desc_tag = cpu_to_be32(0x10007); 629362306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[0].desc_len = 629462306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); 629562306a36Sopenharmony_ci /* Optical Element Descriptor, Voltage */ 629662306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[1].desc_tag = cpu_to_be32(0x10007); 629762306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[1].desc_len = 629862306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); 629962306a36Sopenharmony_ci /* Optical Element Descriptor, Tx Bias Current */ 630062306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[2].desc_tag = cpu_to_be32(0x10007); 630162306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[2].desc_len = 630262306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); 630362306a36Sopenharmony_ci /* Optical Element Descriptor, Tx Power */ 630462306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[3].desc_tag = cpu_to_be32(0x10007); 630562306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[3].desc_len = 630662306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); 630762306a36Sopenharmony_ci /* Optical Element Descriptor, Rx Power */ 630862306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[4].desc_tag = cpu_to_be32(0x10007); 630962306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[4].desc_len = 631062306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc)); 631162306a36Sopenharmony_ci 631262306a36Sopenharmony_ci if (sfp) { 631362306a36Sopenharmony_ci memset(sfp, 0, SFP_RTDI_LEN); 631462306a36Sopenharmony_ci rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 0, 64, 0); 631562306a36Sopenharmony_ci if (!rval) { 631662306a36Sopenharmony_ci __be16 *trx = (__force __be16 *)sfp; /* already be16 */ 631762306a36Sopenharmony_ci 631862306a36Sopenharmony_ci /* Optical Element Descriptor, Temperature */ 631962306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[0].high_alarm = trx[0]; 632062306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[0].low_alarm = trx[1]; 632162306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[0].high_warn = trx[2]; 632262306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[0].low_warn = trx[3]; 632362306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[0].element_flags = 632462306a36Sopenharmony_ci cpu_to_be32(1 << 28); 632562306a36Sopenharmony_ci 632662306a36Sopenharmony_ci /* Optical Element Descriptor, Voltage */ 632762306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[1].high_alarm = trx[4]; 632862306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[1].low_alarm = trx[5]; 632962306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[1].high_warn = trx[6]; 633062306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[1].low_warn = trx[7]; 633162306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[1].element_flags = 633262306a36Sopenharmony_ci cpu_to_be32(2 << 28); 633362306a36Sopenharmony_ci 633462306a36Sopenharmony_ci /* Optical Element Descriptor, Tx Bias Current */ 633562306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[2].high_alarm = trx[8]; 633662306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[2].low_alarm = trx[9]; 633762306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[2].high_warn = trx[10]; 633862306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[2].low_warn = trx[11]; 633962306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[2].element_flags = 634062306a36Sopenharmony_ci cpu_to_be32(3 << 28); 634162306a36Sopenharmony_ci 634262306a36Sopenharmony_ci /* Optical Element Descriptor, Tx Power */ 634362306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[3].high_alarm = trx[12]; 634462306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[3].low_alarm = trx[13]; 634562306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[3].high_warn = trx[14]; 634662306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[3].low_warn = trx[15]; 634762306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[3].element_flags = 634862306a36Sopenharmony_ci cpu_to_be32(4 << 28); 634962306a36Sopenharmony_ci 635062306a36Sopenharmony_ci /* Optical Element Descriptor, Rx Power */ 635162306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[4].high_alarm = trx[16]; 635262306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[4].low_alarm = trx[17]; 635362306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[4].high_warn = trx[18]; 635462306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[4].low_warn = trx[19]; 635562306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[4].element_flags = 635662306a36Sopenharmony_ci cpu_to_be32(5 << 28); 635762306a36Sopenharmony_ci } 635862306a36Sopenharmony_ci 635962306a36Sopenharmony_ci memset(sfp, 0, SFP_RTDI_LEN); 636062306a36Sopenharmony_ci rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 112, 64, 0); 636162306a36Sopenharmony_ci if (!rval) { 636262306a36Sopenharmony_ci /* Temperature high/low alarm/warning */ 636362306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[0].element_flags |= 636462306a36Sopenharmony_ci cpu_to_be32( 636562306a36Sopenharmony_ci (sfp[0] >> 7 & 1) << 3 | 636662306a36Sopenharmony_ci (sfp[0] >> 6 & 1) << 2 | 636762306a36Sopenharmony_ci (sfp[4] >> 7 & 1) << 1 | 636862306a36Sopenharmony_ci (sfp[4] >> 6 & 1) << 0); 636962306a36Sopenharmony_ci 637062306a36Sopenharmony_ci /* Voltage high/low alarm/warning */ 637162306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[1].element_flags |= 637262306a36Sopenharmony_ci cpu_to_be32( 637362306a36Sopenharmony_ci (sfp[0] >> 5 & 1) << 3 | 637462306a36Sopenharmony_ci (sfp[0] >> 4 & 1) << 2 | 637562306a36Sopenharmony_ci (sfp[4] >> 5 & 1) << 1 | 637662306a36Sopenharmony_ci (sfp[4] >> 4 & 1) << 0); 637762306a36Sopenharmony_ci 637862306a36Sopenharmony_ci /* Tx Bias Current high/low alarm/warning */ 637962306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[2].element_flags |= 638062306a36Sopenharmony_ci cpu_to_be32( 638162306a36Sopenharmony_ci (sfp[0] >> 3 & 1) << 3 | 638262306a36Sopenharmony_ci (sfp[0] >> 2 & 1) << 2 | 638362306a36Sopenharmony_ci (sfp[4] >> 3 & 1) << 1 | 638462306a36Sopenharmony_ci (sfp[4] >> 2 & 1) << 0); 638562306a36Sopenharmony_ci 638662306a36Sopenharmony_ci /* Tx Power high/low alarm/warning */ 638762306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[3].element_flags |= 638862306a36Sopenharmony_ci cpu_to_be32( 638962306a36Sopenharmony_ci (sfp[0] >> 1 & 1) << 3 | 639062306a36Sopenharmony_ci (sfp[0] >> 0 & 1) << 2 | 639162306a36Sopenharmony_ci (sfp[4] >> 1 & 1) << 1 | 639262306a36Sopenharmony_ci (sfp[4] >> 0 & 1) << 0); 639362306a36Sopenharmony_ci 639462306a36Sopenharmony_ci /* Rx Power high/low alarm/warning */ 639562306a36Sopenharmony_ci rsp_payload->optical_elmt_desc[4].element_flags |= 639662306a36Sopenharmony_ci cpu_to_be32( 639762306a36Sopenharmony_ci (sfp[1] >> 7 & 1) << 3 | 639862306a36Sopenharmony_ci (sfp[1] >> 6 & 1) << 2 | 639962306a36Sopenharmony_ci (sfp[5] >> 7 & 1) << 1 | 640062306a36Sopenharmony_ci (sfp[5] >> 6 & 1) << 0); 640162306a36Sopenharmony_ci } 640262306a36Sopenharmony_ci } 640362306a36Sopenharmony_ci 640462306a36Sopenharmony_ci /* Optical Product Data Descriptor */ 640562306a36Sopenharmony_ci rsp_payload->optical_prod_desc.desc_tag = cpu_to_be32(0x10008); 640662306a36Sopenharmony_ci rsp_payload->optical_prod_desc.desc_len = 640762306a36Sopenharmony_ci cpu_to_be32(RDP_DESC_LEN(rsp_payload->optical_prod_desc)); 640862306a36Sopenharmony_ci 640962306a36Sopenharmony_ci if (sfp) { 641062306a36Sopenharmony_ci memset(sfp, 0, SFP_RTDI_LEN); 641162306a36Sopenharmony_ci rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 20, 64, 0); 641262306a36Sopenharmony_ci if (!rval) { 641362306a36Sopenharmony_ci memcpy(rsp_payload->optical_prod_desc.vendor_name, 641462306a36Sopenharmony_ci sfp + 0, 641562306a36Sopenharmony_ci sizeof(rsp_payload->optical_prod_desc.vendor_name)); 641662306a36Sopenharmony_ci memcpy(rsp_payload->optical_prod_desc.part_number, 641762306a36Sopenharmony_ci sfp + 20, 641862306a36Sopenharmony_ci sizeof(rsp_payload->optical_prod_desc.part_number)); 641962306a36Sopenharmony_ci memcpy(rsp_payload->optical_prod_desc.revision, 642062306a36Sopenharmony_ci sfp + 36, 642162306a36Sopenharmony_ci sizeof(rsp_payload->optical_prod_desc.revision)); 642262306a36Sopenharmony_ci memcpy(rsp_payload->optical_prod_desc.serial_number, 642362306a36Sopenharmony_ci sfp + 48, 642462306a36Sopenharmony_ci sizeof(rsp_payload->optical_prod_desc.serial_number)); 642562306a36Sopenharmony_ci } 642662306a36Sopenharmony_ci 642762306a36Sopenharmony_ci memset(sfp, 0, SFP_RTDI_LEN); 642862306a36Sopenharmony_ci rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 84, 8, 0); 642962306a36Sopenharmony_ci if (!rval) { 643062306a36Sopenharmony_ci memcpy(rsp_payload->optical_prod_desc.date, 643162306a36Sopenharmony_ci sfp + 0, 643262306a36Sopenharmony_ci sizeof(rsp_payload->optical_prod_desc.date)); 643362306a36Sopenharmony_ci } 643462306a36Sopenharmony_ci } 643562306a36Sopenharmony_ci 643662306a36Sopenharmony_cisend: 643762306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0183, 643862306a36Sopenharmony_ci "Sending ELS Response to RDP Request...\n"); 643962306a36Sopenharmony_ci ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0184, 644062306a36Sopenharmony_ci "-------- ELS RSP -------\n"); 644162306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0185, 644262306a36Sopenharmony_ci rsp_els, sizeof(*rsp_els)); 644362306a36Sopenharmony_ci ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0186, 644462306a36Sopenharmony_ci "-------- ELS RSP PAYLOAD -------\n"); 644562306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0187, 644662306a36Sopenharmony_ci rsp_payload, rsp_payload_length); 644762306a36Sopenharmony_ci 644862306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, rsp_els, rsp_els_dma, 0); 644962306a36Sopenharmony_ci 645062306a36Sopenharmony_ci if (rval) { 645162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0188, 645262306a36Sopenharmony_ci "%s: iocb failed to execute -> %x\n", __func__, rval); 645362306a36Sopenharmony_ci } else if (rsp_els->comp_status) { 645462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0189, 645562306a36Sopenharmony_ci "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n", 645662306a36Sopenharmony_ci __func__, rsp_els->comp_status, 645762306a36Sopenharmony_ci rsp_els->error_subcode_1, rsp_els->error_subcode_2); 645862306a36Sopenharmony_ci } else { 645962306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x018a, "%s: done.\n", __func__); 646062306a36Sopenharmony_ci } 646162306a36Sopenharmony_ci 646262306a36Sopenharmony_cidealloc: 646362306a36Sopenharmony_ci if (stat) 646462306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*stat), 646562306a36Sopenharmony_ci stat, stat_dma); 646662306a36Sopenharmony_ci if (sfp) 646762306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, SFP_RTDI_LEN, 646862306a36Sopenharmony_ci sfp, sfp_dma); 646962306a36Sopenharmony_ci if (rsp_payload) 647062306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_payload), 647162306a36Sopenharmony_ci rsp_payload, rsp_payload_dma); 647262306a36Sopenharmony_ci if (rsp_els) 647362306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els), 647462306a36Sopenharmony_ci rsp_els, rsp_els_dma); 647562306a36Sopenharmony_ci} 647662306a36Sopenharmony_ci 647762306a36Sopenharmony_civoid 647862306a36Sopenharmony_ciqla24xx_free_purex_item(struct purex_item *item) 647962306a36Sopenharmony_ci{ 648062306a36Sopenharmony_ci if (item == &item->vha->default_item) 648162306a36Sopenharmony_ci memset(&item->vha->default_item, 0, sizeof(struct purex_item)); 648262306a36Sopenharmony_ci else 648362306a36Sopenharmony_ci kfree(item); 648462306a36Sopenharmony_ci} 648562306a36Sopenharmony_ci 648662306a36Sopenharmony_civoid qla24xx_process_purex_list(struct purex_list *list) 648762306a36Sopenharmony_ci{ 648862306a36Sopenharmony_ci struct list_head head = LIST_HEAD_INIT(head); 648962306a36Sopenharmony_ci struct purex_item *item, *next; 649062306a36Sopenharmony_ci ulong flags; 649162306a36Sopenharmony_ci 649262306a36Sopenharmony_ci spin_lock_irqsave(&list->lock, flags); 649362306a36Sopenharmony_ci list_splice_init(&list->head, &head); 649462306a36Sopenharmony_ci spin_unlock_irqrestore(&list->lock, flags); 649562306a36Sopenharmony_ci 649662306a36Sopenharmony_ci list_for_each_entry_safe(item, next, &head, list) { 649762306a36Sopenharmony_ci list_del(&item->list); 649862306a36Sopenharmony_ci item->process_item(item->vha, item); 649962306a36Sopenharmony_ci qla24xx_free_purex_item(item); 650062306a36Sopenharmony_ci } 650162306a36Sopenharmony_ci} 650262306a36Sopenharmony_ci 650362306a36Sopenharmony_ci/* 650462306a36Sopenharmony_ci * Context: task, can sleep 650562306a36Sopenharmony_ci */ 650662306a36Sopenharmony_civoid 650762306a36Sopenharmony_ciqla83xx_idc_unlock(scsi_qla_host_t *base_vha, uint16_t requester_id) 650862306a36Sopenharmony_ci{ 650962306a36Sopenharmony_ci#if 0 651062306a36Sopenharmony_ci uint16_t options = (requester_id << 15) | BIT_7; 651162306a36Sopenharmony_ci#endif 651262306a36Sopenharmony_ci uint16_t retry; 651362306a36Sopenharmony_ci uint32_t data; 651462306a36Sopenharmony_ci struct qla_hw_data *ha = base_vha->hw; 651562306a36Sopenharmony_ci 651662306a36Sopenharmony_ci might_sleep(); 651762306a36Sopenharmony_ci 651862306a36Sopenharmony_ci /* IDC-unlock implementation using driver-unlock/lock-id 651962306a36Sopenharmony_ci * remote registers 652062306a36Sopenharmony_ci */ 652162306a36Sopenharmony_ci retry = 0; 652262306a36Sopenharmony_ciretry_unlock: 652362306a36Sopenharmony_ci if (qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCKID, &data) 652462306a36Sopenharmony_ci == QLA_SUCCESS) { 652562306a36Sopenharmony_ci if (data == ha->portnum) { 652662306a36Sopenharmony_ci qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_UNLOCK, &data); 652762306a36Sopenharmony_ci /* Clearing lock-id by setting 0xff */ 652862306a36Sopenharmony_ci qla83xx_wr_reg(base_vha, QLA83XX_DRIVER_LOCKID, 0xff); 652962306a36Sopenharmony_ci } else if (retry < 10) { 653062306a36Sopenharmony_ci /* SV: XXX: IDC unlock retrying needed here? */ 653162306a36Sopenharmony_ci 653262306a36Sopenharmony_ci /* Retry for IDC-unlock */ 653362306a36Sopenharmony_ci msleep(QLA83XX_WAIT_LOGIC_MS); 653462306a36Sopenharmony_ci retry++; 653562306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb064, 653662306a36Sopenharmony_ci "Failed to release IDC lock, retrying=%d\n", retry); 653762306a36Sopenharmony_ci goto retry_unlock; 653862306a36Sopenharmony_ci } 653962306a36Sopenharmony_ci } else if (retry < 10) { 654062306a36Sopenharmony_ci /* Retry for IDC-unlock */ 654162306a36Sopenharmony_ci msleep(QLA83XX_WAIT_LOGIC_MS); 654262306a36Sopenharmony_ci retry++; 654362306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb065, 654462306a36Sopenharmony_ci "Failed to read drv-lockid, retrying=%d\n", retry); 654562306a36Sopenharmony_ci goto retry_unlock; 654662306a36Sopenharmony_ci } 654762306a36Sopenharmony_ci 654862306a36Sopenharmony_ci return; 654962306a36Sopenharmony_ci 655062306a36Sopenharmony_ci#if 0 655162306a36Sopenharmony_ci /* XXX: IDC-unlock implementation using access-control mbx */ 655262306a36Sopenharmony_ci retry = 0; 655362306a36Sopenharmony_ciretry_unlock2: 655462306a36Sopenharmony_ci if (qla83xx_access_control(base_vha, options, 0, 0, NULL)) { 655562306a36Sopenharmony_ci if (retry < 10) { 655662306a36Sopenharmony_ci /* Retry for IDC-unlock */ 655762306a36Sopenharmony_ci msleep(QLA83XX_WAIT_LOGIC_MS); 655862306a36Sopenharmony_ci retry++; 655962306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb066, 656062306a36Sopenharmony_ci "Failed to release IDC lock, retrying=%d\n", retry); 656162306a36Sopenharmony_ci goto retry_unlock2; 656262306a36Sopenharmony_ci } 656362306a36Sopenharmony_ci } 656462306a36Sopenharmony_ci 656562306a36Sopenharmony_ci return; 656662306a36Sopenharmony_ci#endif 656762306a36Sopenharmony_ci} 656862306a36Sopenharmony_ci 656962306a36Sopenharmony_ciint 657062306a36Sopenharmony_ci__qla83xx_set_drv_presence(scsi_qla_host_t *vha) 657162306a36Sopenharmony_ci{ 657262306a36Sopenharmony_ci int rval = QLA_SUCCESS; 657362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 657462306a36Sopenharmony_ci uint32_t drv_presence; 657562306a36Sopenharmony_ci 657662306a36Sopenharmony_ci rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence); 657762306a36Sopenharmony_ci if (rval == QLA_SUCCESS) { 657862306a36Sopenharmony_ci drv_presence |= (1 << ha->portnum); 657962306a36Sopenharmony_ci rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRV_PRESENCE, 658062306a36Sopenharmony_ci drv_presence); 658162306a36Sopenharmony_ci } 658262306a36Sopenharmony_ci 658362306a36Sopenharmony_ci return rval; 658462306a36Sopenharmony_ci} 658562306a36Sopenharmony_ci 658662306a36Sopenharmony_ciint 658762306a36Sopenharmony_ciqla83xx_set_drv_presence(scsi_qla_host_t *vha) 658862306a36Sopenharmony_ci{ 658962306a36Sopenharmony_ci int rval = QLA_SUCCESS; 659062306a36Sopenharmony_ci 659162306a36Sopenharmony_ci qla83xx_idc_lock(vha, 0); 659262306a36Sopenharmony_ci rval = __qla83xx_set_drv_presence(vha); 659362306a36Sopenharmony_ci qla83xx_idc_unlock(vha, 0); 659462306a36Sopenharmony_ci 659562306a36Sopenharmony_ci return rval; 659662306a36Sopenharmony_ci} 659762306a36Sopenharmony_ci 659862306a36Sopenharmony_ciint 659962306a36Sopenharmony_ci__qla83xx_clear_drv_presence(scsi_qla_host_t *vha) 660062306a36Sopenharmony_ci{ 660162306a36Sopenharmony_ci int rval = QLA_SUCCESS; 660262306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 660362306a36Sopenharmony_ci uint32_t drv_presence; 660462306a36Sopenharmony_ci 660562306a36Sopenharmony_ci rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence); 660662306a36Sopenharmony_ci if (rval == QLA_SUCCESS) { 660762306a36Sopenharmony_ci drv_presence &= ~(1 << ha->portnum); 660862306a36Sopenharmony_ci rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRV_PRESENCE, 660962306a36Sopenharmony_ci drv_presence); 661062306a36Sopenharmony_ci } 661162306a36Sopenharmony_ci 661262306a36Sopenharmony_ci return rval; 661362306a36Sopenharmony_ci} 661462306a36Sopenharmony_ci 661562306a36Sopenharmony_ciint 661662306a36Sopenharmony_ciqla83xx_clear_drv_presence(scsi_qla_host_t *vha) 661762306a36Sopenharmony_ci{ 661862306a36Sopenharmony_ci int rval = QLA_SUCCESS; 661962306a36Sopenharmony_ci 662062306a36Sopenharmony_ci qla83xx_idc_lock(vha, 0); 662162306a36Sopenharmony_ci rval = __qla83xx_clear_drv_presence(vha); 662262306a36Sopenharmony_ci qla83xx_idc_unlock(vha, 0); 662362306a36Sopenharmony_ci 662462306a36Sopenharmony_ci return rval; 662562306a36Sopenharmony_ci} 662662306a36Sopenharmony_ci 662762306a36Sopenharmony_cistatic void 662862306a36Sopenharmony_ciqla83xx_need_reset_handler(scsi_qla_host_t *vha) 662962306a36Sopenharmony_ci{ 663062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 663162306a36Sopenharmony_ci uint32_t drv_ack, drv_presence; 663262306a36Sopenharmony_ci unsigned long ack_timeout; 663362306a36Sopenharmony_ci 663462306a36Sopenharmony_ci /* Wait for IDC ACK from all functions (DRV-ACK == DRV-PRESENCE) */ 663562306a36Sopenharmony_ci ack_timeout = jiffies + (ha->fcoe_reset_timeout * HZ); 663662306a36Sopenharmony_ci while (1) { 663762306a36Sopenharmony_ci qla83xx_rd_reg(vha, QLA83XX_IDC_DRIVER_ACK, &drv_ack); 663862306a36Sopenharmony_ci qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence); 663962306a36Sopenharmony_ci if ((drv_ack & drv_presence) == drv_presence) 664062306a36Sopenharmony_ci break; 664162306a36Sopenharmony_ci 664262306a36Sopenharmony_ci if (time_after_eq(jiffies, ack_timeout)) { 664362306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb067, 664462306a36Sopenharmony_ci "RESET ACK TIMEOUT! drv_presence=0x%x " 664562306a36Sopenharmony_ci "drv_ack=0x%x\n", drv_presence, drv_ack); 664662306a36Sopenharmony_ci /* 664762306a36Sopenharmony_ci * The function(s) which did not ack in time are forced 664862306a36Sopenharmony_ci * to withdraw any further participation in the IDC 664962306a36Sopenharmony_ci * reset. 665062306a36Sopenharmony_ci */ 665162306a36Sopenharmony_ci if (drv_ack != drv_presence) 665262306a36Sopenharmony_ci qla83xx_wr_reg(vha, QLA83XX_IDC_DRV_PRESENCE, 665362306a36Sopenharmony_ci drv_ack); 665462306a36Sopenharmony_ci break; 665562306a36Sopenharmony_ci } 665662306a36Sopenharmony_ci 665762306a36Sopenharmony_ci qla83xx_idc_unlock(vha, 0); 665862306a36Sopenharmony_ci msleep(1000); 665962306a36Sopenharmony_ci qla83xx_idc_lock(vha, 0); 666062306a36Sopenharmony_ci } 666162306a36Sopenharmony_ci 666262306a36Sopenharmony_ci qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_COLD); 666362306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xb068, "HW State: COLD/RE-INIT.\n"); 666462306a36Sopenharmony_ci} 666562306a36Sopenharmony_ci 666662306a36Sopenharmony_cistatic int 666762306a36Sopenharmony_ciqla83xx_device_bootstrap(scsi_qla_host_t *vha) 666862306a36Sopenharmony_ci{ 666962306a36Sopenharmony_ci int rval = QLA_SUCCESS; 667062306a36Sopenharmony_ci uint32_t idc_control; 667162306a36Sopenharmony_ci 667262306a36Sopenharmony_ci qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_INITIALIZING); 667362306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xb069, "HW State: INITIALIZING.\n"); 667462306a36Sopenharmony_ci 667562306a36Sopenharmony_ci /* Clearing IDC-Control Graceful-Reset Bit before resetting f/w */ 667662306a36Sopenharmony_ci __qla83xx_get_idc_control(vha, &idc_control); 667762306a36Sopenharmony_ci idc_control &= ~QLA83XX_IDC_GRACEFUL_RESET; 667862306a36Sopenharmony_ci __qla83xx_set_idc_control(vha, 0); 667962306a36Sopenharmony_ci 668062306a36Sopenharmony_ci qla83xx_idc_unlock(vha, 0); 668162306a36Sopenharmony_ci rval = qla83xx_restart_nic_firmware(vha); 668262306a36Sopenharmony_ci qla83xx_idc_lock(vha, 0); 668362306a36Sopenharmony_ci 668462306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 668562306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb06a, 668662306a36Sopenharmony_ci "Failed to restart NIC f/w.\n"); 668762306a36Sopenharmony_ci qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_FAILED); 668862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xb06b, "HW State: FAILED.\n"); 668962306a36Sopenharmony_ci } else { 669062306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb06c, 669162306a36Sopenharmony_ci "Success in restarting nic f/w.\n"); 669262306a36Sopenharmony_ci qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_READY); 669362306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xb06d, "HW State: READY.\n"); 669462306a36Sopenharmony_ci } 669562306a36Sopenharmony_ci 669662306a36Sopenharmony_ci return rval; 669762306a36Sopenharmony_ci} 669862306a36Sopenharmony_ci 669962306a36Sopenharmony_ci/* Assumes idc_lock always held on entry */ 670062306a36Sopenharmony_ciint 670162306a36Sopenharmony_ciqla83xx_idc_state_handler(scsi_qla_host_t *base_vha) 670262306a36Sopenharmony_ci{ 670362306a36Sopenharmony_ci struct qla_hw_data *ha = base_vha->hw; 670462306a36Sopenharmony_ci int rval = QLA_SUCCESS; 670562306a36Sopenharmony_ci unsigned long dev_init_timeout; 670662306a36Sopenharmony_ci uint32_t dev_state; 670762306a36Sopenharmony_ci 670862306a36Sopenharmony_ci /* Wait for MAX-INIT-TIMEOUT for the device to go ready */ 670962306a36Sopenharmony_ci dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ); 671062306a36Sopenharmony_ci 671162306a36Sopenharmony_ci while (1) { 671262306a36Sopenharmony_ci 671362306a36Sopenharmony_ci if (time_after_eq(jiffies, dev_init_timeout)) { 671462306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0xb06e, 671562306a36Sopenharmony_ci "Initialization TIMEOUT!\n"); 671662306a36Sopenharmony_ci /* Init timeout. Disable further NIC Core 671762306a36Sopenharmony_ci * communication. 671862306a36Sopenharmony_ci */ 671962306a36Sopenharmony_ci qla83xx_wr_reg(base_vha, QLA83XX_IDC_DEV_STATE, 672062306a36Sopenharmony_ci QLA8XXX_DEV_FAILED); 672162306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0xb06f, 672262306a36Sopenharmony_ci "HW State: FAILED.\n"); 672362306a36Sopenharmony_ci } 672462306a36Sopenharmony_ci 672562306a36Sopenharmony_ci qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state); 672662306a36Sopenharmony_ci switch (dev_state) { 672762306a36Sopenharmony_ci case QLA8XXX_DEV_READY: 672862306a36Sopenharmony_ci if (ha->flags.nic_core_reset_owner) 672962306a36Sopenharmony_ci qla83xx_idc_audit(base_vha, 673062306a36Sopenharmony_ci IDC_AUDIT_COMPLETION); 673162306a36Sopenharmony_ci ha->flags.nic_core_reset_owner = 0; 673262306a36Sopenharmony_ci ql_dbg(ql_dbg_p3p, base_vha, 0xb070, 673362306a36Sopenharmony_ci "Reset_owner reset by 0x%x.\n", 673462306a36Sopenharmony_ci ha->portnum); 673562306a36Sopenharmony_ci goto exit; 673662306a36Sopenharmony_ci case QLA8XXX_DEV_COLD: 673762306a36Sopenharmony_ci if (ha->flags.nic_core_reset_owner) 673862306a36Sopenharmony_ci rval = qla83xx_device_bootstrap(base_vha); 673962306a36Sopenharmony_ci else { 674062306a36Sopenharmony_ci /* Wait for AEN to change device-state */ 674162306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 674262306a36Sopenharmony_ci msleep(1000); 674362306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 674462306a36Sopenharmony_ci } 674562306a36Sopenharmony_ci break; 674662306a36Sopenharmony_ci case QLA8XXX_DEV_INITIALIZING: 674762306a36Sopenharmony_ci /* Wait for AEN to change device-state */ 674862306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 674962306a36Sopenharmony_ci msleep(1000); 675062306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 675162306a36Sopenharmony_ci break; 675262306a36Sopenharmony_ci case QLA8XXX_DEV_NEED_RESET: 675362306a36Sopenharmony_ci if (!ql2xdontresethba && ha->flags.nic_core_reset_owner) 675462306a36Sopenharmony_ci qla83xx_need_reset_handler(base_vha); 675562306a36Sopenharmony_ci else { 675662306a36Sopenharmony_ci /* Wait for AEN to change device-state */ 675762306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 675862306a36Sopenharmony_ci msleep(1000); 675962306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 676062306a36Sopenharmony_ci } 676162306a36Sopenharmony_ci /* reset timeout value after need reset handler */ 676262306a36Sopenharmony_ci dev_init_timeout = jiffies + 676362306a36Sopenharmony_ci (ha->fcoe_dev_init_timeout * HZ); 676462306a36Sopenharmony_ci break; 676562306a36Sopenharmony_ci case QLA8XXX_DEV_NEED_QUIESCENT: 676662306a36Sopenharmony_ci /* XXX: DEBUG for now */ 676762306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 676862306a36Sopenharmony_ci msleep(1000); 676962306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 677062306a36Sopenharmony_ci break; 677162306a36Sopenharmony_ci case QLA8XXX_DEV_QUIESCENT: 677262306a36Sopenharmony_ci /* XXX: DEBUG for now */ 677362306a36Sopenharmony_ci if (ha->flags.quiesce_owner) 677462306a36Sopenharmony_ci goto exit; 677562306a36Sopenharmony_ci 677662306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 677762306a36Sopenharmony_ci msleep(1000); 677862306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 677962306a36Sopenharmony_ci dev_init_timeout = jiffies + 678062306a36Sopenharmony_ci (ha->fcoe_dev_init_timeout * HZ); 678162306a36Sopenharmony_ci break; 678262306a36Sopenharmony_ci case QLA8XXX_DEV_FAILED: 678362306a36Sopenharmony_ci if (ha->flags.nic_core_reset_owner) 678462306a36Sopenharmony_ci qla83xx_idc_audit(base_vha, 678562306a36Sopenharmony_ci IDC_AUDIT_COMPLETION); 678662306a36Sopenharmony_ci ha->flags.nic_core_reset_owner = 0; 678762306a36Sopenharmony_ci __qla83xx_clear_drv_presence(base_vha); 678862306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 678962306a36Sopenharmony_ci qla8xxx_dev_failed_handler(base_vha); 679062306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 679162306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 679262306a36Sopenharmony_ci goto exit; 679362306a36Sopenharmony_ci case QLA8XXX_BAD_VALUE: 679462306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 679562306a36Sopenharmony_ci msleep(1000); 679662306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 679762306a36Sopenharmony_ci break; 679862306a36Sopenharmony_ci default: 679962306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0xb071, 680062306a36Sopenharmony_ci "Unknown Device State: %x.\n", dev_state); 680162306a36Sopenharmony_ci qla83xx_idc_unlock(base_vha, 0); 680262306a36Sopenharmony_ci qla8xxx_dev_failed_handler(base_vha); 680362306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 680462306a36Sopenharmony_ci qla83xx_idc_lock(base_vha, 0); 680562306a36Sopenharmony_ci goto exit; 680662306a36Sopenharmony_ci } 680762306a36Sopenharmony_ci } 680862306a36Sopenharmony_ci 680962306a36Sopenharmony_ciexit: 681062306a36Sopenharmony_ci return rval; 681162306a36Sopenharmony_ci} 681262306a36Sopenharmony_ci 681362306a36Sopenharmony_civoid 681462306a36Sopenharmony_ciqla2x00_disable_board_on_pci_error(struct work_struct *work) 681562306a36Sopenharmony_ci{ 681662306a36Sopenharmony_ci struct qla_hw_data *ha = container_of(work, struct qla_hw_data, 681762306a36Sopenharmony_ci board_disable); 681862306a36Sopenharmony_ci struct pci_dev *pdev = ha->pdev; 681962306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 682062306a36Sopenharmony_ci 682162306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0x015b, 682262306a36Sopenharmony_ci "Disabling adapter.\n"); 682362306a36Sopenharmony_ci 682462306a36Sopenharmony_ci if (!atomic_read(&pdev->enable_cnt)) { 682562306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0xfffc, 682662306a36Sopenharmony_ci "PCI device disabled, no action req for PCI error=%lx\n", 682762306a36Sopenharmony_ci base_vha->pci_flags); 682862306a36Sopenharmony_ci return; 682962306a36Sopenharmony_ci } 683062306a36Sopenharmony_ci 683162306a36Sopenharmony_ci /* 683262306a36Sopenharmony_ci * if UNLOADING flag is already set, then continue unload, 683362306a36Sopenharmony_ci * where it was set first. 683462306a36Sopenharmony_ci */ 683562306a36Sopenharmony_ci if (test_and_set_bit(UNLOADING, &base_vha->dpc_flags)) 683662306a36Sopenharmony_ci return; 683762306a36Sopenharmony_ci 683862306a36Sopenharmony_ci qla2x00_wait_for_sess_deletion(base_vha); 683962306a36Sopenharmony_ci 684062306a36Sopenharmony_ci qla2x00_delete_all_vps(ha, base_vha); 684162306a36Sopenharmony_ci 684262306a36Sopenharmony_ci qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); 684362306a36Sopenharmony_ci 684462306a36Sopenharmony_ci qla2x00_dfs_remove(base_vha); 684562306a36Sopenharmony_ci 684662306a36Sopenharmony_ci qla84xx_put_chip(base_vha); 684762306a36Sopenharmony_ci 684862306a36Sopenharmony_ci if (base_vha->timer_active) 684962306a36Sopenharmony_ci qla2x00_stop_timer(base_vha); 685062306a36Sopenharmony_ci 685162306a36Sopenharmony_ci base_vha->flags.online = 0; 685262306a36Sopenharmony_ci 685362306a36Sopenharmony_ci qla2x00_destroy_deferred_work(ha); 685462306a36Sopenharmony_ci 685562306a36Sopenharmony_ci /* 685662306a36Sopenharmony_ci * Do not try to stop beacon blink as it will issue a mailbox 685762306a36Sopenharmony_ci * command. 685862306a36Sopenharmony_ci */ 685962306a36Sopenharmony_ci qla2x00_free_sysfs_attr(base_vha, false); 686062306a36Sopenharmony_ci 686162306a36Sopenharmony_ci fc_remove_host(base_vha->host); 686262306a36Sopenharmony_ci 686362306a36Sopenharmony_ci scsi_remove_host(base_vha->host); 686462306a36Sopenharmony_ci 686562306a36Sopenharmony_ci base_vha->flags.init_done = 0; 686662306a36Sopenharmony_ci qla25xx_delete_queues(base_vha); 686762306a36Sopenharmony_ci qla2x00_free_fcports(base_vha); 686862306a36Sopenharmony_ci qla2x00_free_irqs(base_vha); 686962306a36Sopenharmony_ci qla2x00_mem_free(ha); 687062306a36Sopenharmony_ci qla82xx_md_free(base_vha); 687162306a36Sopenharmony_ci qla2x00_free_queues(ha); 687262306a36Sopenharmony_ci 687362306a36Sopenharmony_ci qla2x00_unmap_iobases(ha); 687462306a36Sopenharmony_ci 687562306a36Sopenharmony_ci pci_release_selected_regions(ha->pdev, ha->bars); 687662306a36Sopenharmony_ci pci_disable_device(pdev); 687762306a36Sopenharmony_ci 687862306a36Sopenharmony_ci /* 687962306a36Sopenharmony_ci * Let qla2x00_remove_one cleanup qla_hw_data on device removal. 688062306a36Sopenharmony_ci */ 688162306a36Sopenharmony_ci} 688262306a36Sopenharmony_ci 688362306a36Sopenharmony_ci/************************************************************************** 688462306a36Sopenharmony_ci* qla2x00_do_dpc 688562306a36Sopenharmony_ci* This kernel thread is a task that is schedule by the interrupt handler 688662306a36Sopenharmony_ci* to perform the background processing for interrupts. 688762306a36Sopenharmony_ci* 688862306a36Sopenharmony_ci* Notes: 688962306a36Sopenharmony_ci* This task always run in the context of a kernel thread. It 689062306a36Sopenharmony_ci* is kick-off by the driver's detect code and starts up 689162306a36Sopenharmony_ci* up one per adapter. It immediately goes to sleep and waits for 689262306a36Sopenharmony_ci* some fibre event. When either the interrupt handler or 689362306a36Sopenharmony_ci* the timer routine detects a event it will one of the task 689462306a36Sopenharmony_ci* bits then wake us up. 689562306a36Sopenharmony_ci**************************************************************************/ 689662306a36Sopenharmony_cistatic int 689762306a36Sopenharmony_ciqla2x00_do_dpc(void *data) 689862306a36Sopenharmony_ci{ 689962306a36Sopenharmony_ci scsi_qla_host_t *base_vha; 690062306a36Sopenharmony_ci struct qla_hw_data *ha; 690162306a36Sopenharmony_ci uint32_t online; 690262306a36Sopenharmony_ci struct qla_qpair *qpair; 690362306a36Sopenharmony_ci 690462306a36Sopenharmony_ci ha = (struct qla_hw_data *)data; 690562306a36Sopenharmony_ci base_vha = pci_get_drvdata(ha->pdev); 690662306a36Sopenharmony_ci 690762306a36Sopenharmony_ci set_user_nice(current, MIN_NICE); 690862306a36Sopenharmony_ci 690962306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 691062306a36Sopenharmony_ci while (!kthread_should_stop()) { 691162306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4000, 691262306a36Sopenharmony_ci "DPC handler sleeping.\n"); 691362306a36Sopenharmony_ci 691462306a36Sopenharmony_ci schedule(); 691562306a36Sopenharmony_ci 691662306a36Sopenharmony_ci if (test_and_clear_bit(DO_EEH_RECOVERY, &base_vha->dpc_flags)) 691762306a36Sopenharmony_ci qla_pci_set_eeh_busy(base_vha); 691862306a36Sopenharmony_ci 691962306a36Sopenharmony_ci if (!base_vha->flags.init_done || ha->flags.mbox_busy) 692062306a36Sopenharmony_ci goto end_loop; 692162306a36Sopenharmony_ci 692262306a36Sopenharmony_ci if (ha->flags.eeh_busy) { 692362306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4003, 692462306a36Sopenharmony_ci "eeh_busy=%d.\n", ha->flags.eeh_busy); 692562306a36Sopenharmony_ci goto end_loop; 692662306a36Sopenharmony_ci } 692762306a36Sopenharmony_ci 692862306a36Sopenharmony_ci ha->dpc_active = 1; 692962306a36Sopenharmony_ci 693062306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc + ql_dbg_verbose, base_vha, 0x4001, 693162306a36Sopenharmony_ci "DPC handler waking up, dpc_flags=0x%lx.\n", 693262306a36Sopenharmony_ci base_vha->dpc_flags); 693362306a36Sopenharmony_ci 693462306a36Sopenharmony_ci if (test_bit(UNLOADING, &base_vha->dpc_flags)) 693562306a36Sopenharmony_ci break; 693662306a36Sopenharmony_ci 693762306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) { 693862306a36Sopenharmony_ci if (IS_QLA8044(ha)) { 693962306a36Sopenharmony_ci if (test_and_clear_bit(ISP_UNRECOVERABLE, 694062306a36Sopenharmony_ci &base_vha->dpc_flags)) { 694162306a36Sopenharmony_ci qla8044_idc_lock(ha); 694262306a36Sopenharmony_ci qla8044_wr_direct(base_vha, 694362306a36Sopenharmony_ci QLA8044_CRB_DEV_STATE_INDEX, 694462306a36Sopenharmony_ci QLA8XXX_DEV_FAILED); 694562306a36Sopenharmony_ci qla8044_idc_unlock(ha); 694662306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0x4004, 694762306a36Sopenharmony_ci "HW State: FAILED.\n"); 694862306a36Sopenharmony_ci qla8044_device_state_handler(base_vha); 694962306a36Sopenharmony_ci continue; 695062306a36Sopenharmony_ci } 695162306a36Sopenharmony_ci 695262306a36Sopenharmony_ci } else { 695362306a36Sopenharmony_ci if (test_and_clear_bit(ISP_UNRECOVERABLE, 695462306a36Sopenharmony_ci &base_vha->dpc_flags)) { 695562306a36Sopenharmony_ci qla82xx_idc_lock(ha); 695662306a36Sopenharmony_ci qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, 695762306a36Sopenharmony_ci QLA8XXX_DEV_FAILED); 695862306a36Sopenharmony_ci qla82xx_idc_unlock(ha); 695962306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0x0151, 696062306a36Sopenharmony_ci "HW State: FAILED.\n"); 696162306a36Sopenharmony_ci qla82xx_device_state_handler(base_vha); 696262306a36Sopenharmony_ci continue; 696362306a36Sopenharmony_ci } 696462306a36Sopenharmony_ci } 696562306a36Sopenharmony_ci 696662306a36Sopenharmony_ci if (test_and_clear_bit(FCOE_CTX_RESET_NEEDED, 696762306a36Sopenharmony_ci &base_vha->dpc_flags)) { 696862306a36Sopenharmony_ci 696962306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4005, 697062306a36Sopenharmony_ci "FCoE context reset scheduled.\n"); 697162306a36Sopenharmony_ci if (!(test_and_set_bit(ABORT_ISP_ACTIVE, 697262306a36Sopenharmony_ci &base_vha->dpc_flags))) { 697362306a36Sopenharmony_ci if (qla82xx_fcoe_ctx_reset(base_vha)) { 697462306a36Sopenharmony_ci /* FCoE-ctx reset failed. 697562306a36Sopenharmony_ci * Escalate to chip-reset 697662306a36Sopenharmony_ci */ 697762306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, 697862306a36Sopenharmony_ci &base_vha->dpc_flags); 697962306a36Sopenharmony_ci } 698062306a36Sopenharmony_ci clear_bit(ABORT_ISP_ACTIVE, 698162306a36Sopenharmony_ci &base_vha->dpc_flags); 698262306a36Sopenharmony_ci } 698362306a36Sopenharmony_ci 698462306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4006, 698562306a36Sopenharmony_ci "FCoE context reset end.\n"); 698662306a36Sopenharmony_ci } 698762306a36Sopenharmony_ci } else if (IS_QLAFX00(ha)) { 698862306a36Sopenharmony_ci if (test_and_clear_bit(ISP_UNRECOVERABLE, 698962306a36Sopenharmony_ci &base_vha->dpc_flags)) { 699062306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4020, 699162306a36Sopenharmony_ci "Firmware Reset Recovery\n"); 699262306a36Sopenharmony_ci if (qlafx00_reset_initialize(base_vha)) { 699362306a36Sopenharmony_ci /* Failed. Abort isp later. */ 699462306a36Sopenharmony_ci if (!test_bit(UNLOADING, 699562306a36Sopenharmony_ci &base_vha->dpc_flags)) { 699662306a36Sopenharmony_ci set_bit(ISP_UNRECOVERABLE, 699762306a36Sopenharmony_ci &base_vha->dpc_flags); 699862306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 699962306a36Sopenharmony_ci 0x4021, 700062306a36Sopenharmony_ci "Reset Recovery Failed\n"); 700162306a36Sopenharmony_ci } 700262306a36Sopenharmony_ci } 700362306a36Sopenharmony_ci } 700462306a36Sopenharmony_ci 700562306a36Sopenharmony_ci if (test_and_clear_bit(FX00_TARGET_SCAN, 700662306a36Sopenharmony_ci &base_vha->dpc_flags)) { 700762306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4022, 700862306a36Sopenharmony_ci "ISPFx00 Target Scan scheduled\n"); 700962306a36Sopenharmony_ci if (qlafx00_rescan_isp(base_vha)) { 701062306a36Sopenharmony_ci if (!test_bit(UNLOADING, 701162306a36Sopenharmony_ci &base_vha->dpc_flags)) 701262306a36Sopenharmony_ci set_bit(ISP_UNRECOVERABLE, 701362306a36Sopenharmony_ci &base_vha->dpc_flags); 701462306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x401e, 701562306a36Sopenharmony_ci "ISPFx00 Target Scan Failed\n"); 701662306a36Sopenharmony_ci } 701762306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x401f, 701862306a36Sopenharmony_ci "ISPFx00 Target Scan End\n"); 701962306a36Sopenharmony_ci } 702062306a36Sopenharmony_ci if (test_and_clear_bit(FX00_HOST_INFO_RESEND, 702162306a36Sopenharmony_ci &base_vha->dpc_flags)) { 702262306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4023, 702362306a36Sopenharmony_ci "ISPFx00 Host Info resend scheduled\n"); 702462306a36Sopenharmony_ci qlafx00_fx_disc(base_vha, 702562306a36Sopenharmony_ci &base_vha->hw->mr.fcport, 702662306a36Sopenharmony_ci FXDISC_REG_HOST_INFO); 702762306a36Sopenharmony_ci } 702862306a36Sopenharmony_ci } 702962306a36Sopenharmony_ci 703062306a36Sopenharmony_ci if (test_and_clear_bit(DETECT_SFP_CHANGE, 703162306a36Sopenharmony_ci &base_vha->dpc_flags)) { 703262306a36Sopenharmony_ci /* Semantic: 703362306a36Sopenharmony_ci * - NO-OP -- await next ISP-ABORT. Preferred method 703462306a36Sopenharmony_ci * to minimize disruptions that will occur 703562306a36Sopenharmony_ci * when a forced chip-reset occurs. 703662306a36Sopenharmony_ci * - Force -- ISP-ABORT scheduled. 703762306a36Sopenharmony_ci */ 703862306a36Sopenharmony_ci /* set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); */ 703962306a36Sopenharmony_ci } 704062306a36Sopenharmony_ci 704162306a36Sopenharmony_ci if (test_and_clear_bit 704262306a36Sopenharmony_ci (ISP_ABORT_NEEDED, &base_vha->dpc_flags) && 704362306a36Sopenharmony_ci !test_bit(UNLOADING, &base_vha->dpc_flags)) { 704462306a36Sopenharmony_ci bool do_reset = true; 704562306a36Sopenharmony_ci 704662306a36Sopenharmony_ci switch (base_vha->qlini_mode) { 704762306a36Sopenharmony_ci case QLA2XXX_INI_MODE_ENABLED: 704862306a36Sopenharmony_ci break; 704962306a36Sopenharmony_ci case QLA2XXX_INI_MODE_DISABLED: 705062306a36Sopenharmony_ci if (!qla_tgt_mode_enabled(base_vha) && 705162306a36Sopenharmony_ci !ha->flags.fw_started) 705262306a36Sopenharmony_ci do_reset = false; 705362306a36Sopenharmony_ci break; 705462306a36Sopenharmony_ci case QLA2XXX_INI_MODE_DUAL: 705562306a36Sopenharmony_ci if (!qla_dual_mode_enabled(base_vha) && 705662306a36Sopenharmony_ci !ha->flags.fw_started) 705762306a36Sopenharmony_ci do_reset = false; 705862306a36Sopenharmony_ci break; 705962306a36Sopenharmony_ci default: 706062306a36Sopenharmony_ci break; 706162306a36Sopenharmony_ci } 706262306a36Sopenharmony_ci 706362306a36Sopenharmony_ci if (do_reset && !(test_and_set_bit(ABORT_ISP_ACTIVE, 706462306a36Sopenharmony_ci &base_vha->dpc_flags))) { 706562306a36Sopenharmony_ci base_vha->flags.online = 1; 706662306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4007, 706762306a36Sopenharmony_ci "ISP abort scheduled.\n"); 706862306a36Sopenharmony_ci if (ha->isp_ops->abort_isp(base_vha)) { 706962306a36Sopenharmony_ci /* failed. retry later */ 707062306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, 707162306a36Sopenharmony_ci &base_vha->dpc_flags); 707262306a36Sopenharmony_ci } 707362306a36Sopenharmony_ci clear_bit(ABORT_ISP_ACTIVE, 707462306a36Sopenharmony_ci &base_vha->dpc_flags); 707562306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4008, 707662306a36Sopenharmony_ci "ISP abort end.\n"); 707762306a36Sopenharmony_ci } 707862306a36Sopenharmony_ci } 707962306a36Sopenharmony_ci 708062306a36Sopenharmony_ci if (test_bit(PROCESS_PUREX_IOCB, &base_vha->dpc_flags)) { 708162306a36Sopenharmony_ci if (atomic_read(&base_vha->loop_state) == LOOP_READY) { 708262306a36Sopenharmony_ci qla24xx_process_purex_list 708362306a36Sopenharmony_ci (&base_vha->purex_list); 708462306a36Sopenharmony_ci clear_bit(PROCESS_PUREX_IOCB, 708562306a36Sopenharmony_ci &base_vha->dpc_flags); 708662306a36Sopenharmony_ci } 708762306a36Sopenharmony_ci } 708862306a36Sopenharmony_ci 708962306a36Sopenharmony_ci if (IS_QLAFX00(ha)) 709062306a36Sopenharmony_ci goto loop_resync_check; 709162306a36Sopenharmony_ci 709262306a36Sopenharmony_ci if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) { 709362306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4009, 709462306a36Sopenharmony_ci "Quiescence mode scheduled.\n"); 709562306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) { 709662306a36Sopenharmony_ci if (IS_QLA82XX(ha)) 709762306a36Sopenharmony_ci qla82xx_device_state_handler(base_vha); 709862306a36Sopenharmony_ci if (IS_QLA8044(ha)) 709962306a36Sopenharmony_ci qla8044_device_state_handler(base_vha); 710062306a36Sopenharmony_ci clear_bit(ISP_QUIESCE_NEEDED, 710162306a36Sopenharmony_ci &base_vha->dpc_flags); 710262306a36Sopenharmony_ci if (!ha->flags.quiesce_owner) { 710362306a36Sopenharmony_ci qla2x00_perform_loop_resync(base_vha); 710462306a36Sopenharmony_ci if (IS_QLA82XX(ha)) { 710562306a36Sopenharmony_ci qla82xx_idc_lock(ha); 710662306a36Sopenharmony_ci qla82xx_clear_qsnt_ready( 710762306a36Sopenharmony_ci base_vha); 710862306a36Sopenharmony_ci qla82xx_idc_unlock(ha); 710962306a36Sopenharmony_ci } else if (IS_QLA8044(ha)) { 711062306a36Sopenharmony_ci qla8044_idc_lock(ha); 711162306a36Sopenharmony_ci qla8044_clear_qsnt_ready( 711262306a36Sopenharmony_ci base_vha); 711362306a36Sopenharmony_ci qla8044_idc_unlock(ha); 711462306a36Sopenharmony_ci } 711562306a36Sopenharmony_ci } 711662306a36Sopenharmony_ci } else { 711762306a36Sopenharmony_ci clear_bit(ISP_QUIESCE_NEEDED, 711862306a36Sopenharmony_ci &base_vha->dpc_flags); 711962306a36Sopenharmony_ci qla2x00_quiesce_io(base_vha); 712062306a36Sopenharmony_ci } 712162306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x400a, 712262306a36Sopenharmony_ci "Quiescence mode end.\n"); 712362306a36Sopenharmony_ci } 712462306a36Sopenharmony_ci 712562306a36Sopenharmony_ci if (test_and_clear_bit(RESET_MARKER_NEEDED, 712662306a36Sopenharmony_ci &base_vha->dpc_flags) && 712762306a36Sopenharmony_ci (!(test_and_set_bit(RESET_ACTIVE, &base_vha->dpc_flags)))) { 712862306a36Sopenharmony_ci 712962306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x400b, 713062306a36Sopenharmony_ci "Reset marker scheduled.\n"); 713162306a36Sopenharmony_ci qla2x00_rst_aen(base_vha); 713262306a36Sopenharmony_ci clear_bit(RESET_ACTIVE, &base_vha->dpc_flags); 713362306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x400c, 713462306a36Sopenharmony_ci "Reset marker end.\n"); 713562306a36Sopenharmony_ci } 713662306a36Sopenharmony_ci 713762306a36Sopenharmony_ci /* Retry each device up to login retry count */ 713862306a36Sopenharmony_ci if (test_bit(RELOGIN_NEEDED, &base_vha->dpc_flags) && 713962306a36Sopenharmony_ci !test_bit(LOOP_RESYNC_NEEDED, &base_vha->dpc_flags) && 714062306a36Sopenharmony_ci atomic_read(&base_vha->loop_state) != LOOP_DOWN) { 714162306a36Sopenharmony_ci 714262306a36Sopenharmony_ci if (!base_vha->relogin_jif || 714362306a36Sopenharmony_ci time_after_eq(jiffies, base_vha->relogin_jif)) { 714462306a36Sopenharmony_ci base_vha->relogin_jif = jiffies + HZ; 714562306a36Sopenharmony_ci clear_bit(RELOGIN_NEEDED, &base_vha->dpc_flags); 714662306a36Sopenharmony_ci 714762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, base_vha, 0x400d, 714862306a36Sopenharmony_ci "Relogin scheduled.\n"); 714962306a36Sopenharmony_ci qla24xx_post_relogin_work(base_vha); 715062306a36Sopenharmony_ci } 715162306a36Sopenharmony_ci } 715262306a36Sopenharmony_ciloop_resync_check: 715362306a36Sopenharmony_ci if (!qla2x00_reset_active(base_vha) && 715462306a36Sopenharmony_ci test_and_clear_bit(LOOP_RESYNC_NEEDED, 715562306a36Sopenharmony_ci &base_vha->dpc_flags)) { 715662306a36Sopenharmony_ci /* 715762306a36Sopenharmony_ci * Allow abort_isp to complete before moving on to scanning. 715862306a36Sopenharmony_ci */ 715962306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x400f, 716062306a36Sopenharmony_ci "Loop resync scheduled.\n"); 716162306a36Sopenharmony_ci 716262306a36Sopenharmony_ci if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, 716362306a36Sopenharmony_ci &base_vha->dpc_flags))) { 716462306a36Sopenharmony_ci 716562306a36Sopenharmony_ci qla2x00_loop_resync(base_vha); 716662306a36Sopenharmony_ci 716762306a36Sopenharmony_ci clear_bit(LOOP_RESYNC_ACTIVE, 716862306a36Sopenharmony_ci &base_vha->dpc_flags); 716962306a36Sopenharmony_ci } 717062306a36Sopenharmony_ci 717162306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4010, 717262306a36Sopenharmony_ci "Loop resync end.\n"); 717362306a36Sopenharmony_ci } 717462306a36Sopenharmony_ci 717562306a36Sopenharmony_ci if (IS_QLAFX00(ha)) 717662306a36Sopenharmony_ci goto intr_on_check; 717762306a36Sopenharmony_ci 717862306a36Sopenharmony_ci if (test_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags) && 717962306a36Sopenharmony_ci atomic_read(&base_vha->loop_state) == LOOP_READY) { 718062306a36Sopenharmony_ci clear_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags); 718162306a36Sopenharmony_ci qla2xxx_flash_npiv_conf(base_vha); 718262306a36Sopenharmony_ci } 718362306a36Sopenharmony_ci 718462306a36Sopenharmony_ciintr_on_check: 718562306a36Sopenharmony_ci if (!ha->interrupts_on) 718662306a36Sopenharmony_ci ha->isp_ops->enable_intrs(ha); 718762306a36Sopenharmony_ci 718862306a36Sopenharmony_ci if (test_and_clear_bit(BEACON_BLINK_NEEDED, 718962306a36Sopenharmony_ci &base_vha->dpc_flags)) { 719062306a36Sopenharmony_ci if (ha->beacon_blink_led == 1) 719162306a36Sopenharmony_ci ha->isp_ops->beacon_blink(base_vha); 719262306a36Sopenharmony_ci } 719362306a36Sopenharmony_ci 719462306a36Sopenharmony_ci /* qpair online check */ 719562306a36Sopenharmony_ci if (test_and_clear_bit(QPAIR_ONLINE_CHECK_NEEDED, 719662306a36Sopenharmony_ci &base_vha->dpc_flags)) { 719762306a36Sopenharmony_ci if (ha->flags.eeh_busy || 719862306a36Sopenharmony_ci ha->flags.pci_channel_io_perm_failure) 719962306a36Sopenharmony_ci online = 0; 720062306a36Sopenharmony_ci else 720162306a36Sopenharmony_ci online = 1; 720262306a36Sopenharmony_ci 720362306a36Sopenharmony_ci mutex_lock(&ha->mq_lock); 720462306a36Sopenharmony_ci list_for_each_entry(qpair, &base_vha->qp_list, 720562306a36Sopenharmony_ci qp_list_elem) 720662306a36Sopenharmony_ci qpair->online = online; 720762306a36Sopenharmony_ci mutex_unlock(&ha->mq_lock); 720862306a36Sopenharmony_ci } 720962306a36Sopenharmony_ci 721062306a36Sopenharmony_ci if (test_and_clear_bit(SET_ZIO_THRESHOLD_NEEDED, 721162306a36Sopenharmony_ci &base_vha->dpc_flags)) { 721262306a36Sopenharmony_ci u16 threshold = ha->nvme_last_rptd_aen + ha->last_zio_threshold; 721362306a36Sopenharmony_ci 721462306a36Sopenharmony_ci if (threshold > ha->orig_fw_xcb_count) 721562306a36Sopenharmony_ci threshold = ha->orig_fw_xcb_count; 721662306a36Sopenharmony_ci 721762306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0xffffff, 721862306a36Sopenharmony_ci "SET ZIO Activity exchange threshold to %d.\n", 721962306a36Sopenharmony_ci threshold); 722062306a36Sopenharmony_ci if (qla27xx_set_zio_threshold(base_vha, threshold)) { 722162306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0xffffff, 722262306a36Sopenharmony_ci "Unable to SET ZIO Activity exchange threshold to %d.\n", 722362306a36Sopenharmony_ci threshold); 722462306a36Sopenharmony_ci } 722562306a36Sopenharmony_ci } 722662306a36Sopenharmony_ci 722762306a36Sopenharmony_ci if (!IS_QLAFX00(ha)) 722862306a36Sopenharmony_ci qla2x00_do_dpc_all_vps(base_vha); 722962306a36Sopenharmony_ci 723062306a36Sopenharmony_ci if (test_and_clear_bit(N2N_LINK_RESET, 723162306a36Sopenharmony_ci &base_vha->dpc_flags)) { 723262306a36Sopenharmony_ci qla2x00_lip_reset(base_vha); 723362306a36Sopenharmony_ci } 723462306a36Sopenharmony_ci 723562306a36Sopenharmony_ci ha->dpc_active = 0; 723662306a36Sopenharmony_ciend_loop: 723762306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 723862306a36Sopenharmony_ci } /* End of while(1) */ 723962306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 724062306a36Sopenharmony_ci 724162306a36Sopenharmony_ci ql_dbg(ql_dbg_dpc, base_vha, 0x4011, 724262306a36Sopenharmony_ci "DPC handler exiting.\n"); 724362306a36Sopenharmony_ci 724462306a36Sopenharmony_ci /* 724562306a36Sopenharmony_ci * Make sure that nobody tries to wake us up again. 724662306a36Sopenharmony_ci */ 724762306a36Sopenharmony_ci ha->dpc_active = 0; 724862306a36Sopenharmony_ci 724962306a36Sopenharmony_ci /* Cleanup any residual CTX SRBs. */ 725062306a36Sopenharmony_ci qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); 725162306a36Sopenharmony_ci 725262306a36Sopenharmony_ci return 0; 725362306a36Sopenharmony_ci} 725462306a36Sopenharmony_ci 725562306a36Sopenharmony_civoid 725662306a36Sopenharmony_ciqla2xxx_wake_dpc(struct scsi_qla_host *vha) 725762306a36Sopenharmony_ci{ 725862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 725962306a36Sopenharmony_ci struct task_struct *t = ha->dpc_thread; 726062306a36Sopenharmony_ci 726162306a36Sopenharmony_ci if (!test_bit(UNLOADING, &vha->dpc_flags) && t) 726262306a36Sopenharmony_ci wake_up_process(t); 726362306a36Sopenharmony_ci} 726462306a36Sopenharmony_ci 726562306a36Sopenharmony_ci/* 726662306a36Sopenharmony_ci* qla2x00_rst_aen 726762306a36Sopenharmony_ci* Processes asynchronous reset. 726862306a36Sopenharmony_ci* 726962306a36Sopenharmony_ci* Input: 727062306a36Sopenharmony_ci* ha = adapter block pointer. 727162306a36Sopenharmony_ci*/ 727262306a36Sopenharmony_cistatic void 727362306a36Sopenharmony_ciqla2x00_rst_aen(scsi_qla_host_t *vha) 727462306a36Sopenharmony_ci{ 727562306a36Sopenharmony_ci if (vha->flags.online && !vha->flags.reset_active && 727662306a36Sopenharmony_ci !atomic_read(&vha->loop_down_timer) && 727762306a36Sopenharmony_ci !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))) { 727862306a36Sopenharmony_ci do { 727962306a36Sopenharmony_ci clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); 728062306a36Sopenharmony_ci 728162306a36Sopenharmony_ci /* 728262306a36Sopenharmony_ci * Issue marker command only when we are going to start 728362306a36Sopenharmony_ci * the I/O. 728462306a36Sopenharmony_ci */ 728562306a36Sopenharmony_ci vha->marker_needed = 1; 728662306a36Sopenharmony_ci } while (!atomic_read(&vha->loop_down_timer) && 728762306a36Sopenharmony_ci (test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags))); 728862306a36Sopenharmony_ci } 728962306a36Sopenharmony_ci} 729062306a36Sopenharmony_ci 729162306a36Sopenharmony_cistatic bool qla_do_heartbeat(struct scsi_qla_host *vha) 729262306a36Sopenharmony_ci{ 729362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 729462306a36Sopenharmony_ci u32 cmpl_cnt; 729562306a36Sopenharmony_ci u16 i; 729662306a36Sopenharmony_ci bool do_heartbeat = false; 729762306a36Sopenharmony_ci 729862306a36Sopenharmony_ci /* 729962306a36Sopenharmony_ci * Allow do_heartbeat only if we don’t have any active interrupts, 730062306a36Sopenharmony_ci * but there are still IOs outstanding with firmware. 730162306a36Sopenharmony_ci */ 730262306a36Sopenharmony_ci cmpl_cnt = ha->base_qpair->cmd_completion_cnt; 730362306a36Sopenharmony_ci if (cmpl_cnt == ha->base_qpair->prev_completion_cnt && 730462306a36Sopenharmony_ci cmpl_cnt != ha->base_qpair->cmd_cnt) { 730562306a36Sopenharmony_ci do_heartbeat = true; 730662306a36Sopenharmony_ci goto skip; 730762306a36Sopenharmony_ci } 730862306a36Sopenharmony_ci ha->base_qpair->prev_completion_cnt = cmpl_cnt; 730962306a36Sopenharmony_ci 731062306a36Sopenharmony_ci for (i = 0; i < ha->max_qpairs; i++) { 731162306a36Sopenharmony_ci if (ha->queue_pair_map[i]) { 731262306a36Sopenharmony_ci cmpl_cnt = ha->queue_pair_map[i]->cmd_completion_cnt; 731362306a36Sopenharmony_ci if (cmpl_cnt == ha->queue_pair_map[i]->prev_completion_cnt && 731462306a36Sopenharmony_ci cmpl_cnt != ha->queue_pair_map[i]->cmd_cnt) { 731562306a36Sopenharmony_ci do_heartbeat = true; 731662306a36Sopenharmony_ci break; 731762306a36Sopenharmony_ci } 731862306a36Sopenharmony_ci ha->queue_pair_map[i]->prev_completion_cnt = cmpl_cnt; 731962306a36Sopenharmony_ci } 732062306a36Sopenharmony_ci } 732162306a36Sopenharmony_ci 732262306a36Sopenharmony_ciskip: 732362306a36Sopenharmony_ci return do_heartbeat; 732462306a36Sopenharmony_ci} 732562306a36Sopenharmony_ci 732662306a36Sopenharmony_cistatic void qla_heart_beat(struct scsi_qla_host *vha, u16 dpc_started) 732762306a36Sopenharmony_ci{ 732862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 732962306a36Sopenharmony_ci 733062306a36Sopenharmony_ci if (vha->vp_idx) 733162306a36Sopenharmony_ci return; 733262306a36Sopenharmony_ci 733362306a36Sopenharmony_ci if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha)) 733462306a36Sopenharmony_ci return; 733562306a36Sopenharmony_ci 733662306a36Sopenharmony_ci /* 733762306a36Sopenharmony_ci * dpc thread cannot run if heartbeat is running at the same time. 733862306a36Sopenharmony_ci * We also do not want to starve heartbeat task. Therefore, do 733962306a36Sopenharmony_ci * heartbeat task at least once every 5 seconds. 734062306a36Sopenharmony_ci */ 734162306a36Sopenharmony_ci if (dpc_started && 734262306a36Sopenharmony_ci time_before(jiffies, ha->last_heartbeat_run_jiffies + 5 * HZ)) 734362306a36Sopenharmony_ci return; 734462306a36Sopenharmony_ci 734562306a36Sopenharmony_ci if (qla_do_heartbeat(vha)) { 734662306a36Sopenharmony_ci ha->last_heartbeat_run_jiffies = jiffies; 734762306a36Sopenharmony_ci queue_work(ha->wq, &ha->heartbeat_work); 734862306a36Sopenharmony_ci } 734962306a36Sopenharmony_ci} 735062306a36Sopenharmony_ci 735162306a36Sopenharmony_cistatic void qla_wind_down_chip(scsi_qla_host_t *vha) 735262306a36Sopenharmony_ci{ 735362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 735462306a36Sopenharmony_ci 735562306a36Sopenharmony_ci if (!ha->flags.eeh_busy) 735662306a36Sopenharmony_ci return; 735762306a36Sopenharmony_ci if (ha->pci_error_state) 735862306a36Sopenharmony_ci /* system is trying to recover */ 735962306a36Sopenharmony_ci return; 736062306a36Sopenharmony_ci 736162306a36Sopenharmony_ci /* 736262306a36Sopenharmony_ci * Current system is not handling PCIE error. At this point, this is 736362306a36Sopenharmony_ci * best effort to wind down the adapter. 736462306a36Sopenharmony_ci */ 736562306a36Sopenharmony_ci if (time_after_eq(jiffies, ha->eeh_jif + ql2xdelay_before_pci_error_handling * HZ) && 736662306a36Sopenharmony_ci !ha->flags.eeh_flush) { 736762306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x9009, 736862306a36Sopenharmony_ci "PCI Error detected, attempting to reset hardware.\n"); 736962306a36Sopenharmony_ci 737062306a36Sopenharmony_ci ha->isp_ops->reset_chip(vha); 737162306a36Sopenharmony_ci ha->isp_ops->disable_intrs(ha); 737262306a36Sopenharmony_ci 737362306a36Sopenharmony_ci ha->flags.eeh_flush = EEH_FLUSH_RDY; 737462306a36Sopenharmony_ci ha->eeh_jif = jiffies; 737562306a36Sopenharmony_ci 737662306a36Sopenharmony_ci } else if (ha->flags.eeh_flush == EEH_FLUSH_RDY && 737762306a36Sopenharmony_ci time_after_eq(jiffies, ha->eeh_jif + 5 * HZ)) { 737862306a36Sopenharmony_ci pci_clear_master(ha->pdev); 737962306a36Sopenharmony_ci 738062306a36Sopenharmony_ci /* flush all command */ 738162306a36Sopenharmony_ci qla2x00_abort_isp_cleanup(vha); 738262306a36Sopenharmony_ci ha->flags.eeh_flush = EEH_FLUSH_DONE; 738362306a36Sopenharmony_ci 738462306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x900a, 738562306a36Sopenharmony_ci "PCI Error handling complete, all IOs aborted.\n"); 738662306a36Sopenharmony_ci } 738762306a36Sopenharmony_ci} 738862306a36Sopenharmony_ci 738962306a36Sopenharmony_ci/************************************************************************** 739062306a36Sopenharmony_ci* qla2x00_timer 739162306a36Sopenharmony_ci* 739262306a36Sopenharmony_ci* Description: 739362306a36Sopenharmony_ci* One second timer 739462306a36Sopenharmony_ci* 739562306a36Sopenharmony_ci* Context: Interrupt 739662306a36Sopenharmony_ci***************************************************************************/ 739762306a36Sopenharmony_civoid 739862306a36Sopenharmony_ciqla2x00_timer(struct timer_list *t) 739962306a36Sopenharmony_ci{ 740062306a36Sopenharmony_ci scsi_qla_host_t *vha = from_timer(vha, t, timer); 740162306a36Sopenharmony_ci unsigned long cpu_flags = 0; 740262306a36Sopenharmony_ci int start_dpc = 0; 740362306a36Sopenharmony_ci int index; 740462306a36Sopenharmony_ci srb_t *sp; 740562306a36Sopenharmony_ci uint16_t w; 740662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 740762306a36Sopenharmony_ci struct req_que *req; 740862306a36Sopenharmony_ci unsigned long flags; 740962306a36Sopenharmony_ci fc_port_t *fcport = NULL; 741062306a36Sopenharmony_ci 741162306a36Sopenharmony_ci if (ha->flags.eeh_busy) { 741262306a36Sopenharmony_ci qla_wind_down_chip(vha); 741362306a36Sopenharmony_ci 741462306a36Sopenharmony_ci ql_dbg(ql_dbg_timer, vha, 0x6000, 741562306a36Sopenharmony_ci "EEH = %d, restarting timer.\n", 741662306a36Sopenharmony_ci ha->flags.eeh_busy); 741762306a36Sopenharmony_ci qla2x00_restart_timer(vha, WATCH_INTERVAL); 741862306a36Sopenharmony_ci return; 741962306a36Sopenharmony_ci } 742062306a36Sopenharmony_ci 742162306a36Sopenharmony_ci /* 742262306a36Sopenharmony_ci * Hardware read to raise pending EEH errors during mailbox waits. If 742362306a36Sopenharmony_ci * the read returns -1 then disable the board. 742462306a36Sopenharmony_ci */ 742562306a36Sopenharmony_ci if (!pci_channel_offline(ha->pdev)) { 742662306a36Sopenharmony_ci pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); 742762306a36Sopenharmony_ci qla2x00_check_reg16_for_disconnect(vha, w); 742862306a36Sopenharmony_ci } 742962306a36Sopenharmony_ci 743062306a36Sopenharmony_ci /* Make sure qla82xx_watchdog is run only for physical port */ 743162306a36Sopenharmony_ci if (!vha->vp_idx && IS_P3P_TYPE(ha)) { 743262306a36Sopenharmony_ci if (test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) 743362306a36Sopenharmony_ci start_dpc++; 743462306a36Sopenharmony_ci if (IS_QLA82XX(ha)) 743562306a36Sopenharmony_ci qla82xx_watchdog(vha); 743662306a36Sopenharmony_ci else if (IS_QLA8044(ha)) 743762306a36Sopenharmony_ci qla8044_watchdog(vha); 743862306a36Sopenharmony_ci } 743962306a36Sopenharmony_ci 744062306a36Sopenharmony_ci if (!vha->vp_idx && IS_QLAFX00(ha)) 744162306a36Sopenharmony_ci qlafx00_timer_routine(vha); 744262306a36Sopenharmony_ci 744362306a36Sopenharmony_ci if (vha->link_down_time < QLA2XX_MAX_LINK_DOWN_TIME) 744462306a36Sopenharmony_ci vha->link_down_time++; 744562306a36Sopenharmony_ci 744662306a36Sopenharmony_ci spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); 744762306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 744862306a36Sopenharmony_ci if (fcport->tgt_link_down_time < QLA2XX_MAX_LINK_DOWN_TIME) 744962306a36Sopenharmony_ci fcport->tgt_link_down_time++; 745062306a36Sopenharmony_ci } 745162306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); 745262306a36Sopenharmony_ci 745362306a36Sopenharmony_ci /* Loop down handler. */ 745462306a36Sopenharmony_ci if (atomic_read(&vha->loop_down_timer) > 0 && 745562306a36Sopenharmony_ci !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) && 745662306a36Sopenharmony_ci !(test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags)) 745762306a36Sopenharmony_ci && vha->flags.online) { 745862306a36Sopenharmony_ci 745962306a36Sopenharmony_ci if (atomic_read(&vha->loop_down_timer) == 746062306a36Sopenharmony_ci vha->loop_down_abort_time) { 746162306a36Sopenharmony_ci 746262306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x6008, 746362306a36Sopenharmony_ci "Loop down - aborting the queues before time expires.\n"); 746462306a36Sopenharmony_ci 746562306a36Sopenharmony_ci if (!IS_QLA2100(ha) && vha->link_down_timeout) 746662306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_DEAD); 746762306a36Sopenharmony_ci 746862306a36Sopenharmony_ci /* 746962306a36Sopenharmony_ci * Schedule an ISP abort to return any FCP2-device 747062306a36Sopenharmony_ci * commands. 747162306a36Sopenharmony_ci */ 747262306a36Sopenharmony_ci /* NPIV - scan physical port only */ 747362306a36Sopenharmony_ci if (!vha->vp_idx) { 747462306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, 747562306a36Sopenharmony_ci cpu_flags); 747662306a36Sopenharmony_ci req = ha->req_q_map[0]; 747762306a36Sopenharmony_ci for (index = 1; 747862306a36Sopenharmony_ci index < req->num_outstanding_cmds; 747962306a36Sopenharmony_ci index++) { 748062306a36Sopenharmony_ci fc_port_t *sfcp; 748162306a36Sopenharmony_ci 748262306a36Sopenharmony_ci sp = req->outstanding_cmds[index]; 748362306a36Sopenharmony_ci if (!sp) 748462306a36Sopenharmony_ci continue; 748562306a36Sopenharmony_ci if (sp->cmd_type != TYPE_SRB) 748662306a36Sopenharmony_ci continue; 748762306a36Sopenharmony_ci if (sp->type != SRB_SCSI_CMD) 748862306a36Sopenharmony_ci continue; 748962306a36Sopenharmony_ci sfcp = sp->fcport; 749062306a36Sopenharmony_ci if (!(sfcp->flags & FCF_FCP2_DEVICE)) 749162306a36Sopenharmony_ci continue; 749262306a36Sopenharmony_ci 749362306a36Sopenharmony_ci if (IS_QLA82XX(ha)) 749462306a36Sopenharmony_ci set_bit(FCOE_CTX_RESET_NEEDED, 749562306a36Sopenharmony_ci &vha->dpc_flags); 749662306a36Sopenharmony_ci else 749762306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, 749862306a36Sopenharmony_ci &vha->dpc_flags); 749962306a36Sopenharmony_ci break; 750062306a36Sopenharmony_ci } 750162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, 750262306a36Sopenharmony_ci cpu_flags); 750362306a36Sopenharmony_ci } 750462306a36Sopenharmony_ci start_dpc++; 750562306a36Sopenharmony_ci } 750662306a36Sopenharmony_ci 750762306a36Sopenharmony_ci /* if the loop has been down for 4 minutes, reinit adapter */ 750862306a36Sopenharmony_ci if (atomic_dec_and_test(&vha->loop_down_timer) != 0) { 750962306a36Sopenharmony_ci if (!(vha->device_flags & DFLG_NO_CABLE) && !vha->vp_idx) { 751062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x6009, 751162306a36Sopenharmony_ci "Loop down - aborting ISP.\n"); 751262306a36Sopenharmony_ci 751362306a36Sopenharmony_ci if (IS_QLA82XX(ha)) 751462306a36Sopenharmony_ci set_bit(FCOE_CTX_RESET_NEEDED, 751562306a36Sopenharmony_ci &vha->dpc_flags); 751662306a36Sopenharmony_ci else 751762306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, 751862306a36Sopenharmony_ci &vha->dpc_flags); 751962306a36Sopenharmony_ci } 752062306a36Sopenharmony_ci } 752162306a36Sopenharmony_ci ql_dbg(ql_dbg_timer, vha, 0x600a, 752262306a36Sopenharmony_ci "Loop down - seconds remaining %d.\n", 752362306a36Sopenharmony_ci atomic_read(&vha->loop_down_timer)); 752462306a36Sopenharmony_ci } 752562306a36Sopenharmony_ci /* Check if beacon LED needs to be blinked for physical host only */ 752662306a36Sopenharmony_ci if (!vha->vp_idx && (ha->beacon_blink_led == 1)) { 752762306a36Sopenharmony_ci /* There is no beacon_blink function for ISP82xx */ 752862306a36Sopenharmony_ci if (!IS_P3P_TYPE(ha)) { 752962306a36Sopenharmony_ci set_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags); 753062306a36Sopenharmony_ci start_dpc++; 753162306a36Sopenharmony_ci } 753262306a36Sopenharmony_ci } 753362306a36Sopenharmony_ci 753462306a36Sopenharmony_ci /* check if edif running */ 753562306a36Sopenharmony_ci if (vha->hw->flags.edif_enabled) 753662306a36Sopenharmony_ci qla_edif_timer(vha); 753762306a36Sopenharmony_ci 753862306a36Sopenharmony_ci /* Process any deferred work. */ 753962306a36Sopenharmony_ci if (!list_empty(&vha->work_list)) { 754062306a36Sopenharmony_ci unsigned long flags; 754162306a36Sopenharmony_ci bool q = false; 754262306a36Sopenharmony_ci 754362306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 754462306a36Sopenharmony_ci if (!test_and_set_bit(IOCB_WORK_ACTIVE, &vha->dpc_flags)) 754562306a36Sopenharmony_ci q = true; 754662306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 754762306a36Sopenharmony_ci if (q) 754862306a36Sopenharmony_ci queue_work(vha->hw->wq, &vha->iocb_work); 754962306a36Sopenharmony_ci } 755062306a36Sopenharmony_ci 755162306a36Sopenharmony_ci /* 755262306a36Sopenharmony_ci * FC-NVME 755362306a36Sopenharmony_ci * see if the active AEN count has changed from what was last reported. 755462306a36Sopenharmony_ci */ 755562306a36Sopenharmony_ci index = atomic_read(&ha->nvme_active_aen_cnt); 755662306a36Sopenharmony_ci if (!vha->vp_idx && 755762306a36Sopenharmony_ci (index != ha->nvme_last_rptd_aen) && 755862306a36Sopenharmony_ci ha->zio_mode == QLA_ZIO_MODE_6 && 755962306a36Sopenharmony_ci !ha->flags.host_shutting_down) { 756062306a36Sopenharmony_ci ha->nvme_last_rptd_aen = atomic_read(&ha->nvme_active_aen_cnt); 756162306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x3002, 756262306a36Sopenharmony_ci "nvme: Sched: Set ZIO exchange threshold to %d.\n", 756362306a36Sopenharmony_ci ha->nvme_last_rptd_aen); 756462306a36Sopenharmony_ci set_bit(SET_ZIO_THRESHOLD_NEEDED, &vha->dpc_flags); 756562306a36Sopenharmony_ci start_dpc++; 756662306a36Sopenharmony_ci } 756762306a36Sopenharmony_ci 756862306a36Sopenharmony_ci if (!vha->vp_idx && 756962306a36Sopenharmony_ci atomic_read(&ha->zio_threshold) != ha->last_zio_threshold && 757062306a36Sopenharmony_ci IS_ZIO_THRESHOLD_CAPABLE(ha)) { 757162306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x3002, 757262306a36Sopenharmony_ci "Sched: Set ZIO exchange threshold to %d.\n", 757362306a36Sopenharmony_ci ha->last_zio_threshold); 757462306a36Sopenharmony_ci ha->last_zio_threshold = atomic_read(&ha->zio_threshold); 757562306a36Sopenharmony_ci set_bit(SET_ZIO_THRESHOLD_NEEDED, &vha->dpc_flags); 757662306a36Sopenharmony_ci start_dpc++; 757762306a36Sopenharmony_ci } 757862306a36Sopenharmony_ci qla_adjust_buf(vha); 757962306a36Sopenharmony_ci 758062306a36Sopenharmony_ci /* borrowing w to signify dpc will run */ 758162306a36Sopenharmony_ci w = 0; 758262306a36Sopenharmony_ci /* Schedule the DPC routine if needed */ 758362306a36Sopenharmony_ci if ((test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || 758462306a36Sopenharmony_ci test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) || 758562306a36Sopenharmony_ci start_dpc || 758662306a36Sopenharmony_ci test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) || 758762306a36Sopenharmony_ci test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags) || 758862306a36Sopenharmony_ci test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) || 758962306a36Sopenharmony_ci test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) || 759062306a36Sopenharmony_ci test_bit(VP_DPC_NEEDED, &vha->dpc_flags) || 759162306a36Sopenharmony_ci test_bit(RELOGIN_NEEDED, &vha->dpc_flags) || 759262306a36Sopenharmony_ci test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags))) { 759362306a36Sopenharmony_ci ql_dbg(ql_dbg_timer, vha, 0x600b, 759462306a36Sopenharmony_ci "isp_abort_needed=%d loop_resync_needed=%d " 759562306a36Sopenharmony_ci "start_dpc=%d reset_marker_needed=%d", 759662306a36Sopenharmony_ci test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags), 759762306a36Sopenharmony_ci test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags), 759862306a36Sopenharmony_ci start_dpc, test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags)); 759962306a36Sopenharmony_ci ql_dbg(ql_dbg_timer, vha, 0x600c, 760062306a36Sopenharmony_ci "beacon_blink_needed=%d isp_unrecoverable=%d " 760162306a36Sopenharmony_ci "fcoe_ctx_reset_needed=%d vp_dpc_needed=%d " 760262306a36Sopenharmony_ci "relogin_needed=%d, Process_purex_iocb=%d.\n", 760362306a36Sopenharmony_ci test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags), 760462306a36Sopenharmony_ci test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags), 760562306a36Sopenharmony_ci test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags), 760662306a36Sopenharmony_ci test_bit(VP_DPC_NEEDED, &vha->dpc_flags), 760762306a36Sopenharmony_ci test_bit(RELOGIN_NEEDED, &vha->dpc_flags), 760862306a36Sopenharmony_ci test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags)); 760962306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 761062306a36Sopenharmony_ci w = 1; 761162306a36Sopenharmony_ci } 761262306a36Sopenharmony_ci 761362306a36Sopenharmony_ci qla_heart_beat(vha, w); 761462306a36Sopenharmony_ci 761562306a36Sopenharmony_ci qla2x00_restart_timer(vha, WATCH_INTERVAL); 761662306a36Sopenharmony_ci} 761762306a36Sopenharmony_ci 761862306a36Sopenharmony_ci/* Firmware interface routines. */ 761962306a36Sopenharmony_ci 762062306a36Sopenharmony_ci#define FW_ISP21XX 0 762162306a36Sopenharmony_ci#define FW_ISP22XX 1 762262306a36Sopenharmony_ci#define FW_ISP2300 2 762362306a36Sopenharmony_ci#define FW_ISP2322 3 762462306a36Sopenharmony_ci#define FW_ISP24XX 4 762562306a36Sopenharmony_ci#define FW_ISP25XX 5 762662306a36Sopenharmony_ci#define FW_ISP81XX 6 762762306a36Sopenharmony_ci#define FW_ISP82XX 7 762862306a36Sopenharmony_ci#define FW_ISP2031 8 762962306a36Sopenharmony_ci#define FW_ISP8031 9 763062306a36Sopenharmony_ci#define FW_ISP27XX 10 763162306a36Sopenharmony_ci#define FW_ISP28XX 11 763262306a36Sopenharmony_ci 763362306a36Sopenharmony_ci#define FW_FILE_ISP21XX "ql2100_fw.bin" 763462306a36Sopenharmony_ci#define FW_FILE_ISP22XX "ql2200_fw.bin" 763562306a36Sopenharmony_ci#define FW_FILE_ISP2300 "ql2300_fw.bin" 763662306a36Sopenharmony_ci#define FW_FILE_ISP2322 "ql2322_fw.bin" 763762306a36Sopenharmony_ci#define FW_FILE_ISP24XX "ql2400_fw.bin" 763862306a36Sopenharmony_ci#define FW_FILE_ISP25XX "ql2500_fw.bin" 763962306a36Sopenharmony_ci#define FW_FILE_ISP81XX "ql8100_fw.bin" 764062306a36Sopenharmony_ci#define FW_FILE_ISP82XX "ql8200_fw.bin" 764162306a36Sopenharmony_ci#define FW_FILE_ISP2031 "ql2600_fw.bin" 764262306a36Sopenharmony_ci#define FW_FILE_ISP8031 "ql8300_fw.bin" 764362306a36Sopenharmony_ci#define FW_FILE_ISP27XX "ql2700_fw.bin" 764462306a36Sopenharmony_ci#define FW_FILE_ISP28XX "ql2800_fw.bin" 764562306a36Sopenharmony_ci 764662306a36Sopenharmony_ci 764762306a36Sopenharmony_cistatic DEFINE_MUTEX(qla_fw_lock); 764862306a36Sopenharmony_ci 764962306a36Sopenharmony_cistatic struct fw_blob qla_fw_blobs[] = { 765062306a36Sopenharmony_ci { .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, }, 765162306a36Sopenharmony_ci { .name = FW_FILE_ISP22XX, .segs = { 0x1000, 0 }, }, 765262306a36Sopenharmony_ci { .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, }, 765362306a36Sopenharmony_ci { .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, }, 765462306a36Sopenharmony_ci { .name = FW_FILE_ISP24XX, }, 765562306a36Sopenharmony_ci { .name = FW_FILE_ISP25XX, }, 765662306a36Sopenharmony_ci { .name = FW_FILE_ISP81XX, }, 765762306a36Sopenharmony_ci { .name = FW_FILE_ISP82XX, }, 765862306a36Sopenharmony_ci { .name = FW_FILE_ISP2031, }, 765962306a36Sopenharmony_ci { .name = FW_FILE_ISP8031, }, 766062306a36Sopenharmony_ci { .name = FW_FILE_ISP27XX, }, 766162306a36Sopenharmony_ci { .name = FW_FILE_ISP28XX, }, 766262306a36Sopenharmony_ci { .name = NULL, }, 766362306a36Sopenharmony_ci}; 766462306a36Sopenharmony_ci 766562306a36Sopenharmony_cistruct fw_blob * 766662306a36Sopenharmony_ciqla2x00_request_firmware(scsi_qla_host_t *vha) 766762306a36Sopenharmony_ci{ 766862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 766962306a36Sopenharmony_ci struct fw_blob *blob; 767062306a36Sopenharmony_ci 767162306a36Sopenharmony_ci if (IS_QLA2100(ha)) { 767262306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP21XX]; 767362306a36Sopenharmony_ci } else if (IS_QLA2200(ha)) { 767462306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP22XX]; 767562306a36Sopenharmony_ci } else if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) { 767662306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP2300]; 767762306a36Sopenharmony_ci } else if (IS_QLA2322(ha) || IS_QLA6322(ha)) { 767862306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP2322]; 767962306a36Sopenharmony_ci } else if (IS_QLA24XX_TYPE(ha)) { 768062306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP24XX]; 768162306a36Sopenharmony_ci } else if (IS_QLA25XX(ha)) { 768262306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP25XX]; 768362306a36Sopenharmony_ci } else if (IS_QLA81XX(ha)) { 768462306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP81XX]; 768562306a36Sopenharmony_ci } else if (IS_QLA82XX(ha)) { 768662306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP82XX]; 768762306a36Sopenharmony_ci } else if (IS_QLA2031(ha)) { 768862306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP2031]; 768962306a36Sopenharmony_ci } else if (IS_QLA8031(ha)) { 769062306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP8031]; 769162306a36Sopenharmony_ci } else if (IS_QLA27XX(ha)) { 769262306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP27XX]; 769362306a36Sopenharmony_ci } else if (IS_QLA28XX(ha)) { 769462306a36Sopenharmony_ci blob = &qla_fw_blobs[FW_ISP28XX]; 769562306a36Sopenharmony_ci } else { 769662306a36Sopenharmony_ci return NULL; 769762306a36Sopenharmony_ci } 769862306a36Sopenharmony_ci 769962306a36Sopenharmony_ci if (!blob->name) 770062306a36Sopenharmony_ci return NULL; 770162306a36Sopenharmony_ci 770262306a36Sopenharmony_ci mutex_lock(&qla_fw_lock); 770362306a36Sopenharmony_ci if (blob->fw) 770462306a36Sopenharmony_ci goto out; 770562306a36Sopenharmony_ci 770662306a36Sopenharmony_ci if (request_firmware(&blob->fw, blob->name, &ha->pdev->dev)) { 770762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0063, 770862306a36Sopenharmony_ci "Failed to load firmware image (%s).\n", blob->name); 770962306a36Sopenharmony_ci blob->fw = NULL; 771062306a36Sopenharmony_ci blob = NULL; 771162306a36Sopenharmony_ci } 771262306a36Sopenharmony_ci 771362306a36Sopenharmony_ciout: 771462306a36Sopenharmony_ci mutex_unlock(&qla_fw_lock); 771562306a36Sopenharmony_ci return blob; 771662306a36Sopenharmony_ci} 771762306a36Sopenharmony_ci 771862306a36Sopenharmony_cistatic void 771962306a36Sopenharmony_ciqla2x00_release_firmware(void) 772062306a36Sopenharmony_ci{ 772162306a36Sopenharmony_ci struct fw_blob *blob; 772262306a36Sopenharmony_ci 772362306a36Sopenharmony_ci mutex_lock(&qla_fw_lock); 772462306a36Sopenharmony_ci for (blob = qla_fw_blobs; blob->name; blob++) 772562306a36Sopenharmony_ci release_firmware(blob->fw); 772662306a36Sopenharmony_ci mutex_unlock(&qla_fw_lock); 772762306a36Sopenharmony_ci} 772862306a36Sopenharmony_ci 772962306a36Sopenharmony_cistatic void qla_pci_error_cleanup(scsi_qla_host_t *vha) 773062306a36Sopenharmony_ci{ 773162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 773262306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 773362306a36Sopenharmony_ci struct qla_qpair *qpair = NULL; 773462306a36Sopenharmony_ci struct scsi_qla_host *vp, *tvp; 773562306a36Sopenharmony_ci fc_port_t *fcport; 773662306a36Sopenharmony_ci int i; 773762306a36Sopenharmony_ci unsigned long flags; 773862306a36Sopenharmony_ci 773962306a36Sopenharmony_ci ql_dbg(ql_dbg_aer, vha, 0x9000, 774062306a36Sopenharmony_ci "%s\n", __func__); 774162306a36Sopenharmony_ci ha->chip_reset++; 774262306a36Sopenharmony_ci 774362306a36Sopenharmony_ci ha->base_qpair->chip_reset = ha->chip_reset; 774462306a36Sopenharmony_ci for (i = 0; i < ha->max_qpairs; i++) { 774562306a36Sopenharmony_ci if (ha->queue_pair_map[i]) 774662306a36Sopenharmony_ci ha->queue_pair_map[i]->chip_reset = 774762306a36Sopenharmony_ci ha->base_qpair->chip_reset; 774862306a36Sopenharmony_ci } 774962306a36Sopenharmony_ci 775062306a36Sopenharmony_ci /* 775162306a36Sopenharmony_ci * purge mailbox might take a while. Slot Reset/chip reset 775262306a36Sopenharmony_ci * will take care of the purge 775362306a36Sopenharmony_ci */ 775462306a36Sopenharmony_ci 775562306a36Sopenharmony_ci mutex_lock(&ha->mq_lock); 775662306a36Sopenharmony_ci ha->base_qpair->online = 0; 775762306a36Sopenharmony_ci list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem) 775862306a36Sopenharmony_ci qpair->online = 0; 775962306a36Sopenharmony_ci wmb(); 776062306a36Sopenharmony_ci mutex_unlock(&ha->mq_lock); 776162306a36Sopenharmony_ci 776262306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 776362306a36Sopenharmony_ci 776462306a36Sopenharmony_ci spin_lock_irqsave(&ha->vport_slock, flags); 776562306a36Sopenharmony_ci list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { 776662306a36Sopenharmony_ci atomic_inc(&vp->vref_count); 776762306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->vport_slock, flags); 776862306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vp); 776962306a36Sopenharmony_ci spin_lock_irqsave(&ha->vport_slock, flags); 777062306a36Sopenharmony_ci atomic_dec(&vp->vref_count); 777162306a36Sopenharmony_ci } 777262306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->vport_slock, flags); 777362306a36Sopenharmony_ci 777462306a36Sopenharmony_ci /* Clear all async request states across all VPs. */ 777562306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) 777662306a36Sopenharmony_ci fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); 777762306a36Sopenharmony_ci 777862306a36Sopenharmony_ci spin_lock_irqsave(&ha->vport_slock, flags); 777962306a36Sopenharmony_ci list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { 778062306a36Sopenharmony_ci atomic_inc(&vp->vref_count); 778162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->vport_slock, flags); 778262306a36Sopenharmony_ci list_for_each_entry(fcport, &vp->vp_fcports, list) 778362306a36Sopenharmony_ci fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); 778462306a36Sopenharmony_ci spin_lock_irqsave(&ha->vport_slock, flags); 778562306a36Sopenharmony_ci atomic_dec(&vp->vref_count); 778662306a36Sopenharmony_ci } 778762306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->vport_slock, flags); 778862306a36Sopenharmony_ci} 778962306a36Sopenharmony_ci 779062306a36Sopenharmony_ci 779162306a36Sopenharmony_cistatic pci_ers_result_t 779262306a36Sopenharmony_ciqla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 779362306a36Sopenharmony_ci{ 779462306a36Sopenharmony_ci scsi_qla_host_t *vha = pci_get_drvdata(pdev); 779562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 779662306a36Sopenharmony_ci pci_ers_result_t ret = PCI_ERS_RESULT_NEED_RESET; 779762306a36Sopenharmony_ci 779862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x9000, 779962306a36Sopenharmony_ci "PCI error detected, state %x.\n", state); 780062306a36Sopenharmony_ci ha->pci_error_state = QLA_PCI_ERR_DETECTED; 780162306a36Sopenharmony_ci 780262306a36Sopenharmony_ci if (!atomic_read(&pdev->enable_cnt)) { 780362306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0xffff, 780462306a36Sopenharmony_ci "PCI device is disabled,state %x\n", state); 780562306a36Sopenharmony_ci ret = PCI_ERS_RESULT_NEED_RESET; 780662306a36Sopenharmony_ci goto out; 780762306a36Sopenharmony_ci } 780862306a36Sopenharmony_ci 780962306a36Sopenharmony_ci switch (state) { 781062306a36Sopenharmony_ci case pci_channel_io_normal: 781162306a36Sopenharmony_ci qla_pci_set_eeh_busy(vha); 781262306a36Sopenharmony_ci if (ql2xmqsupport || ql2xnvmeenable) { 781362306a36Sopenharmony_ci set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags); 781462306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 781562306a36Sopenharmony_ci } 781662306a36Sopenharmony_ci ret = PCI_ERS_RESULT_CAN_RECOVER; 781762306a36Sopenharmony_ci break; 781862306a36Sopenharmony_ci case pci_channel_io_frozen: 781962306a36Sopenharmony_ci qla_pci_set_eeh_busy(vha); 782062306a36Sopenharmony_ci ret = PCI_ERS_RESULT_NEED_RESET; 782162306a36Sopenharmony_ci break; 782262306a36Sopenharmony_ci case pci_channel_io_perm_failure: 782362306a36Sopenharmony_ci ha->flags.pci_channel_io_perm_failure = 1; 782462306a36Sopenharmony_ci qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); 782562306a36Sopenharmony_ci if (ql2xmqsupport || ql2xnvmeenable) { 782662306a36Sopenharmony_ci set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags); 782762306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 782862306a36Sopenharmony_ci } 782962306a36Sopenharmony_ci ret = PCI_ERS_RESULT_DISCONNECT; 783062306a36Sopenharmony_ci } 783162306a36Sopenharmony_ciout: 783262306a36Sopenharmony_ci ql_dbg(ql_dbg_aer, vha, 0x600d, 783362306a36Sopenharmony_ci "PCI error detected returning [%x].\n", ret); 783462306a36Sopenharmony_ci return ret; 783562306a36Sopenharmony_ci} 783662306a36Sopenharmony_ci 783762306a36Sopenharmony_cistatic pci_ers_result_t 783862306a36Sopenharmony_ciqla2xxx_pci_mmio_enabled(struct pci_dev *pdev) 783962306a36Sopenharmony_ci{ 784062306a36Sopenharmony_ci int risc_paused = 0; 784162306a36Sopenharmony_ci uint32_t stat; 784262306a36Sopenharmony_ci unsigned long flags; 784362306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); 784462306a36Sopenharmony_ci struct qla_hw_data *ha = base_vha->hw; 784562306a36Sopenharmony_ci struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; 784662306a36Sopenharmony_ci struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; 784762306a36Sopenharmony_ci 784862306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0x9000, 784962306a36Sopenharmony_ci "mmio enabled\n"); 785062306a36Sopenharmony_ci 785162306a36Sopenharmony_ci ha->pci_error_state = QLA_PCI_MMIO_ENABLED; 785262306a36Sopenharmony_ci 785362306a36Sopenharmony_ci if (IS_QLA82XX(ha)) 785462306a36Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 785562306a36Sopenharmony_ci 785662306a36Sopenharmony_ci if (qla2x00_isp_reg_stat(ha)) { 785762306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0x803f, 785862306a36Sopenharmony_ci "During mmio enabled, PCI/Register disconnect still detected.\n"); 785962306a36Sopenharmony_ci goto out; 786062306a36Sopenharmony_ci } 786162306a36Sopenharmony_ci 786262306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 786362306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)){ 786462306a36Sopenharmony_ci stat = rd_reg_word(®->hccr); 786562306a36Sopenharmony_ci if (stat & HCCR_RISC_PAUSE) 786662306a36Sopenharmony_ci risc_paused = 1; 786762306a36Sopenharmony_ci } else if (IS_QLA23XX(ha)) { 786862306a36Sopenharmony_ci stat = rd_reg_dword(®->u.isp2300.host_status); 786962306a36Sopenharmony_ci if (stat & HSR_RISC_PAUSED) 787062306a36Sopenharmony_ci risc_paused = 1; 787162306a36Sopenharmony_ci } else if (IS_FWI2_CAPABLE(ha)) { 787262306a36Sopenharmony_ci stat = rd_reg_dword(®24->host_status); 787362306a36Sopenharmony_ci if (stat & HSRX_RISC_PAUSED) 787462306a36Sopenharmony_ci risc_paused = 1; 787562306a36Sopenharmony_ci } 787662306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 787762306a36Sopenharmony_ci 787862306a36Sopenharmony_ci if (risc_paused) { 787962306a36Sopenharmony_ci ql_log(ql_log_info, base_vha, 0x9003, 788062306a36Sopenharmony_ci "RISC paused -- mmio_enabled, Dumping firmware.\n"); 788162306a36Sopenharmony_ci qla2xxx_dump_fw(base_vha); 788262306a36Sopenharmony_ci } 788362306a36Sopenharmony_ciout: 788462306a36Sopenharmony_ci /* set PCI_ERS_RESULT_NEED_RESET to trigger call to qla2xxx_pci_slot_reset */ 788562306a36Sopenharmony_ci ql_dbg(ql_dbg_aer, base_vha, 0x600d, 788662306a36Sopenharmony_ci "mmio enabled returning.\n"); 788762306a36Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 788862306a36Sopenharmony_ci} 788962306a36Sopenharmony_ci 789062306a36Sopenharmony_cistatic pci_ers_result_t 789162306a36Sopenharmony_ciqla2xxx_pci_slot_reset(struct pci_dev *pdev) 789262306a36Sopenharmony_ci{ 789362306a36Sopenharmony_ci pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; 789462306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); 789562306a36Sopenharmony_ci struct qla_hw_data *ha = base_vha->hw; 789662306a36Sopenharmony_ci int rc; 789762306a36Sopenharmony_ci struct qla_qpair *qpair = NULL; 789862306a36Sopenharmony_ci 789962306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0x9004, 790062306a36Sopenharmony_ci "Slot Reset.\n"); 790162306a36Sopenharmony_ci 790262306a36Sopenharmony_ci ha->pci_error_state = QLA_PCI_SLOT_RESET; 790362306a36Sopenharmony_ci /* Workaround: qla2xxx driver which access hardware earlier 790462306a36Sopenharmony_ci * needs error state to be pci_channel_io_online. 790562306a36Sopenharmony_ci * Otherwise mailbox command timesout. 790662306a36Sopenharmony_ci */ 790762306a36Sopenharmony_ci pdev->error_state = pci_channel_io_normal; 790862306a36Sopenharmony_ci 790962306a36Sopenharmony_ci pci_restore_state(pdev); 791062306a36Sopenharmony_ci 791162306a36Sopenharmony_ci /* pci_restore_state() clears the saved_state flag of the device 791262306a36Sopenharmony_ci * save restored state which resets saved_state flag 791362306a36Sopenharmony_ci */ 791462306a36Sopenharmony_ci pci_save_state(pdev); 791562306a36Sopenharmony_ci 791662306a36Sopenharmony_ci if (ha->mem_only) 791762306a36Sopenharmony_ci rc = pci_enable_device_mem(pdev); 791862306a36Sopenharmony_ci else 791962306a36Sopenharmony_ci rc = pci_enable_device(pdev); 792062306a36Sopenharmony_ci 792162306a36Sopenharmony_ci if (rc) { 792262306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0x9005, 792362306a36Sopenharmony_ci "Can't re-enable PCI device after reset.\n"); 792462306a36Sopenharmony_ci goto exit_slot_reset; 792562306a36Sopenharmony_ci } 792662306a36Sopenharmony_ci 792762306a36Sopenharmony_ci 792862306a36Sopenharmony_ci if (ha->isp_ops->pci_config(base_vha)) 792962306a36Sopenharmony_ci goto exit_slot_reset; 793062306a36Sopenharmony_ci 793162306a36Sopenharmony_ci mutex_lock(&ha->mq_lock); 793262306a36Sopenharmony_ci list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem) 793362306a36Sopenharmony_ci qpair->online = 1; 793462306a36Sopenharmony_ci mutex_unlock(&ha->mq_lock); 793562306a36Sopenharmony_ci 793662306a36Sopenharmony_ci ha->flags.eeh_busy = 0; 793762306a36Sopenharmony_ci base_vha->flags.online = 1; 793862306a36Sopenharmony_ci set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); 793962306a36Sopenharmony_ci ha->isp_ops->abort_isp(base_vha); 794062306a36Sopenharmony_ci clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); 794162306a36Sopenharmony_ci 794262306a36Sopenharmony_ci if (qla2x00_isp_reg_stat(ha)) { 794362306a36Sopenharmony_ci ha->flags.eeh_busy = 1; 794462306a36Sopenharmony_ci qla_pci_error_cleanup(base_vha); 794562306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0x9005, 794662306a36Sopenharmony_ci "Device unable to recover from PCI error.\n"); 794762306a36Sopenharmony_ci } else { 794862306a36Sopenharmony_ci ret = PCI_ERS_RESULT_RECOVERED; 794962306a36Sopenharmony_ci } 795062306a36Sopenharmony_ci 795162306a36Sopenharmony_ciexit_slot_reset: 795262306a36Sopenharmony_ci ql_dbg(ql_dbg_aer, base_vha, 0x900e, 795362306a36Sopenharmony_ci "Slot Reset returning %x.\n", ret); 795462306a36Sopenharmony_ci 795562306a36Sopenharmony_ci return ret; 795662306a36Sopenharmony_ci} 795762306a36Sopenharmony_ci 795862306a36Sopenharmony_cistatic void 795962306a36Sopenharmony_ciqla2xxx_pci_resume(struct pci_dev *pdev) 796062306a36Sopenharmony_ci{ 796162306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); 796262306a36Sopenharmony_ci struct qla_hw_data *ha = base_vha->hw; 796362306a36Sopenharmony_ci int ret; 796462306a36Sopenharmony_ci 796562306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0x900f, 796662306a36Sopenharmony_ci "Pci Resume.\n"); 796762306a36Sopenharmony_ci 796862306a36Sopenharmony_ci 796962306a36Sopenharmony_ci ret = qla2x00_wait_for_hba_online(base_vha); 797062306a36Sopenharmony_ci if (ret != QLA_SUCCESS) { 797162306a36Sopenharmony_ci ql_log(ql_log_fatal, base_vha, 0x9002, 797262306a36Sopenharmony_ci "The device failed to resume I/O from slot/link_reset.\n"); 797362306a36Sopenharmony_ci } 797462306a36Sopenharmony_ci ha->pci_error_state = QLA_PCI_RESUME; 797562306a36Sopenharmony_ci ql_dbg(ql_dbg_aer, base_vha, 0x600d, 797662306a36Sopenharmony_ci "Pci Resume returning.\n"); 797762306a36Sopenharmony_ci} 797862306a36Sopenharmony_ci 797962306a36Sopenharmony_civoid qla_pci_set_eeh_busy(struct scsi_qla_host *vha) 798062306a36Sopenharmony_ci{ 798162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 798262306a36Sopenharmony_ci struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); 798362306a36Sopenharmony_ci bool do_cleanup = false; 798462306a36Sopenharmony_ci unsigned long flags; 798562306a36Sopenharmony_ci 798662306a36Sopenharmony_ci if (ha->flags.eeh_busy) 798762306a36Sopenharmony_ci return; 798862306a36Sopenharmony_ci 798962306a36Sopenharmony_ci spin_lock_irqsave(&base_vha->work_lock, flags); 799062306a36Sopenharmony_ci if (!ha->flags.eeh_busy) { 799162306a36Sopenharmony_ci ha->eeh_jif = jiffies; 799262306a36Sopenharmony_ci ha->flags.eeh_flush = 0; 799362306a36Sopenharmony_ci 799462306a36Sopenharmony_ci ha->flags.eeh_busy = 1; 799562306a36Sopenharmony_ci do_cleanup = true; 799662306a36Sopenharmony_ci } 799762306a36Sopenharmony_ci spin_unlock_irqrestore(&base_vha->work_lock, flags); 799862306a36Sopenharmony_ci 799962306a36Sopenharmony_ci if (do_cleanup) 800062306a36Sopenharmony_ci qla_pci_error_cleanup(base_vha); 800162306a36Sopenharmony_ci} 800262306a36Sopenharmony_ci 800362306a36Sopenharmony_ci/* 800462306a36Sopenharmony_ci * this routine will schedule a task to pause IO from interrupt context 800562306a36Sopenharmony_ci * if caller sees a PCIE error event (register read = 0xf's) 800662306a36Sopenharmony_ci */ 800762306a36Sopenharmony_civoid qla_schedule_eeh_work(struct scsi_qla_host *vha) 800862306a36Sopenharmony_ci{ 800962306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 801062306a36Sopenharmony_ci struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); 801162306a36Sopenharmony_ci 801262306a36Sopenharmony_ci if (ha->flags.eeh_busy) 801362306a36Sopenharmony_ci return; 801462306a36Sopenharmony_ci 801562306a36Sopenharmony_ci set_bit(DO_EEH_RECOVERY, &base_vha->dpc_flags); 801662306a36Sopenharmony_ci qla2xxx_wake_dpc(base_vha); 801762306a36Sopenharmony_ci} 801862306a36Sopenharmony_ci 801962306a36Sopenharmony_cistatic void 802062306a36Sopenharmony_ciqla_pci_reset_prepare(struct pci_dev *pdev) 802162306a36Sopenharmony_ci{ 802262306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); 802362306a36Sopenharmony_ci struct qla_hw_data *ha = base_vha->hw; 802462306a36Sopenharmony_ci struct qla_qpair *qpair; 802562306a36Sopenharmony_ci 802662306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0xffff, 802762306a36Sopenharmony_ci "%s.\n", __func__); 802862306a36Sopenharmony_ci 802962306a36Sopenharmony_ci /* 803062306a36Sopenharmony_ci * PCI FLR/function reset is about to reset the 803162306a36Sopenharmony_ci * slot. Stop the chip to stop all DMA access. 803262306a36Sopenharmony_ci * It is assumed that pci_reset_done will be called 803362306a36Sopenharmony_ci * after FLR to resume Chip operation. 803462306a36Sopenharmony_ci */ 803562306a36Sopenharmony_ci ha->flags.eeh_busy = 1; 803662306a36Sopenharmony_ci mutex_lock(&ha->mq_lock); 803762306a36Sopenharmony_ci list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem) 803862306a36Sopenharmony_ci qpair->online = 0; 803962306a36Sopenharmony_ci mutex_unlock(&ha->mq_lock); 804062306a36Sopenharmony_ci 804162306a36Sopenharmony_ci set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); 804262306a36Sopenharmony_ci qla2x00_abort_isp_cleanup(base_vha); 804362306a36Sopenharmony_ci qla2x00_abort_all_cmds(base_vha, DID_RESET << 16); 804462306a36Sopenharmony_ci} 804562306a36Sopenharmony_ci 804662306a36Sopenharmony_cistatic void 804762306a36Sopenharmony_ciqla_pci_reset_done(struct pci_dev *pdev) 804862306a36Sopenharmony_ci{ 804962306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); 805062306a36Sopenharmony_ci struct qla_hw_data *ha = base_vha->hw; 805162306a36Sopenharmony_ci struct qla_qpair *qpair; 805262306a36Sopenharmony_ci 805362306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0xffff, 805462306a36Sopenharmony_ci "%s.\n", __func__); 805562306a36Sopenharmony_ci 805662306a36Sopenharmony_ci /* 805762306a36Sopenharmony_ci * FLR just completed by PCI layer. Resume adapter 805862306a36Sopenharmony_ci */ 805962306a36Sopenharmony_ci ha->flags.eeh_busy = 0; 806062306a36Sopenharmony_ci mutex_lock(&ha->mq_lock); 806162306a36Sopenharmony_ci list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem) 806262306a36Sopenharmony_ci qpair->online = 1; 806362306a36Sopenharmony_ci mutex_unlock(&ha->mq_lock); 806462306a36Sopenharmony_ci 806562306a36Sopenharmony_ci base_vha->flags.online = 1; 806662306a36Sopenharmony_ci ha->isp_ops->abort_isp(base_vha); 806762306a36Sopenharmony_ci clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); 806862306a36Sopenharmony_ci} 806962306a36Sopenharmony_ci 807062306a36Sopenharmony_cistatic void qla2xxx_map_queues(struct Scsi_Host *shost) 807162306a36Sopenharmony_ci{ 807262306a36Sopenharmony_ci scsi_qla_host_t *vha = (scsi_qla_host_t *)shost->hostdata; 807362306a36Sopenharmony_ci struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; 807462306a36Sopenharmony_ci 807562306a36Sopenharmony_ci if (USER_CTRL_IRQ(vha->hw) || !vha->hw->mqiobase) 807662306a36Sopenharmony_ci blk_mq_map_queues(qmap); 807762306a36Sopenharmony_ci else 807862306a36Sopenharmony_ci blk_mq_pci_map_queues(qmap, vha->hw->pdev, vha->irq_offset); 807962306a36Sopenharmony_ci} 808062306a36Sopenharmony_ci 808162306a36Sopenharmony_cistruct scsi_host_template qla2xxx_driver_template = { 808262306a36Sopenharmony_ci .module = THIS_MODULE, 808362306a36Sopenharmony_ci .name = QLA2XXX_DRIVER_NAME, 808462306a36Sopenharmony_ci .queuecommand = qla2xxx_queuecommand, 808562306a36Sopenharmony_ci 808662306a36Sopenharmony_ci .eh_timed_out = fc_eh_timed_out, 808762306a36Sopenharmony_ci .eh_abort_handler = qla2xxx_eh_abort, 808862306a36Sopenharmony_ci .eh_should_retry_cmd = fc_eh_should_retry_cmd, 808962306a36Sopenharmony_ci .eh_device_reset_handler = qla2xxx_eh_device_reset, 809062306a36Sopenharmony_ci .eh_target_reset_handler = qla2xxx_eh_target_reset, 809162306a36Sopenharmony_ci .eh_bus_reset_handler = qla2xxx_eh_bus_reset, 809262306a36Sopenharmony_ci .eh_host_reset_handler = qla2xxx_eh_host_reset, 809362306a36Sopenharmony_ci 809462306a36Sopenharmony_ci .slave_configure = qla2xxx_slave_configure, 809562306a36Sopenharmony_ci 809662306a36Sopenharmony_ci .slave_alloc = qla2xxx_slave_alloc, 809762306a36Sopenharmony_ci .slave_destroy = qla2xxx_slave_destroy, 809862306a36Sopenharmony_ci .scan_finished = qla2xxx_scan_finished, 809962306a36Sopenharmony_ci .scan_start = qla2xxx_scan_start, 810062306a36Sopenharmony_ci .change_queue_depth = scsi_change_queue_depth, 810162306a36Sopenharmony_ci .map_queues = qla2xxx_map_queues, 810262306a36Sopenharmony_ci .this_id = -1, 810362306a36Sopenharmony_ci .cmd_per_lun = 3, 810462306a36Sopenharmony_ci .sg_tablesize = SG_ALL, 810562306a36Sopenharmony_ci 810662306a36Sopenharmony_ci .max_sectors = 0xFFFF, 810762306a36Sopenharmony_ci .shost_groups = qla2x00_host_groups, 810862306a36Sopenharmony_ci 810962306a36Sopenharmony_ci .supported_mode = MODE_INITIATOR, 811062306a36Sopenharmony_ci .track_queue_depth = 1, 811162306a36Sopenharmony_ci .cmd_size = sizeof(srb_t), 811262306a36Sopenharmony_ci}; 811362306a36Sopenharmony_ci 811462306a36Sopenharmony_cistatic const struct pci_error_handlers qla2xxx_err_handler = { 811562306a36Sopenharmony_ci .error_detected = qla2xxx_pci_error_detected, 811662306a36Sopenharmony_ci .mmio_enabled = qla2xxx_pci_mmio_enabled, 811762306a36Sopenharmony_ci .slot_reset = qla2xxx_pci_slot_reset, 811862306a36Sopenharmony_ci .resume = qla2xxx_pci_resume, 811962306a36Sopenharmony_ci .reset_prepare = qla_pci_reset_prepare, 812062306a36Sopenharmony_ci .reset_done = qla_pci_reset_done, 812162306a36Sopenharmony_ci}; 812262306a36Sopenharmony_ci 812362306a36Sopenharmony_cistatic struct pci_device_id qla2xxx_pci_tbl[] = { 812462306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) }, 812562306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) }, 812662306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2300) }, 812762306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2312) }, 812862306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2322) }, 812962306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6312) }, 813062306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6322) }, 813162306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2422) }, 813262306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) }, 813362306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8432) }, 813462306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) }, 813562306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) }, 813662306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) }, 813762306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2031) }, 813862306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8001) }, 813962306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8021) }, 814062306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8031) }, 814162306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISPF001) }, 814262306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8044) }, 814362306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2071) }, 814462306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2271) }, 814562306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2261) }, 814662306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2061) }, 814762306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2081) }, 814862306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2281) }, 814962306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2089) }, 815062306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2289) }, 815162306a36Sopenharmony_ci { 0 }, 815262306a36Sopenharmony_ci}; 815362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl); 815462306a36Sopenharmony_ci 815562306a36Sopenharmony_cistatic struct pci_driver qla2xxx_pci_driver = { 815662306a36Sopenharmony_ci .name = QLA2XXX_DRIVER_NAME, 815762306a36Sopenharmony_ci .driver = { 815862306a36Sopenharmony_ci .owner = THIS_MODULE, 815962306a36Sopenharmony_ci }, 816062306a36Sopenharmony_ci .id_table = qla2xxx_pci_tbl, 816162306a36Sopenharmony_ci .probe = qla2x00_probe_one, 816262306a36Sopenharmony_ci .remove = qla2x00_remove_one, 816362306a36Sopenharmony_ci .shutdown = qla2x00_shutdown, 816462306a36Sopenharmony_ci .err_handler = &qla2xxx_err_handler, 816562306a36Sopenharmony_ci}; 816662306a36Sopenharmony_ci 816762306a36Sopenharmony_cistatic const struct file_operations apidev_fops = { 816862306a36Sopenharmony_ci .owner = THIS_MODULE, 816962306a36Sopenharmony_ci .llseek = noop_llseek, 817062306a36Sopenharmony_ci}; 817162306a36Sopenharmony_ci 817262306a36Sopenharmony_ci/** 817362306a36Sopenharmony_ci * qla2x00_module_init - Module initialization. 817462306a36Sopenharmony_ci **/ 817562306a36Sopenharmony_cistatic int __init 817662306a36Sopenharmony_ciqla2x00_module_init(void) 817762306a36Sopenharmony_ci{ 817862306a36Sopenharmony_ci int ret = 0; 817962306a36Sopenharmony_ci 818062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(cmd_a64_entry_t) != 64); 818162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(cmd_entry_t) != 64); 818262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(cont_a64_entry_t) != 64); 818362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(cont_entry_t) != 64); 818462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(init_cb_t) != 96); 818562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(mrk_entry_t) != 64); 818662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(ms_iocb_entry_t) != 64); 818762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(request_t) != 64); 818862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct abort_entry_24xx) != 64); 818962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct abort_iocb_entry_fx00) != 64); 819062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct abts_entry_24xx) != 64); 819162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct access_chip_84xx) != 64); 819262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct access_chip_rsp_84xx) != 64); 819362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cmd_bidir) != 64); 819462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cmd_nvme) != 64); 819562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cmd_type_6) != 64); 819662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cmd_type_7) != 64); 819762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cmd_type_7_fx00) != 64); 819862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cmd_type_crc_2) != 64); 819962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ct_entry_24xx) != 64); 820062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ct_fdmi1_hba_attributes) != 2604); 820162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ct_fdmi2_hba_attributes) != 4424); 820262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ct_fdmi2_port_attributes) != 4164); 820362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ct_fdmi_hba_attr) != 260); 820462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ct_fdmi_port_attr) != 260); 820562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ct_rsp_hdr) != 16); 820662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ctio_crc2_to_fw) != 64); 820762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct device_reg_24xx) != 256); 820862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct device_reg_25xxmq) != 24); 820962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct device_reg_2xxx) != 256); 821062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct device_reg_82xx) != 1288); 821162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct device_reg_fx00) != 216); 821262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct els_entry_24xx) != 64); 821362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct els_sts_entry_24xx) != 64); 821462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct fxdisc_entry_fx00) != 64); 821562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct imm_ntfy_from_isp) != 64); 821662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct init_cb_24xx) != 128); 821762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct init_cb_81xx) != 128); 821862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct logio_entry_24xx) != 64); 821962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct mbx_entry) != 64); 822062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct mid_init_cb_24xx) != 5252); 822162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct mrk_entry_24xx) != 64); 822262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct nvram_24xx) != 512); 822362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct nvram_81xx) != 512); 822462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct pt_ls4_request) != 64); 822562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct pt_ls4_rx_unsol) != 64); 822662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct purex_entry_24xx) != 64); 822762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla2100_fw_dump) != 123634); 822862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla2300_fw_dump) != 136100); 822962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla24xx_fw_dump) != 37976); 823062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla25xx_fw_dump) != 39228); 823162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla2xxx_fce_chain) != 52); 823262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla2xxx_fw_dump) != 136172); 823362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla2xxx_mq_chain) != 524); 823462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla2xxx_mqueue_chain) != 8); 823562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla2xxx_mqueue_header) != 12); 823662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla2xxx_offld_chain) != 24); 823762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla81xx_fw_dump) != 39420); 823862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla82xx_uri_data_desc) != 28); 823962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla82xx_uri_table_desc) != 32); 824062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla83xx_fw_dump) != 51196); 824162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla_fcp_prio_cfg) != FCP_PRIO_CFG_SIZE); 824262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla_fdt_layout) != 128); 824362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla_flt_header) != 8); 824462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla_flt_region) != 16); 824562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla_npiv_entry) != 24); 824662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct qla_npiv_header) != 16); 824762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct rdp_rsp_payload) != 336); 824862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct sns_cmd_pkt) != 2064); 824962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct sts_entry_24xx) != 64); 825062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct tsk_mgmt_entry) != 64); 825162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct tsk_mgmt_entry_fx00) != 64); 825262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct verify_chip_entry_84xx) != 64); 825362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct verify_chip_rsp_84xx) != 52); 825462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct vf_evfp_entry_24xx) != 56); 825562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct vp_config_entry_24xx) != 64); 825662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct vp_ctrl_entry_24xx) != 64); 825762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct vp_rpt_id_entry_24xx) != 64); 825862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(sts21_entry_t) != 64); 825962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(sts22_entry_t) != 64); 826062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(sts_cont_entry_t) != 64); 826162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(sts_entry_t) != 64); 826262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(sw_info_t) != 32); 826362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(target_id_t) != 2); 826462306a36Sopenharmony_ci 826562306a36Sopenharmony_ci qla_trace_init(); 826662306a36Sopenharmony_ci 826762306a36Sopenharmony_ci /* Allocate cache for SRBs. */ 826862306a36Sopenharmony_ci srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0, 826962306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN, NULL); 827062306a36Sopenharmony_ci if (srb_cachep == NULL) { 827162306a36Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0x0001, 827262306a36Sopenharmony_ci "Unable to allocate SRB cache...Failing load!.\n"); 827362306a36Sopenharmony_ci return -ENOMEM; 827462306a36Sopenharmony_ci } 827562306a36Sopenharmony_ci 827662306a36Sopenharmony_ci /* Initialize target kmem_cache and mem_pools */ 827762306a36Sopenharmony_ci ret = qlt_init(); 827862306a36Sopenharmony_ci if (ret < 0) { 827962306a36Sopenharmony_ci goto destroy_cache; 828062306a36Sopenharmony_ci } else if (ret > 0) { 828162306a36Sopenharmony_ci /* 828262306a36Sopenharmony_ci * If initiator mode is explictly disabled by qlt_init(), 828362306a36Sopenharmony_ci * prevent scsi_transport_fc.c:fc_scsi_scan_rport() from 828462306a36Sopenharmony_ci * performing scsi_scan_target() during LOOP UP event. 828562306a36Sopenharmony_ci */ 828662306a36Sopenharmony_ci qla2xxx_transport_functions.disable_target_scan = 1; 828762306a36Sopenharmony_ci qla2xxx_transport_vport_functions.disable_target_scan = 1; 828862306a36Sopenharmony_ci } 828962306a36Sopenharmony_ci 829062306a36Sopenharmony_ci /* Derive version string. */ 829162306a36Sopenharmony_ci strcpy(qla2x00_version_str, QLA2XXX_VERSION); 829262306a36Sopenharmony_ci if (ql2xextended_error_logging) 829362306a36Sopenharmony_ci strcat(qla2x00_version_str, "-debug"); 829462306a36Sopenharmony_ci if (ql2xextended_error_logging == 1) 829562306a36Sopenharmony_ci ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK; 829662306a36Sopenharmony_ci 829762306a36Sopenharmony_ci qla2xxx_transport_template = 829862306a36Sopenharmony_ci fc_attach_transport(&qla2xxx_transport_functions); 829962306a36Sopenharmony_ci if (!qla2xxx_transport_template) { 830062306a36Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0x0002, 830162306a36Sopenharmony_ci "fc_attach_transport failed...Failing load!.\n"); 830262306a36Sopenharmony_ci ret = -ENODEV; 830362306a36Sopenharmony_ci goto qlt_exit; 830462306a36Sopenharmony_ci } 830562306a36Sopenharmony_ci 830662306a36Sopenharmony_ci apidev_major = register_chrdev(0, QLA2XXX_APIDEV, &apidev_fops); 830762306a36Sopenharmony_ci if (apidev_major < 0) { 830862306a36Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0x0003, 830962306a36Sopenharmony_ci "Unable to register char device %s.\n", QLA2XXX_APIDEV); 831062306a36Sopenharmony_ci } 831162306a36Sopenharmony_ci 831262306a36Sopenharmony_ci qla2xxx_transport_vport_template = 831362306a36Sopenharmony_ci fc_attach_transport(&qla2xxx_transport_vport_functions); 831462306a36Sopenharmony_ci if (!qla2xxx_transport_vport_template) { 831562306a36Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0x0004, 831662306a36Sopenharmony_ci "fc_attach_transport vport failed...Failing load!.\n"); 831762306a36Sopenharmony_ci ret = -ENODEV; 831862306a36Sopenharmony_ci goto unreg_chrdev; 831962306a36Sopenharmony_ci } 832062306a36Sopenharmony_ci ql_log(ql_log_info, NULL, 0x0005, 832162306a36Sopenharmony_ci "QLogic Fibre Channel HBA Driver: %s.\n", 832262306a36Sopenharmony_ci qla2x00_version_str); 832362306a36Sopenharmony_ci ret = pci_register_driver(&qla2xxx_pci_driver); 832462306a36Sopenharmony_ci if (ret) { 832562306a36Sopenharmony_ci ql_log(ql_log_fatal, NULL, 0x0006, 832662306a36Sopenharmony_ci "pci_register_driver failed...ret=%d Failing load!.\n", 832762306a36Sopenharmony_ci ret); 832862306a36Sopenharmony_ci goto release_vport_transport; 832962306a36Sopenharmony_ci } 833062306a36Sopenharmony_ci return ret; 833162306a36Sopenharmony_ci 833262306a36Sopenharmony_cirelease_vport_transport: 833362306a36Sopenharmony_ci fc_release_transport(qla2xxx_transport_vport_template); 833462306a36Sopenharmony_ci 833562306a36Sopenharmony_ciunreg_chrdev: 833662306a36Sopenharmony_ci if (apidev_major >= 0) 833762306a36Sopenharmony_ci unregister_chrdev(apidev_major, QLA2XXX_APIDEV); 833862306a36Sopenharmony_ci fc_release_transport(qla2xxx_transport_template); 833962306a36Sopenharmony_ci 834062306a36Sopenharmony_ciqlt_exit: 834162306a36Sopenharmony_ci qlt_exit(); 834262306a36Sopenharmony_ci 834362306a36Sopenharmony_cidestroy_cache: 834462306a36Sopenharmony_ci kmem_cache_destroy(srb_cachep); 834562306a36Sopenharmony_ci 834662306a36Sopenharmony_ci qla_trace_uninit(); 834762306a36Sopenharmony_ci return ret; 834862306a36Sopenharmony_ci} 834962306a36Sopenharmony_ci 835062306a36Sopenharmony_ci/** 835162306a36Sopenharmony_ci * qla2x00_module_exit - Module cleanup. 835262306a36Sopenharmony_ci **/ 835362306a36Sopenharmony_cistatic void __exit 835462306a36Sopenharmony_ciqla2x00_module_exit(void) 835562306a36Sopenharmony_ci{ 835662306a36Sopenharmony_ci pci_unregister_driver(&qla2xxx_pci_driver); 835762306a36Sopenharmony_ci qla2x00_release_firmware(); 835862306a36Sopenharmony_ci kmem_cache_destroy(ctx_cachep); 835962306a36Sopenharmony_ci fc_release_transport(qla2xxx_transport_vport_template); 836062306a36Sopenharmony_ci if (apidev_major >= 0) 836162306a36Sopenharmony_ci unregister_chrdev(apidev_major, QLA2XXX_APIDEV); 836262306a36Sopenharmony_ci fc_release_transport(qla2xxx_transport_template); 836362306a36Sopenharmony_ci qlt_exit(); 836462306a36Sopenharmony_ci kmem_cache_destroy(srb_cachep); 836562306a36Sopenharmony_ci qla_trace_uninit(); 836662306a36Sopenharmony_ci} 836762306a36Sopenharmony_ci 836862306a36Sopenharmony_cimodule_init(qla2x00_module_init); 836962306a36Sopenharmony_cimodule_exit(qla2x00_module_exit); 837062306a36Sopenharmony_ci 837162306a36Sopenharmony_ciMODULE_AUTHOR("QLogic Corporation"); 837262306a36Sopenharmony_ciMODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver"); 837362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 837462306a36Sopenharmony_ciMODULE_FIRMWARE(FW_FILE_ISP21XX); 837562306a36Sopenharmony_ciMODULE_FIRMWARE(FW_FILE_ISP22XX); 837662306a36Sopenharmony_ciMODULE_FIRMWARE(FW_FILE_ISP2300); 837762306a36Sopenharmony_ciMODULE_FIRMWARE(FW_FILE_ISP2322); 837862306a36Sopenharmony_ciMODULE_FIRMWARE(FW_FILE_ISP24XX); 837962306a36Sopenharmony_ciMODULE_FIRMWARE(FW_FILE_ISP25XX); 8380